[
  {
    "path": ".gitignore",
    "content": "**/target\n.idea\n*.iml\nlog\n*.log\ndoc/.vuepress/dist\ndoc/node_modules\n备忘.md\n.classpath\n.factorypath\n.vscode\n.settings\n.project\n.DS_Store\n.settings\n.project\nlaunch.json\nwebsite\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change Log\n## latest\n- Fix 业务日志中如果获取不到字段值对应的中文名称则返回字段名本身，代替之前的null\n- Issue IN查询增加使用数组作为参数\n- Change 调整按钮样式\n- Issue BaseService增加缓存支持\n- Issue BaseService添加count方法\n- Issue 添加实现性质功能：使用leaflet提供gis服务\n- Issue 添加实验性质功能：使用actuator对应用进行监控\n- Issue 针对ajax-object.js返回的异常信息统一处理\n- Issue 代码生成功能针对列表页面生成根据字段排序功能\n- Issue service层封装根据sql和条件查询数据列表功能\n\n## Fixes\n- Fix 更新缓存的时候连带更新常量工具类中使用的本地(TimeCacheMap)缓存\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019-present enilu.cn\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n\n"
  },
  {
    "path": "README.md",
    "content": "\nEnglish | [简体中文](./README.zh-CN.md)\n## Introduction\n\n[materail-admin](https://github.com/enilu/material-admin) is a Materail Design Admin Framework based on [Spring Boot2](https://spring.io/projects/spring-boot/) and [Bootstrap](https://www.bootcss.com/). \nIt includes basic functions commonly used in the background of rights management, configuration management, organization, users, scheduled tasks, and message management. Refining a typical business model can help you quickly build an enterprise back-end product system.\n\n- [Online Demo](http://material.enilu.cn)\n- Separate versions of the front and rear ends are also provided.[web-flash](http://enilu.github.com/web-flash) \n \n## Preparation\n\n- Download JAVA IDE :Eclipse or Intellij IDEA\n- Install the Lombook plugin in the IDE.\n- Install JDK1.8 ,MySQL5.5+，Maven\n\n**Welcome to make an issue or pr**\n\n \n## Features\n- Department management\n- Account management\n- Role management\n- Menu management\n- Permission managemenet\n- Configuration \n- Dict managemenet\n- Schedule \n- log  \n\n## Getting started\n\n```\n# create dabase in mysql:\nCREATE DATABASE IF NOT EXISTS material DEFAULT CHARSET utf8 COLLATE utf8_general_ci; \nCREATE USER 'material'@'%' IDENTIFIED BY 'material123';\nGRANT ALL privileges ON material.* TO 'material'@'%';\nflush privileges;\n\n# clone the project\ngit clone https://github.com/enilu/material-admin.git\n# enter the project directory\ncd material-admin\n# build and package \nmvn package \n# run the project\n java -jar target/material.jar\n\n# open the browser and enter:\nhttp://localhost:8085\nuser/password:admin/admin\n\n``` \n## Online Demo\n\n[http://material.enilu.cn](http://material.enilu.cn)\n\n## 交流\n- Bugs: [Issues](https://github.com/enilu/material-admin/issues/new)\n- QQ:752844606\n- wechat:myenilu\n- Gitter: [Gitter channel](https://gitter.im/springboot-material-admin/community)\n\n## License\n\n[MIT](https://github.com/enilu/material-admin/blob/master/LICENSE)\n\nCopyright (c) 2017-present enilu\n"
  },
  {
    "path": "README.zh-CN.md",
    "content": "[English](./README.md) | 简体中文\n## 简介\n[material-admin](https://gitee.com/enilu/material-admin) 是一个通用的基础的后台管理系统，它基于[Spring Boot2](https://spring.io/projects/spring-boot/) 和 [Bootstrap](https://www.bootcss.com/)实现。它使用了当下流行的java 框架Spring Boot和基于Material Design风格的组件构建。内置了权限管理，配置管理，组织机构，用户，定时任务，消息管理等后台常用的基础功能。提炼了典型的业务模型，可以帮助你快速搭建企业级中后台产品系统。\n\n- [在线预览](http://material.enilu.cn) \n- [gitee地址](https://gitee.com/enilu/material-admin)\n- 另提供前后端分离版本[web-flash](http://enilu.gitee.io/web-flash)\n \n## 准备\n\n你需要下载JAVA IDE :Eclipse或者Intellij IDEA\n\n你需要在开发环境中安装Lombok插件，用以生成java entity的set get方法。\n\n你需要在本地安装JDK1.8 ,MySQL5.5+，Maven\n\n\n**如有问题请，欢迎 issue 和 pr**\n\n\n## 技术选型\n\n- 核心框架：spring boot\n- 数据库层：spring data jpa\n- 安全框架：Shiro\n- 数据库连接池：Druid\n- 缓存：Ehcache\n- 前端：Beetl模版+Bootstrap\n \n## 功能\n- 部门管理\n- 用户管理\n- 角色管理\n- 菜单管理\n- 权限分配\n- 参数管理\n- 数据字典\n- 定时任务\n- 业务日志\n- 登录日志\n\n## 开发\n\n- 克隆本项目\n- 导入idea或者eclipse，确保开发工具安装了lombok插件，如果不了解该插件，请自行搜索\n- 创建数据库： \n    ```sql\n    CREATE DATABASE IF NOT EXISTS material DEFAULT CHARSET utf8 COLLATE utf8_general_ci; \n    CREATE USER 'material'@'%' IDENTIFIED BY 'material@123ABC';\n    GRANT ALL privileges ON material.* TO 'material'@'%';\n    flush privileges;\n    \n    ```\n- 更改配置文件中相应数据库配置\n- material-manage启动的时候会自动创建表并导入src/main/resources/import.sql到数据库中，无需开发手动初始化表结构\n- 启动material-manage中的类：cn.enilu.material.admin.AdminApplication\n- 访问 http://localhost:8085，   \n- 登录，用户名密码:admin/admin\n\n \n## Online Demo\n\n[在线 Demo](http://material.enilu.cn)\n\n## 文档\n[https://enilu.gitee.io/material-admin](https://enilu.gitee.io/material-admin)\n\n## 交流\n- 关注公众号：嗨客帝国，点击web-flash菜单进群交流。\n\n![公众号二维码](doc/img/haike.jpg)\n- 论坛提问\n[http://bbs.enilu.cn](http://bbs.enilu.cn)\n- Gitter: [Gitter channel](https://gitter.im/springboot-material-admin/community)\n\n## License\n\n[MIT](https://github.com/enilu/material-admin/blob/master/LICENSE)\n\nCopyright (c) 2017-present enilu\n"
  },
  {
    "path": "doc/.vuepress/config.js",
    "content": "module.exports = {\n    title: 'Material Admin',\n    description: '使用Material Admin快速构建web应用程序',\n    base: '/material-admin/',\n    head: [\n        ['link', { rel: 'shortcut icon', type: \"image/x-icon\", href: './favicon.ico' }]\n    ],\n    evergreen: true,\n    editLinkText:'在 GitHub 上编辑此页',\n    port: 8081,\n    ga: 'UA-71886989-13',\n    themeConfig: {\n        repo: 'enilu/material-admin',\n        docsDir: 'docs',\n        editLinks: true,\n        editLinkText: '编辑此页面！',\n        nav: [\n            {text: '文档', link: '/'},\n            {text: '公告', link: 'https://www.oschina.net/p/material-admin'},\n            // {text: '捐赠',link:'/donate'},\n            {text: '资源',link:'/resource'},\n            {text: '周边',\n                items:[\n                    {text: '代码生成',link:'/ecosystem/code-generator'},\n                    {text: '数据库文档生成',link:'/ecosystem/database-doc-generator'},\n                ]\n            },\n            {text: '码云',link:'https://gitee.com/enilu/material-admin'},\n\n\n        ],\n        sidebar: [\n            {\n                title: '基本准备',\n                collapsable: false,\n                children: [\n                    '/base/jdkAndMaven',\n                    '/base/modules'\n                ]\n            },\n\n            {\n                title: '10分钟将本项目跑起来',\n                collapsable: false,\n                children: [\n                    '/quickstart/quickstart',\n                    '/quickstart/clone',\n                    '/quickstart/initDb',\n                    '/quickstart/config',\n                    '/quickstart/startup'\n                ]\n            },\n            {\n                title: '开发第一个功能',\n                collapsable: false,\n                children: [\n                    '/helloworld/crud',\n                    '/helloworld/create_table',\n                    '/helloworld/base',\n                    '/helloworld/list',\n                    '/helloworld/add',\n                    '/helloworld/delete',\n                    '/helloworld/update',\n                    '/helloworld/menuAndPermission'\n                ]\n            },\n            {\n                title: '基本功能介绍',\n                collapsable: false,\n                children: [\n                    '/feature/modules',\n                    '/feature/menu',\n                    '/feature/dict',\n                    '/feature/log',\n                    '/feature/monitor'\n                    ]\n            },{\n                title: '进阶',\n                collapsable: false,\n                children: [\n                    '/action/sqlite',\n                    '/action/cache',\n                    '/action/task',\n                    '/action/jpaauditing.md'\n\n                ]\n            },{\n                title: '其他',\n                collapsable: false,\n                children:[\n                    '/other/faq'\n                ]\n            }\n        ]\n\n    }\n}\n"
  },
  {
    "path": "doc/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: 快速开始 →\nactionLink: /base/preface\nfooter: MIT Licensed | Copyright © 2018-present enilu\n---\n\n<div style=\"text-align: center\">\n  <Bit/>\n</div>\n\n<div class=\"features\">\n  <div class=\"feature\">\n    <h2>简单快捷</h2>\n    <p>基于spring boot快速构建web应用程序，开发，部署，维护方便快捷。</p>\n  </div>\n  <div class=\"feature\">\n    <h2>功能完善</h2>\n    <p>封装完善的后台管理功能，包括用户、部门、权限、日志、字典、等基础功能。</p>\n  </div>\n  <div class=\"feature\">\n    <h2>现代化界面</h2>\n    <p>使用Bootstrap和Material Design风格的前端框架做展示，拥有良好的使用体验。</p>\n  </div>\n  <div class=\"feature\">\n      <h2>最新技术栈</h2>\n      <p>使用spring boot+jpa构建后端服务，使用Beetl+Bootstrap构建页面。</p>\n   </div>\n   <div class=\"feature\">\n      <h2>成熟方案</h2>\n      <p>基于该系统已经上线了很多大大小小的后管系统，方案成熟，坑少。</p>\n   </div>\n  <div class=\"feature\">\n     <h2>文档完善</h2>\n     <p>完善的文档和使用手册，帮助初级用户也可以快速构建自己的系统。</p>\n  </div>\n</div>\n"
  },
  {
    "path": "doc/action/cache.md",
    "content": "# 缓存的应用\n对缓存的应用几乎成了系统的标配，material-admin中也有对缓存的应用。\n本章节介绍系统中缓存的设计和用法\n\n## 底层缓存支持\n- material-admin为了给上层应用提供缓存支持，提供了CacheDao接口，CacheDao接口负责和底层的缓存组件打交道，比如Ehcache、Redis、ssdb，甚至自己实现的缓存系统皆可。\n- 在material-admin中针对CacheDao的默认实现类是EhcacheDao，没错material-admin默认使用的缓存组件就是Ehcache。\n- 针对ehcache的具体用法实现，可以查看EhcacheDao的实现和ehcache.xml配置，这里不再赘述。\n\n## 缓存应用\n\n目前material-admin中有两种形式的缓存应用方式：\n- 手动管理缓存，比如针对系统参数和字典数据的管理维护，具体用法也很简单，分为以下几个步骤\n    - 系统启动的时候通过CacheListener将数据加载到缓存\n    - 具体的功能中使用的时候注入对应的缓存类使用即可。\n    - 数据更新的时候重新刷新缓存\n- 通过注解自动维护缓存。\n    - 主要在service中通过@Cacheable 和 @CacheEvict 注解来维护缓存，具体可参考BaseService中的用法\n\n下面是一些用法的关键代码：\n- CacheListner 缓存监听器，启动的时候将数据从数据库加载到缓存中\n```java\n@Component\npublic class CacheListener implements CommandLineRunner {\n    @Autowired\n    private ConfigCache configCache;\n    @Autowired\n    private DictCache dictCache;\n    public void loadCache() {\n        configCache.cache();\n        dictCache.cache();\n    }\n\n    @Override\n    public void run(String... strings) throws Exception {\n        Thread thread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                loadCache();\n            }\n        });\n        thread.start();\n    }\n}\n```\n- Cache顶级缓存接口，定义了缓存基本的三个方法\n```java\n\npublic interface Cache {\n\tvoid cache();\n\tObject get(String key);\n\tvoid set(String key, Object val);\n}\n```\n- Service中的缓存的使用\n```java\n   @CacheEvict(value = Cache.APPLICATION ,key = \"#root.targetClass.simpleName+':'+#id\")\n    public void delete(ID id) {\n        dao.deleteById(id);\n    }\n    @Cacheable(value = Cache.APPLICATION ,key = \"#root.targetClass.simpleName+':'+#id\")\n    public T get(ID id) {\n        return  dao.findById(id).get();\n    }\n```\n\n## 备注\n**为什么选用Ehcahce**\n- 目前最流行的缓存中间件非Redis莫属。而且我司大多数产品和项目也是使用redis，但是考虑到Ehcahe的开箱即用（直接整合到项目中，不需要部署专门的缓存服务），所以在material-admin\n默认支持Ehcache，\n- 想用Redis也很简单，参考EhcacheDao实现一个RedisCacheDao即可。\n\n**当数据库中数据变化的时候缓存中的数据如何做到更新**\n- material-admin中的做法简单明了，目前针对全局参数Cfg和字典Dict表的进行更新操作的时候分别调用ConfigCache和DictCache的cache()重新将数据库中的数据加载到缓存中.\n- 也可以通过@CacheEvict注解来刷新缓存\n- 具体生产中，也许会有很多产品都是微服务架构，这时候推荐使用zookeeper来做配置变更的管理，感兴趣的同学可以发issue或者在qq群中讨论，本文档不再赘述\n "
  },
  {
    "path": "doc/action/jpaauditing.md",
    "content": "# 使用注解自动保存数据的维护时间和修改者\n\n\n通常来说，我们都有这样的需求：我需要知道库中的数据是由谁创建，什么时候创建，最后一次修改时间是什么时候，最后一次修改人是谁。\n\n在Spring jpa中可以通过在实体bean的属性或者方法上添加以下注解来实现上述需求@CreatedDate、@CreatedBy、@LastModifiedDate、@LastModifiedBy。\n\n- @CreatedDate 表示该字段为创建时间时间字段，在这个实体被insert的时候，会设置值\n- @CreatedBy 表示该字段为创建人，在这个实体被insert的时候，会设置值\n- @LastModifiedDate 最后修改时间 实体被update的时候会设置\n- @LastModifiedBy  最后修改人 实体被update的时候会设置\n\n## 使用方式\n\n### 实体类添加注解\n\n- 首先在实体中对应的字段加上上述4个注解\n- 在material-admin中我们提取了一个基础实体类BaseEntity，并将对应的字段添加上述4个注解,所有需要记录维护信息的表对应的实体都集成该类\n```java\nimport org.springframework.data.annotation.CreatedBy;\nimport org.springframework.data.annotation.CreatedDate;\nimport org.springframework.data.annotation.LastModifiedBy;\nimport org.springframework.data.annotation.LastModifiedDate;\nimport javax.persistence.Column;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.MappedSuperclass;\nimport java.io.Serializable;\nimport java.util.Date;\n@MappedSuperclass\n@Data\npublic abstract class BaseEntity implements Serializable {\n    @Id\n    @GeneratedValue\n    private Long id;\n    @CreatedDate\n    @Column(name = \"create_time\",columnDefinition=\"DATETIME COMMENT '创建时间/注册时间'\")\n    private Date createTime;\n    @Column(name = \"create_by\",columnDefinition=\"bigint COMMENT '创建人'\")\n    @CreatedBy\n    private Long createBy;\n    @LastModifiedDate\n    @Column(name = \"modify_time\",columnDefinition=\"DATETIME COMMENT '最后更新时间'\")\n    private Date modifyTime;\n    @LastModifiedBy\n    @Column(name = \"modify_by\",columnDefinition=\"bigint COMMENT '最后更新人'\")\n    private Long modifyBy;\n}\n```\n\n### 实现AuditorAware接口返回操作人员的id\n配置完上述4个注解后，在jpa.save方法被调用的时候，时间字段会自动设置并插入数据库，但是CreatedBy和LastModifiedBy并没有赋值\n这两个信息需要实现AuditorAware接口来返回操作人员的id\n- 首先需要在项目启动类添加@EnableJpaAuditing 注解来启用审计功能\n```java\n@SpringBootApplication\n@EnableJpaAuditing\npublic class AdminApplication extends WebMvcConfigurerAdapter {\n //省略\n}\n```\n- 然后实现AuditorAware接口返回操作人员的id\n```java\n@Configuration\npublic class UserIDAuditorConfig implements AuditorAware<Long> {\n    @Override\n    public Optional<Long> getCurrentAuditor() {\n        ShiroUser shiroUser = ShiroKit.getUser();\n        if(shiroUser!=null){\n            return Optional.of(shiroUser.getId());\n        }\n        return Optional.of(Constants.SYSTEM_USER_ID);\n    }\n}\n```\n"
  },
  {
    "path": "doc/action/sqlite.md",
    "content": "# 将数据库切换为sqlite\n\nsqlite和mysql兼容性比较好，使用master分支做很小的调整就可以支持sqlite。\n\n下面介绍如何将master分支经过简单调整将底层数据库从mysql切换为sqlite。\n\n## 数据库替换\n这节描述如何将mysql替换为sqlite。\n\n在本系统中使用的mysql建表语句中，只需要下面字段类型调整下就可以用在sqlite中。\n- 将bigint类型替换为INTEGER\n- 将verchar类型替换为TEXT\n- 将date、datetime类型皆替换为TEXT或INTEGER，我在我司的产品中都是替换为text类型，这样也不用考虑日期格式化的问题。\n将更改过的语句在mysql中执行即可。\n\n## entity模块调整\n\n- 将实体类中所有日期类型的字段替换为String，当然你也可以直接继续用Date（这样的话，sqlite的对应字段类型必须为INTGER）\n\n没错，只需要调整日期类型的属性即可，甚至也不需要调整（如果数据库中对应字段使用INTEGER的话）\n\n## 业务代码调整\n\n 如果在上一小节，你将日期类型调整为String，那么在涉及到所有为entity设置日期属性的时候用DateUtil.getTime()代替new Date()方法即可，\n DateUtil.getTime() 方法会返回当前日期的yyyy-MM-dd HH:mm:ss格式\n \n 大功告成，是不是很简单！\n\n\n\n## 使用sqlite常见问题\n\n### No Dialect mapping for JDBC type: 0\n```\norg.springframework.orm.jpa.JpaSystemException: No Dialect mapping for JDBC type: 0; nested exception is org.hibernate.MappingException: No Dialect mapping for JDBC type: 0\n```\n出现这个问题的原因是：\n**返回值返回类型为Null,hibernate不支持SQLite的空值类型，所以需要我们自定义映射关系**\n\n- 解决方法\n    - 自定义SQLiteDialect\n    ```java\n    package cn.enilu.material.config;\n    import java.sql.Types;\n    public class SQLiteDialect extends com.enigmabridge.hibernate.dialect.SQLiteDialect {\n        public SQLiteDialect(){\n            super();\n            registerHibernateType(Types.NULL,\"null\");\n        }\n    }\n    ```\n    - 配置该方言\n    ```properties\n    spring.jpa.properties.hibernate.dialect=cn.enilu.material.config.SQLiteDialect\n    ```\n\n**参考资料:** \n- https://kevin12.iteye.com/blog/1768258\n- https://stackoverflow.com/questions/10719117/sqlite-no-dialect-mapping-for-jdbc-type-0-hibernate\n"
  },
  {
    "path": "doc/action/task.md",
    "content": "# 定时任务管理\n这两年做的项目和产品几乎多有定时任务管理的需求。\n常用的场景有：\n- 定时给用户发送一些消息\n- 定时进行一些报表的计算\n- 定时去指定的接口get一些数据\n- 定时降一些报表发送到指定的邮箱\n\n当然还有很多，没有必要一一列举\n\n## 需求\n\n定时任务的需求通常是这样的\n- 1 需要添加一个定时任务，做一些事情。但是什么时候做要我自己配置，而且还想配置一些参数进去，比如我想定时给指定的email发送邮件.\n- 2 可以临时禁用一个任务。\n- 3 看定时任务执行的历史日志。\n\n## 具体用法\nmaterial-admin对定时任务管理功能的实现如下。\n\n## 表结构\nmaterial-admin提供了两个表：t_sys_task（任务）和t_sys_task_log(任务执行日志)\n\n- t_sys_task\n```sql\nCREATE TABLE `t_sys_task` (\n  `id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `name` varchar(50) DEFAULT NULL COMMENT '任务名',\n  `job_group` varchar(50) DEFAULT NULL COMMENT '任务组',\n  `job_class` varchar(255) DEFAULT NULL COMMENT '执行类',\n  `note` varchar(255) DEFAULT NULL COMMENT '任务说明',\n  `cron` varchar(50) DEFAULT NULL COMMENT '定时规则',\n  `data` text COMMENT '执行参数',\n  `exec_at` datetime DEFAULT NULL COMMENT '执行时间',\n  `exec_result` text COMMENT '执行结果',\n  `disabled` tinyint(1) DEFAULT NULL COMMENT '是否禁用',\n  `createtime` datetime DEFAULT NULL,\n  `creator` bigint(20) DEFAULT NULL,\n  `concurrent` tinyint(4) DEFAULT '0' COMMENT '是否允许并发',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; \n```\n- t_sys_task_log\n\n```sql\nCREATE TABLE `t_sys_task_log` (\n  `id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `name` varchar(50) DEFAULT NULL COMMENT '任务名',\n  `exec_at` datetime DEFAULT NULL COMMENT '执行时间',\n  `exec_success` int(11) DEFAULT NULL COMMENT '执行结果（成功:1、失败:0)',\n  `job_exception` varchar(255) DEFAULT NULL COMMENT '抛出异常',\n  `id_task` bigint(20) DEFAULT NULL,\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; \n```\n\n### 创建一个定时任务类\n\n比如我创建一个测试任务类\n```java\npackage cn.enilu.material.service.task.job;\nimport cn.enilu.material.service.task.JobExecuter;\nimport com.alibaba.fastjson.JSON;\nimport org.springframework.stereotype.Component;\n@Component\npublic class HelloJob extends JobExecuter {\n    @Override\n    public void execute(Map<String, Object> dataMap) throws Exception {\n        System.out.println(\"输出配置参数如下 :\"+JSON.toJSONString(dataMap));\n        System.out.println(\"这里可以编写任意其他业务逻辑\");\n    }\n}\n\n```\n\n### 页面配置一个定时任务\n在任务管理页面可以增上改查一个定时任务，还可以禁用、启用定时任务\n\n- 添加定时任务\n![task-add](../img/action/task_add.png)\n\n- 定时任务列表\n![task-list](../img/action/task_list.png)\n- 查看定时任务执行历史日志\n![task-log](../img/action/task_log.png)\n\n"
  },
  {
    "path": "doc/base/jdkAndMaven.md",
    "content": "# 开发前必读\n本章介绍本书所需要的一些准备工作. 请确保把各部分的准备工作完成\n\n本文档基于Intellij IDEA,Mysql,Maven，JDK8这四个基本工具，\n当然你也可以用Eclipse开发工具。\n\n**Jdk**\n\n- 请选用当前最新的版本,根据平台选用X64或X86版本的JDK8,并妥善安装\n\n**MySQL**\n\n- [Mysql官网](https://dev.mysql.com/)\n- [下载页面](https://dev.mysql.com/downloads/), 选用5.6以上系列的版本\n- 妥善安装,并配置账号密码\n\n\n**Intellij IDEA**\n- [Intellij IDEA官网](https://www.jetbrains.com/idea/)\n- [下载页面](https://www.jetbrains.com/idea/download/)\n- 请自行下载安装合适版本的IDEA（或者eclipse）\n\n**Lombok**\n- Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具，通过使用对应的注解，可以在编译源码的时候生成对应的方法。\n- 本系统用通过给实体类增加@Data注解让给实体类自动生成setter，getter方法。\n- 开发之前需要安装开发工具对应的Lombok插件\n- 添加新的实体的时候要再类名上增加@Data注解。\n\n**Maven**\n-[下载页面](http://maven.apache.org/download.cgi)\n\n"
  },
  {
    "path": "doc/base/modules.md",
    "content": "# 基本包结构\n\n本节详细说明本项目的基本目录结构\n\n## material-admin模块\n\nmaterial-admin包含3个核心模块：\n- material-core 项目核心模块，包括实体层，dao层，service层，以及各种工具类\n- material-generator 代码生成模块，配合IDEA Intellij的代码生成插件：webflash-generator可以提高开发效率\n- material-manage 项目web模块，包含项目页面内容，controller层 \n\n其中material-manage是一个java web模块\n其他都为java se模块，\n"
  },
  {
    "path": "doc/base/preface.md",
    "content": "# 前言\n\n\n本文档以向导的方式引导用户使用material-admin系统做二次开发，\nmaterial-admin项目本身有readme文件，如果你有使用spring boot的和beetl的经验，那么基本上你是用不上本文档了，\n有什么问题直接看代码即可。大多数功能都可以参考代码，即使找不到的google和百度也能帮到你。\n\n但是考虑到有的开发者可能初次使用上述组件，有的甚至刚接触java不久，那么本文当将引导你一步步使用本系统搭建一个后台管理系统，并做二次开发。\n \n\n## 简介\n[materail-admin](https://github.com/enilu/material-admin) 是一个通用的基础的后台管理系统，它基于[Spring Boot2](https://spring.io/projects/spring-boot/) 和 [Bootstrap](https://www.bootcss.com/)实现。它使用了当下流行的java 框架Spring Boot和基于Materail Design风格的组件构建。内置了权限管理，配置管理，组织机构，用户，定时任务，消息管理等后台常用的基础功能。提炼了典型的业务模型，可以帮助你快速搭建企业级中后台产品系统。\n\n- [在线预览](http://material.enilu.cn) \n- [gitee地址](https://gitee.com/enilu/material-admin)\n \n## 准备\n\n你需要下载JAVA IDE :Eclipse或者Intellij IDEA\n\n你需要在开发环境中安装Lombook插件，用以生成java entity的set get方法。\n\n你需要在本地安装JDK1.8 ,MySQL5.5+，Maven\n\n\n**如有问题请，欢迎 issue 和 pr**\n\n\n## 技术选型\n\n- 核心框架：spring boot\n- 数据库层：spring data jpa\n- 安全框架：Shiro\n- 数据库连接池：Druid\n- 缓存：Ehcache\n- 前端：Beetl模版+Bootstrap\n \n## 功能\n- 部门管理\n- 用户管理\n- 角色管理\n- 菜单管理\n- 权限分配\n- 参数管理\n- 数据字典\n- 定时任务\n- 业务日志\n- 登录日志\n\n## 开发\n\n- 克隆本项目\n- 导入idea或者eclipse，确保开发工具安装了lombok插件，如果不了解该插件，请自行搜索\n- 创建数据库： \n    ```sql\n    CREATE DATABASE IF NOT EXISTS material DEFAULT CHARSET utf8 COLLATE utf8_general_ci; \n    CREATE USER 'material'@'%' IDENTIFIED BY 'material123';\n    GRANT ALL privileges ON material.* TO 'material'@'%';\n    flush privileges;\n    \n    ```\n- 更改配置文件中相应数据库配置\n- material-manage启动的时候会自动创建表并导入src/main/resources/import.sql到数据库中，无需开发手动初始化表结构\n- 启动material-manage中的类：cn.enilu.material.admin.AdminApplication\n- 访问 http://localhost:8085，   \n- 登录，用户名密码:admin/admin\n\n \n## Online Demo\n\n[在线 Demo](http://material.enilu.cn)\n\n## License\n\n[MIT](https://github.com/enilu/material-admin/blob/master/LICENSE)\n\nCopyright (c) 2017-present enilu\n\n\n## 交流\n- Bugs: [Issues](https://github.com/enilu/material-admin/issues/new)\n- QQ: 欢迎加入qq交流群 752844606\n- 微信群: 请添加myenilu好友后入群，添加备注：material-admin\n- Gitter: [Gitter channel](https://gitter.im/material-admin/community) \n"
  },
  {
    "path": "doc/config/application.md",
    "content": "# application配置\n\n完善中..."
  },
  {
    "path": "doc/config/beetl.md",
    "content": "# beetl模板配置\n\n完善中..."
  },
  {
    "path": "doc/config/ehcache.md",
    "content": "# ehcache缓存配置\n\n完善中..."
  },
  {
    "path": "doc/config/logback.md",
    "content": "# 日志输出配置\n\n完善中..."
  },
  {
    "path": "doc/config/shiro.md",
    "content": "# shiro权限配置\n\n完善中..."
  },
  {
    "path": "doc/config/swagger.md",
    "content": "# swagger在线文档配置\n\n完善中..."
  },
  {
    "path": "doc/donate.md",
    "content": "\n::: tip Donate\n如果你觉得这个项目帮助到了你，你可以帮作者买一杯果汁表示鼓励\n:::\n\n<img src=\"./img/donate.jpg\" width = \"600\"     align=center />\n"
  },
  {
    "path": "doc/ecosystem/code-generator.md",
    "content": "# 代码生成\n\n## 用法\n- 在material-core/pom.xml中添加依赖\n```xml\n        <dependency>\n            <groupId>cn.enilu</groupId>\n            <artifactId>material-generator</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n```\n- 下载intellij代码生成插件，在插件中心搜索并安装插件:webflash-generator\n\n- 写好实体类，例如：\n```java\npackage cn.enilu.material.bean.entity.test;\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\n \n@Entity(name=\"t_test_boy\")\n@Table(appliesTo = \"t_test_boy\",comment = \"男孩\")\n@Data\n\npublic class Boy extends BaseEntity {\n    @Column(columnDefinition = \"VARCHAR(32) COMMENT '姓名'\")\n    private String name;\n    @Column(columnDefinition = \"INT COMMENT '年龄'\")\n    private Integer age;\n    @Column(columnDefinition = \"VARCHAR(12) COMMENT '生日'\")\n    private String birthday;\n    @Column(name = \"has_girl_friend\",columnDefinition = \"TINYINT COMMENT '是否有女朋友'\")\n    private Boolean hasGirFriend;\n}\n\n``` \n- 上面实体类注意事项\n    - @Table注解要使用org.hibernate.annotations.Table 不要使用javax.persistence.Table\n    - @Table注解 必须配置表名(applyiesTo)和注释(comment)\n    - @Column注解必须配置columnDefinition来表述列信息(英文全部大写)：包括类型,注释COMMENT\n    - 实体类必须继承BaseEntity\n- 实体类准备好了后,打开实体类，右键点击“Generator\"-->\"web-flash-mvc\"，弹出如下图所示对话框\n![code-generator](./doc/code-generate.jpg)    \n**注意**不用更改对话框中的配置(大部分没有什么作用)\n- 运行生成代码后，将会生成controller,service,repository，以及对应的增上改查页面和js,以TestBoy为例,生成的代码如下所示：\n![generate-result](./doc/generate-result.png)\n- 代码生成后，在系统中配置对应的菜单和权限，即可使用\n![菜单配置](./doc/menu.png)\n\n![权限配置](./doc/role.png)\n\n![功能预览](./doc/boy-list.png)\n\n"
  },
  {
    "path": "doc/ecosystem/database-doc-generator.md",
    "content": "# 数据库文档生成器\n\n- 这是一个简单的小工具，可以根据数据库表结构生成数据库设计文档（格式包括markdown，html，word)，支持数据库（MySQL,Oracle,PostgreSQL)\n- 如果你嫌PowerDesigner太重，那么可以试试该工具。\n- 你可以下载[release](https://github.com/enilu/database-doc-generator/releases/tag/1.0)包来或者下载[源代码](https://github.com/enilu/database-doc-generator)来使用。\n- 如果使用源代码，需要先克隆该项目后运行mvn package打包，然后运行发布包中的bin/start.bat\n- 运行程序后按照下面提示输入对应数据库参数：\n\n```bash\nchoose database:\n1:mysql\n2:oracle\n3:PostgreSQL\nSelect the appropriate numbers choose database type\n(Enter 'c' to cancel): 3\ninput database name:\ngunslite\ninput host:\nlocalhost\ninput port:\n5432\ninput username:\nenilu\ninput password:\n123456\n\n```\n- 输入完成后回车，即可生成数据库文档目录${dbname}-doc,目录中文档以markdown文件为载体：\n\n![doc](./doc/doc.jpg)\n\n- 确保安装了gitbook后，进入上述文件目录的命令行窗口运行：gitbook serve\n```bash\nE:\\\\database-doc-generator-20181006100721\\material-admin-doc>gitbook serve\nopenssl config failed: error:02001003:system library:fopen:No such process\nLive reload server started on port: 35729\nPress CTRL+C to quit ...\n\ninfo: 7 plugins are installed\ninfo: loading plugin \"livereload\"... OK\ninfo: loading plugin \"highlight\"... OK\ninfo: loading plugin \"search\"... OK\ninfo: loading plugin \"lunr\"... OK\ninfo: loading plugin \"sharing\"... OK\ninfo: loading plugin \"fontsettings\"... OK\ninfo: loading plugin \"theme-default\"... OK\ninfo: found 15 pages\ninfo: found 0 asset files\ninfo: >> generation finished with success in 1.6s !\n\nStarting server ...\nServing book on http://localhost:4000\n```\n- 访问 http://localhost:4000，即可在线查看数据库文档\n\n![summary](./doc/summary.jpg)\n\n![table](./doc/table.jpg)\n\n- 另外还可以生成word文档哦;虽然有点简陋:\n![word](./doc/word.jpg)\n"
  },
  {
    "path": "doc/feature/dict.md",
    "content": "# 字典管理\n\n该模块提供了对各种枚举数据进行维护的功能。\n\n![dict](./img/dict.jpg)\n\n后台中常量工厂ConstantFactory封装了的对字典的常规功能。\n\n## 根据名称获取其所有字典列表\n\n使用场景，比如页面查询表单中需要一个联系人关系的下拉框来所搜索，具体用法为：\n  \n```html\n      <#select id=\"account\" name=\"我方账户\" >\n            @for(dict in constant.getDicts('学历类型')){\n            <option value=\"${dict.value}\" }>${dict.name}</option>\n              @}\n      </#select>\n```\n    \n\n## 根据字典id获取字典名称\n\n数据库中存的是字典id，但是页面展示需要具体的值\n\n```java\nString degreeName = ConstantFactory.me().findByPnameAndCode(\"学历类型\",1).getName();\nmodel.addAttribute('degreeName',degreeName);\n```\n\n\n"
  },
  {
    "path": "doc/feature/log.md",
    "content": "# 日志管理\n日志管理包括两方面：\n一个是后台用户登录日志的查看\n一个是业务日志查看，业务日志内容主要包含两方面：系统产生的异常和用户操作日志。\n\n\n\n## 登录日志\n用户登录系统和退出系统的时候会调用LogTaskFactory记录相关日志，并在“登录日志”页面进行展示。\n\n![loginLog](./img/loginLog.jpg)\n\n## 业务日志\n\n业务日志包含异常日志和业务操作日志两大类日志收集、保存和展示。\n\n### 异常日志\n\n系统提供了异常处理类：GlobalExceptionHandler 来对系统各种异常进行统一收集保存。\n该类提供了九个方法来分别对9中常见的异常类型进行收集保存，如果开发者自己有特殊需求需要对其他异常类型处理。，可以通过新增处理方式来对新的异常进行收集。\n\n\n### 业务操作日志\n\n系统提供了通过注解的形式可以方便的添加业务操作日志，比如在新增部门的是增加业务日志通过如下方式：\n\n在DeptController的新增部门方法增加注解：\n\n```java\n    /**\n     * 新增部门\n     */\n    @BussinessLog(value = \"添加部门\", key = \"simplename\", dict = DeptDict.class)\n    @RequestMapping(value = \"/add\")\n    @Permission\n    @ResponseBody\n    public Object add(Dept dept) {\n        if (ToolUtil.isOneEmpty(dept, dept.getSimplename())) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        //完善pids,根据pid拿到pid的pids\n        deptSetPids(dept);\n        return this.deptRepository.save(dept);\n    }\n```\n\n具体的实现逻辑感兴趣的同学可以自行通过注解类：BusinessLog进行跟进查看。"
  },
  {
    "path": "doc/feature/menu.md",
    "content": "# 菜单管理\n\n菜单管理包含两部分：一个是左侧菜单树的维护，一个是页面操作功能（主要是按钮）的维护。\n不管是左侧菜单还是按钮，都需要在角色中进行配置才能正常显示出来。\n\n先看下菜单列表大致了解下菜单管理都维护哪些内容：\n\n![menu](./img/menu.jpg)\n\n## 左侧菜单维护\n- 菜单维护基本上采用了两级菜单形式：如上图所示：第一级菜单为“系统管理”，“系统管理”中包含了“用户管理”、“角色管理”等多个二级菜单。\n- 其中“系统管理”为虚拟菜单，点击“系统管理”并不会跳转到真实的页面而是展开其子菜单列表；所以虚拟菜单的请求地址应配置为“#”。\n- “系统管理”下的子菜单，例如“业务日志”需要配置请求地址，比如配置为“/log”,点击“业务日志”会跳转到业务日志列表页面。\n## 页面功能维护\n- 菜单维护中的另外一种形式我功能（主要是操作按钮或者页面中的链接）的维护。点击按钮虽然不需要跳转到具体的页面但是也需要配置请求地址，因为代码中需要通过该地址来判断用户是否拥有操作权限。\n- 例如“业务日志”菜单中有三个子菜单：“清空日志”的请求地址配置为：\"log/delLog\",则页面进行控制权限的写法为：\n\n    ```html\n    @if(shiro.hasPermission(\"/log/delLog\")){\n        <#button name=\"清空日志\" icon=\"fa-minus\" clickFun=\"OptLog.delLog()\" space=\"true\"/>\n    @}\n    ```\n    \n    \n菜单管理的其他维护参数不赘述，具体作用配置试用一下即可知晓。    "
  },
  {
    "path": "doc/feature/modules.md",
    "content": "# 基本包结构\n\n本节详细说明本项目的基本目录结构\n\n## material-admin模块\n\nmaterial-admin包含3个核心模块：\n- material-core\n- material-generator\n- material-manage \n\n其中material-manage一个java web模块，其他都为java se项目；\n具体每个包的作用通过名字即可看出包含的功能分别为：核心模块，代码生成模块，web管理模块\n \n\n具体每个包里的细节不详细介绍，开发人员可以在使用过程中逐渐了解，本身代码量并不大，熟悉起来不需要花费太多时间。\n\n这里仅详细说明下material-manage的内部结构，毕竟日常开发主要是基于该模块来做的。\n\n## material-manage\nmaterial-manage是一个标准的java web项目\n\n![material-manage](./img/admin.jpg)\n\n目录结构包含：\n\n- src/main/java  java源码\n- src/main/resources  配置文件\n- src/webapp  web页面和静态文件资源\n这里介绍下material-manage的基本目录和开发流程\n\n### src/main/java/ 源代码\n\n目录结构如下所示：\n\n![material-manage](./img/src.jpg)\n\n- **common** 该package 封装了一些工具的类库，如一些注解，常量、枚举，异常等公共类\n- **config** 该package 包含项目支持各种特性的相关配置。例如：\n    - 支持swagger在线文档的配置\n    - EhCache缓存配置\n    - Session配置\n    - Shiro配置\n    - Beetl模版配置\n- **core** 该package是项目的核心，包含注入数据源管理、缓存管理、模版管理、aop，监听器以及分页工具、各种工具类。\n当然开发人员可以根据项目实际情况做二次调整和封装。\n\n- **modular** 该pakcage存放和业务相关的代码。\n比如目前提供了一个**system模块**，主要包含诸如：用户、角色、权限、日志等管理功能的系统管理功能。\nsystem包中除了controller包是必须的，其他包都是根据具体情况选择是否需要。 \n \n\n\n\n### src/webapp  web页面和静态文件资源\n \n目录结构如下所示：\n\n![material-manage](./img/web.jpg)\n\n- static 目录为静态资源\n    - css、fonts，img，js分别为公共的样式、字体，图片，js资源\n    - modular 目录为业务用js资源，比如system即为admin内置功能的js资源，其中每个功能使用一个目录和WEB-INF/view/中的目录一一对应\n    \n    ![material-web-js](./img/web-js.jpg)\n    \n- WEB-INF/view 为页面目录\n    - common 为公共的页面框架和封装的标签目录\n    - 其他目录为业务页面目录，比如system即为内置的功能页面包括用户、角色、权限等管理功能的页面\n    \n    ![material-web-page](./img/web-page.jpg)\n\n"
  },
  {
    "path": "doc/feature/monitor.md",
    "content": "# 监控管理\n\n这里的监控功能用的是alibaba druid自带的监控功能\n\n![monitor](./img/monitor.jpg)"
  },
  {
    "path": "doc/helloworld/add.md",
    "content": "# add\n\n## 添加参数\n\n添加参数功能为点击“添加”按钮后调用对应的js代码逻辑弹出添加页面，在添加页面输入相关信息提交保存，保存成功后关闭弹窗，并刷新参数列表数据.\n\n### 添加按钮注册点击函数:\n\n```html\n @if(shiro.hasPermission(\"/cfg/add\")){\n     <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Cfg.openAddCfg()\" space=\"true\"/>\n @}\n```\n### 添加 按钮点击逻辑：\n\n```javascript\n/**\n * 点击添加系统参数\n */\nCfg.openAddCfg = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加系统参数',\n        area: ['65%', '280px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/cfg/cfg_add'\n    });\n    this.layerIndex = index;\n};\n```\n### 添加页面代码\n\n```html\n@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"\">\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                            <#input id=\"cfgName\" name=\"参数名\"/>\n                            <#input id=\"cfgValue\" name=\"参数值\" underline=\"true\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                            <#input id=\"cfgDesc\" name=\"参数描述\" underline=\"true\"/>\n                </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"CfgInfoDlg.addSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"CfgInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/cfg/cfg_info.js\"></script>\n@}\n```\n\n### 点击“提交”按钮提交参数保存逻辑：\n_cfg_info.js_:\n\n```javascript\n/**\n * 提交添加\n */\nCfgInfoDlg.addSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/cfg/add\", function(data){\n        Feng.success(\"添加成功!\");\n        window.parent.Cfg.table.refresh();\n        CfgInfoDlg.close();\n    },function(data){\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.cfgInfoData);\n    ajax.start();\n}\n\n```\n\n\n## 后台保存逻辑\n\n```java\n/**\n * 跳转到添加参数页面\n */\n@RequestMapping(value = \"/cfg_add\",method = RequestMethod.GET)\npublic String add() {\n    return PREFIX + \"cfg_add.html\";\n}\n\n/**\n * 新增参数\n */\n@RequestMapping(value = \"/add\",method = RequestMethod.POST)\n@ResponseBody\n@BussinessLog(value = \"添加参数\", key = \"cfgName\",dict = CfgDict.class)\npublic Object add(@Valid Cfg cfg) {\n    cfgService.saveOrUpdate(cfg);\n    return SUCCESS_TIP;\n}\n```"
  },
  {
    "path": "doc/helloworld/base.md",
    "content": "# 基础代码\n\n## 实体Entity\n\n```java\npackage cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\nimport javax.validation.constraints.NotBlank;\n\n@Entity(name=\"t_sys_cfg\")\n@Table(appliesTo = \"t_sys_cfg\",comment = \"系统参数\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class Cfg  extends BaseEntity {\n    @Column(name = \"cfg_name\",columnDefinition = \"VARCHAR(256) COMMENT '参数名'\")\n    @NotBlank(message = \"参数名不能为空\")\n    private String cfgName;\n    @Column(name = \"cfg_value\",columnDefinition = \"VARCHAR(512) COMMENT '参数值'\")\n    @NotBlank(message = \"参数值不能为空\")\n    private String cfgValue;\n    @Column(name = \"cfg_desc\",columnDefinition = \"TEXT COMMENT '备注'\")\n    private String cfgDesc;\n\n}\n```\n\n## 数据库操作Repository\n\n```java\npublic interface CfgRepository extends BaseRepository<Cfg,Long> {\n    \n}\n\n```\n## service\n```java\n@Service\npublic class CfgService extends BaseService<Cfg,Long,CfgRepository> {\n\n}    \n```\n## controller\n\n```java\n\n@Controller\n@RequestMapping(\"/cfg\")\npublic class CfgController extends BaseController {\n    @Autowired\n    private CfgService cfgService;\n    private static String PREFIX = \"/system/cfg/\";\n    /**\n     * 跳转到参数首页\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"cfg.html\";\n    }\n\n    /**\n     * 跳转到添加参数\n     */\n    @RequestMapping(\"/cfg_add\")\n    public String add() {\n        return PREFIX + \"cfg_add.html\";\n    }\n\n    /**\n     * 跳转到修改参数\n     */\n    @RequestMapping(\"/cfg_update/{cfgId}\")\n    public String update(@PathVariable Long cfgId, Model model) {\n        Cfg cfg = cfgService.get(cfgId);\n        model.addAttribute(\"item\",cfg);\n        return PREFIX + \"cfg_edit.html\";\n    }\n\n    /**\n     * 获取参数列表\n     */\n    @RequestMapping(value = \"/list\")\n    @ResponseBody\n    public Object list(@RequestParam(required = false) String cfgName, @RequestParam(required = false) String cfgValue) {\n        Page<Cfg> page = new PageFactory<Cfg>().defaultPage();\n        if(StringUtils.isNotEmpty(cfgName)){\n            page.addFilter(SearchFilter.build(\"cfgName\", SearchFilter.Operator.LIKE, cfgName));\n        }\n        if(StringUtils.isNotEmpty(cfgValue)){\n            page.addFilter(SearchFilter.build(\"cfgValue\", SearchFilter.Operator.LIKE, cfgValue));\n        }\n        page = cfgService.queryPage(page);\n        return packForBT(page);\n    }\n\n    /**\n     * 新增参数\n     */\n    @RequestMapping(value = \"/add\")\n    @ResponseBody\n    @BussinessLog(value = \"添加参数\", key = \"cfgName\",dict = CfgDict.class)\n    public Object add(@Valid Cfg cfg) {\n       cfgService.saveOrUpdate(cfg);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 删除参数\n     */\n    @RequestMapping(value = \"/delete\")\n    @ResponseBody\n    @BussinessLog(value = \"删除参数\", key = \"cfgId\",dict = CfgDict.class)\n    public Object delete(@RequestParam Long cfgId) {\n        cfgService.delete(cfgId);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 修改参数\n     */\n    @RequestMapping(value = \"/update\")\n    @ResponseBody\n    @BussinessLog(value = \"编辑参数\", key = \"cfgName\",dict = CfgDict.class)\n    public Object update(@Valid  Cfg cfg) {\n       cfgService.update(cfg);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 参数详情\n     */\n    @RequestMapping(value = \"/detail/{cfgId}\")\n    @ResponseBody\n    public Object detail(@PathVariable(\"cfgId\") Long cfgId) {\n        return cfgService.get(cfgId);\n    }\n\n```\n "
  },
  {
    "path": "doc/helloworld/create_table.md",
    "content": "# 建表\n比如我们要开发一个系统参数的管理功能，该功能主要对系统相关参数进行增删该查。\n\n~~建表语句如下：~~\n\n```sql\nCREATE TABLE `t_sys_cfg` (\n  `id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT '自增主键',\n  `cfg_name` varchar(100) DEFAULT NULL COMMENT '参数名',\n  `cfg_value` varchar(3000) DEFAULT NULL COMMENT '参数值',\n  `cfg_desc` varchar(200) DEFAULT NULL COMMENT '参数描述',\n  PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='系统参数';\n```\n\n**注意**\n\n- 看到上面的 ~~建表语句如下：~~ 了么，知道为什么要划掉么？因为在使用本系统做开发的时候强烈建议不用自己建表，而是直接根据实体在系统启动的时候自动生成表。因为以后如果我们用代码生成工具的话，你要建个表，再写一遍实体类，不近工作做了两套，而且容易出现两别字段定义不一致的问题。\n- 当然在生产环境，我个人是不建议开启Spring Boot的自动更新表结构功能的，还是自己手动建表比较稳妥。\n"
  },
  {
    "path": "doc/helloworld/crud.md",
    "content": "# 简单的CRUD\n\n本章将手把手带你开发一个增删该查功能，包含从建表到代码（controller，service，dao，页面），到权限控制，以及一个相对复杂的查询。\n\n**PS** 其实真正开发中你完全可以使用代码生成工具一键生成这些功能；不过工具再好用，过程自己还是要掌握的，对吧！\n\n接下来我们要开发一个参数管理功能，用于对系统参数进行增删该查\n\n## 本章知识点\n * [建表](./create_table.md)\n * [基础代码](./base.md)\n * [list](./list.md)\n * [add](./add.md)\n * [delete](./delete.md)\n * [update](./update.md)\n * [添加菜单和分配权限](./menuAndPermission.md)\n\n "
  },
  {
    "path": "doc/helloworld/delete.md",
    "content": "# delete\n\n## 针对要删除的数据点击行尾的删除按钮即弹出删除确认空，确认删除\n\n_cfg.js_\n```javascript\n {title: '操作',formatter:function(data,row){\n            return '<button type=\"button\" class=\"btn btn-info btn-icon waves-effect waves-circle\" onclick=\"Cfg.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n        \n        \n/**\n * 删除系统参数\n */\nCfg.delete = function (id) {\n    var operation = function() {\n        var ajax = new $ax(Feng.ctxPath + \"/cfg/delete\", function (data) {\n            Feng.success(\"删除成功!\");\n            Cfg.table.refresh();\n        }, function (data) {\n            Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n        });\n        ajax.set(\"cfgId\", id);\n        ajax.setType('delete');\n        ajax.start();\n    };\n    Feng.confirm(\"确认删除该记录?\", operation);\n};        \n```\n \n\n## 后台逻辑\n\n```java\n/**\n * 删除参数\n */\n@RequestMapping(value = \"/delete\",method = RequestMethod.DELETE)\n@ResponseBody\n@BussinessLog(value = \"删除参数\", key = \"cfgId\",dict = CfgDict.class)\npublic Object delete(@RequestParam Long cfgId) {\n    cfgService.delete(cfgId);\n    return SUCCESS_TIP;\n}    \n```"
  },
  {
    "path": "doc/helloworld/list.md",
    "content": "# list\n\n## 列表页面\n列表页面包含分页（根据指定条件）查询数据列表，添加，修改，删除按钮\n列表页面针对：添加按钮做了权限控制，具体逻辑在下文再详细描述\n\n```html\n@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>参数管理</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"hidden-xs\" id=\"CfgTableToolbar\" role=\"group\">\n                    <div class=\"col-sm-3\">\n                        <#NameCon id=\"cfgName\" placeholder=\"参数名\" />\n                    </div>\n                    <div class=\"col-sm-3\">\n                        <#NameCon id=\"cfgValue\" placeholder=\"参数值\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"Cfg.search()\"/>\n                    <#button name=\"重置\" icon=\"fa-refresh\" clickFun=\"Cfg.reset()\" btnCss=\"info\" space=\"true\"/>\n                    @if(shiro.hasPermission(\"/cfg/add\")){\n                        <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Cfg.openAddCfg()\" space=\"true\"/>\n                    @}\n                </div>\n                <#table id=\"CfgTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/cfg/cfg.js\"></script>\n@}\n```\n\n## 查询列表数据的js代码:\n\n```javascript\n/**\n * 系统参数管理初始化\n */\nvar Cfg = {\n    id: \"CfgTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nCfg.initColumn = function () {\n    return [\n        {field: 'selectItem', checkbox: true},\n        {title: 'ID', field: 'id', visible: true, align: 'center', valign: 'middle'},\n        {title: '参数名', field: 'cfgName', visible: true, align: 'center', valign: 'middle',formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"Cfg.openCfgDetail('+row.id+')\">'+data+'</a>';\n        }},\n        {title: '参数值', field: 'cfgValue', visible: true, align: 'center', valign: 'middle'},\n        {title: '参数描述', field: 'cfgDesc', visible: true, align: 'center', valign: 'middle'},\n        {title: '操作',formatter:function(data,row){\n            return '<button type=\"button\" class=\"btn btn-info btn-icon waves-effect waves-circle\" onclick=\"Cfg.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n    ];\n};\n\n/**\n * 查询系统参数列表\n */\nCfg.search = function () {\n    var queryData = {};\n    queryData['cfgName'] = $(\"#cfgName\").val();\n    queryData['cfgValue'] = $(\"#cfgValue\").val();\n    Cfg.table.refresh({query: queryData});\n};\n\nCfg.reset = function () {\n    $(\"#cfgName\").val(\"\");\n    $(\"#cfgValue\").val(\"\");\n    this.search();\n};\n$(function () {\n    var defaultColunms = Cfg.initColumn();\n    var table = new BSTable(Cfg.id, \"/cfg/list\", defaultColunms);\n    table.setPaginationType(\"server\");\n    Cfg.table = table.init();\n});\n\n\n```\n\n## 后台代码\n**CfgController**\n```java\n\n/**\n * 跳转到参数首页\n */\n@RequestMapping(value = \"\",method = RequestMethod.GET)\npublic String index() {\n    return PREFIX + \"cfg.html\";\n}\n/**\n * 分页查询系统参数\n */\n@RequestMapping(value = \"/list\",method = RequestMethod.POST)\n@ResponseBody\npublic Object list(@RequestParam(required = false) String cfgName, @RequestParam(required = false) String cfgValue) {\n    Page<Cfg> page = new PageFactory<Cfg>().defaultPage();\n    if(StringUtils.isNotEmpty(cfgName)){\n        page.addFilter(SearchFilter.build(\"cfgName\", SearchFilter.Operator.LIKE, cfgName));\n    }\n    if(StringUtils.isNotEmpty(cfgValue)){\n        page.addFilter(SearchFilter.build(\"cfgValue\", SearchFilter.Operator.LIKE, cfgValue));\n    }\n    page = cfgService.queryPage(page);\n    return packForBT(page);\n}\n```"
  },
  {
    "path": "doc/helloworld/menuAndPermission.md",
    "content": "# 添加菜单和分配权限\n现在功能已经开发完毕了，但是在页面上并不能使用这个功能；\n因为我没有给当前用不配置参数管理的权限。下面分两步骤启用参数管理功能\n\n- 在菜单管理中添加参数管理的功能，包括一个菜单项（点击链接进入列表页面）和一个个功能项（新增）\n- 在权限管理中给指定的角色配置上述两个资源\n- 在用户管理中给指定的用户配置指定的角色\n\n\n\n## 添加菜单项\n\n在菜单管理中添加4条记录,添加过程中要注意一下几点：\n - 父级编号：选中的父级编号决定了当前功能所属哪一个模块，比如“参数管理”这一项的父级编号选择“系统管理”，则“参数管理”这一功能菜单在“系统管理”模块下。\n - 是否是菜单：选择“是”，则菜单会在左侧菜单栏显示，选择“否”，则不会显示在左侧菜单栏。针对按钮功能要选择“否”\n - 请求地址，针对菜单选择“是”的记录，则该地址必须为页面打开的地址，针是否是菜单选择“否”的记录，则该地址必须与用作权限判断的字符串一致。\n \n ```\n比如“添加系统参数”这一项的请求地址为“cfg/add”, 则页面判断是否有操作权限的的代码为：\n    \n@if(shiro.hasPermission(\"/cfg/add\")){\n    <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Cfg.openAddCfg()\" space=\"true\"/>\n@}\n```\n    \n添加四条菜单记录：\n    \n- 参数管理\n- 添加系统参数\n\n![menu](../img/helloworld/menu.png)\n\n## 为角色配置菜单项\n\n![role](../img/helloworld/role.png)\n \n\n\n"
  },
  {
    "path": "doc/helloworld/update.md",
    "content": "# update\n\n参数修改逻辑为：\n- 点击参数名，打开编辑页面\n- 更改信息，提交修改\n- 关闭修改弹窗，并刷新列表页面\n\n## 列表页点击要修改的参数名，弹出修改页面\n\n\n```html\n  {title: '参数名', field: 'cfgName', visible: true, align: 'center', valign: 'middle',formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"Cfg.openCfgDetail('+row.id+')\">'+data+'</a>';\n        }},\n```\n\n- 打开参数详情弹窗\n\n```javascript\n/**\n * 打开系统参数详情页\n */\nCfg.openCfgDetail = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '系统参数详情',\n            area: ['65%', '280px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/cfg/cfg_update/' + id\n        });\n        this.layerIndex = index;\n\n};\n```\n- 后台查询参数调准到详情逻辑\n\n```java\n/**\n * 跳转到修改参数\n */\n@RequestMapping(value = \"/cfg_update/{cfgId}\",method = RequestMethod.POST)\npublic String update(@PathVariable Long cfgId, Model model) {\n    Cfg cfg = cfgService.get(cfgId);\n    model.addAttribute(\"item\",cfg);\n    return PREFIX + \"cfg_edit.html\";\n}\n```\n\n- 参数修改页面\n_cfg_edit.html_:\n```html\n@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"${item.id}\">\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                            <#input id=\"id\" name=\"自增主键\" value=\"${item.id}\" disabled=\"disabled\"/>\n                            <#input id=\"cfgName\" name=\"参数名\" value=\"${item.cfgName}\" />\n                </div>\n                <div class=\"col-sm-6\">\n                            <#input id=\"cfgValue\" name=\"参数值\" value=\"${item.cfgValue}\" underline=\"true\"/>\n                            <#input id=\"cfgDesc\" name=\"参数描述\" value=\"${item.cfgDesc}\" />\n                </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"CfgInfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"CfgInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/cfg/cfg_info.js\"></script>\n@}\n\n```\n\n## 更改信息，提交修改\n\n- js逻辑提交修改\n\n```javascript\n\n/**\n * 提交修改\n */\nCfgInfoDlg.editSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/cfg/update\", function(data){\n        Feng.success(\"修改成功!\");\n        window.parent.Cfg.table.refresh();\n        CfgInfoDlg.close();\n    },function(data){\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.cfgInfoData);\n    ajax.start();\n}\n```\n\n- 后台逻辑提交更改\n\n```java\n/**\n * 修改参数\n */\n@RequestMapping(value = \"/update\",method = RequestMethod.POST)\n@ResponseBody\n@BussinessLog(value = \"编辑参数\", key = \"cfgName\",dict = CfgDict.class)\npublic Object update(@Valid  Cfg cfg) {\n   cfgService.update(cfg);\n    return SUCCESS_TIP;\n}\n```\n"
  },
  {
    "path": "doc/other/faq.md",
    "content": "# 常见问题\n\n## 本地开发正常，打包运行的时候提交中文内容乱码，检查了数据库编码也没问题？\n\n打包为jar包运行的时候可以指定运行时编码为UTF8：\n```\njava -Dfile.encoding=utf-8 -jar xxxxxxx.jar\n```\n\n## 使用代码生成器的时候总是报找不到Generator类或者找不到code.json配置文件\n\n下载项目后首先mvn package 保证项目能构建并打包成功再使用代码生成器\n\n"
  },
  {
    "path": "doc/package.json",
    "content": "{\n  \"scripts\": {\n    \"docs:dev\": \"vuepress dev docs\",\n    \"docs:build\": \"vuepress build docs\"\n  },\n  \"devDependencies\": {\n    \"@vuepress/plugin-google-analytics\": \"^1.0.0-alpha.0\"\n  }\n}\n"
  },
  {
    "path": "doc/quickstart/clone.md",
    "content": "# 克隆本项目\n\n本项目地址为：[https://github.com/enilu/material-admin](https://github.com/enilu/material-admin),如果对你有用，欢迎给个star\n\n项目共两个分，支分别为：\n- master 项目主分支\n- develop 开发分支，代码最新，但是不稳定 \n\n进入控制台输入以下命令将项目克隆到本地：\n\ngit clone https://github.com/enilu/material-admin.git\n\n- 使用IDEA Intellij或者eclipse导入项目，记得开发工具要安装lombook插件哦"
  },
  {
    "path": "doc/quickstart/config.md",
    "content": "# 配置项目\n\n你已经下载项目，并且初始化好了数据库，那么接下来只需要更改相应的配置就可以运行该项目了\n\n- 更改src/resources/application-dev.properties配置：\n\n```properties\n## 开发环境配置，修改为真实的用户名密码\nspring.datasource.url=jdbc:mysql://localhost:3306/material\nspring.datasource.username=root\nspring.datasource.password=root\n\n```"
  },
  {
    "path": "doc/quickstart/initDb.md",
    "content": "# 初始化数据\n\n本系统使用mysql数据库：\n\n- 在mysql中创建数据库 material\n\n```sql\nCREATE DATABASE IF NOT EXISTS material DEFAULT CHARSET utf8 COLLATE utf8_general_ci;\n\n```\n- 启动项目系统会自动建表并初始化数据。"
  },
  {
    "path": "doc/quickstart/quickstart.md",
    "content": "# 10分钟把项目跑起来\n\n## 真的10分钟吗?\n当然，如果你的网速给力，并且依赖的软件都下载安装好了，并且手速够快，是不是前置条件有点多？^_^\n\n\n## 本章知识点\n- [克隆项目](./clone.md)\n- [初始化数据](./initDb.md)\n- [配置项目](./config.md)\n- [启动项目](./startup.md)"
  },
  {
    "path": "doc/quickstart/startup.md",
    "content": "# 启动项目\n\n- 右键直接运行 cn.enilu.material.admin.AdminApplication类即可启动material-manage后台管理系统\n- 系统默认是用8085端口，参考配置文件src/resources/application.properties\n```properties\nserver.port=8085\n```\n- 启动成功后访问http://localhost:8085 如下图所示\n![login](../img/quickstart/login.png)\n- 输入用户名/密码：admin/admin即可登录：\n![index](../img/quickstart/index.png)\n\n\nso，是不是很简单!"
  },
  {
    "path": "doc/resource.md",
    "content": "# 资源\n本节会整理提供一些助于开发的相关资源文档，在开发过程中学会恰当的里用这些资源将会是开发过程如虎添翼，事半功倍！。\n\n\n## 前端\n### Material Admin\n- [https://www.sucaihuo.com/templates/3963](https://www.sucaihuo.com/templates/3963)\n- 本项目使用该框架，开发过程中可以参考该框架，该框架封装很多常用的material风格的组件\n\n### Fontawesome 图标库\n- [http://www.fontawesome.com.cn/faicons](http://www.fontawesome.com.cn/faicons)\n- material-manage中使用了fontawesome的图标库，如果你想用一些图标，又不知道用哪些合适，可以通过下面网站，找到合适的图标和样式名\n- 比如菜单管理，在添加菜单的时候，有个图标的配置项:**图标**,这里就要求默认使用fontawesome的图标库样式。<img src=\"./img/resource/menu_1.jpg\" align=center />\n\n### Bootstrap\n- [https://v3.bootcss.com/css/](https://v3.bootcss.com/css/)\n- material-manage中使用了Bootstrap作为前端样式库，Bootstrap有丰富的样式，插件和组件，开发过程中可以参考在线文档，方便搞笑。\n\n### Beetl\n- [http://ibeetl.com/guide](http://ibeetl.com/guide)\n- material-manage使用Beetl做为模板引擎，Beetl是一个很好用的国产模板引擎。使用中有什么问题也可以去其官方论坛提问[http://bbs.ibeetl.com/](http://bbs.ibeetl.com/)\n\n### 阿里巴巴矢量图库\n- [https://iconfont.cn](https://iconfont.cn)\n- 这个站点是阿里巴巴维护的一个图标站点，里面有极其丰富的图标，如果开发过程中如果在Fontawesome和Bootstrap中的找不到合适的图标，可以来这里看看，应该不会让你失望。\n\n\n## 后端\n\n## Spring Boot\n- [https://qbgbook.gitbooks.io/spring-boot-reference-guide-zh/content/](https://qbgbook.gitbooks.io/spring-boot-reference-guide-zh/content/) 文档基于Spring Boot1.4.1的英文文档翻译\n- [https://www.breakyizhan.com/springboot/3028.html](https://www.breakyizhan.com/springboot/3028.html) 文档基于Spring Boot2.0.1的英文文档翻译\n- 本系统基于Spring Boot2.1.1开发，所以建议开发过程中多翻翻第二个在线文档，第一个文档可以作为蛇参考。\n"
  },
  {
    "path": "doc/文档完善中",
    "content": ""
  },
  {
    "path": "material-core/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>material-admin</artifactId>\n        <groupId>cn.enilu</groupId>\n        <version>0.1</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>material-core</artifactId>\n    <dependencies>\n        <dependency>\n            <groupId>cn.enilu</groupId>\n            <artifactId>material-generator</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-web</artifactId>\n            <exclusions>\n                <exclusion>\n                    <groupId>org.springframework.boot</groupId>\n                    <artifactId>spring-boot-starter-tomcat</artifactId>\n                </exclusion>\n            </exclusions>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-mail</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.quartz-scheduler</groupId>\n            <artifactId>quartz</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.quartz-scheduler</groupId>\n            <artifactId>quartz-jobs</artifactId>\n        </dependency>\n        <!-- message  start-->\n        <dependency>\n            <groupId>com.github.qcloudsms</groupId>\n            <artifactId>qcloudsms</artifactId>\n        </dependency>\n        <!-- message end-->\n\n        <!-- entity-->\n        <dependency>\n            <groupId>org.projectlombok</groupId>\n            <artifactId>lombok</artifactId>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context-support</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-jdbc</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>druid-spring-boot-starter</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-cache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.ehcache</groupId>\n            <artifactId>ehcache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.sf.ehcache.internal</groupId>\n            <artifactId>ehcache-core</artifactId>\n        </dependency>\n        <!-- utils-->\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-logging</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.commons</groupId>\n            <artifactId>commons-lang3</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-io</groupId>\n            <artifactId>commons-io</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.nutz</groupId>\n            <artifactId>nutz</artifactId>\n        </dependency>\n        <!--shiro依赖-->\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-spring</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.shiro</groupId>\n            <artifactId>shiro-ehcache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-tomcat</artifactId>\n            <scope>compile</scope>\n        </dependency>\n\n        <!--test-->\n        <dependency>\n            <groupId>junit</groupId>\n            <artifactId>junit</artifactId>\n            <scope>test</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/aop/LogAop.java",
    "content": "package cn.enilu.material.aop;\n\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport cn.enilu.material.dao.cache.TokenCache;\nimport cn.enilu.material.platform.log.LogManager;\nimport cn.enilu.material.platform.log.LogTaskFactory;\nimport cn.enilu.material.service.system.LogObjectHolder;\nimport cn.enilu.material.shiro.ShiroKit;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.utils.HttpKit;\nimport cn.enilu.material.utils.StringUtils;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.Signature;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.aspectj.lang.reflect.MethodSignature;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.stereotype.Component;\n\nimport javax.servlet.http.HttpServletRequest;\nimport java.lang.reflect.Method;\nimport java.util.Map;\n\n/**\n * 日志记录\n *\n * @author fengshuonan\n * @date 2016年12月6日 下午8:48:30\n */\n@Aspect\n@Component\npublic class LogAop {\n\n    private Logger log = LoggerFactory.getLogger(this.getClass());\n\n    @Pointcut(value = \"@annotation(cn.enilu.material.bean.core.BussinessLog)\")\n    public void cutService() {\n    }\n\n    @Around(\"cutService()\")\n    public Object recordSysLog(ProceedingJoinPoint point) throws Throwable {\n\n        //先执行业务\n        Object result = point.proceed();\n\n        try {\n            handle(point);\n        } catch (Exception e) {\n            log.error(\"日志记录出错!\", e);\n        }\n\n        return result;\n    }\n\n    private void handle(ProceedingJoinPoint point) throws Exception {\n\n        //获取拦截的方法名\n        Signature sig = point.getSignature();\n        MethodSignature msig = null;\n        if (!(sig instanceof MethodSignature)) {\n            throw new IllegalArgumentException(\"该注解只能用于方法\");\n        }\n        msig = (MethodSignature) sig;\n        Object target = point.getTarget();\n        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());\n        String methodName = currentMethod.getName();\n\n        //获取用户id，admin和api模块获取idUser方式不同\n        Long idUser = null;\n        HttpServletRequest request = HttpKit.getRequest();\n        String token = request.getHeader(\"Authorization\");\n        if(StringUtils.isNotEmpty(token)) {\n            idUser = SpringContextHolder.getBean(TokenCache.class).get(token);\n        }\n        if(idUser==null) {\n            //如果当前用户未登录，不做日志\n            ShiroUser user = ShiroKit.getUser();\n            if (null == user) {\n                return;\n            }\n            idUser = user.getId();\n        }\n\n        //获取拦截方法的参数\n        String className = point.getTarget().getClass().getName();\n        Object[] params = point.getArgs();\n\n        //获取操作名称\n        BussinessLog annotation = currentMethod.getAnnotation(BussinessLog.class);\n        String bussinessName = annotation.value();\n        String key = annotation.key();\n        Class dictClass = annotation.dict();\n\n        StringBuilder sb = new StringBuilder();\n        for (Object param : params) {\n            sb.append(param);\n            sb.append(\" & \");\n        }\n\n        //如果涉及到修改,比对变化\n        String msg=\"\";\n        if (bussinessName.indexOf(\"修改\") != -1 || bussinessName.indexOf(\"编辑\") != -1) {\n            //todo api模块无法使用该方法获取数据\n            Object obj1 = LogObjectHolder.me().get();\n            Map<String, String> obj2 = HttpKit.getRequestParameters();\n            try {\n                msg = BeanUtil.contrastObj(key, obj1, obj2);\n            }catch (Exception e){\n\n            }\n        } else {\n            Map<String, String> parameters = HttpKit.getRequestParameters();\n            msg = BeanUtil.parseMutiKey(parameters);\n        }\n\n        LogManager.me().executeLog(LogTaskFactory.bussinessLog(idUser, bussinessName, className, methodName, msg));\n    }\n}"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/aop/PermissionAop.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.aop;\n\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.shiro.check.PermissionCheckManager;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.aspectj.lang.reflect.MethodSignature;\nimport org.springframework.stereotype.Component;\n\nimport javax.naming.NoPermissionException;\nimport java.lang.reflect.Method;\n\n/**\n * AOP 权限自定义检查\n */\n@Aspect\n@Component\npublic class PermissionAop {\n\n    @Pointcut(value = \"@annotation(cn.enilu.material.bean.core.Permission)\")\n    private void cutPermission() {\n\n    }\n\n    @Around(\"cutPermission()\")\n    public Object doPermission(ProceedingJoinPoint point) throws Throwable {\n        MethodSignature ms = (MethodSignature) point.getSignature();\n        Method method = ms.getMethod();\n        Permission permission = method.getAnnotation(Permission.class);\n        Object[] permissions = permission.value();\n        if (permissions == null || permissions.length == 0) {\n            //检查全体角色\n            boolean result = PermissionCheckManager.checkAll();\n            if (result) {\n                return point.proceed();\n            } else {\n                throw new NoPermissionException();\n            }\n        } else {\n            //检查指定角色\n            boolean result = PermissionCheckManager.check(permissions);\n            if (result) {\n                return point.proceed();\n            } else {\n                throw new NoPermissionException();\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/Const.java",
    "content": "package cn.enilu.material.bean.constant;\n\n/**\n * 系统常量\n *\n * @author fengshuonan\n * @date 2017年2月12日 下午9:42:53\n */\npublic interface Const {\n    long SYSTEM_USER_ID=-1;\n\n    /**\n     * 用户密码加密key\n     */\n    String CRYPT_DES_KEY = \"sc123456\";\n    /**\n     * 系统默认的管理员密码\n     */\n    String DEFAULT_PWD = \"111111\";\n\n    /**\n     * 管理员角色的名字\n     */\n    String ADMIN_NAME = \"administrator\";\n\n    /**\n     * 管理员id\n     */\n    Integer ADMIN_ID = 1;\n\n    /**\n     * 超级管理员角色id\n     */\n    Integer ADMIN_ROLE_ID = 1;\n\n    /**\n     * 接口文档的菜单名\n     */\n    String API_MENU_NAME = \"接口文档\";\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/cache/Cache.java",
    "content": "package cn.enilu.material.bean.constant.cache;\n\n/**\n * 所有缓存名称的集合\n *\n * @author fengshuonan\n * @date 2017-04-24 21:56\n */\npublic interface Cache {\n\n\n    /**\n     * 常量缓存\n     */\n    String CONSTANT = \"CONSTANT\";\n    String APPLICATION = \"APPLICATION\";\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/cache/CacheKey.java",
    "content": "package cn.enilu.material.bean.constant.cache;\n\n/**\n * 缓存的key集合\n *\n * @author fengshuonan\n * @date 2017-04-25 9:37\n */\npublic interface CacheKey {\n\n    /**\n     * ConstantFactory中的缓存\n     */\n    String ROLES_NAME = \"roles_name_\";\n\n    String SINGLE_ROLE_NAME = \"single_role_name_\";\n\n    String SINGLE_ROLE_TIP = \"single_role_tip_\";\n\n    String DEPT_NAME = \"dept_name_\";\n\n    String DICT_NAME = \"dict_name_\";\n    String DICT = \"dict_\";\n\n\n    String COURSE_NAME = \"course_name_\";\n    String ORG_NAME = \"org_name_\";\n    String DIC_ALL = \"dic_all_\";\n    String CFG = \"cfg_\";\n    String MENU_NAME = \"menu_name_\" ;\n    String SYS_USER_NAME = \"SYS_USER_NAME\" ;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/factory/PageFactory.java",
    "content": "package cn.enilu.material.bean.constant.factory;\n\nimport cn.enilu.material.bean.constant.state.Order;\nimport cn.enilu.material.utils.HttpKit;\nimport cn.enilu.material.utils.StringUtils;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.utils.ToolUtil;\n\nimport javax.servlet.http.HttpServletRequest;\n/**\n * BootStrap Table默认的分页参数创建\n *\n * @author fengshuonan\n * @date 2017-04-05 22:25\n */\npublic class PageFactory<T> {\n\n    public Page<T> defaultPage() {\n        HttpServletRequest request = HttpKit.getRequest();\n        //每页多少条数据\n        int limit = Integer.valueOf(request.getParameter(\"limit\"));\n        String pageNum = request.getParameter(\"page\");\n        //每页的偏移量(本页当前有多少条)\n        int offset = 0;\n        if(StringUtils.isNotEmpty(pageNum)){\n            offset = (Integer.valueOf(pageNum)-1)*limit;\n        }else {\n\n            offset = Integer.valueOf(request.getParameter(\"offset\"));\n        }\n        //排序字段名称\n        String sort = request.getParameter(\"sort\");\n        //asc或desc(升序或降序)\n        String order = request.getParameter(\"order\");\n        if (ToolUtil.isEmpty(sort)) {\n            Page<T> page = new Page<>((offset / limit + 1), limit);\n            page.setOpenSort(false);\n            return page;\n        } else {\n            Page<T> page = new Page<>((offset / limit + 1), limit, sort);\n            if (Order.ASC.getDes().equals(order)) {\n                page.setAsc(true);\n            } else {\n                page.setAsc(false);\n            }\n            return page;\n        }\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/package-info.java",
    "content": "/**\n * Created  on 2018/3/28 0028.\n *\n * @author enilu\n */\npackage cn.enilu.material.bean.constant;"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/state/BizLogType.java",
    "content": "package cn.enilu.material.bean.constant.state;\n\n/**\n * 业务日志类型\n *\n * @author fengshuonan\n * @Date 2017年1月22日 下午12:14:59\n */\npublic enum BizLogType {\n\n    ALL(0, null),//全部日志\n    BUSSINESS(1, \"业务日志\"),\n    EXCEPTION(2, \"异常日志\");\n\n    Integer val;\n    String message;\n\n    BizLogType(Integer val, String message) {\n        this.val = val;\n        this.message = message;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public Integer getVal() {\n        return val;\n    }\n\n    public void setVal(Integer val) {\n        this.val = val;\n    }\n\n    public static String valueOf(Integer value) {\n        if (value == null) {\n            return null;\n        } else {\n            for (BizLogType bizLogType : BizLogType.values()) {\n                if (bizLogType.getVal().equals(value)) {\n                    return bizLogType.getMessage();\n                }\n            }\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/state/LogSucceed.java",
    "content": "package cn.enilu.material.bean.constant.state;\n\n/**\n * 业务是否成功的日志记录\n *\n * @author fengshuonan\n * @Date 2017年1月22日 下午12:14:59\n */\npublic enum LogSucceed {\n\n    SUCCESS(\"成功\"),\n    FAIL(\"失败\");\n\n    String message;\n\n    LogSucceed(String message) {\n        this.message = message;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/state/LogType.java",
    "content": "package cn.enilu.material.bean.constant.state;\n\n/**\n * 日志类型\n *\n * @author fengshuonan\n * @Date 2017年1月22日 下午12:14:59\n */\npublic enum LogType {\n\n    LOGIN(\"登录日志\"),\n    LOGIN_FAIL(\"登录失败日志\"),\n    EXIT(\"退出日志\"),\n    EXCEPTION(\"异常日志\"),\n    BUSSINESS(\"业务日志\");\n\n    String message;\n\n    LogType(String message) {\n        this.message = message;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/state/ManagerStatus.java",
    "content": "package cn.enilu.material.bean.constant.state;\n\n/**\n * 管理员的状态\n *\n * @author fengshuonan\n * @Date 2017年1月10日 下午9:54:13\n */\npublic enum ManagerStatus {\n\n    OK(1, \"启用\"), FREEZED(2, \"冻结\"), DELETED(3, \"被删除\");\n\n    int code;\n    String message;\n\n    ManagerStatus(int code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public static String valueOf(Integer value) {\n        if (value == null) {\n            return \"\";\n        } else {\n            for (ManagerStatus ms : ManagerStatus.values()) {\n                if (ms.getCode() == value) {\n                    return ms.getMessage();\n                }\n            }\n            return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/state/MenuStatus.java",
    "content": "package cn.enilu.material.bean.constant.state;\n\n/**\n * 菜单的状态\n *\n * @author fengshuonan\n * @Date 2017年1月22日 下午12:14:59\n */\npublic enum MenuStatus {\n\n    ENABLE(1, \"启用\"),\n    DISABLE(0, \"禁用\");\n\n    int code;\n    String message;\n\n    MenuStatus(int code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public static String valueOf(Integer status) {\n        if (status == null) {\n            return \"\";\n        } else {\n            for (MenuStatus s : MenuStatus.values()) {\n                if (s.getCode() == status) {\n                    return s.getMessage();\n                }\n            }\n            return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/constant/state/Order.java",
    "content": "package cn.enilu.material.bean.constant.state;\n\n/**\n * 数据库排序\n *\n * @author fengshuonan\n * @Date 2017年5月31日20:48:41\n */\npublic enum Order {\n\n    ASC(\"asc\"), DESC(\"desc\");\n\n    private String des;\n\n    Order(String des) {\n        this.des = des;\n    }\n\n    public String getDes() {\n        return des;\n    }\n\n    public void setDes(String des) {\n        this.des = des;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/core/BussinessLog.java",
    "content": "package cn.enilu.material.bean.core;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\nimport cn.enilu.material.bean.dictmap.SystemDict;\n\nimport java.lang.annotation.*;\n\n/**\n * 标记需要做业务日志的方法\n *\n * @author fengshuonan\n * @date 2017-03-31 12:46\n */\n@Inherited\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.METHOD})\npublic @interface BussinessLog {\n\n    /**\n     * 业务的名称,例如:\"修改菜单\"\n     */\n    String value() default \"\";\n\n    /**\n     * 被修改的实体的唯一标识,例如:菜单实体的唯一标识为\"id\"\n     */\n    String key() default \"id\";\n\n    /**\n     * 字典(用于查找key的中文名称和字段的中文名称)\n     */\n    Class<? extends AbstractDictMap> dict() default SystemDict.class;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/core/Permission.java",
    "content": "package cn.enilu.material.bean.core;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Inherited;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.annotation.Target;\n\n/**\n * 权限注解 用于检查权限 规定访问权限\n *\n * @example @Permission({roleID1,roleID2})\n * @example @Permission\n */\n@Inherited\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.METHOD})\npublic @interface Permission {\n    String[] value() default {};\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/core/ShiroUser.java",
    "content": "package cn.enilu.material.bean.core;\n\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.bean.vo.node.MenuNode;\n\nimport java.io.Serializable;\nimport java.util.List;\n\n/**\n * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息\n *\n * @author fengshuonan\n * @date 2016年12月5日 上午10:26:43\n */\npublic class ShiroUser implements Serializable {\n\n    private static final long serialVersionUID = 1L;\n\n    private Long id;          // 主键ID\n    private String account;      // 账号\n    private String name;         // 姓名\n    private Long deptId;      // 部门id\n    private List<Long> roleList; // 角色集\n    private String deptName;        // 部门名称\n    private List<String> roleNames; // 角色名称集\n    private List<String> roleCodes;//角色编码\n    private User profile;//用户详细资料\n    private List<MenuNode> titles;//用户可用菜单资源\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public String getAccount() {\n        return account;\n    }\n\n    public void setAccount(String account) {\n        this.account = account;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public Long getDeptId() {\n        return deptId;\n    }\n\n    public void setDeptId(Long deptId) {\n        this.deptId = deptId;\n    }\n\n    public List<Long> getRoleList() {\n        return roleList;\n    }\n\n    public void setRoleList(List<Long> roleList) {\n        this.roleList = roleList;\n    }\n\n    public String getDeptName() {\n        return deptName;\n    }\n\n    public void setDeptName(String deptName) {\n        this.deptName = deptName;\n    }\n\n    public List<String> getRoleNames() {\n        return roleNames;\n    }\n\n    public void setRoleNames(List<String> roleNames) {\n        this.roleNames = roleNames;\n    }\n\n    public List<String> getRoleCodes() {\n        return roleCodes;\n    }\n\n    public void setRoleCodes(List<String> roleCodes) {\n        this.roleCodes = roleCodes;\n    }\n\n    public User getProfile() {\n        return profile;\n    }\n\n    public void setProfile(User profile) {\n        this.profile = profile;\n    }\n\n    public List<MenuNode> getTitles() {\n        return titles;\n    }\n\n    public void setTitles(List<MenuNode> titles) {\n        this.titles = titles;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/CfgDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 字典map\n *\n * @author fengshuonan\n * @date 2017-05-06 15:43\n */\npublic class CfgDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"cfgId\",\"参数id\");\n        put(\"cfgName\",\"参数名称\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/CommonDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\npublic class CommonDict extends AbstractDictMap {\n    @Override\n    public void init() {\n        put(\"id\",\"ID\");\n        put(\"name\",\"名称\");\n        put(\"code\",\"编码\");\n        put(\"title\",\"标题\");\n        put(\"remark\",\"备注\");\n        put(\"descript\",\"备注\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/DeleteDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 用于删除业务的字典\n *\n * @author fengshuonan\n * @date 2017-05-06 15:01\n */\npublic class DeleteDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"roleId\",\"角色名称\");\n        put(\"deptId\", \"部门名称\");\n        put(\"menuId\", \"菜单名称\");\n        put(\"dictId\", \"字典名称\");\n        put(\"noticeId\", \"标题\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n        putFieldWrapperMethodName(\"roleId\",\"getCacheObject\");\n        putFieldWrapperMethodName(\"deptId\",\"getCacheObject\");\n        putFieldWrapperMethodName(\"menuId\",\"getCacheObject\");\n        putFieldWrapperMethodName(\"dictId\",\"getCacheObject\");\n        putFieldWrapperMethodName(\"noticeId\",\"getCacheObject\");\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/DeptDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 部门的映射\n *\n * @author fengshuonan\n * @date 2017-05-06 15:01\n */\npublic class DeptDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"deptId\", \"部门名称\");\n        put(\"id\",\"部门名称\");\n        put(\"num\", \"部门排序\");\n        put(\"pid\", \"上级名称\");\n        put(\"simplename\", \"部门简称\");\n        put(\"fullname\", \"部门全称\");\n        put(\"tips\", \"备注\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n        putFieldWrapperMethodName(\"deptId\", \"getDeptName\");\n        putFieldWrapperMethodName(\"pid\", \"getDeptName\");\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/DictMap.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 字典map\n *\n * @author fengshuonan\n * @date 2017-05-06 15:43\n */\npublic class DictMap extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"dictId\",\"字典名称\");\n        put(\"dictName\",\"字典名称\");\n        put(\"dictValues\",\"字典内容\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/LogDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 日志的字典\n *\n * @author fengshuonan\n * @date 2017-05-06 15:01\n */\npublic class LogDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"tips\",\"备注\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/MenuDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 菜单的字典\n *\n * @author fengshuonan\n * @date 2017-05-06 15:01\n */\npublic class MenuDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"menuId\",\"菜单id\");\n        put(\"id\",\"菜单id\");\n        put(\"code\",\"菜单编号\");\n        put(\"pcode\",\"菜单父编号\");\n        put(\"name\",\"菜单名称\");\n        put(\"icon\",\"菜单图标\");\n        put(\"url\",\"url地址\");\n        put(\"num\",\"菜单排序号\");\n        put(\"levels\",\"菜单层级\");\n        put(\"tips\",\"备注\");\n        put(\"status\",\"菜单状态\");\n        put(\"isopen\",\"是否打开\");\n        put(\"\",\"\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/NoticeMap.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 通知的映射\n *\n * @author fengshuonan\n * @date 2017-05-06 15:01\n */\npublic class NoticeMap extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"title\", \"标题\");\n        put(\"content\", \"内容\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/RoleDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 角色的字典\n *\n * @author fengshuonan\n * @date 2017-05-06 15:01\n */\npublic class RoleDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"roleId\",\"角色名称\");\n        put(\"num\",\"角色排序\");\n        put(\"pid\",\"角色的父级\");\n        put(\"name\",\"角色名称\");\n        put(\"deptid\",\"部门名称\");\n        put(\"tips\",\"备注\");\n        put(\"ids\",\"资源名称\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n        putFieldWrapperMethodName(\"pid\",\"getSingleRoleName\");\n        putFieldWrapperMethodName(\"deptid\",\"getDeptName\");\n        putFieldWrapperMethodName(\"roleId\",\"getSingleRoleName\");\n        putFieldWrapperMethodName(\"ids\",\"getMenuNames\");\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/SystemDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 系统相关的字典\n *\n * @author fengshuonan\n * @date 2017-05-06 15:48\n */\npublic class SystemDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n\n    }\n\n    @Override\n    protected void initBeWrapped() {\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/TaskDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 字典map\n *\n * @author fengshuonan\n * @date 2017-05-06 15:43\n */\npublic class TaskDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"taskId\",\"任务id\");\n        put(\"name\",\"任务名称\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/UserDict.java",
    "content": "package cn.enilu.material.bean.dictmap;\n\nimport cn.enilu.material.bean.dictmap.base.AbstractDictMap;\n\n/**\n * 用户的字典\n *\n * @author fengshuonan\n * @date 2017-05-06 15:01\n */\npublic class UserDict extends AbstractDictMap {\n\n    @Override\n    public void init() {\n        put(\"userId\",\"账号\");\n        put(\"avatar\",\"头像\");\n        put(\"account\",\"账号\");\n        put(\"name\",\"名字\");\n        put(\"birthday\",\"生日\");\n        put(\"sex\",\"性别\");\n        put(\"email\",\"电子邮件\");\n        put(\"phone\",\"电话\");\n        put(\"roleid\",\"角色名称\");\n        put(\"deptid\",\"部门名称\");\n        put(\"roleIds\",\"角色名称集合\");\n    }\n\n    @Override\n    protected void initBeWrapped() {\n        putFieldWrapperMethodName(\"sex\",\"getSexName\");\n        putFieldWrapperMethodName(\"deptid\",\"getDeptName\");\n        putFieldWrapperMethodName(\"roleid\",\"getSingleRoleName\");\n        putFieldWrapperMethodName(\"userId\",\"getUserAccountById\");\n        putFieldWrapperMethodName(\"roleIds\",\"getRoleName\");\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dictmap/base/AbstractDictMap.java",
    "content": "package cn.enilu.material.bean.dictmap.base;\n\nimport java.util.HashMap;\n\n/**\n * 字典映射抽象类\n *\n * @author fengshuonan\n * @date 2017-05-06 14:58\n */\npublic abstract class AbstractDictMap {\n\n    protected HashMap<String, String> dictory = new HashMap<>();\n    protected HashMap<String, String> fieldWarpperDictory = new HashMap<>();\n\n    public AbstractDictMap(){\n        put(\"id\",\"主键id\");\n        init();\n        initBeWrapped();\n    }\n\n    /**\n     * 初始化字段英文名称和中文名称对应的字典\n     *\n     * @author enilu.cn\n     * @Date 2017/5/9 19:39\n     */\n    public abstract void init();\n\n    /**\n     * 初始化需要被包装的字段(例如:性别为1:男,2:女,需要被包装为汉字)\n     *\n     * @author enilu.cn\n     * @Date 2017/5/9 19:35\n     */\n    protected abstract void initBeWrapped();\n\n    public String get(String key) {\n        return this.dictory.get(key);\n    }\n\n    public void put(String key, String value) {\n        this.dictory.put(key, value);\n    }\n\n    public String getFieldWarpperMethodName(String key){\n        return this.fieldWarpperDictory.get(key);\n    }\n\n    public void putFieldWrapperMethodName(String key,String methodName){\n        this.fieldWarpperDictory.put(key,methodName);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/dto/UserDto.java",
    "content": "package cn.enilu.material.bean.dto;\n\nimport lombok.Data;\nimport org.springframework.format.annotation.DateTimeFormat;\n\nimport java.util.Date;\n\n/**\n * 用户传输bean\n * \n * @author enilu.cn\n * @Date 2017/5/5 22:40\n */\n@Data\npublic class UserDto{\n\n\tprivate Long id;\n\tprivate String account;\n\tprivate String password;\n\tprivate String salt;\n\tprivate String name;\n\n\t@DateTimeFormat(pattern = \"yyyy-MM-dd\")\n\tprivate Date birthday;\n\tprivate Integer sex;\n\tprivate String email;\n\tprivate String phone;\n\tprivate String roleid;\n\tprivate Long deptid;\n\tprivate Long eduorgid;\n\tprivate Integer status;\n\tprivate Date createtime;\n\tprivate Integer version;\n\tprivate String avatar;\n\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/BaseEntity.java",
    "content": "package cn.enilu.material.bean.entity;\n\nimport lombok.Data;\nimport org.springframework.data.annotation.CreatedBy;\nimport org.springframework.data.annotation.CreatedDate;\nimport org.springframework.data.annotation.LastModifiedBy;\nimport org.springframework.data.annotation.LastModifiedDate;\n\nimport javax.persistence.Column;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport javax.persistence.MappedSuperclass;\nimport java.io.Serializable;\nimport java.util.Date;\n\n\n\n/**\n * Created  on 2019/1/8 0002.\n *\n * @author enilu\n */\n@MappedSuperclass\n@Data\npublic abstract class BaseEntity implements Serializable {\n\n    @Id\n    @GeneratedValue\n    private Long id;\n    @CreatedDate\n    @Column(name = \"create_time\",columnDefinition=\"DATETIME COMMENT '创建时间/注册时间'\")\n    private Date createTime;\n    @Column(name = \"create_by\",columnDefinition=\"bigint COMMENT '创建人'\")\n    @CreatedBy\n    private Long createBy;\n    @LastModifiedDate\n    @Column(name = \"modify_time\",columnDefinition=\"DATETIME COMMENT '最后更新时间'\")\n    private Date modifyTime;\n    @LastModifiedBy\n    @Column(name = \"modify_by\",columnDefinition=\"bigint COMMENT '最后更新人'\")\n    private Long modifyBy;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/message/Message.java",
    "content": "package cn.enilu.material.bean.entity.message;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\n\n/**\n * 历史消息\n */\n@Data\n@Entity(name=\"t_message\")\n@Table(appliesTo = \"t_message\",comment = \"历史消息\")\npublic class Message extends BaseEntity {\n    @Column(name=\"tpl_code\",columnDefinition = \"VARCHAR(32) COMMENT '模板编码'\")\n    private String tplCode;\n    @Column(name=\"content\",columnDefinition = \"TEXT COMMENT '消息内容'\")\n    private String content;\n    @Column(name=\"receiver\",columnDefinition = \"VARCHAR(64) COMMENT '接收者'\")\n    private String receiver;\n    @Column(name=\"type\",columnDefinition = \"VARCHAR(32) COMMENT '消息类型,0:短信,1:邮件'\")\n    private Integer type;\n    @Column(name=\"state\",columnDefinition = \"VARCHAR(32) COMMENT '消息类型,0:初始,1:成功,2:失败'\")\n    private Integer state;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/message/MessageSender.java",
    "content": "package cn.enilu.material.bean.entity.message;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.validation.constraints.NotBlank;\n\n/**\n * 消息发送者\n */\n@Data\n@Entity(name=\"t_message_sender\")\n@Table(appliesTo = \"t_message_sender\",comment = \"消息发送者\")\npublic class MessageSender extends BaseEntity {\n    @Column(name=\"name\",columnDefinition = \"VARCHAR(64) COMMENT '名称'\")\n    @NotBlank(message = \"名称并能为空\")\n    private String name;\n    @Column(name=\"class_name\",columnDefinition = \"VARCHAR(64) COMMENT '发送类'\")\n    @NotBlank(message = \"发送类不能为空\")\n    private String className;\n    @Column(name=\"tpl_code\",columnDefinition = \"VARCHAR(64) COMMENT '短信运营商模板编号'\")\n    private String tplCode;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/message/MessageTemplate.java",
    "content": "package cn.enilu.material.bean.entity.message;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\n\nimport javax.persistence.*;\nimport javax.validation.constraints.NotBlank;\nimport javax.validation.constraints.NotNull;\n\n/**\n * 消息模板\n */\n@Data\n@Entity(name=\"t_message_template\")\n@Table(appliesTo = \"t_message_template\",comment = \"消息模板\")\npublic class MessageTemplate extends BaseEntity {\n    @Column(name=\"code\",columnDefinition = \"VARCHAR(32) COMMENT '编号'\")\n    @NotBlank(message = \"编号不能为空\")\n    private String code;\n    @NotBlank(message = \"标题不能为空\")\n    @Column(name=\"title\",columnDefinition = \"VARCHAR(64) COMMENT '标题'\")\n    private String title;\n    @NotBlank(message = \"内容并能为空\")\n    @Column(name=\"content\",columnDefinition = \"TEXT COMMENT '内容'\")\n    private String content;\n    @Column(name=\"cond\",columnDefinition = \"VARCHAR(32) COMMENT '发送条件'\")\n    private String cond;\n    @Column(name=\"id_message_sender\",columnDefinition = \"BIGINT COMMENT '发送者id'\")\n    @NotNull(message = \"发送器不能为空\")\n    private Long idMessageSender;\n    @Column(name=\"type\",columnDefinition = \"VARCHAR(32) COMMENT '消息类型,0:短信,1:邮件'\")\n    private Integer type;\n    @JoinColumn(name=\"id_message_sender\", referencedColumnName = \"id\",  columnDefinition = \"BIGINT comment '发送者id'\", insertable = false, updatable = false,foreignKey = @ForeignKey(name=\"none\",value = ConstraintMode.NO_CONSTRAINT))\n    @ManyToOne(fetch = FetchType.EAGER)\n    private MessageSender messageSender;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/Cfg.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\nimport javax.validation.constraints.NotBlank;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name=\"t_sys_cfg\")\n@Table(appliesTo = \"t_sys_cfg\",comment = \"系统参数\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class Cfg  extends BaseEntity {\n    @Column(name = \"cfg_name\",columnDefinition = \"VARCHAR(256) COMMENT '参数名'\")\n    @NotBlank(message = \"参数名不能为空\")\n    private String cfgName;\n    @Column(name = \"cfg_value\",columnDefinition = \"VARCHAR(512) COMMENT '参数值'\")\n    @NotBlank(message = \"参数值不能为空\")\n    private String cfgValue;\n    @Column(name = \"cfg_desc\",columnDefinition = \"TEXT COMMENT '备注'\")\n    private String cfgDesc;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/Dept.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name=\"t_sys_dept\")\n@Table(appliesTo = \"t_sys_dept\",comment = \"部门\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class Dept extends BaseEntity {\n    @Column\n    private Integer num;\n    @Column\n    private Long pid;\n    @Column\n    private String pids;\n    @Column\n    private String simplename;\n    @Column\n    private String fullname;\n    @Column\n    private String tips;\n    @Column\n    private Integer version;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/Dict.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name=\"t_sys_dict\")\n@Table(appliesTo = \"t_sys_dict\",comment = \"字典\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class Dict extends BaseEntity {\n    @Column(columnDefinition = \"BIGINT COMMENT '字典组id'\")\n    private Long pid;\n    @Column(columnDefinition = \"VARCHAR(32) COMMENT '字典值'\")\n    private String value;\n    @Column(columnDefinition = \"VARCHAR(32) COMMENT '字典显示值'\")\n    private String name;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/FileInfo.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.Table;\nimport javax.persistence.Transient;\n\n@Data\n@Entity\n@Table(name=\"t_sys_file_info\")\npublic class FileInfo extends BaseEntity {\n    @Column\n    private String originalFileName;\n    @Column\n    private String realFileName;\n    @Transient\n    private String ablatePath;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/LoginLog.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport lombok.Data;\nimport org.hibernate.annotations.CreationTimestamp;\nimport org.hibernate.annotations.Table;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport java.util.Date;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name=\"t_sys_login_log\")\n@Table(appliesTo = \"t_sys_login_log\",comment = \"登录日志\")\n@Data\npublic class LoginLog {\n    @Id\n    @GeneratedValue\n    private Integer id;\n    @Column\n    private String logname;\n    @Column\n    private Integer userid;\n    @Column\n    private String succeed;\n    @Column\n    private String message;\n    @Column\n    private String ip;\n    @CreationTimestamp\n    @Column(name = \"create_time\",columnDefinition=\"DATETIME COMMENT '创建时间'\")\n    private Date createTime;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/Menu.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name = \"t_sys_menu\")\n@Table(appliesTo = \"t_sys_menu\",comment = \"菜单\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class Menu  extends BaseEntity {\n    @Column\n    private String code;\n    @Column\n    private String pcode;\n    @Column\n    private String pcodes;\n    @Column\n    private String name;\n    @Column\n    private String icon;\n    @Column\n    private String url;\n    @Column\n    private Integer num;\n    @Column\n    private Integer levels;\n    @Column\n    private Integer ismenu;\n    @Column\n    private String tips;\n    @Column\n    private Integer status;\n    @Column\n    private Integer isopen;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/Notice.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name=\"t_sys_notice\")\n@Table(appliesTo = \"t_sys_notice\",comment = \"系统通知\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class Notice extends BaseEntity {\n    @Column\n    private String title;\n    @Column\n    private Integer type;\n    @Column\n    private String content;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/OperationLog.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport java.util.Date;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name = \"t_sys_operation_log\")\n@Table(appliesTo= \"t_sys_operation_log\",comment = \"操作日志\")\n@Data\npublic class OperationLog {\n\n    @Id\n    @GeneratedValue\n    private Long id;\n    @Column\n    private String logtype;\n    @Column\n    private String logname;\n    @Column\n    private Integer userid;\n    @Column\n    private String classname;\n    @Column\n    private String method;\n    @Column(name=\"create_time\")\n    private Date createTime;\n    @Column\n    private String succeed;\n    @Column(columnDefinition = \"TEXT COMMENT '详细信息'\")\n    private String message;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/Relation.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\n\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name=\"t_sys_relation\")\n@Table(appliesTo = \"t_sys_relation\",comment = \"角色菜单关系\")\n@Data\npublic class Relation {\n    @Id\n    @GeneratedValue\n    private Long id;\n    @Column\n    private Long menuid;\n    @Column\n    private Long roleid;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/Role.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name=\"t_sys_role\")\n@Table(appliesTo = \"t_sys_role\",comment = \"角色\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class Role extends BaseEntity {\n    @Column\n    private Integer num;\n    @Column\n    private Long pid;\n    @Column\n    private String name;\n    @Column\n    private Long deptid;\n    @Column\n    private String tips;\n    @Column\n    private Integer version;\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/Task.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\nimport javax.validation.constraints.NotBlank;\nimport java.util.Date;\n\n@Table(appliesTo=\"t_sys_task\",comment = \"定时任务\")\n@Entity(name=\"t_sys_task\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class Task extends BaseEntity {\n\n    @Column(columnDefinition = \"VARCHAR(50) COMMENT '任务名'\")\n    @NotBlank(message = \"任务名不能为空\")\n    private String name;\n\n    @Column(name=\"job_group\", columnDefinition = \"VARCHAR(50) COMMENT '任务组名'\")\n    private String jobGroup;\n\n    @Column(name=\"job_class\", columnDefinition = \"VARCHAR(255) COMMENT '执行类'\")\n    @NotBlank(message = \"执行类不能为空\")\n    private String jobClass;\n\n    @Column(name=\"note\", columnDefinition = \"VARCHAR(255) COMMENT '任务说明'\")\n    private String note;\n\n    @Column(name=\"cron\", columnDefinition = \"VARCHAR(50) COMMENT '定时规则'\")\n    @NotBlank(message = \"定时规则不能为空\")\n    private String cron;\n\n    @Column(name=\"concurrent\", columnDefinition = \"TINYINT COMMENT '是否允许并发'\")\n    private boolean concurrent;\n\n    @Column(name=\"data\", columnDefinition = \"TEXT COMMENT '执行参数'\")\n    private String data;\n\n    @Column(name=\"exec_at\", columnDefinition = \"DateTime COMMENT '执行时间'\")\n    private Date execAt;\n\n    @Column(name=\"exec_result\", columnDefinition = \"text COMMENT '执行结果'\")\n    private String execResult;\n\n    @Column(name=\"disabled\", columnDefinition = \"TINYINT COMMENT '是否禁用'\")\n    private boolean disabled;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/TaskLog.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\n\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.GeneratedValue;\nimport javax.persistence.Id;\nimport java.util.Date;\n\n/**\n * <p>\n * User: Yao\n * Date: 2017-06-22 11:12:48\n */\n@Table(appliesTo=\"t_sys_task_log\",comment = \"定时任务日志\")\n@Entity(name=\"t_sys_task_log\")\n@Data\npublic class TaskLog{\n    public static final int EXE_FAILURE_RESULT = 0;\n    public static final int EXE_SUCCESS_RESULT = 1;\n\n    @Id\n    @GeneratedValue\n    private Long id;\n    @Column\n    private Long idTask;\n    @Column(columnDefinition = \"VARCHAR(50) COMMENT '任务名'\")\n    private String name;\n\n    @Column(columnDefinition = \"DATETime COMMENT '执行时间'\")\n    private Date execAt;\n\n    @Column(columnDefinition = \"INTEGER COMMENT '执行结果（成功:1、失败:0)'\")\n    private int execSuccess;\n\n    @Column(columnDefinition = \"VARCHAR(500) COMMENT '抛出异常'\")\n    private String jobException;\n}"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/system/User.java",
    "content": "package cn.enilu.material.bean.entity.system;\n\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport org.springframework.data.jpa.domain.support.AuditingEntityListener;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\nimport javax.persistence.EntityListeners;\nimport java.util.Date;\n\n/**\n * Created  on 2018/4/2 0002.\n *\n * @author enilu\n */\n@Entity(name = \"t_sys_user\")\n@Table(appliesTo = \"t_sys_user\",comment = \"系统管理员\")\n@Data\n@EntityListeners(AuditingEntityListener.class)\npublic class User  extends BaseEntity {\n    @Column\n    private String avatar=\"\";\n    @Column\n    private String account;\n    @Column\n    private String password;\n    @Column\n    private String salt;\n    @Column\n    private String name;\n    @Column\n    private Date birthday;\n    @Column\n    private Integer sex;\n    @Column\n    private String email;\n    @Column\n    private String phone;\n    @Column\n    private String roleid;\n    @Column\n    private Long deptid;\n    @Column\n    private Integer status;\n    @Column\n    private Integer version;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/entity/test/Boy.java",
    "content": "package cn.enilu.material.bean.entity.test;\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\n\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\n/**\n * 该实体用于测试生成代码\n */\n@Entity(name=\"t_test_boy\")\n@Table(appliesTo = \"t_test_boy\",comment = \"男孩\")\n@Data\n\npublic class Boy extends BaseEntity {\n    @Column(columnDefinition = \"VARCHAR(32) COMMENT '姓名'\")\n    private String name;\n    @Column(columnDefinition = \"INT COMMENT '年龄'\")\n    private Integer age;\n    @Column(columnDefinition = \"VARCHAR(12) COMMENT '生日'\")\n    private String birthday;\n    @Column(name = \"has_girl_friend\",columnDefinition = \"TINYINT COMMENT '是否有女朋友'\")\n    private Boolean hasGirFriend;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/enumeration/BizExceptionEnum.java",
    "content": "package cn.enilu.material.bean.enumeration;\n\nimport cn.enilu.material.bean.exception.ServiceExceptionEnum;\n\n/**\n * @Description 所有业务异常的枚举\n * @author fengshuonan\n * @date 2016年11月12日 下午5:04:51\n */\npublic enum BizExceptionEnum implements ServiceExceptionEnum {\n\n\t/**\n\t * 字典\n\t */\n\tDICT_EXISTED(400,\"字典已经存在\"),\n\tERROR_CREATE_DICT(500,\"创建字典失败\"),\n\tERROR_WRAPPER_FIELD(500,\"包装字典属性失败\"),\n\n\n\t/**\n\t * 文件上传\n\t */\n\tFILE_READING_ERROR(400,\"FILE_READING_ERROR!\"),\n\tFILE_NOT_FOUND(400,\"FILE_NOT_FOUND!\"),\n\tNOT_ALLOW(400, \"不允许该操作\"),\n\tUPLOAD_ERROR(500,\"上传图片出错\"),\n\n\t/**\n\t * 权限和数据问题\n\t */\n\tDB_RESOURCE_NULL(400,\"数据库中没有该资源\"),\n\tNO_PERMITION(405, \"没有该操作权限\"),\n\tREQUEST_INVALIDATE(400,\"请求数据格式不正确\"),\n\tINVALID_KAPTCHA(400,\"验证码不正确\"),\n\tCANT_DELETE_ADMIN(600,\"不能删除超级管理员\"),\n\tCANT_FREEZE_ADMIN(600,\"不能冻结超级管理员\"),\n\tCANT_CHANGE_ADMIN(600,\"不能修改超级管理员\"),\n\n\t/**\n\t * 账户问题\n\t */\n\tUSER_ALREADY_REG(401,\"该用户已经注册\"),\n\tNO_THIS_USER(400,\"没有此用户\"),\n\tUSER_NOT_EXISTED(400, \"没有此用户\"),\n\tACCOUNT_FREEZED(401, \"账号被冻结\"),\n\tOLD_PWD_NOT_RIGHT(402, \"原密码不正确\"),\n\tTWO_PWD_NOT_MATCH(405, \"两次输入密码不一致\"),\n\n\t/**\n\t * 错误的请求\n\t */\n\tMENU_PCODE_COINCIDENCE(400,\"菜单编号和副编号不能一致\"),\n\tEXISTED_THE_MENU(400,\"菜单编号重复，不能添加\"),\n\tDICT_MUST_BE_NUMBER(400,\"字典的值必须为数字\"),\n\tREQUEST_NULL(400, \"请求有错误\"),\n\tSESSION_TIMEOUT(400, \"会话超时\"),\n\tSERVER_ERROR(500, \"服务器异常\"),\n\tCAN_NOT_DELETE(400,\"数据被引用，无法删除\");\n\n\tBizExceptionEnum(int code, String message) {\n\t\tthis.code = code;\n\t\tthis.message = message;\n\t}\n\t\n\tprivate Integer code;\n\n\tprivate String message;\n\n\t@Override\n\tpublic Integer getCode() {\n\t\treturn code;\n\t}\n\n\tpublic void setCode(Integer code) {\n\t\tthis.code = code;\n\t}\n\n\t@Override\n\tpublic String getMessage() {\n\t\treturn message;\n\t}\n\n\tpublic void setMessage(String message) {\n\t\tthis.message = message;\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/enumeration/ConfigKeyEnum.java",
    "content": "package cn.enilu.material.bean.enumeration;\n\npublic enum ConfigKeyEnum {\n\n    SYSTEM_FILE_UPLOAD_PATH(\"system.file.upload.path\"),\n    SYSTEM_APP_NAME(\"system.app.name\"),\n    SYSTEM_RESOURCE_VERSION(\"system.resource.version\"),\n    /**\n     * 腾讯sms接口appid\n     */\n    API_TENCENT_SMS_APPID(\"api.tencent.sms.appid\"),\n    /**\n     * 腾讯sms接口appkey\n     */\n    API_TENCENT_SMS_APPKEY(\"api.tencent.sms.appkey\"),\n    /**\n     * 腾讯sms接口签名参数\n     */\n    API_TENCENT_SMS_SIGN(\"api.tencent.sms.sign\");\n\n    private String value;\n\n    ConfigKeyEnum(String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/enumeration/ProjectEnum.java",
    "content": "package cn.enilu.material.bean.enumeration;\n\n/**\n * Created by deanyule on 17/8/16.\n */\npublic enum ProjectEnum {\n\n    SCORE_CARD(\"ScoreCard\"),\n    DOLPHIN_PROD(\"dolphin\"),\n    SNOW_PRODUCT(\"PRJ_SNOW_PRODUCT\");\n\n    private String value;\n\n    ProjectEnum(String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/enumeration/RedisQueueName.java",
    "content": "package cn.enilu.material.bean.enumeration;\n\n/**\n * redis队列名称\n * Created by zt on 2017/8/25 0015.\n */\npublic enum RedisQueueName {\n    CREDIT_LIMIT(\"credit_limit\"),COLLECTION_TAG(\"collection_tag\");\n\n    private String value;\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n\n    RedisQueueName(String value) {\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/enumeration/SerialNumberEnum.java",
    "content": "package cn.enilu.material.bean.enumeration;\n\n/**\n * Created by deanyule on 17/4/13.\n * 系统各种编号枚举\n */\npublic enum SerialNumberEnum {\n\n    //交易编号\n    TR_DFYW_KLT(\"TRDFYWKLT\", \"代付-开联通\"),\n    TR_DFYW_CJ0(\"TRDFYWCJ0\", \"代付-畅捷\"),\n    TR_DFYW_LL0(\"TRDFYWLL0\", \"代付-连连\"),\n    TR_DFYW_RB0(\"TRDFYWRB0\", \"代付-融宝\"),\n    TR_DFYW_YSB(\"TRDFYWYSB\", \"代付-银生宝\"),\n    TR_DSYW_CJ0(\"TRDSYWCJ0\", \"代收-畅捷\"),\n    TR_DSYW_YSB(\"TRDSYWYSB\", \"代收-银生宝\"),\n    TR_DSYW_CPCN(\"TRDSYWCPC\", \"代收-中金\"),\n    TR_DSYW_BAOFU(\"TRDSYWBF\", \"代收-宝付\"),\n    TR_DSYW_FY0(\"TRDSYWFY0\", \"代收-富友\"),\n    TR_KJWG_CJ0(\"TRKJWGCJ0\", \"快捷-畅捷\"),\n    TR_KJWG_FY0(\"TRFY\", \"快捷-富友\"),\n    TR_KJWG_LL0(\"TRKJWGLL0\", \"快捷-连连\"),\n    TR_KJWG_WX0(\"TRKJWGWX0\", \"快捷-微信\"),\n    TR_KJTK_CJ0(\"TRKJTKCJ0\", \"快捷-退款-畅捷\"),\n    TR_KJZL_KLT(\"TRKJZLKLT\", \"快捷-直连-开联通\"),\n    /**第三方抽成*/\n    TR_CCSN_000(\"TRCCSN000\", \"第三方抽成\"),\n    TR_MANUL_000(\"TRMANUL00\", \"手工还款记账\"),\n\n    //借款申请编号\n    JK_SQC(\"JKSQC\", \"借款申请客户为Company\"),\n    JK_SQP(\"JKSQP\", \"借款申请客户为PC\"),\n    JK_SQS(\"JKSQS\", \"借款申请客户为ShareTransfer\"),\n    JK_SQM(\"JKSQM\", \"借款申请客户为Mobile\"),\n    JK_SQH(\"JKSQH\", \"借款申请客户为person on H5\"),\n\n    //协议模板编号\n    XDXY_L_C(\"XDXYLC\",\"借款项目Lending Company\"),\n    XDXY_L_P(\"XDXYLP\", \"借款项目Lending Person\"),\n    XDXY_M_J(\"XDXYMJ\", \"居间协议M 借款居间J\"),\n    XDXY_R(\"XDXYR0\", \"注册协议R 0补位\"),\n    XDXY_Z(\"XDXYZ0\", \"征信协议Z 0补位\"),\n\n    //协议子编号\n    XDXY_L_P_0001(\"XDXYLP0001\", \"协议编号,借款项目Lending Person\"),\n    XDXY_R_P_0001(\"XDXYRP0001\", \"协议编号,代收协议签约\"),\n\n    //消息发送编号\n    XX_E(\"XXE\", \"发送方式Email\"),\n    XX_S(\"XXS\", \"发送方式SMS\"),\n    XX_L(\"XXL\", \"发送方式Letter\"),\n    XX_W(\"XXW\", \"发送方式微信\"),\n\n    //消息模板编号\n    XXMB_CL(\"XXMBCL\",\"credit lending个人信贷\"),\n    XXMB_MC(\"XXMBMC\", \"小贷\"),\n    XXMB_YX(\"XXMBYX\", \"营销类\"),\n\n    //用户ID编号\n    US_JK_C(\"USJKC\", \"借款JK来源Company\"),\n    US_JK_P(\"USJKP\", \"借款JK 来源Person on PC\"),\n    US_JK_S(\"USJKS\", \"借款JK 来源Share transfer\"),\n    US_JK_M(\"USJKM\", \"借款JK 来源person on Mobile\"),\n    US_JK_H(\"USJKH\", \"借款JK 来源person on H5\")\n    ;\n\n\n    private String code;\n\n    private String desc;\n\n    private SerialNumberEnum(String code, String desc) {\n        this.code = code;\n        this.desc = desc;\n    }\n\n    public String getDesc() {\n        return desc;\n    }\n\n    public void setDesc(String desc) {\n        this.desc = desc;\n    }\n\n    public String getCode() {\n        return code;\n    }\n\n    public void setCode(String code) {\n        this.code = code;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/enumeration/TypeEnum.java",
    "content": "package cn.enilu.material.bean.enumeration;\n\npublic class TypeEnum {\n\n\t/**\n\t * 输入数据的html类型\n\t */\n\tpublic enum DataItemShowType {\n\t\t/**\n\t\t * 0为文本框；1为下拉框；2为日期框\n\t\t */\n\t\tTEXT(0), SELECT(1), DATE(2);\n\n\t\tprivate int value;\n\n\t\tprivate DataItemShowType(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic int getValue() {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic void setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\t}\n\n\t/**\n\t * 调用类型枚举类\n\t */\n\tpublic enum InvokeTypeEnum {\n\n\t\t/**\n\t\t * 1:本地；1：远程\n\t\t */\n\t\tLOCAL(\"local\"), REMOTE(\"remote\");\n\n\t\tprivate String value;\n\n\t\tprivate InvokeTypeEnum(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic String getValue() {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic void setValue(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\t}\n\n\t/**\n\t * 调用结果枚举类\n\t */\n\tpublic enum InvokeStateEnum {\n\n\t\t/**\n\t\t * 1:查询成功；-1：查询无数据；2：查询异常\n\t\t */\n\t\tSUCCESS(1, \"0000\"), NO_DATA(-1, \"0001\"), ERROR(2, \"9999\"), ERROR_NO_WARN(2, \"9999\");\n\n\t\tprivate int value;\n\n\t\tprivate String code;\n\n\t\tprivate InvokeStateEnum(int value, String code) {\n\t\t\tthis.value = value;\n\t\t\tthis.code = code;\n\t\t}\n\n\t\tpublic int getValue() {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic void setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic String getCode() {\n\t\t\treturn code;\n\t\t}\n\n\t\tpublic void setCode(String code) {\n\t\t\tthis.code = code;\n\t\t}\n\n\t\tpublic static boolean isError(InvokeStateEnum invokeState) {\n\t\t\treturn InvokeStateEnum.ERROR == invokeState || InvokeStateEnum.ERROR_NO_WARN == invokeState;\n\t\t}\n\n\t\tpublic static boolean isNeedWarning(InvokeStateEnum invokeState) {\n\t\t\treturn InvokeStateEnum.ERROR == invokeState;\n\t\t}\n\n\t\tpublic static InvokeStateEnum getNoData() {\n\t\t\treturn InvokeStateEnum.NO_DATA;\n\t\t}\n\n\t\tpublic static InvokeStateEnum getSuccess() {\n\t\t\treturn InvokeStateEnum.SUCCESS;\n\t\t}\n\n\t\tpublic static InvokeStateEnum getError() {\n\t\t\treturn InvokeStateEnum.ERROR;\n\t\t}\n\n\t\tpublic static InvokeStateEnum getErrorNoWarn() {\n\t\t\treturn InvokeStateEnum.ERROR_NO_WARN;\n\t\t}\n\t}\n\n\t/**\n\t * 订单来源枚举类\n\t */\n\tpublic enum OrderChannelEnum {\n\t\tWEB(0, \"web\"), WS(1, \"接口\");\n\n\t\tprivate int value;\n\n\t\tprivate String name;\n\n\t\tprivate OrderChannelEnum(int value, String name) {\n\t\t\tthis.value = value;\n\t\t\tthis.name = name;\n\t\t}\n\n\t\tpublic int getValue() {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic void setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\n\t\tpublic void setName(String name) {\n\t\t\tthis.name = name;\n\t\t}\n\t}\n\n\tpublic enum AdminType {\n\t\t/**\n\t\t * 0为普通用户；1为超级管理员；2为机构管理员\n\t\t */\n\t\tNORMAL(0), SUPERADMIN(1), ORGADMIN(2);\n\n\t\tprivate int value;\n\n\t\tprivate AdminType(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic int getValue() {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic void setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\t}\n\n\tpublic enum MatchType {\n\t\t/**\n\t\t * 0为模糊匹配;1为精确匹配;\n\t\t */\n\t\tFUZZY(0), EXACT(1);\n\n\t\tprivate int value;\n\n\t\tprivate MatchType(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic int getValue() {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic void setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\t}\n\n\tpublic enum MessageType {\n\t\t/**\n\t\t * 0为系统通知;1为订阅通知;2为用户发送\n\t\t */\n\t\tNOTIFY(0), SUBSCRIBE(1), SEND(2);\n\n\t\tprivate int value;\n\n\t\tprivate MessageType(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic int getValue() {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic void setValue(int value) {\n\t\t\tthis.value = value;\n\t\t}\n\t}\n\n\tpublic enum Aspect {\n\n\t\tAFTERPAY(\"afterPay\"),\n\t\tEVENTTRACK(\"eventTrack\"),\n\t\tSNOWLOG(\"snowlog\"),\n\t\tAFTERACTION(\"afterAction\"),\n\t\tENTERFINAL(\"enterFinal\"),\n\t\tQUARTZJOB(\"quartzJob\"),\n\t\tAUTOTRIGGER(\"autoTrigger\"),\n\t\tPAYLIMIT(\"payLimit\");\n\n\t\tprivate String value;\n\n\t\tprivate Aspect(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\n\t\tpublic String getValue() {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic void setValue(String value) {\n\t\t\tthis.value = value;\n\t\t}\n\t}\n\n\tpublic enum JobStatus {\n\t\tNONE(\"NONE\", \"未知\"),\n\t\tNORMAL(\"NORMAL\", \"正常运行\"),\n\t\tPAUSED(\"PAUSED\", \"暂停状态\"),\n\t\tCOMPLETE(\"COMPLETE\", \"运行完成\"),\n\t\tERROR(\"ERROR\", \"错误状态\"),\n\t\tBLOCKED(\"BLOCKED\", \"锁定状态\");\n\n\t\tprivate JobStatus(String index, String name) {\n\t\t\tthis.name = name;\n\t\t\tthis.index = index;\n\t\t}\n\n\t\tprivate String index;\n\t\tprivate String name;\n\n\t\tpublic String getName() {\n\t\t\treturn name;\n\t\t}\n\n\t\tpublic String getIndex() {\n\t\t\treturn index;\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/enumeration/cms/BannerTypeEnum.java",
    "content": "package cn.enilu.material.bean.enumeration.cms;\n\npublic enum  BannerTypeEnum {\n\n    INDEX(\"index\"),\n    NEWS(\"news\"),\n    CASE (\"case\"),\n    PRODUCT(\"product\"),\n    SOLUTION(\"solution\");\n\n    private String value;\n\n    BannerTypeEnum(String value) {\n        this.value = value;\n    }\n\n    public String getValue() {\n        return value;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/enumeration/cms/ChannelEnum.java",
    "content": "package cn.enilu.material.bean.enumeration.cms;\n\npublic enum ChannelEnum {\n\n    NEWS(1L,\"news\"),\n    PRODUCT(2L,\"product\"),\n    SOLUTION(3L,\"solution\"),\n    CASE(4L,\"case\");\n\n\n    private String value;\n    private Long id;\n    ChannelEnum(Long id,String value) {\n        this.id = id;\n        this.value = value;\n    }\n\n    public String getValue() {\n        return value;\n    }\n    public Long getId(){\n        return id;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/ApplicationException.java",
    "content": "package cn.enilu.material.bean.exception;\n\n/**\n * 封装异常\n *\n * @author fengshuonan\n * @Date 2017/12/28 下午10:32\n */\npublic class ApplicationException extends RuntimeException {\n\n    private Integer code;\n\n    private String message;\n\n    public ApplicationException(ServiceExceptionEnum serviceExceptionEnum) {\n        this.code = serviceExceptionEnum.getCode();\n        this.message = serviceExceptionEnum.getMessage();\n    }\n\n    public Integer getCode() {\n        return code;\n    }\n\n    public void setCode(Integer code) {\n        this.code = code;\n    }\n\n    @Override\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/ExceptionEnum.java",
    "content": "package cn.enilu.material.bean.exception;\n\n/**\n * 异常枚举\n *\n * @author fengshuonan\n * @Date 2017/12/28 下午10:33\n */\npublic enum ExceptionEnum implements ServiceExceptionEnum{\n\n\t/**\n\t * 其他\n\t */\n\tWRITE_ERROR(500,\"渲染界面错误\"),\n\n\t/**\n\t * 文件上传\n\t */\n\tFILE_READING_ERROR(400,\"FILE_READING_ERROR!\"),\n\tFILE_NOT_FOUND(400,\"FILE_NOT_FOUND!\"),\n\n\t/**\n\t * 错误的请求\n\t */\n\tREQUEST_NULL(400, \"请求有错误\"),\n\tSERVER_ERROR(500, \"服务器异常\"),\n\tTEST_NOT_ALLOWED(400, \"演示环境不允许该操作\"),\n\tONLY_DEMO_ACCOUNT(400,\"演示环境不能试用其他账号的登录\"),\n\n\tTASK_CONFIG_ERROR(500, \"定时任务配置错误\");\n\n\tExceptionEnum(int code, String message) {\n\t\tthis.code = code;\n\t\tthis.message = message;\n\t}\n\n\tprivate Integer code;\n\n\tprivate String message;\n\n\t@Override\n\tpublic Integer getCode() {\n\t\treturn code;\n\t}\n\n\tpublic void setCode(Integer code) {\n\t\tthis.code = code;\n\t}\n\n\t@Override\n\tpublic String getMessage() {\n\t\treturn message;\n\t}\n\n\tpublic void setMessage(String message) {\n\t\tthis.message = message;\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/InvalidKaptchaException.java",
    "content": "package cn.enilu.material.bean.exception;\n\n/**\n * 验证码错误异常\n *\n * @author fengshuonan\n * @date 2017-05-05 23:52\n */\npublic class InvalidKaptchaException extends RuntimeException {\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/MailException.java",
    "content": "package cn.enilu.material.bean.exception;\n\npublic class MailException extends Exception {\n\n\tpublic MailException(String msg) {\n\t\tsuper(msg);\n\t}\n\n\tpublic MailException(String msg, Throwable e) {\n\t\tsuper(msg, e);\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/ParamException.java",
    "content": "package cn.enilu.material.bean.exception;\n\npublic class ParamException extends Exception {\n\n\tpublic ParamException(String msg) {\n\t\tsuper(msg);\n\t}\n\n\tpublic ParamException(String msg, Throwable e) {\n\t\tsuper(msg, e);\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/ServiceExceptionEnum.java",
    "content": "package cn.enilu.material.bean.exception;\n\n/**\n * 抽象接口\n *\n * @author fengshuonan\n * @date 2017-12-28-下午10:27\n */\npublic interface ServiceExceptionEnum {\n\n    /**\n     * 获取异常编码\n     */\n    Integer getCode();\n\n    /**\n     * 获取异常信息\n     */\n    String getMessage();\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/SlConnectException.java",
    "content": "package cn.enilu.material.bean.exception;\n\nimport java.util.List;\n\npublic class SlConnectException extends Exception {\n\n\tprivate static final long serialVersionUID = 1L;\n\n\tprivate String errorCode;\n\tprivate List<String> details;\n\t\n\tpublic SlConnectException(String errorCode, String errorMessage) {\n\t\tsuper(errorMessage);\n\t\tthis.errorCode = errorCode;\n\t}\n\n\tpublic String getErrorCode() {\n\t\treturn errorCode;\n\t}\n\n\tpublic List<String> getDetails() {\n\t\treturn details;\n\t}\n\n\tpublic void setDetails(List<String> details) {\n\t\tthis.details = details;\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/SlEvalException.java",
    "content": "package cn.enilu.material.bean.exception;\n\nimport java.util.List;\n\npublic class SlEvalException extends Exception {\n\n\tprivate static final long serialVersionUID = 1L;\n\t\n\tprivate String errorCode;\n\tprivate List<String> details;\n\t\n\tpublic SlEvalException(String errorCode, String errorMessage) {\n\t\tsuper(errorMessage);\n\t\tthis.errorCode = errorCode;\n\t}\n\n\tpublic String getErrorCode() {\n\t\treturn errorCode;\n\t}\n\n\tpublic List<String> getDetails() {\n\t\treturn details;\n\t}\n\n\tpublic void setDetails(List<String> details) {\n\t\tthis.details = details;\n\t}\n\t\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/ValidException.java",
    "content": "package cn.enilu.material.bean.exception;\n\npublic class ValidException extends RuntimeException {\n\n\tpublic ValidException(String msg) {\n\t\tsuper(msg);\n\t}\n\n\tpublic ValidException(String msg, Throwable e) {\n\t\tsuper(msg, e);\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/XSException.java",
    "content": "package cn.enilu.material.bean.exception;\n\n/**\n * 定义通用异常\n * code 存储异常代码\n * @author czhou\n */\npublic class XSException extends Exception {\n\n\tprivate static final long serialVersionUID = 1L;\n\t\n\tprivate String code;\n\t\n\tpublic String getCode() {\n\t\treturn this.code;\n\t}\n\n\tpublic XSException(String code, String message, Throwable t) {\n\t\tsuper(message, t);\n\t\tthis.code = code;\n\t}\n\n\tpublic XSException(String code, String message) {\n\t\tthis(code, message, null);\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/exception/XSRuntimeException.java",
    "content": "package cn.enilu.material.bean.exception;\n\n@SuppressWarnings(\"serial\")\npublic class XSRuntimeException extends RuntimeException {\n\n\tpublic XSRuntimeException(String msg) {\n\t\tsuper(msg);\n\t}\n\t\n\tpublic XSRuntimeException(String msg, Throwable e) {\n\t\tsuper(msg, e);\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/DictVo.java",
    "content": "package cn.enilu.material.bean.vo;\n\n/**\n * DictVo\n *\n * @author enilu\n * @version 2018/8/14 0014\n */\npublic class DictVo {\n    private String key;\n    private String value;\n\n    public String getKey() {\n        return key;\n    }\n\n    public void setKey(String key) {\n        this.key = key;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n    public void setValue(String value) {\n        this.value = value;\n    }\n\n    public DictVo() {\n    }\n\n    public DictVo(String key, String value) {\n        this.key = key;\n        this.value = value;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/QuartzJob.java",
    "content": "package cn.enilu.material.bean.vo;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\nimport java.io.Serializable;\nimport java.util.Date;\nimport java.util.Map;\n\n@Getter\n@Setter\npublic class QuartzJob implements Serializable {\n\tprivate String jobId;\n\tprivate String jobName;\n\tprivate String jobGroup;\n\tprivate String jobClass;\n\tprivate String description;\n\tprivate String cronExpression;\n\tprivate boolean concurrent;\n\tprivate String jobStatus;\n\tprivate Date nextTime;\n\tprivate Date previousTime;\n\tprivate boolean disabled;\n\tprivate Map<String, Object> dataMap;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/SpringContextHolder.java",
    "content": "package cn.enilu.material.bean.vo;\n\nimport org.springframework.beans.BeansException;\nimport org.springframework.context.ApplicationContext;\nimport org.springframework.context.ApplicationContextAware;\nimport org.springframework.stereotype.Component;\n\n/**\n * Spring的ApplicationContext的持有者,可以用静态方法的方式获取spring容器中的bean\n *\n * @author fengshuonan\n * @date 2016年11月27日 下午3:32:11\n */\n@Component\npublic class SpringContextHolder implements ApplicationContextAware {\n\n    private static ApplicationContext applicationContext;\n\n    @Override\n    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {\n        SpringContextHolder.applicationContext = applicationContext;\n    }\n\n    public static ApplicationContext getApplicationContext() {\n        assertApplicationContext();\n        return applicationContext;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getBean(String beanName) {\n        assertApplicationContext();\n        return (T) applicationContext.getBean(beanName);\n    }\n\n    public static <T> T getBean(Class<T> requiredType) {\n        assertApplicationContext();\n        return applicationContext.getBean(requiredType);\n    }\n\n    private static void assertApplicationContext() {\n        if (SpringContextHolder.applicationContext == null) {\n            throw new RuntimeException(\"applicaitonContext属性为null,请检查是否注入了SpringContextHolder!\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/front/Ret.java",
    "content": "package cn.enilu.material.bean.vo.front;\n\nimport lombok.Getter;\nimport lombok.Setter;\n\n@Getter\n@Setter\npublic class Ret<T> {\n\n    private Integer code;\n    private String msg;\n    private T data;\n    private boolean success;\n\n    public Ret() {\n\n    }\n\n    public Ret(Integer code, String msg, T data) {\n        this.code = code;\n        this.msg = msg;\n        this.data = data;\n        this.success = \"0000\".equals(code);\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder builder = new StringBuilder();\n        builder.append(\"{\");\n        builder.append(\"'code':\").append(code).append(\",\");\n        builder.append(\"'msg':\").append(msg).append(\",\");\n        builder.append(\"'success':\").append(success).append(\",\");\n        builder.append(\"}\");\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/front/Rets.java",
    "content": "package cn.enilu.material.bean.vo.front;\n\npublic class Rets {\n\n    public static final Integer SUCCESS = 20000;\n    public static final Integer FAILURE = 9999;\n    public static  final Integer TOKEN_EXPIRE=50014;\n\n    public static Ret success(Object data) {\n        return new Ret(Rets.SUCCESS, \"成功\", data);\n    }\n\n    public static Ret failure(String msg) {\n        return new Ret(Rets.FAILURE, msg, null);\n    }\n\n    public static Ret success() {\n        return new Ret(Rets.SUCCESS, \"成功\", null);\n    }\n    public static  Ret expire(){\n        return new Ret(Rets.TOKEN_EXPIRE,\"token 过期\",null);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/node/DeptNode.java",
    "content": "package cn.enilu.material.bean.vo.node;\n\nimport cn.enilu.material.bean.entity.system.Dept;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * DeptNode\n *\n * @author enilu\n * @version 2018/9/15 0015\n */\npublic class DeptNode extends Dept {\n\n    private List<DeptNode> children = new ArrayList<>(10);\n\n    public List<DeptNode> getChildren() {\n        return children;\n    }\n\n    public void setChildren(List<DeptNode> children) {\n        this.children = children;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/node/IsMenu.java",
    "content": "package cn.enilu.material.bean.vo.node;\n\n/**\n * 是否是菜单的枚举\n *\n * @author fengshuonan\n * @date 2017年6月1日22:50:11\n */\npublic enum IsMenu {\n\n    YES(1, \"是\"),\n    NO(0, \"不是\");//不是菜单的是按钮\n\n    int code;\n    String message;\n\n    IsMenu(int code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public static String valueOf(Integer status) {\n        if (status == null) {\n            return \"\";\n        } else {\n            for (IsMenu s : IsMenu.values()) {\n                if (s.getCode() == status) {\n                    return s.getMessage();\n                }\n            }\n            return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/node/MenuNode.java",
    "content": "package cn.enilu.material.bean.vo.node;\n\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\n\n/**\n * @author fengshuonan\n * @Description 菜单的节点\n * @date 2016年12月6日 上午11:34:17\n */\npublic class MenuNode implements Comparable , Serializable {\n\n    /**\n     * 节点id\n     */\n    private Long id;\n\n    /**\n     * 父节点\n     */\n    private Long parentId;\n\n    /**\n     * 节点名称\n     */\n    private String name;\n\n    /**\n     * 按钮级别\n     */\n    private Integer levels;\n\n    /**\n     * 按钮级别\n     */\n    private Integer ismenu;\n    private String isMenuName;\n    private Integer status;\n    private String statusName;\n\n    /**\n     * 按钮的排序\n     */\n    private Integer num;\n\n    /**\n     * 节点的url\n     */\n    private String url;\n\n    /**\n     * 节点图标\n     */\n    private String icon;\n    /**\n     * 菜单编码\n     */\n    private String code;\n    /**\n     * 子节点的集合\n     */\n    private List<MenuNode> children = new ArrayList<>(10);\n\n    /**\n     * 查询子节点时候的临时集合\n     */\n    private List<MenuNode> linkedList = new ArrayList<MenuNode>();\n\n    public MenuNode() {\n        super();\n    }\n\n    public MenuNode(Long id, Long parentId) {\n        super();\n        this.id = id;\n        this.parentId = parentId;\n    }\n\n    public String getCode() {\n        return code;\n    }\n\n    public void setCode(String code) {\n        this.code = code;\n    }\n\n    public Integer getLevels() {\n        return levels;\n    }\n\n    public void setLevels(Integer levels) {\n        this.levels = levels;\n    }\n\n    public String getIcon() {\n        return icon;\n    }\n\n    public void setIcon(String icon) {\n        this.icon = icon;\n    }\n\n    public static MenuNode createRoot() {\n        return new MenuNode(0L, -1L);\n    }\n\n    public Long getId() {\n        return id;\n    }\n\n    public void setId(Long id) {\n        this.id = id;\n    }\n\n    public Long getParentId() {\n        return parentId;\n    }\n\n    public void setParentId(Long parentId) {\n        this.parentId = parentId;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public List<MenuNode> getChildren() {\n        return children;\n    }\n\n    public void setChildren(List<MenuNode> children) {\n        this.children = children;\n    }\n\n    public Integer getNum() {\n        return num;\n    }\n\n    public void setNum(Integer num) {\n        this.num = num;\n    }\n\n    public Integer getIsmenu() {\n        return ismenu;\n    }\n\n    public void setIsmenu(Integer ismenu) {\n        this.ismenu = ismenu;\n    }\n\n    public String getIsMenuName() {\n\n        return ismenu == 1 ?\"是\":\"否\";\n    }\n\n    public void setIsMenuName(String isMenuName) {\n        this.isMenuName = isMenuName;\n    }\n\n    public Integer getStatus() {\n        return status;\n    }\n\n    public void setStatus(Integer status) {\n        this.status = status;\n    }\n\n    public String getStatusName() {\n        return status == 1 ?\"启用\":\"禁用\";\n    }\n\n    public void setStatusName(String statusName) {\n       this.statusName = statusName;\n    }\n\n    @Override\n    public String toString() {\n        return \"MenuNode{\" +\n                \"id=\" + id +\n                \", parentId=\" + parentId +\n                \", name='\" + name + '\\'' +\n                \", levels=\" + levels +\n                \", num=\" + num +\n                \", url='\" + url + '\\'' +\n                \", icon='\" + icon + '\\'' +\n                \", children=\" + children +\n                \", linkedList=\" + linkedList +\n                '}';\n    }\n\n    @Override\n    public int compareTo(Object o) {\n        MenuNode menuNode = (MenuNode) o;\n        Integer num = menuNode.getNum();\n        if (num == null) {\n            num = 0;\n        }\n        return this.num.compareTo(num);\n    }\n\n    /**\n     * 构建整个菜单树\n     *\n     * @author fengshuonan\n     */\n    public void buildNodeTree(List<MenuNode> nodeList) {\n        for (MenuNode treeNode : nodeList) {\n            List<MenuNode> linkedList = treeNode.findChildNodes(nodeList, treeNode.getId());\n            if (linkedList.size() > 0) {\n                treeNode.setChildren(linkedList);\n            }\n        }\n    }\n\n    /**\n     * 查询子节点的集合\n     *\n     * @author fengshuonan\n     */\n    public List<MenuNode> findChildNodes(List<MenuNode> nodeList, Long parentId) {\n        if (nodeList == null && parentId == null)\n            return null;\n        for (Iterator<MenuNode> iterator = nodeList.iterator(); iterator.hasNext(); ) {\n            MenuNode node = (MenuNode) iterator.next();\n            // 根据传入的某个父节点ID,遍历该父节点的所有子节点\n            if (node.getParentId() != 0 && parentId.equals(node.getParentId())) {\n                recursionFn(nodeList, node, parentId);\n            }\n        }\n        return linkedList;\n    }\n\n    /**\n     * 遍历一个节点的子节点\n     *\n     * @author fengshuonan\n     */\n    public void recursionFn(List<MenuNode> nodeList, MenuNode node, Long pId) {\n        List<MenuNode> childList = getChildList(nodeList, node);// 得到子节点列表\n        if (childList.size() > 0) {// 判断是否有子节点\n            if (node.getParentId().equals(pId)) {\n                linkedList.add(node);\n            }\n            Iterator<MenuNode> it = childList.iterator();\n            while (it.hasNext()) {\n                MenuNode n = (MenuNode) it.next();\n                recursionFn(nodeList, n, pId);\n            }\n        } else {\n            if (node.getParentId().equals(pId)) {\n                linkedList.add(node);\n            }\n        }\n    }\n\n    /**\n     * 得到子节点列表\n     *\n     * @author fengshuonan\n     */\n    private List<MenuNode> getChildList(List<MenuNode> list, MenuNode node) {\n        List<MenuNode> nodeList = new ArrayList<MenuNode>();\n        Iterator<MenuNode> it = list.iterator();\n        while (it.hasNext()) {\n            MenuNode n = (MenuNode) it.next();\n            if (n.getParentId().equals(node.getId())) {\n                nodeList.add(n);\n            }\n        }\n        return nodeList;\n    }\n\n    /**\n     * 清除掉按钮级别的资源\n     *\n     * @date 2017年2月19日 下午11:04:11\n     */\n    public static List<MenuNode> clearBtn(List<MenuNode> nodes) {\n        ArrayList<MenuNode> noBtns = new ArrayList<MenuNode>();\n        for (MenuNode node : nodes) {\n            if(node.getIsmenu() == IsMenu.YES.getCode()){\n                noBtns.add(node);\n            }\n        }\n        return noBtns;\n    }\n\n    /**\n     * 清除所有二级菜单\n     *\n     * @date 2017年2月19日 下午11:18:19\n     */\n    public static List<MenuNode> clearLevelTwo(List<MenuNode> nodes) {\n        ArrayList<MenuNode> results = new ArrayList<MenuNode>();\n        for (MenuNode node : nodes) {\n            Integer levels = node.getLevels();\n            if (levels.equals(1)) {\n                results.add(node);\n            }\n        }\n        return results;\n    }\n\n    /**\n     * 构建菜单列表\n     *\n     * @date 2017年2月19日 下午11:18:19\n     */\n    public static List<MenuNode> buildTitle(List<MenuNode> nodes) {\n\n        List<MenuNode> clearBtn = clearBtn(nodes);\n\n        new MenuNode().buildNodeTree(clearBtn);\n\n        List<MenuNode> menuNodes = clearLevelTwo(clearBtn);\n\n        //对菜单排序\n        Collections.sort(menuNodes);\n\n        //对菜单的子菜单进行排序\n        for (MenuNode menuNode : menuNodes) {\n            if (menuNode.getChildren() != null && menuNode.getChildren().size() > 0) {\n                Collections.sort(menuNode.getChildren());\n            }\n        }\n\n        return menuNodes;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/node/Node.java",
    "content": "package cn.enilu.material.bean.vo.node;\n\nimport lombok.Data;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Node\n *\n * @author enilu\n * @version 2018/11/24 0024\n */\n@Data\npublic class Node {\n    private Long id;\n    private Long pid;\n    private String name;\n    private Boolean checked;\n    private List<Node> children = new ArrayList<>(10);\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/node/ZTreeNode.java",
    "content": "package cn.enilu.material.bean.vo.node;\n\n/**\n * \n * jquery ztree 插件的节点\n * \n * @author fengshuonan\n * @date 2017年2月17日 下午8:25:14\n */\npublic class ZTreeNode {\n\n\tprivate Long id;\t//节点id\n\t\n\tprivate Long pId;//父节点id\n\tprivate String code;//编号\n\t\n\tprivate String name;//节点名称\n\t\n\tprivate Boolean open;//是否打开节点\n\t\n\tprivate Boolean checked;//是否被选中\n\n\tprivate Object nodeData;//自定义数据\n\n\tpublic Long getId() {\n\t\treturn id;\n\t}\n\n\tpublic void setId(Long id) {\n\t\tthis.id = id;\n\t}\n\n\tpublic Long getpId() {\n\t\treturn pId;\n\t}\n\n\tpublic void setpId(Long pId) {\n\t\tthis.pId = pId;\n\t}\n\n\tpublic String getName() {\n\t\treturn name;\n\t}\n\n\tpublic void setName(String name) {\n\t\tthis.name = name;\n\t}\n\n\tpublic Boolean getOpen() {\n\t\treturn open;\n\t}\n\n\tpublic void setOpen(Boolean open) {\n\t\tthis.open = open;\n\t}\n\n\tpublic Boolean getIsOpen() {\n\t\treturn open;\n\t}\n\n\tpublic void setIsOpen(Boolean open) {\n\t\tthis.open = open;\n\t}\n\n\tpublic Boolean getChecked() {\n\t\treturn checked;\n\t}\n\n\tpublic void setChecked(Boolean checked) {\n\t\tthis.checked = checked;\n\t}\n\n\tpublic Object getNodeData() {\n\t\treturn nodeData;\n\t}\n\n\tpublic void setNodeData(Object nodeData) {\n\t\tthis.nodeData = nodeData;\n\t}\n\n\tpublic String getCode() {\n\t\treturn code;\n\t}\n\n\tpublic void setCode(String code) {\n\t\tthis.code = code;\n\t}\n\n\tpublic static ZTreeNode createParent(){\n\t\tZTreeNode zTreeNode = new ZTreeNode();\n\t\tzTreeNode.setChecked(true);\n\t\tzTreeNode.setId(0L);\n\t\tzTreeNode.setName(\"顶级\");\n\t\tzTreeNode.setOpen(true);\n\t\tzTreeNode.setpId(0L);\n\t\tzTreeNode.setCode(\"\");\n\t\treturn zTreeNode;\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/query/DynamicSpecifications.java",
    "content": "package cn.enilu.material.bean.vo.query;\n\nimport cn.enilu.material.utils.Lists;\nimport org.apache.commons.lang3.StringUtils;\nimport org.springframework.data.jpa.domain.Specification;\n\nimport javax.persistence.criteria.*;\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\n\n/**\n * descript\n *\n * @author ：enilu\n * @date ：Created in 2019/6/30 16:04\n */\npublic class DynamicSpecifications {\n\n\n    public static <T> Specification<T> bySearchFilter(final Collection<SearchFilter> filters, final Class<T> entityClazz) {\n        return new Specification<T>() {\n            @Override\n            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {\n                if (filters!=null && !filters.isEmpty()) {\n\n                    List<Predicate> predicates = Lists.newArrayList();\n                    for (SearchFilter filter : filters) {\n                        // nested path translate, 如Task的名为\"user.name\"的filedName, 转换为Task.user.name属性\n                        String[] names = StringUtils.split(filter.fieldName, \".\");\n                        Path expression = root.get(names[0]);\n                        for (int i = 1; i < names.length; i++) {\n                            expression = expression.get(names[i]);\n                        }\n                        // logic operator\n                        switch (filter.operator) {\n                            case EQ:\n                                predicates.add(builder.equal(expression, filter.value));\n                                break;\n                            case LIKE:\n                                predicates.add(builder.like(expression, \"%\" + filter.value + \"%\"));\n                                break;\n                            case GT:\n                                predicates.add(builder.greaterThan(expression, (Comparable) filter.value));\n                                break;\n                            case LT:\n                                predicates.add(builder.lessThan(expression, (Comparable) filter.value));\n                                break;\n                            case GTE:\n                                predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.value));\n                                break;\n                            case LTE:\n                                predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.value));\n                                break;\n                            case IN:\n                                if(filter.value.getClass().isArray()){\n                                    predicates.add(expression.in((Object[]) filter.value));\n                                }else {\n                                    predicates.add(expression.in((ArrayList) filter.value));\n                                }\n                                break;\n                            case ISNULL:\n                                predicates.add(expression.isNull());\n                                break;\n                            case ISNOTNULL:\n                                predicates.add(expression.isNotNull());\n                                break;\n                        }\n                    }\n\n                    // 将所有条件用 and 联合起来\n                    if (!predicates.isEmpty()) {\n                        return builder.and(predicates.toArray(new Predicate[predicates.size()]));\n                    }\n                }\n\n                return builder.conjunction();\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/query/MutiStrFactory.java",
    "content": "package cn.enilu.material.bean.vo.query;\n\n\nimport cn.enilu.material.utils.ToolUtil;\nimport cn.enilu.material.utils.StrKit;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 组合字符串生产者\n *\n * @author fengshuonan\n * @date 2017-04-27 16:42\n */\npublic class MutiStrFactory {\n\n    /**\n     * 每个条目之间的分隔符\n     */\n    public static final String ITEM_SPLIT = \";\";\n\n    /**\n     * 属性之间的分隔符\n     */\n    public static final String ATTR_SPLIT = \":\";\n\n    /**\n     * 拼接字符串的id\n     */\n    public static final String MUTI_STR_ID = \"ID\";\n\n    /**\n     * 拼接字符串的key\n     */\n    public static final String MUTI_STR_KEY = \"KEY\";\n\n    /**\n     * 拼接字符串的value\n     */\n    public static final String MUTI_STR_VALUE = \"VALUE\";\n\n    /**\n     * 解析一个组合字符串(例如:  \"1:启用;2:禁用;3:冻结\"  这样的字符串)\n     *\n     * @author fengshuonan\n     * @Date 2017/4/27 16:44\n     */\n    public static List<Map<String,String>> parseKeyValue(String mutiString){\n        if(ToolUtil.isEmpty(mutiString)){\n            return new ArrayList<>();\n        }else{\n            ArrayList<Map<String,String>> results = new ArrayList<>();\n            String[] items = StrKit.split(StrKit.removeSuffix(mutiString, ITEM_SPLIT), ITEM_SPLIT);\n            for (String item : items) {\n                String[] attrs = item.split(ATTR_SPLIT);\n                HashMap<String, String> itemMap = new HashMap<>();\n                itemMap.put(MUTI_STR_KEY,attrs[0]);\n                itemMap.put(MUTI_STR_VALUE,attrs[1]);\n                results.add(itemMap);\n            }\n            return results;\n        }\n    }\n    \n    /**\n     * 解析id:key:value这样类型的字符串\n     * \n     * @author fengshuonan\n     * @Date 2017/4/28 11:06\n     */\n    public static List<Map<String,String>> parseIdKeyValue(String mutiString){\n        if(ToolUtil.isEmpty(mutiString)){\n            return new ArrayList<>();\n        }else{\n            ArrayList<Map<String,String>> results = new ArrayList<>();\n            String[] items = StrKit.split(StrKit.removeSuffix(mutiString, ITEM_SPLIT), ITEM_SPLIT);\n            for (String item : items) {\n                String[] attrs = item.split(ATTR_SPLIT);\n                HashMap<String, String> itemMap = new HashMap<>();\n                itemMap.put(MUTI_STR_ID,attrs[0]);\n                itemMap.put(MUTI_STR_KEY,attrs[1]);\n                itemMap.put(MUTI_STR_VALUE,attrs[2]);\n                results.add(itemMap);\n            }\n            return results;\n        }\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/query/Page.java",
    "content": "package cn.enilu.material.bean.vo.query;\n\nimport cn.enilu.material.utils.Lists;\nimport cn.enilu.material.utils.StringUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Created  on 2018/3/22 0022.\n *\n * @author enilu\n */\npublic class Page<T>  {\n    /**\n     * 该操作只是为了忽略RowBounds属性\n     *\n     *\n     */\n    private transient int offset;\n    /**\n     * 该操作只是为了忽略RowBounds属性\n     *\n     *\n     */\n    private transient int limit;\n\n    /**\n     * 总数\n     */\n    private int total;\n\n    /**\n     * 每页显示条数，默认 10\n     */\n    private int size = 10;\n\n    /**\n     * 总页数\n     */\n    private int pages;\n\n    /**\n     * 当前页\n     */\n    private int current = 1;\n\n    /**\n     * 查询总记录数（默认 true）\n     */\n    private transient boolean searchCount = true;\n\n    /**\n     * 开启排序（默认 true） 只在代码逻辑判断 并不截取sql分析\n     *\n     *\n     **/\n    private transient boolean openSort = true;\n\n\n    /**\n     * <p>\n     * SQL 排序 ASC 集合\n     * </p>\n     */\n    private transient List<String> ascs;\n    /**\n     * <p>\n     * SQL 排序 DESC 集合\n     * </p>\n     */\n    private transient List<String> descs;\n\n    /**\n     * 是否为升序 ASC（ 默认： true ）\n     *\n     * @see #ascs\n     * @see #descs\n     */\n    private transient boolean isAsc = true;\n\n    /**\n     * <p>\n     * SQL 排序 ORDER BY 字段，例如： id DESC（根据id倒序查询）\n     * </p>\n     * <p>\n     * DESC 表示按倒序排序(即：从大到小排序)<br>\n     * ASC 表示按正序排序(即：从小到大排序)\n     *\n     * @see #ascs\n     * @see #descs\n     * </p>\n     */\n    private transient String orderByField;\n\n    public Page() {\n\n    }\n\n    public Page(int current, int size, String orderByField) {\n\n        this.setOrderByField(orderByField);\n    }\n\n    public Page(int current, int size, String orderByField, boolean isAsc) {\n        this(current, size, orderByField);\n        this.setAsc(isAsc);\n    }\n\n    /**\n     * <p>\n     * 分页构造函数\n     * </p>\n     *\n     * @param current 当前页\n     * @param size    每页显示条数\n     */\n    public Page(int current, int size) {\n        this(current,size,true);\n    }\n\n    public Page(int current, int size, boolean searchCount) {\n        this(current, size, searchCount, true);\n    }\n\n    public Page(int current, int size, boolean searchCount, boolean openSort) {\n\n        setOffset(offsetCurrent(current, size));\n        setLimit(size);\n        if (current > 1) {\n            this.current = current;\n        }\n        this.size = size;\n        this.searchCount = searchCount;\n        this.openSort = openSort;\n    }\n\n    protected static int offsetCurrent(int current, int size) {\n        if (current > 0) {\n            return (current - 1) * size;\n        }\n        return 0;\n    }\n\n    public int offsetCurrent() {\n        return offsetCurrent(this.current, this.size);\n    }\n\n    public boolean hasPrevious() {\n        return this.current > 1;\n    }\n\n    public boolean hasNext() {\n        return this.current < this.pages;\n    }\n\n    public int getTotal() {\n        return total;\n    }\n\n    public Page setTotal(int total) {\n        this.total = total;\n        return this;\n    }\n\n    public int getSize() {\n        return size;\n    }\n\n    public Page setSize(int size) {\n        this.size = size;\n        return this;\n    }\n\n    public int getPages() {\n        if (this.size == 0) {\n            return 0;\n        }\n        this.pages = this.total / this.size;\n        if (this.total % this.size != 0) {\n            this.pages++;\n        }\n        return this.pages;\n    }\n\n    public int getCurrent() {\n        return current;\n    }\n\n    public Page setCurrent(int current) {\n        this.current = current;\n        return this;\n    }\n\n    public boolean isSearchCount() {\n        return searchCount;\n    }\n\n    public Page setSearchCount(boolean searchCount) {\n        this.searchCount = searchCount;\n        return this;\n    }\n\n    /**\n     * @see #ascs\n     * @see #descs\n     */\n    @Deprecated\n    public String getOrderByField() {\n        return orderByField;\n    }\n\n    /**\n     * @see #ascs\n     * @see #descs\n     */\n    public Page setOrderByField(String orderByField) {\n        if (StringUtils.isNotEmpty(orderByField)) {\n            this.orderByField = orderByField;\n        }\n        return this;\n    }\n\n    public boolean isOpenSort() {\n        return openSort;\n    }\n\n    public Page setOpenSort(boolean openSort) {\n        this.openSort = openSort;\n        return this;\n    }\n\n    public List<String> getAscs() {\n        return orders(isAsc, ascs);\n    }\n\n    private List<String> orders(boolean condition, List<String> columns) {\n        if (condition && StringUtils.isNotEmpty(orderByField)) {\n            if (columns == null) {\n                columns = new ArrayList<>();\n            }\n            if (!columns.contains(orderByField)) {\n                columns.add(orderByField);\n            }\n        }\n        return columns;\n    }\n\n    public Page setAscs(List<String> ascs) {\n        this.ascs = ascs;\n        return this;\n    }\n\n    public List<String> getDescs() {\n        return orders(!isAsc, descs);\n    }\n\n    public Page setDescs(List<String> descs) {\n        this.descs = descs;\n        return this;\n    }\n\n    /**\n     * @see #ascs\n     * @see #descs\n     */\n    @Deprecated\n    public boolean isAsc() {\n        return isAsc;\n    }\n\n    /**\n     * @see #ascs\n     * @see #descs\n     */\n    public Page setAsc(boolean isAsc) {\n        this.isAsc = isAsc;\n        return this;\n    }\n\n    public int getOffset() {\n        return offset;\n    }\n\n    public Page setOffset(int offset) {\n        this.offset = offset;\n        return this;\n    }\n\n    public int getLimit() {\n        return limit;\n    }\n\n    public Page setLimit(int limit) {\n        this.limit = limit;\n        return this;\n    }\n    /**\n     * 查询数据列表\n     */\n    private List<T> records = Collections.emptyList();\n\n    /**\n     * 查询参数\n     */\n    private transient Map<String, Object> condition;\n\n    private transient  List<SearchFilter> filters;\n\n\n    public List<T> getRecords() {\n        return records;\n    }\n\n    public Page<T> setRecords(List<T> records) {\n        this.records = records;\n        return this;\n    }\n\n    public Map<String, Object> getCondition() {\n        return condition;\n    }\n\n    public Page<T> setCondition(Map<String, Object> condition) {\n        this.condition = condition;\n        return this;\n    }\n\n\n    public List<SearchFilter> getFilters() {\n        return filters;\n    }\n\n    public void setFilters(List<SearchFilter> filters) {\n        this.filters = filters;\n    }\n    public void addFilter(SearchFilter filter){\n        if(filter==null){\n            return ;\n        }\n        if(filters==null){\n            filters = Lists.newArrayList();\n        }\n        filters.add(filter);\n    }\n    public void addFilter(String fieldName, SearchFilter.Operator operator, Object value){\n        if(!StringUtils.isNullOrEmpty(value)){\n            addFilter(SearchFilter.build(fieldName,operator,value));\n        }\n    }\n    public void addFilter(String fieldName, SearchFilter.Operator operator){\n        addFilter(SearchFilter.build(fieldName,operator));\n    }\n\n    @Override\n    public String toString() {\n        StringBuilder pg = new StringBuilder();\n        pg.append(\" Page:{ [\").append(super.toString()).append(\"], \");\n        if (records != null) {\n            pg.append(\"records-size:\").append(records.size());\n        } else {\n            pg.append(\"records is null\");\n        }\n        return pg.append(\" }\").toString();\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/bean/vo/query/SearchFilter.java",
    "content": "package cn.enilu.material.bean.vo.query;\n\nimport cn.enilu.material.utils.Maps;\nimport org.apache.commons.lang3.StringUtils;\n\nimport java.util.Map;\n\n/**\n * descript\n *\n * @author ：enilu\n * @date ：Created in 2019/6/30 16:02\n */\npublic class SearchFilter {\n    public enum Operator {\n        EQ, LIKE, GT, LT, GTE, LTE,IN,ISNULL,ISNOTNULL\n    }\n\n    public String fieldName;\n    public Object value;\n    public Operator operator = Operator.EQ;\n    public  static SearchFilter build(String fieldName, Operator operator, Object value){\n        return  new SearchFilter(fieldName,operator,value);\n    }\n    public  static SearchFilter build(String fieldName, Object val){\n        return  new SearchFilter(fieldName,Operator.EQ,val);\n    }\n    public SearchFilter(String fieldName, Object val) {\n        this.fieldName = fieldName;\n        this.value = val;\n    }\n    public SearchFilter(String fieldName, Operator operator, Object value) {\n        this.fieldName = fieldName;\n        this.value = value;\n        this.operator = operator;\n    }\n\n    /**\n     * searchParams中key的格式为OPERATOR_FIELDNAME\n     */\n    public static Map<String, SearchFilter> parse(Map<String, Object> searchParams) {\n        Map<String, SearchFilter> filters = Maps.newHashMap();\n\n        for (Map.Entry<String, Object> entry : searchParams.entrySet()) {\n            // 过滤掉空值\n            String key = entry.getKey();\n            Object value = entry.getValue();\n\t\t\t/*if (StringUtils.isBlank((String) value)) {\n\t\t\t\tcontinue;\n\t\t\t}*/\n\n            // 拆分operator与filedAttribute\n            String[] names = StringUtils.split(key, \"_\");\n            if (names.length != 2) {\n                throw new IllegalArgumentException(key + \" is not a valid search filter name\");\n            }\n            String filedName = names[1];\n            Operator operator = Operator.valueOf(names[0]);\n\n            // 创建searchFilter\n            SearchFilter filter = new SearchFilter(filedName, operator, value);\n            filters.put(key, filter);\n        }\n\n        return filters;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/BaseRepository.java",
    "content": "package cn.enilu.material.dao;\n\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\nimport org.springframework.data.repository.NoRepositoryBean;\nimport org.springframework.data.repository.PagingAndSortingRepository;\n\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 封装基础的dao接口\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 12:50\n */\n@NoRepositoryBean\npublic interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID>\n        , PagingAndSortingRepository<T, ID>\n        , JpaSpecificationExecutor<T> {\n    List<Map> queryBySql(String sql);\n    List<Map> queryBySql(String sql, List<SearchFilter> filter);\n    List<T> query(String sql);\n    Object getBySql(String sql);\n    T get(String sql);\n    int execute(String sql);\n    Class<T> getDataClass();\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/BaseRepositoryFactoryBean.java",
    "content": "package cn.enilu.material.dao;\n\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.support.JpaEntityInformation;\nimport org.springframework.data.jpa.repository.support.JpaRepositoryFactory;\nimport org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;\nimport org.springframework.data.jpa.repository.support.JpaRepositoryImplementation;\nimport org.springframework.data.repository.core.RepositoryInformation;\nimport org.springframework.data.repository.core.RepositoryMetadata;\nimport org.springframework.data.repository.core.support.RepositoryFactorySupport;\nimport org.springframework.util.Assert;\n\nimport javax.persistence.EntityManager;\nimport java.io.Serializable;\n\n/**\n * 自定义repository工厂类\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 12:59\n */\npublic class BaseRepositoryFactoryBean<JR extends JpaRepository<T, ID>, T, ID extends Serializable>\n        extends JpaRepositoryFactoryBean<JR, T, ID> {\n    public BaseRepositoryFactoryBean(Class<? extends JR> repositoryInterface) {\n        super(repositoryInterface);\n    }\n\n    @Override\n    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {\n        return new BaseRepositoryFactory(entityManager);\n    }\n\n    private static class BaseRepositoryFactory<T, ID extends Serializable> extends JpaRepositoryFactory {\n        private final EntityManager entityManager;\n        public BaseRepositoryFactory(EntityManager entityManager) {\n            super(entityManager);\n            this.entityManager = entityManager;\n        }\n\n        @Override\n        protected JpaRepositoryImplementation<?, ?> getTargetRepository(RepositoryInformation information, EntityManager entityManager) {\n            JpaEntityInformation<?, Serializable> entityInformation = this.getEntityInformation(information.getDomainType());\n            Object repository = this.getTargetRepositoryViaReflection(information, new Object[]{entityInformation, entityManager});\n            Assert.isInstanceOf(BaseRepositoryImpl.class, repository);\n            return (JpaRepositoryImplementation)repository;\n        }\n\n        @Override\n        protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {\n            return BaseRepositoryImpl.class;\n        }\n    }\n}"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/BaseRepositoryImpl.java",
    "content": "package cn.enilu.material.dao;\n\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport org.hibernate.SQLQuery;\nimport org.hibernate.query.internal.NativeQueryImpl;\nimport org.hibernate.transform.Transformers;\nimport org.springframework.data.jpa.repository.support.JpaEntityInformation;\nimport org.springframework.data.jpa.repository.support.SimpleJpaRepository;\n\nimport javax.persistence.EntityManager;\nimport javax.persistence.Query;\nimport java.io.Serializable;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 基础dao实现类\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 12:53\n */\npublic class BaseRepositoryImpl<T, ID extends Serializable>\n        extends SimpleJpaRepository<T, ID>\n        implements BaseRepository<T, ID> {\n    private final EntityManager entityManager;\n    private Class<T> klass;\n\n\n    BaseRepositoryImpl(JpaEntityInformation<T, ID> entityInformation,\n                       EntityManager entityManager) {\n        super(entityInformation, entityManager);\n        this.entityManager = entityManager;\n        this.klass = (Class<T>) entityInformation.getJavaType();\n    }\n\n    @Override\n    public List<Map> queryBySql(String sql) {\n        return queryBySql(sql,null);\n    }\n\n    @Override\n    public List<Map> queryBySql(String sql, List<SearchFilter> filters) {\n            Query query = entityManager.createNativeQuery(sql);\n        query.unwrap(NativeQueryImpl.class)\n                .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);\n        if(filters!=null&&!filters.isEmpty()) {\n            for (SearchFilter filter : filters) {\n                query.setParameter(filter.fieldName, filter.value);\n            }\n        }\n\n        List list = query.getResultList();\n        return list;\n    }\n\n    @Override\n    public Object getBySql(String sql) {\n        List list = entityManager.createNativeQuery(sql).getResultList();\n        if(list.isEmpty()){\n            return null;\n        }\n        return list.get(0);\n    }\n\n    @Override\n    public T get(String sql) {\n        List<T> list =  entityManager.createNativeQuery(sql,klass).getResultList();\n        return list.get(0);\n    }\n\n    @Override\n    public int execute(String sql) {\n        return entityManager.createNativeQuery(sql).executeUpdate();\n    }\n\n    @Override\n    public Class<T> getDataClass() {\n        return klass;\n    }\n\n    @Override\n    public List<T> query(String sql) {\n        return entityManager.createNativeQuery(sql,klass).getResultList();\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/DaoConfiguration.java",
    "content": "package cn.enilu.material.dao;\n\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\n\n/**\n * Name: DabConfiguration<br>\n * User: Yao<br>\n * Date: 2018/2/27<br>\n * Time: 13:54<br>\n */\n@Configuration\n@EnableJpaRepositories(\"cn.enilu.material.dao\")\npublic class DaoConfiguration {\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/BaseCache.java",
    "content": "package cn.enilu.material.dao.cache;\n\n\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\n\n/**\n * @author ：enilu\n * @date ：Created in 2020/4/26 19:07\n */\npublic abstract  class BaseCache implements Cache {\n    @Override\n    public void cache() {\n        SpringContextHolder.getBean(ConstantFactory.class).cleanLocalCache();\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/Cache.java",
    "content": "package cn.enilu.material.dao.cache;\n\n/**\n * 顶级缓存接口\n */\npublic interface Cache {\n\t/**\n\t * 将数据库中的数据加载到缓存中\n\t */\n\tvoid cache();\n\n\n\t/**\n\t * 获取缓存数据\n\t *\n\t * @param key\n\t * @return\n\t */\n\tObject get(String key);\n\n\n\t/**\n\t * 设置缓存数据\n\t *\n\t * @param key\n\t * @param val\n\t */\n\tvoid set(String key, Object val);\n\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/CacheDao.java",
    "content": "package cn.enilu.material.dao.cache;\n\nimport java.io.Serializable;\n\n/**\n * CacheDao\n *\n * @author enilu\n * @version 2018/9/12 0012\n */\npublic interface CacheDao {\n\n\n    /**\n     * 设置hash key值\n     *\n     * @param key\n     * @param k\n     * @param val\n     */\n    void hset(Serializable key, Serializable k, Object val);\n\n    /**\n     * 获取hash key值\n     *\n     * @param key\n     * @param k\n     * @return\n     */\n    Serializable hget(Serializable key, Serializable k);\n\n    /**\n     * 获取hash key值\n     * @param key\n     * @param k\n     * @param klass\n     * @param <T>\n     * @return\n     */\n    <T>T hget(Serializable key, Serializable k,Class<T> klass);\n\n    /**\n     * 设置key值，超时失效\n     *\n     * @param key\n     * @param val\n     */\n    void set(Serializable key, Object val);\n\n\n\n    /**\n     * 获取key值\n     *\n     * @param key\n     * @return\n     */\n      <T>T get(Serializable key,Class<T> klass);\n      String get(Serializable key);\n\n\n      void del(Serializable key);\n      void hdel(Serializable key, Serializable k);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/ConfigCache.java",
    "content": "package cn.enilu.material.dao.cache;\n\n/**\n * 全局配置数据访问\n */\npublic interface ConfigCache extends Cache {\n\n\n\t/**\n\t * 获取全局配置参数值，可选本地缓存\n\t * @param key\n\t * @return\n\t */\n\tString get(String key, boolean local);\n\n\t/**\n\t * 获取全局配置参数值(带默认值)\n\t *\n\t * @param key the key\n\t * @param def the default value\n\t * @return the config\n\t */\n\tString get(String key, String def);\n\n\t/**\n\t * 删除缓存\n\t * @param key\n\t * @param val\n\t */\n\tvoid del(String key, String val);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/DictCache.java",
    "content": "package cn.enilu.material.dao.cache;\n\nimport cn.enilu.material.bean.entity.system.Dict;\n\nimport java.util.List;\n\n/**\n * 字典缓存\n *\n * @author zt\n * @version 2018/12/23 0023\n */\npublic interface DictCache  extends Cache{\n\n    List<Dict> getDictsByPname(String dictName);\n    String getDict(Long dictId);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/TokenCache.java",
    "content": "package cn.enilu.material.dao.cache;\n\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.dao.cache.impl.EhcacheDao;\nimport cn.enilu.material.utils.HttpKit;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n/**\n * 用户登录时，生成的Token与用户ID的对应关系\n */\n@Service\npublic   class TokenCache {\n\n    @Autowired\n    private EhcacheDao ehcacheDao;\n\n    public   void put(String token, Long idUser) {\n        ehcacheDao.hset(EhcacheDao.SESSION,token, idUser);\n    }\n\n    public   Long get(String token) {\n        return ehcacheDao.hget(EhcacheDao.SESSION,token,Long.class);\n    }\n    public Long getIdUser(){\n        return ehcacheDao.hget(EhcacheDao.SESSION,HttpKit.getToken(),Long.class );\n    }\n\n    public   void remove(String token) {\n        ehcacheDao.hdel(EhcacheDao.SESSION,token);\n    }\n\n    public void setUser(String token, ShiroUser shiroUser){\n        ehcacheDao.hset(EhcacheDao.SESSION,token+\"user\",shiroUser);\n    }\n    public ShiroUser getUser(String token){\n        return ehcacheDao.hget(EhcacheDao.SESSION,token+\"user\",ShiroUser.class);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/impl/ConfigCacheImpl.java",
    "content": "package cn.enilu.material.dao.cache.impl;\n\nimport cn.enilu.material.bean.entity.system.Cfg;\nimport cn.enilu.material.dao.cache.BaseCache;\nimport cn.enilu.material.dao.cache.CacheDao;\nimport cn.enilu.material.dao.cache.ConfigCache;\nimport cn.enilu.material.dao.system.CfgRepository;\nimport cn.enilu.material.utils.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * 全局参数缓存实现类\n *\n * @author enilu\n * @version 2018/12/20 0020\n */\n@Service\npublic class ConfigCacheImpl  extends BaseCache implements ConfigCache {\n    private static  final Logger logger = LoggerFactory.getLogger(ConfigCacheImpl.class);\n    @Autowired\n    private CfgRepository cfgRepository;\n    @Autowired\n    private CacheDao cacheDao;\n\n    @Override\n    public Object get(String key) {\n        return (String) cacheDao.hget(EhcacheDao.CONSTANT,key);\n    }\n\n    @Override\n    public String get(String key, boolean local) {\n        String ret = null;\n        if(local) {\n             ret = (String) get(key);\n        }else{\n            ret = cfgRepository.findByCfgName(key).getCfgValue();\n            set(key,ret);\n        }\n        return ret;\n    }\n\n    @Override\n    public String get(String key, String def) {\n        String ret = (String) get(key);\n        if(StringUtils.isEmpty(ret)){\n            return ret;\n        }\n        return ret;\n    }\n\n\n    @Override\n    public void set(String key, Object val) {\n        cacheDao.hset(EhcacheDao.CONSTANT,key,val);\n    }\n\n    @Override\n    public void del(String key, String val) {\n        cacheDao.hdel(EhcacheDao.CONSTANT,val);\n    }\n\n    @Override\n    public void cache() {\n        super.cache();\n        logger.info(\"reset config cache\");\n        List<Cfg> list = cfgRepository.findAll();\n        if (list != null && !list.isEmpty()) {\n            for (Cfg cfg : list) {\n                if (StringUtils.isNotEmpty(cfg.getCfgName()) && StringUtils.isNotEmpty(cfg.getCfgValue())) {\n                    set(cfg.getCfgName(),cfg.getCfgValue());\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/impl/DictCacheImpl.java",
    "content": "package cn.enilu.material.dao.cache.impl;\n\nimport cn.enilu.material.bean.constant.cache.CacheKey;\nimport cn.enilu.material.bean.entity.system.Dict;\nimport cn.enilu.material.dao.cache.BaseCache;\nimport cn.enilu.material.dao.cache.CacheDao;\nimport cn.enilu.material.dao.cache.DictCache;\nimport cn.enilu.material.dao.system.DictRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\n\n/**\n * DictCacheImpl\n *\n * @author zt\n * @version 2018/12/23 0023\n */\n@Component\npublic class DictCacheImpl extends BaseCache implements DictCache {\n    @Autowired\n    private DictRepository dictRepository;\n    @Autowired\n    private CacheDao cacheDao;\n\n    @Override\n    public List<Dict> getDictsByPname(String dictName) {\n        return (List<Dict>) cacheDao.hget(EhcacheDao.CONSTANT, CacheKey.DICT + dictName, List.class);\n    }\n\n    @Override\n    public String getDict(Long dictId) {\n        return (String) get(CacheKey.DICT_NAME + String.valueOf(dictId));\n    }\n\n    @Override\n    public void cache() {\n        super.cache();\n        List<Dict> list = dictRepository.findByPid(0L);\n        for (Dict dict : list) {\n            List<Dict> children = dictRepository.findByPid(dict.getId());\n            if (children.isEmpty()) {\n                continue;\n            }\n            set(String.valueOf(dict.getId()), children);\n            set(dict.getName(), children);\n            for (Dict child : children) {\n                set(CacheKey.DICT_NAME + String.valueOf(child.getId()), child.getName());\n            }\n\n        }\n\n    }\n\n    @Override\n    public Object get(String key) {\n        return cacheDao.hget(EhcacheDao.CONSTANT, CacheKey.DICT + key);\n    }\n\n    @Override\n    public void set(String key, Object val) {\n        cacheDao.hset(EhcacheDao.CONSTANT, CacheKey.DICT + key, val);\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/impl/EhcacheDao.java",
    "content": "package cn.enilu.material.dao.cache.impl;\n\nimport cn.enilu.material.dao.cache.CacheDao;\nimport org.springframework.cache.Cache;\nimport org.springframework.cache.CacheManager;\nimport org.springframework.stereotype.Component;\n\nimport javax.annotation.Resource;\nimport java.io.Serializable;\n\n/**\n * EhcacheDao\n *\n * @author enilu\n * @version 2018/9/12 0012\n */\n@Component\npublic class EhcacheDao implements CacheDao {\n    //缓存常量，永不过期\n    public static  final String CONSTANT = \"CONSTANT\";\n    public static  final String SESSION = \"SESSION\";\n    @Resource\n    private CacheManager cacheManager;\n\n    @Override\n    public void hset(Serializable key, Serializable k, Object val) {\n        Cache cache = cacheManager.getCache(String.valueOf(key));\n        cache.put(k,val);\n    }\n\n    @Override\n    public Serializable hget(Serializable key, Serializable k) {\n        Cache cache = cacheManager.getCache(String.valueOf(key));\n        return cache.get(k,String.class);\n    }\n    @Override\n    public <T>T hget(Serializable key, Serializable k,Class<T> klass) {\n        Cache cache = cacheManager.getCache(String.valueOf(key));\n        return cache.get(k,klass);\n    }\n    @Override\n    public void set(Serializable key, Object val) {\n        Cache cache = cacheManager.getCache(CONSTANT);\n        cache.put(key,val);\n\n    }\n\n    @Override\n    public <T>T get(Serializable key,Class<T> klass) {\n        return cacheManager.getCache(CONSTANT).get(String.valueOf(key),klass);\n    }\n\n    @Override\n    public String get(Serializable key) {\n        return cacheManager.getCache(CONSTANT).get(String.valueOf(key),String.class);\n    }\n\n    @Override\n    public void del(Serializable key) {\n        cacheManager.getCache(CONSTANT).put(String.valueOf(key),null);\n    }\n\n    @Override\n    public void hdel(Serializable key, Serializable k) {\n        cacheManager.getCache(String.valueOf(key)).put(String.valueOf(k),null);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/cache/package-info.java",
    "content": "/**\n * package-info\n *\n * @version 2018/9/11 0011\n * @author enilu\n */\npackage cn.enilu.material.dao.cache;"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/message/MessageRepository.java",
    "content": "package cn.enilu.material.dao.message;\n\n\nimport cn.enilu.material.bean.entity.message.Message;\nimport cn.enilu.material.dao.BaseRepository;\n\nimport java.util.ArrayList;\n\n\npublic interface MessageRepository extends BaseRepository<Message,Long> {\n    void deleteAllByIdIn(ArrayList<String> list);\n}\n\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/message/MessagesenderRepository.java",
    "content": "package cn.enilu.material.dao.message;\n\n\nimport cn.enilu.material.bean.entity.message.MessageSender;\nimport cn.enilu.material.dao.BaseRepository;\n\n\npublic interface MessagesenderRepository extends BaseRepository<MessageSender,Long> {\n}\n\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/message/MessagetemplateRepository.java",
    "content": "package cn.enilu.material.dao.message;\n\n\n\nimport cn.enilu.material.bean.entity.message.MessageTemplate;\nimport cn.enilu.material.dao.BaseRepository;\n\nimport java.util.List;\n\n\npublic interface MessagetemplateRepository extends BaseRepository<MessageTemplate,Long> {\n    MessageTemplate findByCode(String code);\n\n    List<MessageTemplate> findByIdMessageSender(Long idMessageSender);\n}\n\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/CfgRepository.java",
    "content": "\npackage cn.enilu.material.dao.system;\n\nimport cn.enilu.material.bean.entity.system.Cfg;\nimport cn.enilu.material.dao.BaseRepository;\n\npublic interface CfgRepository extends BaseRepository<Cfg,Long> {\n    Cfg findByCfgName(String cfgName);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/DeptRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\n\nimport cn.enilu.material.bean.entity.system.Dept;\nimport cn.enilu.material.dao.BaseRepository;\nimport org.springframework.data.jpa.repository.Query;\n\nimport java.util.List;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\npublic interface DeptRepository  extends BaseRepository<Dept,Long> {\n    List<Dept> findByPidsLike(String pid);\n    @Query(nativeQuery = true,value = \"SELECT id, pid AS pId, simplename AS NAME, ( CASE WHEN (pId = 0 OR pId IS NULL) THEN 'true' ELSE 'false' END ) AS isOpen FROM t_sys_dept\")\n    List tree();\n\n    List<Dept> findBySimplenameLikeOrFullnameLike(String name,String name2);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/DictRepository.java",
    "content": "\npackage cn.enilu.material.dao.system;\n\n\nimport cn.enilu.material.bean.entity.system.Dict;\nimport cn.enilu.material.dao.BaseRepository;\n\nimport java.util.List;\n\npublic interface DictRepository extends BaseRepository<Dict,Long> {\n    List<Dict> findByPid(Long pid);\n    List<Dict> findByNameAndPid(String name,Long pid);\n\n    List<Dict> findByNameLike(String name);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/FileInfoRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\nimport cn.enilu.material.bean.entity.system.FileInfo;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\nimport org.springframework.data.repository.PagingAndSortingRepository;\n\npublic interface FileInfoRepository  extends PagingAndSortingRepository<FileInfo,Long>\n        , JpaRepository<FileInfo,Long>, JpaSpecificationExecutor<FileInfo> {\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/LoginLogRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\nimport cn.enilu.material.bean.entity.system.LoginLog;\nimport cn.enilu.material.dao.BaseRepository;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\npublic interface LoginLogRepository extends BaseRepository<LoginLog,Long>{\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/MenuRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\nimport cn.enilu.material.bean.entity.system.Menu;\nimport cn.enilu.material.dao.BaseRepository;\nimport org.springframework.data.jpa.repository.Modifying;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.List;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\npublic interface MenuRepository extends BaseRepository<Menu,Long> {\n    Menu findByCode(String code);\n    List<Menu> findByPcodesLike(String code);\n    List<Menu> findByNameLikeAndLevels(String name,Integer levels);\n    @Query(nativeQuery = true,value=\"SELECT m1.id AS id, m1.icon AS icon, ( CASE WHEN (m2.id = 0 OR m2.id IS NULL) \" +\n            \"THEN 0 ELSE m2.id END ) AS parentId, m1. NAME AS NAME, m1.url AS url, m1.levels AS levels, m1.ismenu AS \" +\n            \"ismenu, m1.num AS num,m1.code as code,m1.status as status FROM t_sys_menu m1 LEFT JOIN t_sys_menu m2 ON \" +\n            \"m1.pcode = \" +\n            \"m2. \" +\n            \"CODE \" +\n            \"INNER \" +\n            \"JOIN ( SELECT ID FROM t_sys_menu WHERE ID IN ( SELECT menuid FROM t_sys_relation rela WHERE rela.roleid IN (?1))) m3 ON m1.id = m3.id WHERE m1.ismenu = 1 and m1.status = 1 ORDER BY levels, num ASC\")\n    List getMenusByRoleIds(List<Long> roleList);\n    @Query(nativeQuery = true,value=\"SELECT m1.id AS id, m1.icon AS icon, ( CASE WHEN (m2.id = 0 OR m2.id IS NULL) \" +\n            \"THEN 0 ELSE m2.id END ) AS parentId, m1. NAME AS NAME, m1.url AS url, m1.levels AS levels, m1.ismenu AS \" +\n            \"ismenu, m1.num AS num, m1. CODE AS CODE,m1.status as status FROM t_sys_menu m1 LEFT JOIN t_sys_menu m2 \" +\n            \"ON \" +\n            \"m1.pcode = m2. CODE ORDER BY levels, num ASC\")\n    List getMenus();\n    @Query(nativeQuery = true,value=\"select menuid from t_sys_relation where roleid=?1\")\n    List getMenuIdsByRoleId(Integer roleId);\n    @Query(nativeQuery = true,value = \"SELECT m1.id AS id, ( CASE WHEN (m2.id = 0 OR m2.id IS NULL) THEN 0 ELSE m2.id END ) AS pId, m1. NAME AS NAME, ( CASE WHEN (m2.id = 0 OR m2.id IS NULL) THEN 'true' ELSE 'false' END ) AS isOpen,  m1.code FROM t_sys_menu m1 LEFT JOIN t_sys_menu m2 ON m1.pcode = m2. CODE ORDER BY m1.id ASC\")\n    List menuTreeList();\n    @Query(nativeQuery = true,value = \"SELECT m1.id AS id, ( CASE WHEN (m2.id = 0 OR m2.id IS NULL) THEN 0 ELSE m2.id END ) AS pId, m1. NAME AS NAME, ( CASE WHEN (m2.id = 0 OR m2.id IS NULL) THEN 'true' ELSE 'false' END ) AS isOpen, ( CASE WHEN (m3.ID = 0 OR m3.ID IS NULL) THEN 'false' ELSE 'true' END ) \\\"checked\\\" FROM t_sys_menu m1 LEFT JOIN t_sys_menu m2 ON m1.pcode = m2. CODE LEFT JOIN ( SELECT ID FROM t_sys_menu WHERE ID IN (?1)) m3 ON m1.id = m3.id ORDER BY m1.id ASC\")\n    List menuTreeListByMenuIds(List<Long> menuIds);\n\n    @Modifying\n    @Transactional\n    @Query(nativeQuery = true,value = \"delete from t_sys_relation where menuid=?1\")\n    void deleteRelationByMenu(Long menuId);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/OperationLogRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\n\nimport cn.enilu.material.bean.entity.system.OperationLog;\nimport cn.enilu.material.dao.BaseRepository;\nimport org.springframework.data.jpa.repository.Modifying;\nimport org.springframework.data.jpa.repository.Query;\n\nimport javax.transaction.Transactional;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\npublic interface OperationLogRepository extends BaseRepository<OperationLog,Long> {\n    @Modifying\n    @Transactional\n    @Query(nativeQuery = true,value = \"delete from t_sys_operation_log\")\n    int clear();\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/RelationRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\nimport cn.enilu.material.bean.entity.system.Relation;\nimport cn.enilu.material.dao.BaseRepository;\nimport org.springframework.data.jpa.repository.Modifying;\nimport org.springframework.data.jpa.repository.Query;\nimport org.springframework.transaction.annotation.Transactional;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\npublic interface RelationRepository extends BaseRepository<Relation,Long> {\n    @Transactional\n    @Modifying\n    @Query(nativeQuery = true,value = \"delete from t_sys_relation where roleid=?1\")\n    int deleteByRoleId(Long roleId);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/RoleRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\n\nimport cn.enilu.material.bean.entity.system.Role;\nimport cn.enilu.material.dao.BaseRepository;\nimport org.springframework.data.jpa.repository.Query;\n\nimport java.util.List;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\npublic interface RoleRepository extends BaseRepository<Role,Long> {\n    @Query(nativeQuery = true,value = \"SELECT id, pId, NAME, ( CASE WHEN (pId = 0 OR pId IS NULL) THEN 'true' ELSE 'false' END ) OPEN FROM t_sys_role\")\n    List roleTreeList();\n\n    @Query(nativeQuery = true,value=\"SELECT r.id AS id, pId AS pId, NAME AS NAME, ( CASE WHEN (pId = 0 OR pId IS NULL) THEN 'true' ELSE 'false' END ) \\\"open\\\", ( CASE WHEN (r1.ID = 0 OR r1.ID IS NULL) THEN 'false' ELSE 'true' END ) AS checked FROM t_sys_role r LEFT JOIN ( SELECT ID FROM t_sys_role WHERE ID IN (?1)) r1 ON r.ID = r1.ID ORDER BY pId, num ASC\")\n    List roleTreeListByRoleId(Long[] ids);\n\n    List findByName(String roleName);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/SysNoticeRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\n\nimport cn.enilu.material.bean.entity.system.Notice;\nimport cn.enilu.material.dao.BaseRepository;\n\nimport java.util.List;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\npublic interface SysNoticeRepository extends BaseRepository<Notice,Long> {\n    List<Notice> findByTitleLike(String name);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/TaskLogRepository.java",
    "content": "\npackage cn.enilu.material.dao.system;\n\n\nimport cn.enilu.material.bean.entity.system.TaskLog;\nimport org.springframework.data.jpa.repository.JpaRepository;\nimport org.springframework.data.jpa.repository.JpaSpecificationExecutor;\nimport org.springframework.data.repository.PagingAndSortingRepository;\n\npublic interface TaskLogRepository  extends PagingAndSortingRepository<TaskLog,Long>\n        ,JpaSpecificationExecutor<TaskLog>\n        ,JpaRepository<TaskLog,Long> {\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/TaskRepository.java",
    "content": "\npackage cn.enilu.material.dao.system;\n\n\nimport cn.enilu.material.bean.entity.system.Task;\nimport cn.enilu.material.dao.BaseRepository;\n\nimport java.util.List;\n\npublic interface TaskRepository extends BaseRepository<Task, Long> {\n\n    long countByNameLike(String name);\n\n    List<Task> findByNameLike(String name);\n    List<Task> findAllByDisabled(boolean disable);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/dao/system/UserRepository.java",
    "content": "package cn.enilu.material.dao.system;\n\n\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.dao.BaseRepository;\n\nimport java.util.List;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\npublic interface UserRepository extends BaseRepository<User,Long> {\n    User findByAccount(String account);\n\n    List<User> findByRoleid(String idRole);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/factory/DictFieldWarpperFactory.java",
    "content": "package cn.enilu.material.factory;\n\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.service.system.IConstantFactory;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.reflect.Method;\n\n/**\n * 字段的包装创建工厂\n *\n * @author fengshuonan\n * @date 2017-05-06 15:12\n */\npublic class DictFieldWarpperFactory {\n    private static Logger logger = LoggerFactory.getLogger(DictFieldWarpperFactory.class);\n    public static Object createFieldWarpper(Object field, String methodName) {\n        IConstantFactory me = ConstantFactory.me();\n        try {\n            Method method = IConstantFactory.class.getMethod(methodName, field.getClass());\n            Object result = method.invoke(me, field);\n            return result;\n        } catch (Exception e) {\n           logger.error(\"field:{},methodName:{}\",field,methodName);\n            try {\n                Method method = IConstantFactory.class.getMethod(methodName, Long.class);\n                Object result = method.invoke(me, Long.valueOf(field.toString()));\n                return result;\n            } catch (Exception e1) {\n                throw new ApplicationException(BizExceptionEnum.ERROR_WRAPPER_FIELD);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/factory/UserFactory.java",
    "content": "package cn.enilu.material.factory;\n\nimport cn.enilu.material.bean.dto.UserDto;\nimport cn.enilu.material.bean.entity.system.User;\nimport org.springframework.beans.BeanUtils;\n\n/**\n * 用户创建工厂\n *\n * @author fengshuonan\n * @date 2017-05-05 22:43\n */\npublic class UserFactory {\n\n    public static User createUser(UserDto userDto, User user){\n        if(userDto == null){\n            return null;\n        }else{\n            BeanUtils.copyProperties(userDto,user);\n            return user;\n        }\n    }\n    public static User updateUser(UserDto userDto,User user){\n        if(userDto == null){\n            return null;\n        }else{\n            user.setName(userDto.getName());\n            user.setDeptid(userDto.getDeptid());\n            user.setSex(userDto.getSex());\n            user.setPhone(userDto.getPhone());\n            user.setEmail(userDto.getEmail());\n            user.setBirthday(userDto.getBirthday());\n            user.setAvatar(userDto.getAvatar());\n            if(userDto.getStatus()!=null){\n                user.setStatus(userDto.getStatus());\n            }\n            return user;\n        }\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/platform/package-info.java",
    "content": "/**\n * package-info\n *\n * @version 2018/9/11 0011\n * @author enilu\n */\npackage cn.enilu.material.platform;"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/BaseService.java",
    "content": "package cn.enilu.material.service;\n\nimport cn.enilu.material.bean.constant.cache.Cache;\nimport cn.enilu.material.bean.vo.query.DynamicSpecifications;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.dao.BaseRepository;\nimport cn.enilu.material.utils.Lists;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.cache.annotation.CacheEvict;\nimport org.springframework.cache.annotation.Cacheable;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.jpa.domain.Specification;\n\nimport java.io.Serializable;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 22:32\n */\npublic abstract  class BaseService<T, ID extends Serializable, R extends BaseRepository<T, ID>>\n        implements CrudService<T, ID> {\n    @Autowired\n    private R dao;\n\n\n\n\n    @Override\n    @CacheEvict(value = Cache.APPLICATION ,key = \"#root.targetClass.simpleName+':'+#id\")\n    public void delete(ID id) {\n        dao.deleteById(id);\n    }\n\n    @Override\n    public void delete(Iterable<ID> ids) {\n        Iterator<ID> iterator = ids.iterator();\n        while (iterator.hasNext()) {\n            ID id = iterator.next();\n            dao.deleteById(id);\n        }\n    }\n\n    @Override\n    public T insert(T record) {\n        return dao.save(record);\n    }\n\n    @Override\n    @Cacheable(value = Cache.APPLICATION ,key = \"#root.targetClass.simpleName+':'+#id\")\n    public T get(ID id) {\n        return  dao.findById(id).get();\n    }\n\n    @Override\n    public T get(SearchFilter filter) {\n        List<T> list = queryAll(filter);\n        return list.isEmpty()?null:list.get(0);\n    }\n\n    @Override\n    public T get(List<SearchFilter> filters) {\n        List<T> list = queryAll(filters);\n        return list.isEmpty()?null:list.get(0);\n    }\n\n    @Override\n    public List<T> query(Iterable<ID> ids) {\n        return dao.findAllById(ids);\n    }\n\n    @Override\n    public List<T> queryAll() {\n        return dao.findAll();\n    }\n\n    @Override\n    public Page<T> queryPage(Page<T> page) {\n        Pageable pageable = null;\n        if(page.isOpenSort()) {\n            pageable = new PageRequest(page.getCurrent()-1, page.getSize(), page.isAsc() ? Sort.Direction.ASC : Sort.Direction.DESC, page.getOrderByField());\n        }else{\n            pageable = new PageRequest(page.getCurrent()-1,page.getSize(), Sort.Direction.DESC,\"id\");\n        }\n        Specification<T> specification = DynamicSpecifications.bySearchFilter(page.getFilters(),dao.getDataClass());\n        org.springframework.data.domain.Page<T> pageResult  = dao.findAll(specification,pageable);\n        page.setTotal(Integer.valueOf(pageResult.getTotalElements()+\"\"));\n        page.setRecords(pageResult.getContent());\n        return page;\n    }\n\n    @Override\n    public List<T> queryAll(List<SearchFilter> filters) {\n        return queryAll(filters,null);\n    }\n\n    @Override\n    public List<T> queryAll(SearchFilter filter) {\n        return queryAll(filter,null);\n    }\n\n    @Override\n    public List<T> queryAll(List<SearchFilter> filters, Sort sort) {\n        Specification<T> specification = DynamicSpecifications.bySearchFilter(filters,dao.getDataClass());\n        if(sort==null){\n            return dao.findAll(specification);\n        }\n        return dao.findAll(specification,sort);\n    }\n\n    @Override\n    public List<T> queryAll(SearchFilter filter, Sort sort) {\n        if(filter!=null){\n            return queryAll(Lists.newArrayList(filter),sort);\n        }else {\n            return queryAll(Lists.newArrayList(), sort);\n        }\n    }\n    @Override\n    public List<Map> queryBySql(String sql){\n        return queryBySql(sql,Lists.newArrayList());\n    }\n    @Override\n    public List<Map> queryBySql(String sql, SearchFilter filter){\n        return dao.queryBySql(sql,Lists.newArrayList(filter));\n    }\n    @Override\n    public List<Map> queryBySql(String sql, List<SearchFilter> filter){\n        return dao.queryBySql(sql,filter);\n    }\n\n    @Override\n    public long count(SearchFilter filter) {\n        return count(Lists.newArrayList(filter));\n    }\n\n    @Override\n    public long count(List<SearchFilter> filters) {\n        Specification<T> specification = DynamicSpecifications.bySearchFilter(filters,dao.getDataClass());\n        return dao.count(specification);\n    }\n    @Override\n    @CacheEvict(value = Cache.APPLICATION ,key = \"#root.targetClass.simpleName+':'+#record.id\")\n    public T update(T record) {\n        return dao.save(record);\n    }\n\n    @Override\n    public void clear() {\n        dao.deleteAllInBatch();\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/CrudService.java",
    "content": "package cn.enilu.material.service;\n\n/**\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 22:31\n */\npublic interface CrudService <T, ID> extends\n        InsertService<T, ID>,\n        UpdateService<T,ID>,\n        DeleteService<ID>,\n        SelectService<T, ID> {\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/DeleteService.java",
    "content": "package cn.enilu.material.service;\n\n/**\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 22:29\n */\npublic interface DeleteService<ID> {\n\n    /**\n     * 根据主键删除记录\n     *\n     * @param id 主键\n     */\n    void delete(ID id);\n\n    /**\n     * 根据主键删除记录\n     *\n     * @param ids 主键集合\n     */\n    void delete(Iterable<ID> ids);\n\n    /**\n     * 清空表数据\n     */\n    void clear();\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/InsertService.java",
    "content": "package cn.enilu.material.service;\n\n/**\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 22:28\n */\npublic interface InsertService<T, ID> {\n\n    /**\n     * 添加一条数据\n     *\n     * @param record 要添加的数据\n     * @return 添加后生成的主键\n     */\n    T insert(T record);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/SelectService.java",
    "content": "package cn.enilu.material.service;\n\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.bean.vo.query.Page;\nimport org.springframework.data.domain.Sort;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 22:30\n */\npublic interface SelectService <T, ID> {\n\n    /**\n     * 根据主键查询\n     * @param id 主键\n     * @return 查询结果,无结果时返回{@code null}\n     */\n    T get(ID id);\n    T get(SearchFilter filter);\n    T get(List<SearchFilter> filters);\n    /**\n     * 根据多个主键查询\n     * @param ids 主键集合\n     * @return 查询结果,如果无结果返回空集合\n     */\n    List<T> query(Iterable<ID> ids);\n\n    /**\n     * 查询所有结果\n     * @return 所有结果,如果无结果则返回空集合\n     */\n    List<T> queryAll();\n\n    /**\n     * 查询所有结果\n     * @return 获取分页结果\n     */\n    Page<T> queryPage(Page<T> page);\n\n    /**\n     * 根据多个条件查询列表数据\n     * @param filters\n     * @return\n     */\n    List<T> queryAll(List<SearchFilter> filters);\n\n    /**\n     * 根据多个条件查询列表数据，并排序\n     * @param filters\n     * @param sort\n     * @return\n     */\n    List<T> queryAll(List<SearchFilter> filters, Sort sort);\n\n    /**\n     * 根据的单个条件查询列表数据\n     * @param filter\n     * @return\n     */\n    List<T> queryAll(SearchFilter filter);\n\n    /**\n     * 根据的单个条件查询列表数据\n     * @param filter\n     * @param sort\n     * @return\n     */\n    List<T> queryAll(SearchFilter filter,Sort sort);\n\n    /**\n     * 根据原生sql查询数据列表，\n     * 例：select sum(a.1+a.2) from a where a.c=:c\n     * @param sql\n     * @return\n     */\n    List<Map> queryBySql(String sql);\n\n    /**\n     * 根据原生sql查询数据列表\n     * @param sql\n     * @param filter\n     * @return\n     */\n    List<Map> queryBySql(String sql, SearchFilter filter);\n\n    /**\n     * 根据原生sql查询数据列表\n     * @param sql\n     * @param filter\n     * @return\n     */\n    List<Map> queryBySql(String sql, List<SearchFilter> filter);\n    /**\n     * 查询记录数\n     * @param filter\n     * @return\n     */\n    long count(SearchFilter filter);\n\n    /**\n     * 查询记录数\n     * @param filters\n     * @return\n     */\n    long count(List<SearchFilter> filters);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/UpdateService.java",
    "content": "package cn.enilu.material.service;\n\n/**\n *\n * @author ：enilu\n * @date ：Created in 2019/6/29 22:30\n */\npublic interface UpdateService <T, ID> {\n    /**\n     * 修改记录信息\n     *\n     * @param record 要修改的对象\n     * @return 返回修改的记录\n     */\n    T update(T record);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/message/MessageService.java",
    "content": "package cn.enilu.material.service.message;\n\n\nimport cn.enilu.material.bean.entity.message.Message;\nimport cn.enilu.material.bean.entity.message.MessageSender;\nimport cn.enilu.material.bean.entity.message.MessageTemplate;\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport cn.enilu.material.dao.message.MessageRepository;\nimport cn.enilu.material.dao.message.MessagesenderRepository;\nimport cn.enilu.material.dao.message.MessagetemplateRepository;\nimport cn.enilu.material.service.BaseService;\nimport cn.enilu.material.service.message.email.EmailSender;\nimport cn.enilu.material.service.message.sms.SmsSender;\nimport cn.enilu.material.utils.StringUtils;\nimport com.google.common.base.Splitter;\nimport com.google.common.collect.Lists;\nimport org.apache.commons.lang3.text.StrSubstitutor;\nimport org.nutz.lang.Lang;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.io.InputStreamSource;\nimport org.springframework.stereotype.Service;\n\nimport java.text.MessageFormat;\nimport java.util.*;\n\n/**\n * MessageService\n *\n * @author enilu\n * @version 2019/05/17 0017\n */\n@Service\npublic class MessageService extends BaseService<Message,Long, MessageRepository> {\n    private Logger logger = LoggerFactory.getLogger(getClass());\n    @Autowired\n    private MessageRepository messageRepository;\n    @Autowired\n    private MessagesenderRepository messagesenderRepository;\n    @Autowired\n    private MessagetemplateRepository messagetemplateRepository;\n\n\n\n    public boolean delete(String ids) {\n        final ArrayList<String> list = Lists.newArrayList(Splitter.on(',').split(ids));\n        messageRepository.deleteAllByIdIn(list);\n        return true;\n    }\n\n    /**\n     * 发送复杂模板的邮件\n     * @param tplCode\n     * @param from\n     * @param to\n     * @param cc\n     * @param title\n     * @param dataMap\n     */\n    public void sendTplEmail(String tplCode, String from, String to, String cc, String title, Map<String, Object> dataMap) {\n        MessageTemplate messageTemplate = messagetemplateRepository.findByCode(tplCode);\n        String content = getContent(messageTemplate.getContent(), dataMap);\n        sendEmailMessage(tplCode,from,to,cc,title,content,messageTemplate,null,null);\n    }\n\n    /**\n     * 发送带附件的邮件\n     * @param tplCode\n     * @param from\n     * @param to\n     * @param cc\n     * @param title\n     * @param attachmentFilename\n     * @param inputStreamSource\n     * @param dataMap\n     */\n    public void sendTplEmail(String tplCode, String from, String to, String cc, String title,\n                             String attachmentFilename, InputStreamSource inputStreamSource,\n                             Map<String, Object> dataMap) {\n        MessageTemplate messageTemplate = messagetemplateRepository.findByCode(tplCode);\n        String content = getContent(messageTemplate.getContent(), dataMap);\n        sendEmailMessage(tplCode,from,to,cc,title,content,messageTemplate,attachmentFilename,inputStreamSource);\n    }\n\n    /**\n     * 发送简单模板邮件\n     * @param tplCode\n     * @param from\n     * @param to\n     * @param cc\n     * @param title\n     * @param args\n     */\n    public void sendSimpleEmail(String tplCode, String from, String to, String cc, String title, String... args) {\n        MessageTemplate messageTemplate = messagetemplateRepository.findByCode(tplCode);\n        String content = getContent(messageTemplate.getContent(), args);\n        sendEmailMessage(tplCode,from,to,cc,title,content,messageTemplate,null,null);\n    }\n\n    /**\n     * 发送短信\n     * @param tplCode\n     * @param receiver\n     * @param args\n     */\n    public void sendSms(String tplCode, String receiver, String... args) {\n        MessageTemplate messageTemplate = messagetemplateRepository.findByCode(tplCode);\n        String content = getContent(messageTemplate.getContent(), args);\n        boolean isSuccess = false;\n        try {\n            isSuccess = this.sendSmsMessage(receiver, content, messageTemplate, args);\n        }catch (Exception e){\n            logger.error(e.getMessage(), e);\n        }\n        saveMessage(0,tplCode,receiver,content,isSuccess);\n    }\n    private void sendEmailMessage(String tplCode, String from, String to, String cc, String title,\n                                  String content,MessageTemplate messageTemplate,\n                                  String attachmentFilename, InputStreamSource inputStreamSource){\n        try {\n            EmailSender emailSender = getEmailSender(messageTemplate);\n            boolean isSuccess = false;\n            if(inputStreamSource!=null){\n                isSuccess = emailSender.sendEmail(from, to, cc, title, content,attachmentFilename,inputStreamSource);\n            }else {\n                  isSuccess = emailSender.sendEmail(from, to, cc, title, content);\n            }\n            saveMessage(1, tplCode, to, content, isSuccess);\n        }catch (Exception e){\n            logger.error(e.getMessage(), e);\n            saveMessage(1, tplCode, to, content, false);\n        }\n    }\n\n    private String getContent(String template, String... args) {\n        List<Object> argList = new ArrayList<>();\n        argList.add(\"\");\n        if (args != null) {\n            Collections.addAll(argList, args);\n        }\n        String content = MessageFormat.format(template, Lang.collection2array(argList));\n        return content;\n    }\n\n    private String getContent(String template, Map<String, Object> dataMap) {\n        return StrSubstitutor.replace(template, dataMap);\n    }\n\n    private void saveMessage(Integer type, String tplCode, String receiver, String content, Boolean sendResult) {\n        Message message = new Message();\n        message.setType(type);\n        message.setTplCode(tplCode);\n        message.setType(0);\n        message.setState(sendResult ? 1 : 2);\n        message.setReceiver(receiver);\n        message.setCreateTime(new Date());\n        message.setContent(content);\n        messageRepository.save(message);\n\n    }\n\n\n\n\n    private boolean sendSmsMessage( String receiver, String content,  MessageTemplate messageTemplate,String... args) throws Exception {\n        String tplCode = getTpl(messageTemplate);\n        SmsSender smsSender = getSmsSender(messageTemplate);\n\n        boolean success = false;\n        String[] receivers = receiver.split(\",|;\", -1);\n        for (String oneReceiver : receivers) {\n            try {\n\n                if (StringUtils.isNotEmpty(oneReceiver)) {\n                    success = smsSender.sendSms(tplCode, oneReceiver, args, content);\n                }\n            } catch (Exception e) {\n                logger.error(e.getMessage(), e);\n            }\n        }\n\n        return success;\n    }\n\n    private SmsSender getSmsSender(MessageTemplate messageTemplate) throws Exception {\n        MessageSender messageSender = messagesenderRepository.findById(messageTemplate.getIdMessageSender()).get();\n        if (messageSender != null) {\n            try {\n                return SpringContextHolder.getBean(messageSender.getClassName());\n            } catch (Exception e) {\n                logger.error(\"获取SmsService实现类失败\", e);\n                throw new Exception(\"smsService名称配置失败:\" + messageSender.getClassName());\n            }\n        } else {\n            throw new Exception(\"未配置运营商模版id\");\n        }\n    }\n\n    private EmailSender getEmailSender(MessageTemplate messageTemplate) throws Exception {\n        MessageSender messageSender = messagesenderRepository.findById(messageTemplate.getIdMessageSender()).get();\n        if (messageSender != null) {\n            try {\n                return SpringContextHolder.getBean(messageSender.getClassName());\n            } catch (Exception e) {\n                logger.error(\"获取SmsService实现类失败\", e);\n                throw new Exception(\"smsService名称配置失败:\" + messageSender.getClassName());\n            }\n        } else {\n            throw new Exception(\"未配置运营商模版id\");\n        }\n    }\n    private String getTpl(MessageTemplate messageTemplate) {\n        MessageSender messageSender = messagesenderRepository.findById(messageTemplate.getIdMessageSender()).get();\n\n        if (messageSender != null && StringUtils.isNotEmpty(messageSender.getTplCode())) {\n            return messageSender.getTplCode();\n        } else {\n            return null;\n        }\n    }\n}\n\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/message/MessagesenderService.java",
    "content": "package cn.enilu.material.service.message;\n\n\nimport cn.enilu.material.bean.entity.message.MessageSender;\nimport cn.enilu.material.bean.entity.message.MessageTemplate;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.dao.message.MessagesenderRepository;\nimport cn.enilu.material.dao.message.MessagetemplateRepository;\nimport cn.enilu.material.service.BaseService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * MessagesenderService\n *\n * @author enilu\n * @version 2019/05/17 0017\n */\n@Service\npublic class MessagesenderService extends BaseService<MessageSender,Long, MessagesenderRepository> {\n    private Logger logger = LoggerFactory.getLogger(getClass());\n    @Autowired\n    private MessagesenderRepository messageSenderRepository;\n    @Autowired\n    private MessagetemplateRepository messagetemplateRepository;\n\n    public void save(MessageSender messageSender){\n        messageSenderRepository.save(messageSender);\n    }\n    @Override\n    public void  delete(Long id) throws ApplicationException {\n        List<MessageTemplate> templateList = messagetemplateRepository.findByIdMessageSender(id);\n        if(templateList.isEmpty()) {\n            messageSenderRepository.deleteById(id);\n        }else{\n            throw  new ApplicationException(BizExceptionEnum.CAN_NOT_DELETE);\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/message/MessagetemplateService.java",
    "content": "package cn.enilu.material.service.message;\n\nimport cn.enilu.material.bean.entity.message.MessageTemplate;\nimport cn.enilu.material.dao.message.MessagetemplateRepository;\nimport cn.enilu.material.service.BaseService;\nimport org.springframework.stereotype.Service;\n\n/**\n * MessagetemplateService\n *\n * @author enilu\n * @version 2019/05/17 0017\n */\n@Service\npublic class MessagetemplateService  extends BaseService<MessageTemplate,Long, MessagetemplateRepository> {\n\n}\n\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/message/email/DefaultEmailSender.java",
    "content": "package cn.enilu.material.service.message.email;\n\nimport cn.enilu.material.utils.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.core.io.InputStreamSource;\nimport org.springframework.mail.javamail.JavaMailSender;\nimport org.springframework.mail.javamail.MimeMessageHelper;\nimport org.springframework.stereotype.Service;\n\nimport javax.mail.internet.MimeMessage;\n\n/**\n * 默认的邮件发送服务类\n *\n * @author ：enilu\n * @date ：Created in 2019/6/11 15:19\n */\n@Service\npublic class DefaultEmailSender implements EmailSender{\n    @Autowired\n    private JavaMailSender javaMailSender;\n    @Override\n    public boolean sendEmail(String from, String to, String cc, String title, String content){\n        return sendEmail(from,to,cc,title,content,null,null);\n    }\n\n    @Override\n    public boolean sendEmail(String from, String to, String cc, String title, String content, String attachmentFilename, InputStreamSource inputStreamSource) {\n        MimeMessage message = null;\n        try {\n            message = javaMailSender.createMimeMessage();\n            MimeMessageHelper helper = new MimeMessageHelper(message, true);\n            helper.setFrom(from);\n            helper.setTo(to);\n            if(StringUtils.isNotEmpty(cc)) {\n                helper.setCc(cc);\n            }\n            helper.setSubject(title);\n            helper.setText(content, true);\n            if(inputStreamSource!=null) {\n                helper.addAttachment(attachmentFilename, inputStreamSource);\n            }\n            javaMailSender.send(message);\n            return true;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/message/email/EmailSender.java",
    "content": "package cn.enilu.material.service.message.email;\n\nimport org.springframework.core.io.InputStreamSource;\n\n/**\n * 邮件发送接口\n *\n * @author ：enilu\n * @date ：Created in 2019/6/17 19:33\n */\npublic interface EmailSender {\n    /**\n     * 发送邮件\n     * @param from\n     * @param to\n     * @param cc\n     * @param title\n     * @param content\n     * @return\n     */\n    boolean sendEmail(String from, String to, String cc, String title, String content);\n\n    /**\n     * 发送带附件的邮件\n     * @param from\n     * @param to\n     * @param cc\n     * @param title\n     * @param content\n     * @param attachmentFilename\n     * @param inputStreamSource\n     * @return\n     */\n    boolean sendEmail(String from, String to, String cc, String title, String content, String attachmentFilename, InputStreamSource inputStreamSource);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/message/sms/SmsSender.java",
    "content": "package cn.enilu.material.service.message.sms;\n\npublic interface SmsSender {\n\n    /**\n     * 发送短信，如果内容content不为空，则直接发送内容\n     * @param tplCode 短信运营商模板号码\n     * @param receiver\n     * @param args\n     * @param content\n     * @return\n     */\n    boolean sendSms(String tplCode, String receiver, String[] args, String content);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/message/sms/tencent/TencentSmsSender.java",
    "content": "package cn.enilu.material.service.message.sms.tencent;\n\nimport cn.enilu.material.bean.enumeration.ConfigKeyEnum;\nimport cn.enilu.material.dao.cache.ConfigCache;\nimport cn.enilu.material.service.message.sms.SmsSender;\nimport cn.enilu.material.utils.StringUtils;\nimport com.github.qcloudsms.SmsSingleSender;\nimport com.github.qcloudsms.SmsSingleSenderResult;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class TencentSmsSender implements SmsSender {\n    private Logger logger = LoggerFactory.getLogger(TencentSmsSender.class);\n    @Autowired\n    private ConfigCache configCache;\n    @Override\n    public boolean sendSms(String tplCode, String receiver, String[] args, String content) {\n        Integer appid = Integer.valueOf((String) configCache.get(ConfigKeyEnum.API_TENCENT_SMS_APPID.getValue()));\n        String appkey = (String) configCache.get(ConfigKeyEnum.API_TENCENT_SMS_APPKEY.getValue());\n        String smsSign = (String) configCache.get(ConfigKeyEnum.API_TENCENT_SMS_SIGN.getValue());\n        SmsSingleSender ssender = new SmsSingleSender(appid, appkey);\n        SmsSingleSenderResult result = null;\n        try{\n            if(StringUtils.isNotEmpty(tplCode)){\n                //根据指定模板id发送短信\n                // 签名参数未提供或者为空时，会使用默认签名发送短信\n                result = ssender.sendWithParam(\"86\", receiver,\n                    Integer.valueOf(tplCode), args, smsSign, \"\", \"\");\n            }else {\n                //发送固定内容短信\n                result = ssender.send(0, \"86\", receiver,\n                        content, \"\", \"\");\n\n            }\n            logger.info(result.errMsg);\n            return result.result == 0;\n        } catch (Exception e) {\n                logger.error(\"发送短信异常\",e);\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/AccountService.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.dao.cache.TokenCache;\nimport cn.enilu.material.platform.log.LogManager;\nimport cn.enilu.material.platform.log.LogTaskFactory;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.Convert;\nimport cn.enilu.material.utils.HttpKit;\nimport com.google.common.collect.Lists;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\nimport java.util.UUID;\n\n/**\n * AccountService\n *\n * @author enilu\n * @version 2018/9/12 0012\n */\n@Service\npublic class AccountService {\n    @Autowired\n    private TokenCache tokenCache;\n    @Autowired\n    private UserService userService;\n\n    public String login(Long idUser) {\n        String token = UUID.randomUUID().toString();\n        tokenCache.put(token, idUser);\n        LogManager.me().executeLog(LogTaskFactory.loginLog(idUser, HttpKit.getIp()));\n        User user = userService.get(idUser);\n        Long[] roleArray = Convert.toLongArray(true,Convert.toStrArray(\",\",  user.getRoleid()));\n        ShiroUser shiroUser = new ShiroUser();\n        shiroUser.setAccount(user.getAccount());\n        shiroUser.setDeptId(user.getDeptid());\n        shiroUser.setDeptName(ConstantFactory.me().getDeptName(user.getDeptid()));\n        shiroUser.setId(idUser);\n        shiroUser.setName(user.getName());\n        shiroUser.setRoleList(Lists.newArrayList(roleArray));\n        List<String> roleNames = Lists.newArrayList();\n        List<String> roleCodes = Lists.newArrayList();\n        for (Long roleId : roleArray) {\n            roleCodes.add(ConstantFactory.me().getSingleRoleTip(roleId));\n            roleNames.add(ConstantFactory.me().getSingleRoleName(roleId));\n\n        }\n        shiroUser.setRoleNames(roleNames);\n        shiroUser.setRoleCodes(roleCodes);\n        tokenCache.setUser(token,shiroUser);\n        return token;\n    }\n\n\n    public void logout(String token) {\n        tokenCache.remove(token);\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/CfgService.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.entity.system.Cfg;\nimport cn.enilu.material.dao.cache.ConfigCache;\nimport cn.enilu.material.dao.system.CfgRepository;\nimport cn.enilu.material.service.BaseService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n/**\n * CfgService\n *\n * @author enilu\n * @version 2018/11/17 0017\n */\n\n@Service\npublic class CfgService extends BaseService<Cfg,Long,CfgRepository> {\n    @Autowired\n    private ConfigCache configCache;\n    \n    public Cfg saveOrUpdate(Cfg cfg) {\n        if(cfg.getId()==null){\n            insert(cfg);\n        }else{\n            update(cfg);\n        }\n        configCache.cache();\n        return cfg;\n    }\n    @Override\n    public void delete(Long id) {\n        super.delete(id);\n        configCache.cache();\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/DeptService.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.entity.system.Dept;\nimport cn.enilu.material.bean.vo.node.DeptNode;\nimport cn.enilu.material.bean.vo.node.ZTreeNode;\nimport cn.enilu.material.dao.system.DeptRepository;\nimport cn.enilu.material.service.BaseService;\nimport cn.enilu.material.utils.ToolUtil;\nimport com.google.common.base.Strings;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * Created  on 2018/3/21 0021.\n *\n * @author enilu\n */\n@Service\npublic class DeptService extends BaseService<Dept,Long,DeptRepository> {\n    @Autowired\n    private DeptRepository deptRepository;\n\n    public List<ZTreeNode> tree() {\n        List<Object[]> list = deptRepository.tree();\n        List<ZTreeNode> nodes = new ArrayList<>();\n        for(Object[] obj:list){\n            ZTreeNode node = transfer(obj);\n            nodes.add(node);\n        }\n        return nodes;\n    }\n\n    private ZTreeNode transfer(Object[] obj){\n        ZTreeNode node = new ZTreeNode();\n        node.setId(Long.valueOf(obj[0].toString()));\n        node.setpId(Long.valueOf(obj[1].toString()));\n        node.setName(obj[2].toString());\n        node.setIsOpen(Boolean.valueOf(obj[3].toString()));\n        return node;\n    }\n    public List<Dept> query(String condition) {\n        List<Dept> list = new ArrayList<>();\n        if(Strings.isNullOrEmpty(condition)){\n            list = (List<Dept>) deptRepository.findAll();\n        }else{\n            condition = \"%\"+condition+\"%\";\n            list = deptRepository.findBySimplenameLikeOrFullnameLike(condition,condition);\n        }\n        return list;\n    }\n\n    public void deleteDept(Long deptId) {\n        Dept dept = get(deptId);\n\n        List<Dept> subDepts = deptRepository.findByPidsLike(\"%[\" + dept.getId() + \"]%\");\n        deptRepository.deleteAll(subDepts);\n        deptRepository.delete(dept);\n    }\n    public List<DeptNode> queryAllNode() {\n        List<Dept> list = queryAll();\n        return generateTree(list);\n    }\n\n    public void deptSetPids(Dept dept) {\n        if (ToolUtil.isEmpty(dept.getPid()) || dept.getPid().equals(0)) {\n            dept.setPid(0L);\n            dept.setPids(\"[0],\");\n        } else {\n            Long pid = dept.getPid();\n            Dept temp = get(pid);\n            String pids = \"\";\n            if(temp!=null){\n                pids = temp.getPids();\n            }\n            dept.setPid(pid);\n            dept.setPids(pids + \"[\" + pid + \"],\");\n        }\n    }\n\n    private List<DeptNode> generateTree(List<Dept> list){\n\n        List<DeptNode> nodes = new ArrayList<>(20);\n        for(Dept dept:list){\n            DeptNode deptNode = new DeptNode();\n            BeanUtils.copyProperties(dept,deptNode);\n            nodes.add(deptNode);\n        }\n        for(DeptNode deptNode:nodes){\n            for(DeptNode child:nodes){\n                if(child.getPid().intValue() == deptNode.getId().intValue()){\n                    deptNode.getChildren().add(child);\n                }\n            }\n        }\n        List<DeptNode> result = new ArrayList<>(20);\n        for(DeptNode node:nodes){\n            if(node.getPid().intValue() == 0){\n                result.add(node);\n            }\n        }\n        return result;\n\n\n    }\n\n\n    public Dept get(Long id) {\n        Optional<Dept> optiona = deptRepository.findById(id);\n        if (optiona.isPresent()) {\n            return optiona.get();\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/DictService.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.entity.system.Dict;\nimport cn.enilu.material.dao.cache.DictCache;\nimport cn.enilu.material.dao.system.DictRepository;\nimport cn.enilu.material.bean.vo.query.MutiStrFactory;\nimport cn.enilu.material.service.BaseService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport javax.annotation.Resource;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Optional;\n\n/**\n * 字典服务\n *\n * @author fengshuonan\n * @date 2017-04-27 17:00\n */\n@Service\npublic class DictService extends BaseService<Dict,Long,DictRepository> {\n    private Logger logger = LoggerFactory.getLogger(DictService.class);\n    @Resource\n    DictRepository dictRepository;\n    @Autowired\n    private DictCache dictCache;\n\n    public void addDict(String dictName, String dictValues) {\n        //判断有没有该字典\n        List<Dict> dicts = dictRepository.findByNameAndPid(dictName,0L);\n        if(dicts != null && dicts.size() > 0){\n            return ;\n        }\n\n        //解析dictValues\n        List<Map<String, String>> items = MutiStrFactory.parseKeyValue(dictValues);\n\n        //添加字典\n        Dict dict = new Dict();\n        dict.setName(dictName);\n        dict.setValue(\"0\");\n        dict.setPid(0L);\n        this.dictRepository.save(dict);\n\n        //添加字典条目\n        for (Map<String, String> item : items) {\n            String val = item.get(MutiStrFactory.MUTI_STR_KEY);\n            String name = item.get(MutiStrFactory.MUTI_STR_VALUE);\n            Dict itemDict = new Dict();\n            itemDict.setPid(dict.getId());\n            itemDict.setName(name);\n            try {\n                itemDict.setValue(val);\n            }catch (NumberFormatException e){\n                logger.error(e.getMessage(),e);\n            }\n            this.dictRepository.save(itemDict);\n        }\n        dictCache.cache();\n    }\n\n    public void editDict(Long dictId, String dictName, String dicts) {\n        //删除之前的字典\n        this.delteDict(dictId);\n\n        //重新添加新的字典\n        this.addDict(dictName,dicts);\n\n        dictCache.cache();\n    }\n\n    public void delteDict(Long dictId) {\n        //删除这个字典的子词典\n        List<Dict> subList = dictRepository.findByPid(dictId);\n        dictRepository.deleteAll(subList);\n        //删除这个词典\n        dictRepository.deleteById(dictId);\n\n        dictCache.cache();\n    }\n    public Dict get(Long id) {\n        Optional<Dict> optional = dictRepository.findById(id);\n        if (optional.isPresent()) {\n            return optional.get();\n        }\n        return null;\n    }\n\n    public List<Dict> queryByPid(Long pid) {\n        return dictRepository.findByPid(pid);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/FileService.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.entity.system.FileInfo;\nimport cn.enilu.material.bean.enumeration.ConfigKeyEnum;\nimport cn.enilu.material.dao.cache.ConfigCache;\nimport cn.enilu.material.dao.cache.TokenCache;\nimport cn.enilu.material.dao.system.FileInfoRepository;\nimport cn.enilu.material.utils.StringUtils;\nimport cn.enilu.material.bean.vo.query.Page;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.jpa.domain.Specification;\nimport org.springframework.stereotype.Service;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.persistence.criteria.CriteriaBuilder;\nimport javax.persistence.criteria.CriteriaQuery;\nimport javax.persistence.criteria.Predicate;\nimport javax.persistence.criteria.Root;\nimport java.io.File;\nimport java.util.*;\n\n@Service\npublic class FileService {\n    @Autowired\n    private ConfigCache configCache;\n    @Autowired\n    private FileInfoRepository fileInfoRepository;\n    @Autowired\n    private TokenCache tokenCache;\n    public FileInfo save(MultipartFile multipartFile){\n        String uuid = UUID.randomUUID().toString();\n        String realFileName =   uuid +\".\"+ multipartFile.getOriginalFilename().split(\"\\\\.\")[1];\n        try {\n\n            File file = new File(configCache.get(ConfigKeyEnum.SYSTEM_FILE_UPLOAD_PATH.getValue()) + File.separator+realFileName);\n            if (!file.getParentFile().exists()) {\n                file.getParentFile().mkdirs();\n            }\n            multipartFile.transferTo(file);\n            FileInfo fileInfo = new FileInfo();\n            fileInfo.setCreateTime(new Date());\n            fileInfo.setCreateBy(tokenCache.getIdUser());\n            fileInfo.setOriginalFileName(multipartFile.getOriginalFilename());\n            fileInfo.setRealFileName(realFileName);\n            fileInfoRepository.save(fileInfo);\n            return fileInfo;\n        } catch (Exception e) {\n            e.printStackTrace();\n             return null;\n        }\n    }\n\n    public FileInfo get(Long id){\n        FileInfo fileInfo = fileInfoRepository.getOne(id);\n        fileInfo.setAblatePath(configCache.get(ConfigKeyEnum.SYSTEM_FILE_UPLOAD_PATH.getValue()) + File.separator+fileInfo.getRealFileName());\n        return fileInfo;\n    }\n\n    public Page<FileInfo> findPage(Page<FileInfo> page, HashMap<String, String> params) {\n        Pageable pageable  = new PageRequest(page.getCurrent() - 1, page.getSize(), Sort.Direction.DESC,\"id\");\n        org.springframework.data.domain.Page<FileInfo> pageResult = fileInfoRepository.findAll(new Specification<FileInfo>() {\n            @Override\n            public Predicate toPredicate(Root<FileInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {\n                List<Predicate> list = new ArrayList<Predicate>();\n                if (StringUtils.isNotEmpty(params.get(\"originalFileName\"))) {\n                    list.add(criteriaBuilder.like(root.get(\"originalFileName\").as(String.class), \"%\" + params.get(\"originalFileName\") + \"%\"));\n                }\n\n                Predicate[] p = new Predicate[list.size()];\n                return criteriaBuilder.and(list.toArray(p));\n            }\n        }, pageable);\n        page.setTotal(Integer.valueOf(pageResult.getTotalElements() + \"\"));\n        page.setRecords(pageResult.getContent());\n        return page;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/IConstantFactory.java",
    "content": "package cn.enilu.material.service.system;\n\n\nimport cn.enilu.material.bean.entity.system.*;\nimport cn.enilu.material.bean.vo.DictVo;\n\nimport java.util.List;\n\n/**\n * 常量生产工厂的接口\n *\n * @author fengshuonan\n * @date 2017-06-14 21:12\n */\npublic interface IConstantFactory {\n    /**\n     * 获取静态资源版本号\n     * @return\n     */\n    String resourceVersion();\n    /**\n     * 根据用户id获取用户名称\n     *\n     * @author enilu.cn\n     * @Date 2017/5/9 23:41\n     */\n    String getUserNameById(Long userId);\n\n    /**\n     * 根据用户id获取用户账号\n     *\n     * @author enilu.cn\n     * @date 2017年5月16日21:55:371\n     */\n    String getUserAccountById(Long userId);\n\n    /**\n     * 通过角色ids获取角色名称\n     */\n    String getRoleName(String roleIds);\n\n    /**\n     * 通过角色id获取角色名称\n     */\n    String getSingleRoleName(Long roleId);\n\n    /**\n     * 通过角色id获取角色英文名称\n     */\n    String getSingleRoleTip(Long roleId);\n\n    /**\n     * 获取部门名称\n     */\n    String getDeptName(Long deptId);\n\n    /**\n     * 获取菜单的名称们(多个)\n     */\n    String getMenuNames(String menuIds);\n\n    /**\n     * 获取菜单名称\n     */\n    String getMenuName(Long menuId);\n\n    /**\n     * 获取菜单名称通过编号\n     */\n    String getMenuNameByCode(String code);\n\n    /**\n     * 根据字典名称获取字典列表\n     * @param dictName\n     * @return\n     */\n    List<DictVo> findByDictName(String dictName);\n    /**\n     * 获取字典名称\n     */\n    String getDictName(Long dictId);\n\n    /**\n     * 获取通知标题\n     */\n    String getNoticeTitle(Long dictId);\n\n    /**\n     * 根据字典名称和字典中的值获取对应的名称\n     */\n    String getDictsByName(String name, String val);\n\n    /**\n     * 获取性别名称\n     */\n    String getSexName(Integer sex);\n    /**\n     * 获取银行卡类型名称\n     * @param cardType\n     * @return\n     */\n    String getCardTypeName(String cardType);\n\n    /**\n     * 获取个人证件类型\n     * @param cardType\n     * @return\n     */\n    String getIdCardTypeName(String cardType);\n\n    /**\n     * 获取联系人关系\n     * @param relation\n     * @return\n     */\n    String getRelationName(String relation);\n    /**\n     * 获取用户登录状态\n     */\n    String getStatusName(Integer status);\n\n    /**\n     * 获取菜单状态\n     */\n    String getMenuStatusName(Integer status);\n\n    /**\n     * 查询字典\n     */\n    List<Dict> findInDict(Long id);\n\n    /**\n     * 获取被缓存的对象(用户删除业务)\n     */\n    String getCacheObject(String para);\n\n    /**\n     * 获取子部门id\n     */\n    List<Long> getSubDeptId(Long deptid);\n\n    /**\n     * 获取所有父部门id\n     */\n    List<Integer> getParentDeptIds(Long deptid);\n\n\n    /**\n     * 获取指定名称下的字典列表\n     * @param pname\n     * @return\n     */\n    List<Dict> getDicts(String pname);\n    /**\n     * 获取全局参数\n     * @param cfgName\n     * @return\n     */\n    String getCfg(String cfgName);\n\n\n    Role getRole(Long id) ;\n    Dept getDept(Long id);\n    Menu getMenu(Long id) ;\n\n    Notice getNotice(Long id);\n    void cleanLocalCache() ;\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/LogObjectHolder.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport org.springframework.context.annotation.Scope;\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.context.WebApplicationContext;\n\nimport java.io.Serializable;\n\n/**\n * 被修改的bean临时存放的地方\n *\n * @author fengshuonan\n * @date 2017-03-31 11:19\n */\n@Component\n@Scope(scopeName = WebApplicationContext.SCOPE_SESSION)\npublic class LogObjectHolder implements Serializable{\n\n    private Object object = null;\n\n    public void set(Object obj) {\n        this.object = obj;\n    }\n\n    public Object get() {\n        return object;\n    }\n\n    public static LogObjectHolder me(){\n        LogObjectHolder bean = SpringContextHolder.getBean(LogObjectHolder.class);\n        return bean;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/LoginLogService.java",
    "content": "package cn.enilu.material.service.system;\n\n\nimport cn.enilu.material.bean.entity.system.LoginLog;\nimport cn.enilu.material.dao.system.LoginLogRepository;\nimport cn.enilu.material.service.BaseService;\nimport org.springframework.stereotype.Service;\n\n/**\n * Created  on 2018/3/26 0026.\n *\n * @author enilu\n */\n@Service\npublic class LoginLogService extends BaseService<LoginLog,Long,LoginLogRepository> {\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/MenuService.java",
    "content": "package cn.enilu.material.service.system;\n\n\nimport cn.enilu.material.bean.entity.system.Menu;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.vo.node.MenuNode;\nimport cn.enilu.material.bean.vo.node.Node;\nimport cn.enilu.material.bean.vo.node.ZTreeNode;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.dao.system.MenuRepository;\nimport cn.enilu.material.service.BaseService;\nimport cn.enilu.material.utils.ToolUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.*;\n\n/**\n * Created  on 2018/3/23 0023.\n *\n * @author enilu\n */\n@Service\npublic class MenuService  extends BaseService<Menu,Long,MenuRepository> {\n\n    private Logger logger = LoggerFactory.getLogger(MenuService.class);\n    @Autowired\n    private MenuRepository menuRepository;\n\n\n    public void delMenu(Long menuId) {\n        //删除菜单\n        delete(menuId);\n        //删除关联的relation\n        menuRepository.deleteRelationByMenu(menuId);\n\n    }\n\n    public void delMenuContainSubMenus(Long menuId) {\n        Menu menu = get(menuId);\n        //删除所有子菜单\n        List<Menu> menus = menuRepository.findByPcodesLike(\"%[\" + menu.getCode() + \"]%\");\n        menuRepository.deleteAll(menus);\n        //删除当前菜单\n        delMenu(menuId);\n\n    }\n    public List<MenuNode> getMenusByRoleIds(List<Long> roleList) {\n        List menus = menuRepository.getMenusByRoleIds(roleList);\n        return transferMenuNode(menus);\n\n    }\n\n    public List<MenuNode> getMenusTreeByRoleIds(List<Long> roleList) {\n        List menus = menuRepository.getMenusByRoleIds(roleList);\n        List<MenuNode> result =  generateTree(transferMenuNode(menus));\n        for(MenuNode menuNode:result){\n            if(!menuNode.getChildren().isEmpty()){\n                sortTree(menuNode.getChildren());\n                for(MenuNode menuNode1: menuNode.getChildren()){\n                    if(!menuNode1.getChildren().isEmpty()) {\n                        sortTree(menuNode1.getChildren());\n                    }\n                }\n            }\n        }\n        sortTree(result);\n        return result;\n    }\n\n    public List<MenuNode> getMenus() {\n        List<MenuNode> list =  transferMenuNode(menuRepository.getMenus());\n        List<MenuNode> result =  generateTree(list);\n\n\n        for(MenuNode menuNode:result){\n            if(!menuNode.getChildren().isEmpty()){\n                sortTree(menuNode.getChildren());\n                for(MenuNode menuNode1: menuNode.getChildren()){\n                    if(!menuNode1.getChildren().isEmpty()) {\n                        sortTree(menuNode1.getChildren());\n                    }\n                }\n            }\n        }\n        sortTree(result);\n        return result;\n    }\n    private void sortTree(List<MenuNode> list){\n        Collections.sort(list, new Comparator<MenuNode>() {\n            @Override\n            public int compare(MenuNode o1, MenuNode o2) {\n                return o1.getNum()-o2.getNum();\n            }\n        });\n    }\n    private List<MenuNode> generateTree(List<MenuNode> list){\n        List<MenuNode> result = new ArrayList<>(20);\n        Map<Long,MenuNode> map = cn.enilu.material.utils.Lists.toMap(list,\"id\");\n        for(Map.Entry<Long,MenuNode> entry:map.entrySet()){\n            MenuNode menuNode = entry.getValue();\n\n            if(menuNode.getParentId().intValue()!=0){\n                MenuNode parentNode = map.get(menuNode.getParentId());\n                parentNode.getChildren().add(menuNode);\n            }else{\n                result.add(menuNode);\n            }\n        }\n        return result;\n\n    }\n    private List<MenuNode> transferMenuNode(List menus){\n        List<MenuNode> menuNodes = new ArrayList<>();\n        try {\n            for(int i=0;i<menus.size();i++){\n                Object[] source = (Object[]) menus.get(i);\n                MenuNode menuNode = new MenuNode();\n                menuNode.setId(Long.valueOf(source[0].toString()));\n                menuNode.setIcon(String.valueOf(source[1]));\n                menuNode.setParentId(Long.valueOf(source[2].toString()));\n                menuNode.setName(String.valueOf(source[3]));\n                menuNode.setUrl(String.valueOf(source[4]));\n                menuNode.setLevels((Integer) source[5]);\n                menuNode.setIsmenu((Integer) source[6]);\n                menuNode.setNum((Integer) source[7]);\n                menuNode.setCode(String.valueOf(source[8]));\n                menuNode.setStatus((Integer)source[9]);\n                menuNodes.add(menuNode);\n\n            }\n        }catch (Exception e){\n            logger.error(e.getMessage(),e);\n        }\n        return menuNodes;\n    }\n    public List<ZTreeNode> menuTreeList() {\n        List list = menuRepository.menuTreeList();\n        List<ZTreeNode> nodes  =new ArrayList<>();\n        for(int i=0;i<list.size();i++){\n            Object[] source = (Object[]) list.get(i);\n            ZTreeNode node = new ZTreeNode();\n            node.setId(Long.valueOf(source[0].toString()));\n            node.setpId(Long.valueOf(source[1].toString()));\n            node.setName(source[2].toString());\n            node.setIsOpen(Boolean.valueOf(source[3].toString()));\n            node.setCode(source[4].toString());\n            nodes.add(node);\n        }\n        return nodes;\n    }\n\n    public List<ZTreeNode> menuTreeListByMenuIds(List<Long> menuIds) {\n        List list = menuRepository.menuTreeListByMenuIds(menuIds);\n        List<ZTreeNode> nodes  =new ArrayList<>();\n        for(int i=0;i<list.size();i++){\n            Object[] source = (Object[]) list.get(i);\n            ZTreeNode node = new ZTreeNode();\n            node.setId(Long.valueOf(source[0].toString()));\n            node.setpId(Long.valueOf(source[1].toString()));\n            node.setName(source[2].toString());\n            node.setIsOpen(Boolean.valueOf(source[3].toString()));\n            node.setChecked(Boolean.valueOf(source[4].toString()));\n            nodes.add(node);\n        }\n        return nodes;\n    }\n\n    public void menuSetPcode(Menu menu) {\n        if (ToolUtil.isEmpty(menu.getPcode()) || menu.getPcode().equals(\"0\")) {\n            menu.setPcode(\"0\");\n            menu.setPcodes(\"[0],\");\n            menu.setLevels(1);\n        } else {\n\n            Menu pMenu = menuRepository.findByCode(menu.getPcode());\n            Integer pLevels = pMenu.getLevels();\n            menu.setPcode(pMenu.getCode());\n\n            //如果编号和父编号一致会导致无限递归\n            if (menu.getCode().equals(menu.getPcode())) {\n                throw new ApplicationException(BizExceptionEnum.MENU_PCODE_COINCIDENCE);\n            }\n\n            menu.setLevels(pLevels + 1);\n            menu.setPcodes(pMenu.getPcodes() + \"[\" + pMenu.getCode() + \"],\");\n        }\n    }\n\n    public List<Node> generateMenuTreeForRole(List<ZTreeNode> list){\n\n        List<Node> nodes = new ArrayList<>(20);\n        for(ZTreeNode menu:list){\n            Node permissionNode = new Node();\n            permissionNode.setId(menu.getId());\n            permissionNode.setName(menu.getName());\n            permissionNode.setPid(menu.getpId());\n            permissionNode.setChecked(menu.getChecked());\n            nodes.add(permissionNode);\n        }\n        for(Node permissionNode:nodes){\n            for(Node child:nodes){\n                if(child.getPid().intValue() == permissionNode.getId().intValue()){\n                    permissionNode.getChildren().add(child);\n                }\n            }\n        }\n        List<Node> result = new ArrayList<>(20);\n        for(Node node:nodes){\n            if(node.getPid().intValue() == 0){\n                result.add(node);\n            }\n        }\n        return result;\n\n\n    }\n\n    public Menu get(Long id) {\n        Optional<Menu> optiona = menuRepository.findById(id);\n        if (optiona.isPresent()) {\n            return optiona.get();\n        }\n        return null;\n    }\n\n    public Menu findByCode(String code) {\n        return menuRepository.findByCode(code);\n    }\n\n\n    public List<Menu> findByNameLike(String name) {\n        return  queryAll(SearchFilter.build(\"name\", SearchFilter.Operator.LIKE,name));\n    }\n\n    public List<Menu> findByLevels(Integer level) {\n        return queryAll(SearchFilter.build(\"levels\",level));\n    }\n\n    public List<Long> getMenuIdsByRoleId(Integer roleId) {\n        return menuRepository.getMenuIdsByRoleId(roleId);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/NoticeService.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.entity.system.Notice;\nimport cn.enilu.material.dao.system.SysNoticeRepository;\nimport cn.enilu.material.service.BaseService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.List;\n\n/**\n * @author ：enilu\n * @date ：Created in 2019/7/21 21:29\n */\n@Service\npublic class NoticeService extends BaseService<Notice,Long, SysNoticeRepository> {\n    @Autowired\n    private SysNoticeRepository sysNoticeRepository;\n    public List<Notice> findByTitleLike(String title) {\n        return sysNoticeRepository.findByTitleLike(title);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/OperationLogService.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.entity.system.OperationLog;\nimport cn.enilu.material.dao.system.OperationLogRepository;\nimport cn.enilu.material.service.BaseService;\nimport org.springframework.stereotype.Service;\n\n/**\n * Created  on 2018/3/26 0026.\n *\n * @author enilu\n */\n@Service\npublic class OperationLogService extends BaseService<OperationLog,Long,OperationLogRepository> {\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/RoleService.java",
    "content": "package cn.enilu.material.service.system;\n\n\nimport cn.enilu.material.bean.entity.system.Relation;\nimport cn.enilu.material.bean.entity.system.Role;\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.exception.ExceptionEnum;\nimport cn.enilu.material.bean.vo.node.Node;\nimport cn.enilu.material.bean.vo.node.ZTreeNode;\nimport cn.enilu.material.dao.system.RelationRepository;\nimport cn.enilu.material.dao.system.RoleRepository;\nimport cn.enilu.material.dao.system.UserRepository;\nimport cn.enilu.material.service.BaseService;\nimport cn.enilu.material.utils.Convert;\nimport com.fasterxml.jackson.annotation.JacksonAnnotationsInside;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\n/**\n * Created  on 2018/3/25 0025.\n *\n * @author enilu\n */\n@Service\npublic class RoleService extends BaseService<Role,Long,RoleRepository> {\n    @Autowired\n    private RoleRepository roleRepository;\n    @Autowired\n    private RelationRepository relationRepository;\n    @Autowired\n    private UserRepository userRepository;\n\n    public List<ZTreeNode> roleTreeList() {\n        List list = roleRepository.roleTreeList();\n        List<ZTreeNode> treeNodes = new ArrayList<>();\n        for (int i = 0; i < list.size(); i++) {\n            Object[] arr = (Object[]) list.get(i);\n            ZTreeNode node = new ZTreeNode();\n            node.setId(Long.valueOf(arr[0].toString()));\n            node.setpId(Long.valueOf(arr[1].toString()));\n            node.setName(arr[2].toString());\n            node.setOpen(Boolean.valueOf(arr[3].toString()));\n            treeNodes.add(node);\n        }\n        return treeNodes;\n    }\n\n\n    public List<ZTreeNode> roleTreeListByRoleId(Long[] ids) {\n        List list = roleRepository.roleTreeListByRoleId(ids);\n        List<ZTreeNode> treeNodes = new ArrayList<>();\n        for (int i = 0; i < list.size(); i++) {\n            Object[] arr = (Object[]) list.get(i);\n            ZTreeNode node = new ZTreeNode();\n            node.setId(Long.valueOf(arr[0].toString()));\n            node.setpId(Long.valueOf(arr[1].toString()));\n            node.setName(arr[2].toString());\n            node.setOpen(Boolean.valueOf(arr[3].toString()));\n            node.setChecked(Boolean.valueOf(arr[4].toString()));\n            treeNodes.add(node);\n        }\n        return treeNodes;\n    }\n\n\n    public void setAuthority(Long roleId, String ids) {\n        // 删除该角色所有的权限\n        relationRepository.deleteByRoleId(roleId);\n\n        // 添加新的权限\n        for (Long id : Convert.toLongArray(true, Convert.toStrArray(\",\", ids))) {\n            Relation relation = new Relation();\n            relation.setRoleid(roleId);\n            relation.setMenuid(id);\n            relationRepository.save(relation);\n        }\n    }\n\n    public void delRoleById(Long roleId) { List<User> list = userRepository.findByRoleid(String.valueOf(roleId));\n        if(!list.isEmpty()){\n            throw  new ApplicationException(BizExceptionEnum.NOT_ALLOW);\n        }\n\n        //删除角色\n        roleRepository.deleteById(roleId);\n\n        // 删除该角色所有的权限\n        relationRepository.deleteByRoleId(roleId);\n    }\n\n\n    public List<Node> generateRoleTree(List<ZTreeNode> list) {\n        List<Node> nodes = new ArrayList<>();\n        for (ZTreeNode role : list) {\n            Node roleNode = new Node();\n            roleNode.setId(role.getId());\n            roleNode.setName(role.getName());\n            roleNode.setPid(role.getpId());\n            roleNode.setChecked(role.getChecked());\n            nodes.add(roleNode);\n        }\n        return nodes;\n    }\n\n    public Role get(Long id) {\n        Optional<Role> optional = roleRepository.findById(id);\n        if (optional.isPresent()) {\n            return optional.get();\n        }\n        return null;\n    }\n\n    public List findByName(String roleName) {\n        return roleRepository.findByName(roleName);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/UserService.java",
    "content": "package cn.enilu.material.service.system;\n\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.dao.system.UserRepository;\nimport cn.enilu.material.service.BaseService;\nimport cn.enilu.material.utils.DateUtil;\nimport com.google.common.base.Strings;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.jpa.domain.Specification;\nimport org.springframework.stereotype.Service;\n\nimport javax.persistence.criteria.CriteriaBuilder;\nimport javax.persistence.criteria.CriteriaQuery;\nimport javax.persistence.criteria.Predicate;\nimport javax.persistence.criteria.Root;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * Created  on 2018/3/23 0023.\n *\n * @author enilu\n */\n@Service\npublic class UserService extends BaseService<User,Long,UserRepository> {\n    @Autowired\n    private UserRepository userRepository;\n\n    public List<User> findAll(final Map<String, Object> params) {\n        return userRepository.findAll(new Specification<User>(){\n            @Override\n            public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {\n                List<Predicate> list = new ArrayList<Predicate>();\n                if(params.get(\"deptid\") !=null && !Strings.isNullOrEmpty(params.get(\"deptid\").toString())){\n                    list.add(criteriaBuilder.equal(root.get(\"deptid\").as(String.class), params.get(\"deptid\").toString()));\n                }\n                if(params.get(\"name\") !=null && !Strings.isNullOrEmpty(params.get(\"name\").toString())){\n                    Predicate p1 = criteriaBuilder.like(root.get(\"name\").as(String.class), params.get(\"name\").toString());\n                    Predicate p2 = criteriaBuilder.like(root.get(\"account\").as(String.class),params.get(\"name\").toString());\n                    list.add(criteriaBuilder.or(p1,p2));\n                }\n\n                list.add(criteriaBuilder.notEqual(root.get(\"id\").as(Long.class), Const.SYSTEM_USER_ID));\n                if(params.get(\"beginTime\") != null && !Strings.isNullOrEmpty(params.get(\"beginTime\").toString())){\n                    list.add(criteriaBuilder.greaterThan(root.get(\"createTime\").as(Date.class), DateUtil.parseDate(params.get(\"beginTime\").toString())));\n                }\n                if(params.get(\"endTime\") != null && !Strings.isNullOrEmpty(params.get(\"endTime\").toString())){\n                    list.add(criteriaBuilder.lessThan(root.get(\"createTime\").as(Date.class),DateUtil.parseDate(params.get(\"endTime\").toString())));\n                }\n\n\n                Predicate[] p = new Predicate[list.size()];\n                return criteriaBuilder.and(list.toArray(p));\n            }\n        });\n\n    }\n\n    public User findByAccount(String account) {\n        return userRepository.findByAccount(account);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/system/impl/ConstantFactory.java",
    "content": "package cn.enilu.material.service.system.impl;\n\nimport cn.enilu.material.bean.constant.cache.CacheKey;\nimport cn.enilu.material.bean.constant.state.ManagerStatus;\nimport cn.enilu.material.bean.constant.state.MenuStatus;\nimport cn.enilu.material.bean.entity.system.*;\nimport cn.enilu.material.bean.enumeration.ConfigKeyEnum;\nimport cn.enilu.material.bean.vo.DictVo;\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport cn.enilu.material.dao.cache.ConfigCache;\nimport cn.enilu.material.dao.cache.DictCache;\nimport cn.enilu.material.dao.system.*;\nimport cn.enilu.material.service.system.IConstantFactory;\nimport cn.enilu.material.service.system.LogObjectHolder;\nimport cn.enilu.material.utils.Convert;\nimport cn.enilu.material.utils.StrKit;\nimport cn.enilu.material.utils.StringUtils;\nimport cn.enilu.material.utils.cache.TimeCacheMap;\nimport org.springframework.cache.annotation.CacheConfig;\nimport org.springframework.context.annotation.DependsOn;\nimport org.springframework.stereotype.Component;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Optional;\n\n\n/**\n * 常量的生产工厂\n *\n * @author fengshuonan\n * @date 2017年2月13日 下午10:55:21\n */\n@Component\n@DependsOn(\"springContextHolder\")\n@CacheConfig\npublic class ConstantFactory implements IConstantFactory {\n    public static TimeCacheMap<String, String> cache = new TimeCacheMap<String, String>(3600, 2);\n    private RoleRepository roleRepository = SpringContextHolder.getBean(RoleRepository.class);\n    private DeptRepository deptRepository = SpringContextHolder.getBean(DeptRepository.class);\n    private DictCache dictCache = SpringContextHolder.getBean(DictCache.class);\n    private DictRepository dictRepository = SpringContextHolder.getBean(DictRepository.class);\n    private UserRepository userRepository = SpringContextHolder.getBean(UserRepository.class);\n    private MenuRepository menuRepository = SpringContextHolder.getBean(MenuRepository.class);\n    private SysNoticeRepository sysNoticeRepository = SpringContextHolder.getBean(SysNoticeRepository.class);\n    private ConfigCache configCache = SpringContextHolder.getBean(ConfigCache.class);\n\n    public static IConstantFactory me() {\n        return SpringContextHolder.getBean(\"constantFactory\");\n    }\n\n    public String get(String key) {\n        return cache.get(key);\n    }\n\n    public void set(String key, String val) {\n        cache.put(key, val);\n\n    }\n    @Override\n    public String resourceVersion(){\n        return (String) configCache.get(ConfigKeyEnum.SYSTEM_RESOURCE_VERSION.getValue());\n    }\n\n    /**\n     * 根据用户id获取用户名称\n     *\n     * @author enilu.cn\n     * @Date 2017/5/9 23:41\n     */\n    @Override\n    public String getUserNameById(Long userId) {\n        String val = get(CacheKey.SYS_USER_NAME + userId);\n        if (StringUtils.isNotEmpty(val)) {\n            return val;\n        }\n\n        User user = getUser(userId);\n        if (user != null) {\n            val = user.getName();\n            set(CacheKey.SYS_USER_NAME + userId, val);\n            return val;\n        }\n\n\n        return \"--\";\n    }\n\n    private User getUser(Long id) {\n        Optional<User> optionalUser = userRepository.findById(id);\n        if (optionalUser.isPresent()) {\n            User user = optionalUser.get();\n            return user;\n        }\n        return null;\n    }\n\n    /**\n     * 根据用户id获取用户账号\n     *\n     * @author enilu.cn\n     * @date 2017年5月16日21:55:371\n     */\n    @Override\n    public String getUserAccountById(Long userId) {\n        User user = getUser(userId);\n        if (user != null) {\n            return user.getAccount();\n        } else {\n            return \"--\";\n        }\n    }\n\n    /**\n     * 通过角色ids获取角色名称\n     */\n    @Override\n    public String getRoleName(String roleIds) {\n        String val = get(CacheKey.ROLES_NAME + roleIds);\n        if (StringUtils.isNotEmpty(val)) {\n            return val;\n        }\n        Integer[] roles = Convert.toIntArray(roleIds);\n        StringBuilder sb = new StringBuilder();\n        for (Integer role : roles) {\n            Role roleObj = getRole(Long.valueOf(role));\n            if (StringUtils.isNotNullOrEmpty(roleObj) && StringUtils.isNotEmpty(roleObj.getName())) {\n                sb.append(roleObj.getName()).append(\",\");\n            }\n        }\n        val = StrKit.removeSuffix(sb.toString(), \",\");\n        set(CacheKey.ROLES_NAME + roleIds, val);\n        return val;\n    }\n\n    /**\n     * 通过角色id获取角色名称\n     */\n    @Override\n    public String getSingleRoleName(Long roleId) {\n        if (0 == roleId) {\n            return \"--\";\n        }\n        Role roleObj = getRole(roleId);\n        if (StringUtils.isNotNullOrEmpty(roleObj) && StringUtils.isNotEmpty(roleObj.getName())) {\n            return roleObj.getName();\n        }\n        return \"\";\n    }\n\n    /**\n     * 通过角色id获取角色英文名称\n     */\n    @Override\n    public String getSingleRoleTip(Long roleId) {\n        if (0 == roleId) {\n            return \"--\";\n        }\n        Role roleObj = getRole(roleId);\n        if (StringUtils.isNotNullOrEmpty(roleObj) && StringUtils.isNotEmpty(roleObj.getName())) {\n            return roleObj.getTips();\n        }\n        return \"\";\n    }\n\n    /**\n     * 获取部门名称\n     */\n    @Override\n    public String getDeptName(Long deptId) {\n        if (deptId == null) {\n            return null;\n        }\n        String val = get(CacheKey.DEPT_NAME + deptId);\n        if (StringUtils.isNotEmpty(val)) {\n            return val;\n        }\n        Dept dept = getDept(deptId);\n        if (StringUtils.isNotNullOrEmpty(dept) && StringUtils.isNotEmpty(dept.getFullname())) {\n            val = dept.getFullname();\n            set(CacheKey.DEPT_NAME + deptId, val);\n            return val;\n        }\n        return \"\";\n    }\n\n    /**\n     * 获取菜单的名称们(多个)\n     */\n    @Override\n    public String getMenuNames(String menuIds) {\n        Integer[] menuArray = Convert.toIntArray(menuIds);\n        StringBuilder sb = new StringBuilder();\n        for (int menuId : menuArray) {\n            Menu menuObj = getMenu(Long.valueOf(menuId));\n            if (StringUtils.isNotNullOrEmpty(menuObj) && StringUtils.isNotEmpty(menuObj.getName())) {\n                sb.append(menuObj.getName()).append(\",\");\n            }\n        }\n        return StrKit.removeSuffix(sb.toString(), \",\");\n    }\n\n    /**\n     * 获取菜单名称\n     */\n    @Override\n    public String getMenuName(Long menuId) {\n\n        Menu menu = getMenu(menuId);\n        if (menu == null) {\n            return \"\";\n        } else {\n            return menu.getName();\n        }\n    }\n\n    /**\n     * 获取菜单名称通过编号\n     */\n    @Override\n    public String getMenuNameByCode(String code) {\n\n        Menu menu = menuRepository.findByCode(code);\n        if (menu == null) {\n            return \"\";\n        } else {\n            return menu.getName();\n        }\n    }\n\n    @Override\n    public List<DictVo> findByDictName(String dictName) {\n\n        List<DictVo> list = new ArrayList<DictVo>();\n\n        List<Dict> dicts = dictCache.getDictsByPname(dictName);\n        if (dicts != null) {\n            for (int i = 0; i < dicts.size(); i++) {\n                Dict dict = dicts.get(i);\n                DictVo dictVo = new DictVo(dict.getValue(), dict.getName());\n                list.add(dictVo);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * 获取字典名称\n     */\n    @Override\n    public String getDictName(Long dictId) {\n\n        String val = get(CacheKey.DICT_NAME + dictId);\n        if (StringUtils.isNotEmpty(val)) {\n            return val;\n        }\n        val = dictCache.getDict(dictId);\n        set(CacheKey.DICT_NAME + dictId, val);\n        return val;\n\n    }\n\n    /**\n     * 获取通知标题\n     */\n    @Override\n    public String getNoticeTitle(Long id) {\n\n        Notice notice = getNotice(id);\n        if (notice == null) {\n            return \"\";\n        } else {\n            return notice.getTitle();\n        }\n\n    }\n\n    /**\n     * 根据字典名称和字典中的值获取对应的名称\n     */\n    @Override\n    public String getDictsByName(String name, String val) {\n        String result = get(CacheKey.DICT_NAME + name + val);\n        if (StringUtils.isNotEmpty(result)) {\n            return result;\n        }\n        List<Dict> dicts = dictCache.getDictsByPname(name);\n        for (Dict item : dicts) {\n            if (item.getValue() != null && item.getValue().equals(val)) {\n                result = item.getName();\n                set(CacheKey.DICT_NAME + name + val, result);\n                return result;\n            }\n        }\n        return \"\";\n\n    }\n\n    /**\n     * 获取性别名称\n     */\n    @Override\n    public String getSexName(Integer sex) {\n        return getDictsByName(\"性别\", String.valueOf(sex));\n    }\n\n    @Override\n    public String getCardTypeName(String cardType) {\n        return getDictsByName(\"银行卡类型\", cardType);\n    }\n\n    @Override\n    public String getIdCardTypeName(String cardType) {\n        return getDictsByName(\"证件类型\", cardType);\n    }\n\n    @Override\n    public String getRelationName(String relation) {\n        return getDictsByName(\"联系人关系\", relation);\n    }\n\n    /**\n     * 获取用户登录状态\n     */\n    @Override\n    public String getStatusName(Integer status) {\n        return ManagerStatus.valueOf(status);\n    }\n\n    /**\n     * 获取菜单状态\n     */\n    @Override\n    public String getMenuStatusName(Integer status) {\n        return MenuStatus.valueOf(status);\n    }\n\n    /**\n     * 查询字典\n     */\n    @Override\n    public List<Dict> findInDict(Long id) {\n        return dictRepository.findByPid(id);\n\n    }\n\n    /**\n     * 获取被缓存的对象(用户删除业务)\n     */\n    @Override\n    public String getCacheObject(String para) {\n        return LogObjectHolder.me().get().toString();\n    }\n\n    /**\n     * 获取子部门id\n     */\n    @Override\n    public List<Long> getSubDeptId(Long deptid) {\n\n        List<Dept> depts = this.deptRepository.findByPidsLike(\"%[\" + deptid + \"]%\");\n\n        ArrayList<Long> deptids = new ArrayList<>();\n\n        if (depts != null && depts.size() > 0) {\n            for (Dept dept : depts) {\n                deptids.add(dept.getId());\n            }\n        }\n\n        return deptids;\n    }\n\n    /**\n     * 获取所有父部门id\n     */\n    @Override\n    public List<Integer> getParentDeptIds(Long deptid) {\n        Dept dept = getDept(deptid);\n        String pids = dept.getPids();\n        String[] split = pids.split(\",\");\n        ArrayList<Integer> parentDeptIds = new ArrayList<>();\n        for (String s : split) {\n            parentDeptIds.add(Integer.valueOf(StrKit.removeSuffix(StrKit.removePrefix(s, \"[\"), \"]\")));\n        }\n        return parentDeptIds;\n    }\n\n\n    @Override\n    public List<Dict> getDicts(String pname) {\n        return dictCache.getDictsByPname(pname);\n    }\n\n    @Override\n    public String getCfg(String cfgName) {\n        String val = get(CacheKey.CFG + cfgName);\n        if (StringUtils.isNotEmpty(val)) {\n            return val;\n        }\n        val = (String) configCache.get(cfgName);\n        set(CacheKey.CFG + cfgName, val);\n        return val;\n    }\n    @Override\n    public Role getRole(Long id) {\n        Optional<Role> optional = roleRepository.findById(id);\n        if (optional.isPresent()) {\n            return optional.get();\n        }\n        return null;\n    }\n    @Override\n    public Dept getDept(Long id) {\n        Optional<Dept> optional = deptRepository.findById(id);\n        if (optional.isPresent()) {\n            return optional.get();\n        }\n        return null;\n    }\n    @Override\n    public Menu getMenu(Long id) {\n        Optional<Menu> optiona = menuRepository.findById(id);\n        if (optiona.isPresent()) {\n            return optiona.get();\n        }\n        return null;\n    }\n    @Override\n    public Notice getNotice(Long id) {\n        Optional<Notice> optional = sysNoticeRepository.findById(id);\n        if (optional.isPresent()) {\n            return optional.get();\n        }\n        return null;\n    }\n    @Override\n    public void cleanLocalCache() {\n        cache.cleanup();\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/task/BaseJob.java",
    "content": "package cn.enilu.material.service.task;\n\nimport cn.enilu.material.bean.vo.QuartzJob;\nimport org.quartz.Job;\nimport org.quartz.JobDataMap;\nimport org.quartz.JobExecutionContext;\nimport org.quartz.JobExecutionException;\nimport org.springframework.stereotype.Component;\n\n@Component\npublic class BaseJob implements Job {\n\n\t@Override\n\tpublic void execute(JobExecutionContext context) throws JobExecutionException {\n\t\tJobDataMap data = context.getJobDetail().getJobDataMap();\n\t\tQuartzJob job = (QuartzJob) data.get(\"job\");\n\t\ttry {\n\t\t\tTaskUtils.executeJob(job);\n\t\t} catch (Exception e) {\n\t\t\tthrow new JobExecutionException(e);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/task/JobExecuter.java",
    "content": "package cn.enilu.material.service.task;\n\nimport cn.enilu.material.bean.entity.system.Task;\nimport cn.enilu.material.bean.entity.system.TaskLog;\nimport cn.enilu.material.bean.vo.QuartzJob;\nimport cn.enilu.material.dao.system.TaskLogRepository;\nimport cn.enilu.material.utils.StringUtils;\nimport org.apache.commons.lang3.exception.ExceptionUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Date;\nimport java.util.Map;\n\n@Component\npublic abstract class JobExecuter {\n\n    protected static final Logger log = LoggerFactory.getLogger(JobExecuter.class);\n\n    @Autowired\n    private TaskService taskService;\n\n    @Autowired\n    private TaskLogRepository taskLogRepository;\n\n    private QuartzJob job;\n\n    public void setJob(QuartzJob job) {\n        this.job = job;\n    }\n\n    public void execute() {\n        Map dataMap = job.getDataMap();\n        String taskId = job.getJobName();\n        Task task = taskService.get(Long.valueOf(taskId));\n        final String taskName = task.getName();\n        log.info(\">>>>>>>>>>>>>>>>>开始执行定时任务[\" + taskName + \"]...<<<<<<<<<<<<<<<<<<<\");\n\n        String exeResult = \"执行成功\";\n        final TaskLog taskLog = new TaskLog();\n        taskLog.setName(taskName);\n        final Date exeAt = new Date();\n        taskLog.setExecAt(exeAt);\n        taskLog.setIdTask(task.getId());\n        //默认是成功 出异常后改成失败\n        taskLog.setExecSuccess(TaskLog.EXE_SUCCESS_RESULT);\n        try {\n            execute(dataMap);\n        } catch (Exception e) {\n            log.error(\"exeucte \" + getClass().getName() + \" error : \", e);\n            exeResult = \"执行失败\\n\";\n            exeResult += ExceptionUtils.getStackTrace(e);\n            taskLog.setExecSuccess(TaskLog.EXE_FAILURE_RESULT);\n            taskLog.setJobException(e.getClass().getName());\n        }\n        task.setExecResult(exeResult);\n        task.setExecAt(exeAt);\n        taskLogRepository.save(taskLog);\n        taskService.simpleUpdate(task);\n        log.info(\">>>>>>>>>>>>>>>>>执行定时任务[\" + taskName + \"]结束<<<<<<<<<<<<<<<<<<<\");\n    }\n\n    /**\n     *\n     * @param dataMap 数据库配置的参数\n     */\n    public abstract void execute(Map<String, Object> dataMap) throws Exception;\n\n    public String getEmail() {\n        return getEmail(\"snowalert@xuezhongdai.cn\");\n    }\n\n    public String getEmail(String defaultEmail) {\n        Map<String, Object> dataMap = job.getDataMap();\n        String toEmail = null;\n        if (dataMap != null && dataMap.containsKey(\"email\")) {\n            toEmail = StringUtils.sNull(dataMap.get(\"email\"));\n        }\n        if (StringUtils.isEmpty(toEmail)) {\n            toEmail = defaultEmail;\n        }\n        return toEmail;\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/task/JobService.java",
    "content": "package cn.enilu.material.service.task;\n\nimport cn.enilu.material.bean.entity.system.Task;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.exception.ExceptionEnum;\nimport cn.enilu.material.bean.vo.QuartzJob;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport com.alibaba.fastjson.JSON;\nimport org.apache.commons.lang3.StringUtils;\nimport org.quartz.*;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 任务服务\n */\n@Service\npublic class JobService {\n    private static final Logger logger = LoggerFactory.getLogger(JobService.class);\n    @Autowired\n    private Scheduler scheduler;\n    @Autowired\n    private TaskService taskService;\n\n    /**\n     * 获取单个任务\n     *\n     * @param jobName\n     * @param jobGroup\n     * @return\n     * @throws SchedulerException\n     */\n\n    public QuartzJob getJob(String jobName, String jobGroup) throws SchedulerException {\n        QuartzJob job = null;\n        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);\n        Trigger trigger = scheduler.getTrigger(triggerKey);\n        if (null != trigger) {\n            job = new QuartzJob();\n            job.setJobName(jobName);\n            job.setJobGroup(jobGroup);\n            job.setDescription(\"触发器:\" + trigger.getKey());\n            job.setNextTime(trigger.getNextFireTime());\n            job.setPreviousTime(trigger.getPreviousFireTime());\n            Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());\n            job.setJobStatus(triggerState.name());\n            if (trigger instanceof CronTrigger) {\n                CronTrigger cronTrigger = (CronTrigger) trigger;\n                String cronExpression = cronTrigger.getCronExpression();\n                job.setCronExpression(cronExpression);\n            }\n        }\n        return job;\n    }\n\n    public List<QuartzJob> getTaskList() {\n        List<Task> tasks = taskService.queryAll(SearchFilter.build(\"disabled\", SearchFilter.Operator.EQ,false));\n        List<QuartzJob> jobs = new ArrayList<>();\n        for (Task task : tasks) {\n            jobs.add(getJob(task));\n        }\n        return jobs;\n    }\n\n    public QuartzJob getJob(Task task) {\n        QuartzJob job = null;\n        if (task != null) {\n            job = new QuartzJob();\n            job.setJobName(String.valueOf(task.getId()));\n            job.setJobGroup(task.getJobGroup());\n            job.setCronExpression(task.getCron());\n            job.setConcurrent(task.isConcurrent());\n            job.setJobClass(task.getJobClass());\n            job.setDescription(task.getName());\n            job.setDisabled(task.isDisabled());\n            if (StringUtils.isNotBlank(task.getData())) {\n                try {\n                    Map<String, Object> dataMap = JSON.parseObject( task.getData(),Map.class);\n                    job.setDataMap(dataMap);\n                } catch (Exception e) {\n                    throw  new ApplicationException(ExceptionEnum.TASK_CONFIG_ERROR);\n                }\n            }\n        }\n        return job;\n    }\n\n    /**\n     * 添加任务\n     *\n     * @param job\n     * @throws SchedulerException\n     */\n\n    public boolean addJob(QuartzJob job) throws SchedulerException {\n        logger.info(\"新增任务Id：{}, name:{}\", job.getJobName(), job.getDescription());\n        if (job == null || job.isDisabled()) {\n            return false;\n        }\n        if (!TaskUtils.isValidExpression(job.getCronExpression())) {\n            logger.error(\"时间表达式错误（\" + job.getJobName() + \",\" + job.getJobGroup() + \"）,\" + job.getCronExpression());\n            return false;\n        } else {\n            // 任务名称和任务组设置规则：    // 名称：task_1 ..    // 组 ：group_1 ..\n            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());\n            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);\n            // 不存在，创建一个\n            if (null == trigger) {\n                //是否允许并发执行\n                Class<? extends Job> clazz = job.isConcurrent() ? BaseJob.class : NoConurrentBaseJob.class;\n                JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();\n                jobDetail.getJobDataMap().put(\"job\", job);\n                // 表达式调度构建器\n                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());\n                // 按新的表达式构建一个新的trigger\n                trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();\n                scheduler.scheduleJob(jobDetail, trigger);\n            } else {     // trigger已存在，则更新相应的定时设置\n                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());\n                // 按新的cronExpression表达式重新构建trigger\n                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();\n                // 按新的trigger重新设置job执行\n                scheduler.rescheduleJob(triggerKey, trigger);\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 删除任务\n     */\n\n    public boolean deleteJob(QuartzJob job) {\n        logger.info(\"删除任务：{}\", job.getJobName());\n        JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());\n        try {\n            scheduler.deleteJob(jobKey);\n            return true;\n        } catch (SchedulerException e) {\n            logger.error(e.getMessage(), e);\n        }\n        return false;\n    }\n\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/task/NoConurrentBaseJob.java",
    "content": "package cn.enilu.material.service.task;\n\nimport org.quartz.DisallowConcurrentExecution;\nimport org.springframework.stereotype.Component;\n\n@Component\n@DisallowConcurrentExecution\npublic class NoConurrentBaseJob extends BaseJob {\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/task/QuartzConfigration.java",
    "content": "package cn.enilu.material.service.task;\n\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.scheduling.quartz.SchedulerFactoryBean;\n\n@Configuration\npublic class QuartzConfigration {\n\n    @Bean(name = \"scheduler\")\n    public SchedulerFactoryBean schedulerFactory() {\n        SchedulerFactoryBean bean = new SchedulerFactoryBean();\n        return bean;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/task/TaskService.java",
    "content": "package cn.enilu.material.service.task;\n\n\nimport cn.enilu.material.bean.entity.system.Task;\nimport cn.enilu.material.bean.entity.system.TaskLog;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.exception.ExceptionEnum;\nimport cn.enilu.material.bean.vo.QuartzJob;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.dao.system.TaskLogRepository;\nimport cn.enilu.material.dao.system.TaskRepository;\nimport cn.enilu.material.service.BaseService;\nimport org.quartz.SchedulerException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.data.domain.PageRequest;\nimport org.springframework.data.domain.Pageable;\nimport org.springframework.data.domain.Sort;\nimport org.springframework.data.jpa.domain.Specification;\nimport org.springframework.stereotype.Service;\n\nimport javax.persistence.criteria.CriteriaBuilder;\nimport javax.persistence.criteria.CriteriaQuery;\nimport javax.persistence.criteria.Predicate;\nimport javax.persistence.criteria.Root;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 任务计划服务\n */\n@Service\npublic class TaskService extends BaseService<Task,Long,TaskRepository> {\n\tprivate static final Logger logger = LoggerFactory.getLogger(TaskService.class);\n\t@Autowired\n\tprivate TaskRepository taskRepository;\n\t@Autowired\n\tprivate TaskLogRepository taskLogRepository;\n\t@Autowired\n\tprivate JobService jobService;\n\n\n\tpublic Task save(Task task) {\n\t\tlogger.info(\"新增定时任务%s\", task.getName());\n\t\ttask = taskRepository.save(task);\n\t\ttry {\n\t\t\tjobService.addJob(jobService.getJob(task));\n\t\t} catch (SchedulerException e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t\treturn task;\n\t}\n\n\t@Override\n\tpublic Task update(Task record) {\n\t\tlogger.info(\"更新定时任务{}\", record.getName());\n\t\ttaskRepository.save(record);\n\t\ttry {\n\t\t\tQuartzJob job = jobService.getJob(record.getId().toString(), record.getJobGroup());\n\t\t\tif (job != null) {\n\t\t\t\tjobService.deleteJob(job);\n\t\t\t}\n\t\t\tjobService.addJob(jobService.getJob(record));\n\t\t} catch (SchedulerException e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t\treturn record;\n\t}\n\n\n\tpublic boolean simpleUpdate(Task task) {\n\t\ttaskRepository.save(task);\n\t\treturn true;\n\t}\n\n\n\tpublic Task disable(Long id) {\n\t\tTask task = get(id);\n\t\ttask.setDisabled(true);\n\t\ttaskRepository.save(task);\n\t\tlogger.info(\"禁用定时任务{}\", id.toString());\n\t\ttry {\n\t\t\tQuartzJob job = jobService.getJob(task.getId().toString(), task.getJobGroup());\n\t\t\tif (job != null) {\n\t\t\t\tjobService.deleteJob(job);\n\t\t\t}\n\t\t} catch (SchedulerException e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t\treturn task;\n\t}\n\n\n\tpublic Task enable(Long id) {\n\t\tTask task = get(id);\n\t\ttask.setDisabled(false);\n\t\ttaskRepository.save(task);\n\t\tlogger.info(\"启用定时任务{}\", id.toString());\n\t\ttry {\n\t\t\tQuartzJob job = jobService.getJob(task.getId().toString(), task.getJobGroup());\n\t\t\tif (job != null) {\n\t\t\t\tjobService.deleteJob(job);\n\t\t\t}\n\t\t\tif (!task.isDisabled()) {\n\t\t\t\tjobService.addJob(jobService.getJob(task));\n\t\t\t}\n\t\t} catch (SchedulerException e) {\n\t\t\tthrow  new ApplicationException(ExceptionEnum.TASK_CONFIG_ERROR);\n\t\t}\n\t\treturn task;\n\t}\n\n\t@Override\n\tpublic void delete(Long id) {\n\t\tTask task = get(id);\n\t\ttask.setDisabled(true);\n\t\ttaskRepository.delete(task);\n\t\tlogger.info(\"删除定时任务{}\", id.toString());\n\n\t\ttry {\n\t\t\tQuartzJob job = jobService.getJob(task);\n\t\t\tif (job != null) {\n\t\t\t\tjobService.deleteJob(job);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t}\n\n\n\tpublic Page<TaskLog> getTaskLogs(Page<TaskLog> page, Long taskId) {\n\t\tPageable pageable = null;\n\t\tif(page.isOpenSort()) {\n\t\t\tpageable = new PageRequest(page.getCurrent()-1, page.getSize(), page.isAsc() ? Sort.Direction.ASC : Sort.Direction.DESC, page.getOrderByField());\n\t\t}else{\n\t\t\tpageable = new PageRequest(page.getCurrent()-1,page.getSize(),Sort.Direction.DESC,\"id\");\n\t\t}\n\n\t\torg.springframework.data.domain.Page<TaskLog> taskLogPage = taskLogRepository.findAll(new  Specification<TaskLog>(){\n\n\t\t\t@Override\n\t\t\tpublic Predicate toPredicate(Root<TaskLog> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder\n\t\t\t\t\tcriteriaBuilder) {\n\t\t\t\tList<Predicate> list = new ArrayList<Predicate>();\n\t\t\t\tlist.add(criteriaBuilder.equal(root.get(\"idTask\").as(Long.class),taskId));\n\t\t\t\tPredicate[] p = new Predicate[list.size()];\n\t\t\t\treturn criteriaBuilder.and(list.toArray(p));\n\t\t\t}\n\t\t},pageable);\n\t\tpage.setTotal(Integer.valueOf(taskLogPage.getTotalElements()+\"\"));\n\t\tpage.setRecords(taskLogPage.getContent());\n\t\treturn page;\n\t}\n\n\tpublic Object findByNameLike(String name) {\n\t\treturn taskRepository.findByNameLike(name);\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/task/TaskUtils.java",
    "content": "package cn.enilu.material.service.task;\n\nimport cn.enilu.material.bean.vo.QuartzJob;\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport org.apache.commons.lang3.StringUtils;\nimport org.quartz.impl.triggers.CronTriggerImpl;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.text.ParseException;\nimport java.util.Date;\n\n/**\n * Created by czhou on 1/10/17.\n */\npublic class TaskUtils {\n\n\tprivate static final Logger logger = LoggerFactory.getLogger(TaskUtils.class);\n\n\t/**\n\t * 通过反射调用job中定义的方法\n\t *\n\t * @param job\n\t * @throws Exception\n\t */\n\tpublic static void executeJob(QuartzJob job) throws Exception {\n\t\tJobExecuter jobExecuter = null;\n\t\tClass<?> clazz = null;\n\t\tif (StringUtils.isNotBlank(job.getJobClass())) {\n\t\t\tclazz = Class.forName(job.getJobClass());\n\t\t\tjobExecuter = (JobExecuter) SpringContextHolder.getBean(clazz);\n\t\t\tjobExecuter.setJob(job);\n\t\t}\n\t\tif (jobExecuter == null) {\n\t\t\tthrow new RuntimeException(\"任务名称 = [\" + job.getDescription() + \"]未启动成功，请检查执行类是否配置正确！！！\");\n\t\t}\n\t\tjobExecuter.execute();\n\t}\n\n\t/**\n\t * 判断cron时间表达式正确性\n\t *\n\t * @param cronExpression\n\t * @return\n\t */\n\tpublic static boolean isValidExpression(final String cronExpression) {\n\t\tCronTriggerImpl trigger = new CronTriggerImpl();\n\t\ttry {\n\t\t\ttrigger.setCronExpression(cronExpression);\n\t\t\tDate date = trigger.computeFirstFireTime(null);\n\t\t\treturn date != null && date.after(new Date());\n\t\t} catch (ParseException e) {\n\t\t\tlogger.error(e.getMessage(), e);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(isValidExpression(\"0 0/1 * * * ?\"));\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/service/task/job/HelloJob.java",
    "content": "package cn.enilu.material.service.task.job;\n\nimport cn.enilu.material.bean.entity.system.Cfg;\nimport cn.enilu.material.service.system.CfgService;\nimport cn.enilu.material.service.task.JobExecuter;\nimport cn.enilu.material.utils.DateUtil;\nimport com.alibaba.fastjson.JSON;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Component;\n\nimport java.util.Map;\n\n/**\n * HelloJob\n *\n * @author zt\n * @version 2018/12/30 0030\n */\n@Component\npublic class HelloJob extends JobExecuter {\n    private Logger logger = LoggerFactory.getLogger(getClass());\n    @Autowired\n    private CfgService cfgService;\n    @Override\n    public void execute(Map<String, Object> dataMap) throws Exception {\n        Cfg cfg = cfgService.get(1L);\n        cfg.setCfgDesc(\"update by \"+ DateUtil.getTime());\n        cfgService.update(cfg);\n        logger.info(\"hello :\"+JSON.toJSONString(dataMap));\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/shiro/ShiroDbRealm.java",
    "content": "package cn.enilu.material.shiro;\n\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.shiro.factory.IShiro;\nimport cn.enilu.material.shiro.factory.ShiroFactroy;\nimport cn.enilu.material.utils.ToolUtil;\nimport org.apache.shiro.authc.*;\nimport org.apache.shiro.authc.credential.CredentialsMatcher;\nimport org.apache.shiro.authc.credential.HashedCredentialsMatcher;\nimport org.apache.shiro.authz.AuthorizationInfo;\nimport org.apache.shiro.authz.SimpleAuthorizationInfo;\nimport org.apache.shiro.realm.AuthorizingRealm;\nimport org.apache.shiro.subject.PrincipalCollection;\n\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\npublic class ShiroDbRealm extends AuthorizingRealm {\n\n    /**\n     * 登录认证\n     */\n    @Override\n    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)\n            throws AuthenticationException {\n        IShiro shiroFactory = ShiroFactroy.me();\n        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;\n        User user = shiroFactory.user(token.getUsername());\n        ShiroUser shiroUser = shiroFactory.shiroUser(user);\n        SimpleAuthenticationInfo info = shiroFactory.info(shiroUser, user, super.getName());\n        return info;\n    }\n\n    /**\n     * 权限认证\n     */\n    @Override\n    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {\n        IShiro shiroFactory = ShiroFactroy.me();\n        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();\n        List<Long> roleList = shiroUser.getRoleList();\n\n        Set<String> permissionSet = new HashSet<>();\n        Set<String> roleNameSet = new HashSet<>();\n\n        for (Long roleId : roleList) {\n            List<String> permissions = shiroFactory.findPermissionsByRoleId(roleId.intValue());\n            if (permissions != null) {\n                for (String permission : permissions) {\n                    if (ToolUtil.isNotEmpty(permission)) {\n                        permissionSet.add(permission);\n                    }\n                }\n            }\n            String roleName = shiroFactory.findRoleNameByRoleId(roleId);\n            roleNameSet.add(roleName);\n        }\n\n        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();\n        info.addStringPermissions(permissionSet);\n        info.addRoles(roleNameSet);\n        return info;\n    }\n\n    /**\n     * 设置认证加密方式\n     */\n    @Override\n    public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {\n        HashedCredentialsMatcher md5CredentialsMatcher = new HashedCredentialsMatcher();\n        md5CredentialsMatcher.setHashAlgorithmName(ShiroKit.hashAlgorithmName);\n        md5CredentialsMatcher.setHashIterations(ShiroKit.hashIterations);\n        super.setCredentialsMatcher(md5CredentialsMatcher);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/shiro/ShiroKit.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.shiro;\n\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.ToolUtil;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.crypto.hash.Md5Hash;\nimport org.apache.shiro.crypto.hash.SimpleHash;\nimport org.apache.shiro.session.Session;\nimport org.apache.shiro.subject.Subject;\nimport org.apache.shiro.util.ByteSource;\n\nimport java.util.List;\n\n/**\n * shiro工具类\n *\n * @author dafei, Chill Zhuang\n */\npublic class ShiroKit {\n\n    private static final String NAMES_DELIMETER = \",\";\n\n    /**\n     * 加盐参数\n     */\n    public final static String hashAlgorithmName = \"MD5\";\n\n    /**\n     * 循环次数\n     */\n    public final static int hashIterations = 1024;\n\n    /**\n     * shiro密码加密工具类\n     *\n     * @param credentials 密码\n     * @param saltSource 密码盐\n     * @return\n     */\n    public static String md5(String credentials, String saltSource) {\n        ByteSource salt = new Md5Hash(saltSource);\n        return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations).toString();\n    }\n\n    /**\n     * 获取随机盐值\n     * @param length\n     * @return\n     */\n    public static String getRandomSalt(int length) {\n        return ToolUtil.getRandomString(length);\n    }\n\n    /**\n     * 获取当前 Subject\n     *\n     * @return Subject\n     */\n    public static Subject getSubject() {\n        return SecurityUtils.getSubject();\n    }\n\n    /**\n     * 获取封装的 ShiroUser\n     *\n     * @return ShiroUser\n     */\n    public static ShiroUser getUser() {\n        if (isGuest()) {\n            return null;\n        } else {\n            return (ShiroUser) getSubject().getPrincipals().getPrimaryPrincipal();\n        }\n    }\n\n    /**\n     * 从shiro获取session\n     *\n     */\n    public static Session getSession() {\n        return getSubject().getSession();\n    }\n\n    /**\n     * 获取shiro指定的sessionKey\n     *\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T getSessionAttr(String key) {\n        Session session = getSession();\n        return session != null ? (T) session.getAttribute(key) : null;\n    }\n\n    /**\n     * 设置shiro指定的sessionKey\n     *\n     */\n    public static void setSessionAttr(String key, Object value) {\n        Session session = getSession();\n        session.setAttribute(key, value);\n    }\n\n    /**\n     * 移除shiro指定的sessionKey\n     */\n    public static void removeSessionAttr(String key) {\n        Session session = getSession();\n        if (session != null) {\n            session.removeAttribute(key);\n        }\n    }\n\n    /**\n     * 验证当前用户是否属于该角色？,使用时与lacksRole 搭配使用\n     *\n     * @param roleName\n     *            角色名\n     * @return 属于该角色：true，否则false\n     */\n    public static boolean hasRole(String roleName) {\n        return getSubject() != null && roleName != null\n                && roleName.length() > 0 && getSubject().hasRole(roleName);\n    }\n\n    /**\n     * 与hasRole标签逻辑相反，当用户不属于该角色时验证通过。\n     *\n     * @param roleName\n     *            角色名\n     * @return 不属于该角色：true，否则false\n     */\n    public static boolean lacksRole(String roleName) {\n        return !hasRole(roleName);\n    }\n\n    /**\n     * 验证当前用户是否属于以下任意一个角色。\n     *\n     * @param roleNames\n     *            角色列表\n     * @return 属于:true,否则false\n     */\n    public static boolean hasAnyRoles(String roleNames) {\n        boolean hasAnyRole = false;\n        Subject subject = getSubject();\n        if (subject != null && roleNames != null && roleNames.length() > 0) {\n            for (String role : roleNames.split(NAMES_DELIMETER)) {\n                if (subject.hasRole(role.trim())) {\n                    hasAnyRole = true;\n                    break;\n                }\n            }\n        }\n        return hasAnyRole;\n    }\n\n    /**\n     * 验证当前用户是否属于以下所有角色。\n     *\n     * @param roleNames\n     *            角色列表\n     * @return 属于:true,否则false\n     */\n    public static boolean hasAllRoles(String roleNames) {\n        boolean hasAllRole = true;\n        Subject subject = getSubject();\n        if (subject != null && roleNames != null && roleNames.length() > 0) {\n            for (String role : roleNames.split(NAMES_DELIMETER)) {\n                if (!subject.hasRole(role.trim())) {\n                    hasAllRole = false;\n                    break;\n                }\n            }\n        }\n        return hasAllRole;\n    }\n\n    /**\n     * 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用\n     *\n     * @param permission\n     *            权限名\n     * @return 拥有权限：true，否则false\n     */\n    public static boolean hasPermission(String permission) {\n        return getSubject() != null && permission != null\n                && permission.length() > 0\n                && getSubject().isPermitted(permission);\n    }\n\n    /**\n     * 与hasPermission标签逻辑相反，当前用户没有制定权限时，验证通过。\n     *\n     * @param permission\n     *            权限名\n     * @return 拥有权限：true，否则false\n     */\n    public static boolean lacksPermission(String permission) {\n        return !hasPermission(permission);\n    }\n\n    /**\n     * 已认证通过的用户。不包含已记住的用户，这是与user标签的区别所在。与notAuthenticated搭配使用\n     *\n     * @return 通过身份验证：true，否则false\n     */\n    public static boolean isAuthenticated() {\n        return getSubject() != null && getSubject().isAuthenticated();\n    }\n\n    /**\n     * 未认证通过用户，与authenticated标签相对应。与guest标签的区别是，该标签包含已记住用户。。\n     *\n     * @return 没有通过身份验证：true，否则false\n     */\n    public static boolean notAuthenticated() {\n        return !isAuthenticated();\n    }\n\n    /**\n     * 认证通过或已记住的用户。与guset搭配使用。\n     *\n     * @return 用户：true，否则 false\n     */\n    public static boolean isUser() {\n        return getSubject() != null && getSubject().getPrincipal() != null;\n    }\n\n    /**\n     * 验证当前用户是否为“访客”，即未认证（包含未记住）的用户。用user搭配使用\n     *\n     * @return 访客：true，否则false\n     */\n    public static boolean isGuest() {\n        return !isUser();\n    }\n\n    /**\n     * 输出当前用户信息，通常为登录帐号信息。\n     *\n     * @return 当前用户信息\n     */\n    public static String principal() {\n        if (getSubject() != null) {\n            Object principal = getSubject().getPrincipal();\n            return principal.toString();\n        }\n        return \"\";\n    }\n\n    /**\n     * 获取当前用户的部门数据范围的集合\n     */\n    public static List<Long> getDeptDataScope() {\n        Long deptId = getUser().getDeptId();\n        List<Long> subDeptIds = ConstantFactory.me().getSubDeptId(deptId);\n        subDeptIds.add(deptId);\n        return subDeptIds;\n    }\n\n    /**\n     * 判断当前用户是否是超级管理员\n     */\n    public static boolean isAdmin() {\n        List<Long> roleList = ShiroKit.getUser().getRoleList();\n        for (Long integer : roleList) {\n            String singleRoleTip = ConstantFactory.me().getSingleRoleTip(integer);\n            if (singleRoleTip.equals(Const.ADMIN_NAME)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/shiro/check/ICheck.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.shiro.check;\n\n\n/**\n *  检查用接口\n */\npublic interface ICheck {\n\n    /**\n     * 检查指定角色\n     * @param permissions\n     * @return boolean\n     */\n    boolean check(Object[] permissions);\n\n    /**\n     * 检查全体角色\n     * @return boolean\n     */\n    boolean checkAll();\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/shiro/check/PermissionCheckFactory.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.shiro.check;\n\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport cn.enilu.material.shiro.ShiroKit;\nimport cn.enilu.material.utils.CollectionKit;\nimport cn.enilu.material.utils.HttpKit;\nimport cn.enilu.material.web.listener.ConfigListener;\nimport org.springframework.context.annotation.DependsOn;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport javax.servlet.http.HttpServletRequest;\n\n/**\n * 权限自定义检查\n */\n@Service\n@DependsOn(\"springContextHolder\")\n@Transactional(readOnly = true)\npublic class PermissionCheckFactory implements ICheck {\n\n    public static ICheck me() {\n        return SpringContextHolder.getBean(ICheck.class);\n    }\n\n    @Override\n    public boolean check(Object[] permissions) {\n        ShiroUser user = ShiroKit.getUser();\n        if (null == user) {\n            return false;\n        }\n        String join = CollectionKit.join(permissions, \",\");\n        if (ShiroKit.hasAnyRoles(join)) {\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean checkAll() {\n        HttpServletRequest request = HttpKit.getRequest();\n        ShiroUser user = ShiroKit.getUser();\n        if (null == user) {\n            return false;\n        }\n        String requestURI = request.getRequestURI().replaceFirst(ConfigListener.getConf().get(\"contextPath\"), \"\");\n        String[] str = requestURI.split(\"/\");\n        if (str.length > 3) {\n            requestURI = \"/\" + str[1] + \"/\" + str[2];\n        }\n        if (ShiroKit.hasPermission(requestURI)) {\n            return true;\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/shiro/check/PermissionCheckManager.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.shiro.check;\n\n\nimport cn.enilu.material.bean.vo.SpringContextHolder;\n\n/**\n * 权限检查工厂\n */\npublic class PermissionCheckManager {\n    private final static PermissionCheckManager me = new PermissionCheckManager();\n\n    private ICheck defaultCheckFactory = SpringContextHolder.getBean(ICheck.class);\n\n    public static PermissionCheckManager me() {\n        return me;\n    }\n\n    private PermissionCheckManager() {\n    }\n\n    public PermissionCheckManager(ICheck checkFactory) {\n        this.defaultCheckFactory = checkFactory;\n    }\n\n    public void setDefaultCheckFactory(ICheck defaultCheckFactory) {\n        this.defaultCheckFactory = defaultCheckFactory;\n    }\n\n    public static boolean check(Object[] permissions) {\n        return me.defaultCheckFactory.check(permissions);\n    }\n\n    public static boolean checkAll() {\n        return me.defaultCheckFactory.checkAll();\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/shiro/factory/IShiro.java",
    "content": "package cn.enilu.material.shiro.factory;\n\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.bean.entity.system.User;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\n\nimport java.util.List;\n\n/**\n * 定义shirorealm所需数据的接口\n *\n * @author fengshuonan\n * @date 2016年12月5日 上午10:23:34\n */\npublic interface IShiro {\n\n    /**\n     * 根据账号获取登录用户\n     *\n     * @param account 账号\n     */\n    User user(String account);\n\n    /**\n     * 根据系统用户获取Shiro的用户\n     *\n     * @param user 系统用户\n     */\n    ShiroUser shiroUser(User user);\n\n    /**\n     * 获取权限列表通过角色id\n     *\n     * @param roleId 角色id\n     */\n    List<String> findPermissionsByRoleId(Integer roleId);\n\n    /**\n     * 根据角色id获取角色名称\n     *\n     * @param roleId 角色id\n     */\n    String findRoleNameByRoleId(Long roleId);\n\n    /**\n     * 获取shiro的认证信息\n     */\n    SimpleAuthenticationInfo info(ShiroUser shiroUser, User user, String realmName);\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/shiro/factory/ShiroFactroy.java",
    "content": "package cn.enilu.material.shiro.factory;\n\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport cn.enilu.material.bean.constant.state.ManagerStatus;\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.bean.vo.node.MenuNode;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.dao.system.MenuRepository;\nimport cn.enilu.material.dao.system.UserRepository;\nimport cn.enilu.material.service.system.MenuService;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.Convert;\nimport cn.enilu.material.utils.Lists;\nimport org.apache.shiro.authc.CredentialsException;\nimport org.apache.shiro.authc.LockedAccountException;\nimport org.apache.shiro.authc.SimpleAuthenticationInfo;\nimport org.apache.shiro.crypto.hash.Md5Hash;\nimport org.apache.shiro.util.ByteSource;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.DependsOn;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\n\n@Service\n@DependsOn(\"springContextHolder\")\n@Transactional(readOnly = true)\npublic class ShiroFactroy implements IShiro {\n\n    @Autowired\n    private UserRepository userRepository;\n\n    @Autowired\n    private MenuRepository menuRepository;\n    @Autowired\n    private MenuService menuService;\n\n    public static IShiro me() {\n        return SpringContextHolder.getBean(IShiro.class);\n    }\n\n    @Override\n    public User user(String account) {\n\n        User user = userRepository.findByAccount(account);\n\n        // 账号不存在\n        if (null == user) {\n            throw new CredentialsException();\n        }\n        // 账号被冻结\n        if (user.getStatus() != ManagerStatus.OK.getCode()) {\n            throw new LockedAccountException();\n        }\n        return user;\n    }\n\n    @Override\n    public ShiroUser shiroUser(User user) {\n        ShiroUser shiroUser = new ShiroUser();\n\n        shiroUser.setId(Long.valueOf(user.getId()));            // 账号id\n        shiroUser.setAccount(user.getAccount());// 账号\n        shiroUser.setDeptId(user.getDeptid());    // 部门id\n        shiroUser.setDeptName(ConstantFactory.me().getDeptName(user.getDeptid()));// 部门名称\n        shiroUser.setName(user.getName());        // 用户名称\n\n\n        Long[] roleArray = Convert.toLongArray(\",\", user.getRoleid());\n        List<Long> roleList = new ArrayList<Long>();\n        List<String> roleNameList = new ArrayList<String>();\n        for (Long roleId : roleArray) {\n            roleList.add(roleId);\n            roleNameList.add(ConstantFactory.me().getSingleRoleName(roleId));\n        }\n        shiroUser.setRoleList(roleList);\n        shiroUser.setRoleNames(roleNameList);\n\n        List<MenuNode> menuNodes =  menuService.getMenusByRoleIds(roleList);\n        List<MenuNode> titles = MenuNode.buildTitle(menuNodes);\n        shiroUser.setTitles(titles);\n        if(user.getAvatar()==null){\n            user.setAvatar(\"avatar.png\");\n        }\n        shiroUser.setProfile(user);\n        return shiroUser;\n    }\n\n    @Override\n    public List<String> findPermissionsByRoleId(Integer roleId) {\n        String sql = \"select url from t_sys_relation rel inner join t_sys_menu m on rel.menuid = m.id where m.status=1 and  rel.roleid=:roleId\";\n        List<Map>  list = menuService.queryBySql(sql, SearchFilter.build(\"roleId\",roleId));\n        List<String> resUrls = Lists.newArrayList();\n        if(list!=null&&!list.isEmpty()){\n            for(Map map :list){\n                resUrls.add(map.get(\"url\").toString());\n            }\n        }\n        return resUrls;\n    }\n\n    @Override\n    public String findRoleNameByRoleId(Long roleId) {\n        return ConstantFactory.me().getSingleRoleTip(roleId);\n    }\n\n    @Override\n    public SimpleAuthenticationInfo info(ShiroUser shiroUser, User user, String realmName) {\n        String credentials = user.getPassword();\n        // 密码加盐处理\n        String source = user.getSalt();\n        ByteSource credentialsSalt = new Md5Hash(source);\n        return new SimpleAuthenticationInfo(shiroUser, credentials, credentialsSalt, realmName);\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/BasicType.java",
    "content": "package cn.enilu.material.utils;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 基本变量类型的枚举\n * @author xiaoleilu\n */\npublic enum BasicType {\n\tBYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING;\n\t\n\t/** 原始类型为Key，包装类型为Value，例如： int.class -> Integer.class. */\n\tpublic static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<Class<?>, Class<?>>(8);\n\t/** 包装类型为Key，原始类型为Value，例如： Integer.class -> int.class. */\n\tpublic static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>(8);\n\t\n\tstatic {\n\t\twrapperPrimitiveMap.put(Boolean.class, boolean.class);\n\t\twrapperPrimitiveMap.put(Byte.class, byte.class);\n\t\twrapperPrimitiveMap.put(Character.class, char.class);\n\t\twrapperPrimitiveMap.put(Double.class, double.class);\n\t\twrapperPrimitiveMap.put(Float.class, float.class);\n\t\twrapperPrimitiveMap.put(Integer.class, int.class);\n\t\twrapperPrimitiveMap.put(Long.class, long.class);\n\t\twrapperPrimitiveMap.put(Short.class, short.class);\n\n\t\tfor (Map.Entry<Class<?>, Class<?>> entry : wrapperPrimitiveMap.entrySet()) {\n\t\t\tprimitiveWrapperMap.put(entry.getValue(), entry.getKey());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/BeanUtil.java",
    "content": "package cn.enilu.material.utils;\n\nimport com.google.common.collect.Lists;\nimport com.google.common.collect.Maps;\nimport org.springframework.beans.BeanUtils;\nimport org.springframework.cglib.beans.BeanMap;\n\nimport javax.persistence.Column;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * Created  on 2018/2/26 0026.\n *\n * @author enilu\n */\npublic class BeanUtil {\n\n    /**\n     * 缓存字段名和中文注释对应关系的map\n     */\n    private static Map<String, String> fieldMap = Maps.newHashMap();\n    public static final Pattern COLUMN_DEFINITION_PATTERN = Pattern\n            .compile(\"([A-Za-z]+)(?:\\\\(\\\\d+\\\\))?\\\\s*(?:(?:COMMENT|[Cc]omment)\\\\s+'(.*?)')?\");\n\n    /**\n     * 将对象装换为map\n     *\n     * @param bean\n     * @return\n     */\n    public static <T> Map<String, Object> beanToMap(T bean) {\n        Map<String, Object> map = Maps.newHashMap();\n        if (bean != null) {\n            BeanMap beanMap = BeanMap.create(bean);\n            for (Object key : beanMap.keySet()) {\n                map.put(key + \"\", beanMap.get(key));\n            }\n        }\n        return map;\n    }\n\n    /**\n     * 将map装换为javabean对象\n     *\n     * @param map\n     * @param bean\n     * @return\n     */\n    public static <T> T mapToBean(Map<String, Object> map, T bean) {\n        BeanMap beanMap = BeanMap.create(bean);\n        beanMap.putAll(map);\n        return bean;\n    }\n\n    /**\n     * 将List<T>转换为List<Map<String, Object>>\n     *\n     * @param objList\n     * @return\n     */\n    public static <T> List<Map<String, Object>> objectsToMaps(List<T> objList) {\n        List<Map<String, Object>> list = com.google.common.collect.Lists.newArrayList();\n        if (objList != null && objList.size() > 0) {\n            Map<String, Object> map = null;\n            T bean = null;\n            for (int i = 0, size = objList.size(); i < size; i++) {\n                bean = objList.get(i);\n                map = beanToMap(bean);\n                list.add(map);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * 将List<Map<String,Object>>转换为List<T>\n     *\n     * @param maps\n     * @param clazz\n     * @return\n     * @throws InstantiationException\n     * @throws IllegalAccessException\n     */\n    public static <T> List<T> mapsToObjects(List<Map<String, Object>> maps, Class<T> clazz)\n            throws InstantiationException, IllegalAccessException {\n        List<T> list = com.google.common.collect.Lists.newArrayList();\n        if (maps != null && maps.size() > 0) {\n            Map<String, Object> map = null;\n            T bean = null;\n            for (int i = 0, size = maps.size(); i < size; i++) {\n                map = maps.get(i);\n                bean = clazz.newInstance();\n                mapToBean(map, bean);\n                list.add(bean);\n            }\n        }\n        return list;\n    }\n\n    public static <T> List<T> objectToObjects(List<Object> objectList, Class<T> clazz)\n            throws InstantiationException, IllegalAccessException {\n        List<T> list = Lists.newArrayList();\n        if (objectList != null && objectList.size() > 0) {\n            Object source = null;\n            T bean = null;\n            for (int i = 0, size = objectList.size(); i < size; i++) {\n                source = objectList.get(i);\n                bean = clazz.newInstance();\n                BeanUtils.copyProperties(source, bean);\n                list.add(bean);\n            }\n        }\n        return list;\n    }\n\n    /**\n     * 比较两个对象pojo1和pojo2,并输出不一致信息\n     *\n     * @param key\n     * @param pojo1\n     * @param pojo2\n     * @return\n     * @throws IllegalAccessException\n     * @throws InstantiationException\n     */\n    public static String contrastObj(String key, Object pojo1, Map<String, String> pojo2)\n            throws IllegalAccessException, InstantiationException {\n\n        StringBuilder str = new StringBuilder();\n        String headerName = key;\n        String headerValue = pojo2.get(key);\n        try {\n            Class clazz = pojo1.getClass();\n            Field[] fields = pojo1.getClass().getDeclaredFields();\n            int i = 1;\n            for (Field field : fields) {\n                if (\"serialVersionUID\".equals(field.getName())) {\n                    continue;\n                }\n                // PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);\n                Method getMethod = getReadMethod(field.getName(), clazz);\n                Object o1 = \"null\";\n                if (StringUtils.isNotNullOrEmpty(pojo2.get(\"id\"))) {\n                    o1 = getMethod.invoke(pojo1);\n                }\n                Object o2 = pojo2.get(StringUtils.firstCharToLowerCase(getMethod.getName().substring(3)));\n                if (StringUtils.equals(key, field.getName())) {\n                    headerName = getFieldComment(clazz, field);\n                }\n                if (o1 == null || o2 == null) {\n                    continue;\n                }\n                if (o1 instanceof Date) {\n                    o1 = DateUtil.getDay((Date) o1);\n                } else if (o1 instanceof Integer) {\n                    o2 = Integer.parseInt(o2.toString());\n                }\n                if (!o1.toString().equals(o2.toString())) {\n                    if (i != 1) {\n                        str.append(Constants.SEPARATOR);\n                    }\n                    String fieldName = getFieldComment(clazz, field);\n                    str.append(fieldName + \":\" + o1 + \"=>\" + o2);\n                    i++;\n                }\n            }\n        } catch (Exception e) {\n        }\n        String header = headerName + \"=\" + headerValue + Constants.SEPARATOR;\n        return header + str;\n    }\n\n    private static Method getReadMethod(String fieldName, Class clazz) {\n        String methodName = \"get\" + StringUtils.firstCharToUpperCase(fieldName);\n        Method method = null;\n        ;\n        try {\n            method = clazz.getDeclaredMethod(methodName);\n        } catch (Exception e) {\n            methodName = \"is\" + StringUtils.firstCharToUpperCase(fieldName);\n            try {\n                method = clazz.getDeclaredMethod(methodName);\n            } catch (Exception e1) {\n                e1.printStackTrace();\n            }\n        }\n\n        return method;\n    }\n    /**\n     * 从实体类的columDefinition中获取字段的中文注释，如果\n     *\n     * @param clazz\n     * @param field\n     * @return\n     */\n    public static String getFieldComment(Class clazz, Field field) {\n        String key = clazz.getName() + field.getName();\n        String comment = fieldMap.get(key);\n        if (comment == null) {\n            Annotation[] annotations = field.getAnnotations();\n            for (Annotation annotation : annotations) {\n                if (annotation instanceof Column) {\n                    Column columnAnno = (Column) annotation;\n                    String columnDefinition = columnAnno.columnDefinition();\n                    if (columnDefinition != null && !\"\".equals(columnDefinition.trim())) {\n                        Matcher matcher = COLUMN_DEFINITION_PATTERN.matcher(columnDefinition.trim());\n                        if (matcher.find()) {\n                            comment = matcher.group(2);\n                            fieldMap.put(key, comment);\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n        if (comment == null) {\n            comment = field.getName();\n            fieldMap.put(key, comment);\n        }\n        return comment;\n    }\n\n    /**\n     * 解析多个key(逗号隔开的)\n     */\n    public static String parseMutiKey(Map<String, String> requests) {\n        StringBuilder sb = new StringBuilder();\n        for (Map.Entry<String, String> entry : requests.entrySet()) {\n            sb.append(entry.getKey()).append(\"=\").append(entry.getValue()).append(\";\");\n        }\n        return sb.toString();\n\n    }\n\n    /**\n     * 对象组中是否存在 Empty Object\n     *\n     * @param os 对象组\n     * @return\n     */\n    public static boolean isOneEmpty(Object... os) {\n        for (Object o : os) {\n            if (StringUtils.isNullOrEmpty(o)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/BirthUtils.java",
    "content": "package cn.enilu.material.utils;\n\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.GregorianCalendar;\n\npublic class BirthUtils {\n\t\n\tpublic static final String[] zodiacArr = { \"猴\", \"鸡\", \"狗\", \"猪\", \"鼠\", \"牛\", \"虎\", \"兔\", \"龙\", \"蛇\", \"马\", \"羊\" };\n\t \n\tpublic static final String[] constellationArr = { \"水瓶座\", \"双鱼座\", \"白羊座\", \"金牛座\", \"双子座\", \"巨蟹座\", \"狮子座\", \"处女座\", \"天秤座\", \"天蝎座\", \"射手座\", \"魔羯座\" };\n\t \n\tpublic static final int[] constellationEdgeDay = { 20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22 };\n\t \n\t/**\n\t * 根据日期获取生肖\n\t * @return\n\t */\n\tpublic static String getZodica(Date date) {\n\t    Calendar cal = Calendar.getInstance();\n\t    cal.setTime(date);\n\t    return zodiacArr[cal.get(Calendar.YEAR) % 12];\n\t}\n\t \n\t/**\n\t * 根据日期获取星座\n\t * @return\n\t */\n\tpublic static String getConstellation(Date date) {\n\t    if (date == null) {\n\t        return \"\";\n\t    }\n\t    Calendar cal = Calendar.getInstance();\n\t    cal.setTime(date);\n\t    int month = cal.get(Calendar.MONTH);\n\t    int day = cal.get(Calendar.DAY_OF_MONTH);\n\t    if (day < constellationEdgeDay[month]) {\n\t        month = month - 1;\n\t    }\n\t    if (month >= 0) {\n\t        return constellationArr[month];\n\t    }\n\t    // default to return 魔羯\n\t    return constellationArr[11];\n\t}\n\t\n\t/**\n\t *  根据身份证号判断用户性别\n\t * @param cardNo\n\t * @return\n\t */\n\tpublic static String getSex(String cardNo) {\n\t\tString sexStr = \"0\";\n\t\tif (cardNo.length() == 15) {\n\t\t\tsexStr = cardNo.substring(14, 15);\n\t\t} else if (cardNo.length() == 18) {\n\t\t\tsexStr = cardNo.substring(16,17);\n\t\t}\n\t\tint sexNo = Integer.parseInt(sexStr);\n\t\treturn sexNo % 2 == 0 ? \"女\" : \"男\";\n\t}\n\t\n\t/**\n\t *  根据身份证号判断用户生肖\n\t * @param cardNo\n\t * @return\n\t */\n\tpublic static String getZodica(String cardNo) {\n\t\t// 获取出生日期\n\t\tString birthday = cardNo.substring(6, 14);\n\t\tDate birthdate = null;\n\t\ttry {\n\t\t\tbirthdate = new SimpleDateFormat(\"yyyyMMdd\").parse(birthday);\n\t\t\treturn getZodica(birthdate);\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\t\n\t/**\n\t *  根据身份证号判断用户星座\n\t * @param cardNo\n\t * @return\n\t */\n\tpublic static String getConstellation(String cardNo) {\n\t\t// 获取出生日期\n\t\tString birthday = cardNo.substring(6, 14);\n\t\tDate birthdate = null;\n\t\ttry {\n\t\t\tbirthdate = new SimpleDateFormat(\"yyyyMMdd\").parse(birthday);\n\t\t\treturn getConstellation(birthdate);\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn null;\n\t}\n\n    public static int getAge(String cardNo) {\n        String birthday = cardNo.substring(6, 14);\n        Date birthdate = null;\n        try {\n            birthdate = new SimpleDateFormat(\"yyyyMMdd\").parse(birthday);\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n        GregorianCalendar currentDay = new GregorianCalendar();\n        currentDay.setTime(birthdate);\n        int birYear = currentDay.get(Calendar.YEAR);\n\n        // 获取年龄\n        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy\");\n        String thisYear = simpleDateFormat.format(new Date());\n        int age = Integer.parseInt(thisYear) - birYear;\n\n        return age;\n    }\n\n    public static int getAge(String cardNo, Date date) {\n        String birthday = cardNo.substring(6, 14);\n        Date birthdate = null;\n        try {\n            birthdate = new SimpleDateFormat(\"yyyyMMdd\").parse(birthday);\n        } catch (ParseException e) {\n            e.printStackTrace();\n        }\n        GregorianCalendar currentDay = new GregorianCalendar();\n        currentDay.setTime(birthdate);\n        int birYear = currentDay.get(Calendar.YEAR);\n\n        // 获取年龄\n        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(\"yyyy\");\n        String thisYear = simpleDateFormat.format(date);\n        int age = Integer.parseInt(thisYear) - birYear;\n\n        return age;\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/CollectionKit.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport cn.enilu.material.utils.cache.exception.ToolBoxException;\n\nimport java.lang.reflect.Array;\nimport java.util.*;\nimport java.util.Map.Entry;\n\n/**\n * 集合相关工具类，包括数组\n *\n * @author xiaoleilu\n *\n */\npublic class CollectionKit {\n\n\tprivate CollectionKit() {\n\t\t// 静态类不可实例化\n\t}\n\n\t/**\n\t * 以 conjunction 为分隔符将集合转换为字符串\n\t *\n\t * @param <T> 被处理的集合\n\t * @param collection 集合\n\t * @param conjunction 分隔符\n\t * @return 连接后的字符串\n\t */\n\tpublic static <T> String join(Iterable<T> collection, String conjunction) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tboolean isFirst = true;\n\t\tfor (T item : collection) {\n\t\t\tif (isFirst) {\n\t\t\t\tisFirst = false;\n\t\t\t} else {\n\t\t\t\tsb.append(conjunction);\n\t\t\t}\n\t\t\tsb.append(item);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 以 conjunction 为分隔符将数组转换为字符串\n\t *\n\t * @param <T> 被处理的集合\n\t * @param array 数组\n\t * @param conjunction 分隔符\n\t * @return 连接后的字符串\n\t */\n\tpublic static <T> String join(T[] array, String conjunction) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tboolean isFirst = true;\n\t\tfor (T item : array) {\n\t\t\tif (isFirst) {\n\t\t\t\tisFirst = false;\n\t\t\t} else {\n\t\t\t\tsb.append(conjunction);\n\t\t\t}\n\t\t\tsb.append(item);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将多个集合排序并显示不同的段落（分页）\n\t * @param pageNo 页码\n\t * @param numPerPage 每页的条目数\n\t * @param comparator 比较器\n\t * @param colls 集合数组\n\t * @return 分页后的段落内容\n\t */\n\t@SafeVarargs\n\tpublic static <T> List<T> sortPageAll(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) {\n\t\tfinal List<T> result = new ArrayList<T>();\n\t\tfor (Collection<T> coll : colls) {\n\t\t\tresult.addAll(coll);\n\t\t}\n\n\t\tCollections.sort(result, comparator);\n\n\t\t//第一页且数目少于第一页显示的数目\n\t\tif(pageNo <=1 && result.size() <= numPerPage) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfinal int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage);\n\t\treturn result.subList(startEnd[0], startEnd[1]);\n\t}\n\n\t/**\n\t * 将多个集合排序并显示不同的段落（分页）\n\t * @param pageNo 页码\n\t * @param numPerPage 每页的条目数\n\t * @param comparator 比较器\n\t * @param colls 集合数组\n\t * @return 分业后的段落内容\n\t */\n//\t@SafeVarargs\n//\tpublic static <T> List<T> sortPageAll2(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) {\n//\t\tBoundedPriorityQueue<T> queue = new BoundedPriorityQueue<T>(pageNo * numPerPage);\n//\t\tfor (Collection<T> coll : colls) {\n//\t\t\tqueue.addAll(coll);\n//\t\t}\n//\n//\t\t//第一页且数目少于第一页显示的数目\n//\t\tif(pageNo <=1 && queue.size() <= numPerPage) {\n//\t\t\treturn queue.toList();\n//\t\t}\n//\n//\t\tfinal int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage);\n//\t\treturn queue.toList().subList(startEnd[0], startEnd[1]);\n//\t}\n\n\t/**\n\t * 将Set排序（根据Entry的值）\n\t *\n\t * @param set 被排序的Set\n\t * @return 排序后的Set\n\t */\n\tpublic static List<Entry<Long, Long>> sortEntrySetToList(Set<Entry<Long, Long>> set) {\n\t\tList<Entry<Long, Long>> list = new LinkedList<Entry<Long, Long>>(set);\n\t\tCollections.sort(list, new Comparator<Entry<Long, Long>>(){\n\n\t\t\t@Override\n\t\t\tpublic int compare(Entry<Long, Long> o1, Entry<Long, Long> o2) {\n\t\t\t\tif (o1.getValue() > o2.getValue()){\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tif (o1.getValue() < o2.getValue()){\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t});\n\t\treturn list;\n\t}\n\n\t/**\n\t * 切取部分数据\n\t *\n\t * @param <T> 集合元素类型\n\t * @param surplusAlaDatas 原数据\n\t * @param partSize 每部分数据的长度\n\t * @return 切取出的数据或null\n\t */\n\tpublic static <T> List<T> popPart(Stack<T> surplusAlaDatas, int partSize) {\n\t\tif (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal List<T> currentAlaDatas = new ArrayList<T>();\n\t\tint size = surplusAlaDatas.size();\n\t\t// 切割\n\t\tif (size > partSize) {\n\t\t\tfor (int i = 0; i < partSize; i++) {\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t} else {\n\t\t\tfor (int i = 0; i < size; i++) {\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t}\n\t\treturn currentAlaDatas;\n\t}\n\n\t/**\n\t * 切取部分数据\n\t *\n\t * @param <T> 集合元素类型\n\t * @param surplusAlaDatas 原数据\n\t * @param partSize 每部分数据的长度\n\t * @return 切取出的数据或null\n\t */\n\tpublic static <T> List<T> popPart(Deque<T> surplusAlaDatas, int partSize) {\n\t\tif (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal List<T> currentAlaDatas = new ArrayList<T>();\n\t\tint size = surplusAlaDatas.size();\n\t\t// 切割\n\t\tif (size > partSize) {\n\t\t\tfor (int i = 0; i < partSize; i++) {\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t} else {\n\t\t\tfor (int i = 0; i < size; i++) {\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t}\n\t\treturn currentAlaDatas;\n\t}\n\n\t/**\n\t * 新建一个HashMap\n\t *\n\t * @return HashMap对象\n\t */\n\tpublic static <T, K> HashMap<T, K> newHashMap() {\n\t\treturn new HashMap<T, K>();\n\t}\n\n\t/**\n\t * 新建一个HashMap\n\t * @param size 初始大小，由于默认负载因子0.75，传入的size会实际初始大小为size / 0.75\n\t * @return HashMap对象\n\t */\n\tpublic static <T, K> HashMap<T, K> newHashMap(int size) {\n\t\treturn new HashMap<T, K>((int)(size / 0.75));\n\t}\n\n\t/**\n\t * 新建一个HashSet\n\t *\n\t * @return HashSet对象\n\t */\n\tpublic static <T> HashSet<T> newHashSet() {\n\t\treturn new HashSet<T>();\n\t}\n\n\t/**\n\t * 新建一个HashSet\n\t *\n\t * @return HashSet对象\n\t */\n\t@SafeVarargs\n\tpublic static <T> HashSet<T> newHashSet(T... ts) {\n\t\tHashSet<T> set = new HashSet<T>();\n\t\tfor (T t : ts) {\n\t\t\tset.add(t);\n\t\t}\n\t\treturn set;\n\t}\n\n\t/**\n\t * 新建一个ArrayList\n\t *\n\t * @return ArrayList对象\n\t */\n\tpublic static <T> ArrayList<T> newArrayList() {\n\t\treturn new ArrayList<T>();\n\t}\n\n\t/**\n\t * 新建一个ArrayList\n\t *\n\t * @return ArrayList对象\n\t */\n\t@SafeVarargs\n\tpublic static <T> ArrayList<T> newArrayList(T... values) {\n\t\treturn new ArrayList<T>(Arrays.asList(values));\n\t}\n\n\t/**\n\t * 将新元素添加到已有数组中<br/>\n\t * 添加新元素会生成一个新的数组，不影响原数组\n\t *\n\t * @param buffer 已有数组\n\t * @param newElement 新元素\n\t * @return 新数组\n\t */\n\tpublic static <T> T[] append(T[] buffer, T newElement) {\n\t\tT[] t = resize(buffer, buffer.length + 1, newElement.getClass());\n\t\tt[buffer.length] = newElement;\n\t\treturn t;\n\t}\n\n\t/**\n\t * 生成一个新的重新设置大小的数组\n\t *\n\t * @param buffer 原数组\n\t * @param newSize 新的数组大小\n\t * @param componentType 数组元素类型\n\t * @return 调整后的新数组\n\t */\n\tpublic static <T> T[] resize(T[] buffer, int newSize, Class<?> componentType) {\n\t\tT[] newArray = newArray(componentType, newSize);\n\t\tSystem.arraycopy(buffer, 0, newArray, 0, buffer.length >= newSize ? newSize : buffer.length);\n\t\treturn newArray;\n\t}\n\n\t/**\n\t * 新建一个空数组\n\t * @param componentType 元素类型\n\t * @param newSize 大小\n\t * @return 空数组\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T[] newArray(Class<?> componentType, int newSize) {\n\t\treturn (T[]) Array.newInstance(componentType, newSize);\n\t}\n\n\t/**\n\t * 生成一个新的重新设置大小的数组<br/>\n\t * 新数组的类型为原数组的类型\n\t *\n\t * @param buffer 原数组\n\t * @param newSize 新的数组大小\n\t * @return 调整后的新数组\n\t */\n\tpublic static <T> T[] resize(T[] buffer, int newSize) {\n\t\treturn resize(buffer, newSize, buffer.getClass().getComponentType());\n\t}\n\n\t/**\n\t * 将多个数组合并在一起<br>\n\t * 忽略null的数组\n\t *\n\t * @param arrays 数组集合\n\t * @return 合并后的数组\n\t */\n\t@SafeVarargs\n\tpublic static <T> T[] addAll(T[]... arrays) {\n\t\tif (arrays.length == 1) {\n\t\t\treturn arrays[0];\n\t\t}\n\n\t\tint length = 0;\n\t\tfor (T[] array : arrays) {\n\t\t\tif(array == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlength += array.length;\n\t\t}\n\t\tT[] result = newArray(arrays.getClass().getComponentType().getComponentType(), length);\n\n\t\tlength = 0;\n\t\tfor (T[] array : arrays) {\n\t\t\tif(array == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tSystem.arraycopy(array, 0, result, length, array.length);\n\t\t\tlength += array.length;\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * 克隆数组\n\t * @param array 被克隆的数组\n\t * @return 新数组\n\t */\n\tpublic static <T> T[] clone(T[] array) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn array.clone();\n\t}\n\n\t/**\n\t * 生成一个数字列表<br>\n\t * 自动判定正序反序\n\t * @param excludedEnd 结束的数字（不包含）\n\t * @return 数字列表\n\t */\n\tpublic static int[] range(int excludedEnd) {\n\t\treturn range(0, excludedEnd, 1);\n\t}\n\n\t/**\n\t * 生成一个数字列表<br>\n\t * 自动判定正序反序\n\t * @param includedStart 开始的数字（包含）\n\t * @param excludedEnd 结束的数字（不包含）\n\t * @return 数字列表\n\t */\n\tpublic static int[] range(int includedStart, int excludedEnd) {\n\t\treturn range(includedStart, excludedEnd, 1);\n\t}\n\n\t/**\n\t * 生成一个数字列表<br>\n\t * 自动判定正序反序\n\t * @param includedStart 开始的数字（包含）\n\t * @param excludedEnd 结束的数字（不包含）\n\t * @param step 步进\n\t * @return 数字列表\n\t */\n\tpublic static int[] range(int includedStart, int excludedEnd, int step) {\n\t\tif(includedStart > excludedEnd) {\n\t\t\tint tmp = includedStart;\n\t\t\tincludedStart = excludedEnd;\n\t\t\texcludedEnd = tmp;\n\t\t}\n\n\t\tif(step <=0) {\n\t\t\tstep = 1;\n\t\t}\n\n\t\tint deviation = excludedEnd - includedStart;\n\t\tint length = deviation / step;\n\t\tif(deviation % step != 0) {\n\t\t\tlength += 1;\n\t\t}\n\t\tint[] range = new int[length];\n\t\tfor(int i = 0; i < length; i++) {\n\t\t\trange[i] = includedStart;\n\t\t\tincludedStart += step;\n\t\t}\n\t\treturn range;\n\t}\n\n\t/**\n\t * 截取数组的部分\n\t * @param list 被截取的数组\n\t * @param start 开始位置（包含）\n\t * @param end 结束位置（不包含）\n\t * @return 截取后的数组，当开始位置超过最大时，返回null\n\t */\n\tpublic static <T> List<T> sub(List<T> list, int start, int end) {\n\t\tif(list == null || list.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif(start < 0) {\n\t\t\tstart = 0;\n\t\t}\n\t\tif(end < 0) {\n\t\t\tend = 0;\n\t\t}\n\n\t\tif(start > end) {\n\t\t\tint tmp = start;\n\t\t\tstart = end;\n\t\t\tend = tmp;\n\t\t}\n\n\t\tfinal int size = list.size();\n\t\tif(end > size) {\n\t\t\tif(start >= size) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tend = size;\n\t\t}\n\n\t\treturn list.subList(start, end);\n\t}\n\n\t/**\n\t * 截取集合的部分\n\t * @param list 被截取的数组\n\t * @param start 开始位置（包含）\n\t * @param end 结束位置（不包含）\n\t * @return 截取后的数组，当开始位置超过最大时，返回null\n\t */\n\tpublic static <T> List<T> sub(Collection<T> list, int start, int end) {\n\t\tif(list == null || list.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn sub(new ArrayList<T>(list), start, end);\n\t}\n\n\t/**\n\t * 数组是否为空\n\t * @param array 数组\n\t * @return 是否为空\n\t */\n\tpublic static <T> boolean isEmpty(T[] array) {\n\t\treturn array == null || array.length == 0;\n\t}\n\n\t/**\n\t * 数组是否为非空\n\t * @param array 数组\n\t * @return 是否为非空\n\t */\n\tpublic static <T> boolean isNotEmpty(T[] array) {\n\t\treturn false == isEmpty(array);\n\t}\n\n\t/**\n\t * 集合是否为空\n\t * @param collection 集合\n\t * @return 是否为空\n\t */\n\tpublic static boolean isEmpty(Collection<?> collection) {\n\t\treturn collection == null || collection.isEmpty();\n\t}\n\n\t/**\n\t * 集合是否为非空\n\t * @param collection 集合\n\t * @return 是否为非空\n\t */\n\tpublic static boolean isNotEmpty(Collection<?> collection) {\n\t\treturn false == isEmpty(collection);\n\t}\n\n\t/**\n\t * Map是否为空\n\t * @param map 集合\n\t * @return 是否为空\n\t */\n\tpublic static boolean isEmpty(Map<?, ?> map) {\n\t\treturn map == null || map.isEmpty();\n\t}\n\n\t/**\n\t * Map是否为非空\n\t * @param map 集合\n\t * @return 是否为非空\n\t */\n\tpublic static <T> boolean isNotEmpty(Map<?, ?> map) {\n\t\treturn false == isEmpty(map);\n\t}\n\n\t/**\n\t * 映射键值（参考Python的zip()函数）<br>\n\t * 例如：<br>\n\t * \t\tkeys =    [a,b,c,d]<br>\n\t *\t\tvalues = [1,2,3,4]<br>\n\t * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>\n\t * 如果两个数组长度不同，则只对应最短部分\n\t * @param keys 键列表\n\t * @param values 值列表\n\t * @return Map\n\t */\n\tpublic static <T, K> Map<T, K> zip(T[] keys, K[] values) {\n\t\tif(isEmpty(keys) || isEmpty(values)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal int size = Math.min(keys.length, values.length);\n\t\tfinal Map<T, K> map = new HashMap<T, K>((int)(size / 0.75));\n\t\tfor(int i = 0; i < size; i++) {\n\t\t\tmap.put(keys[i], values[i]);\n\t\t}\n\n\t\treturn map;\n\t}\n\n\t/**\n\t * 映射键值（参考Python的zip()函数）<br>\n\t * 例如：<br>\n\t * \t\tkeys =    a,b,c,d<br>\n\t *\t\tvalues = 1,2,3,4<br>\n\t *\t\tdelimiter = ,\n\t * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>\n\t * 如果两个数组长度不同，则只对应最短部分\n\t * @param keys 键列表\n\t * @param values 值列表\n\t * @return Map\n\t */\n\tpublic static Map<String, String> zip(String keys, String values, String delimiter) {\n\t\treturn zip(StrKit.split(keys, delimiter), StrKit.split(values, delimiter));\n\t}\n\n\t/**\n\t * 映射键值（参考Python的zip()函数）<br>\n\t * 例如：<br>\n\t * \t\tkeys =    [a,b,c,d]<br>\n\t *\t\tvalues = [1,2,3,4]<br>\n\t * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>\n\t * 如果两个数组长度不同，则只对应最短部分\n\t * @param keys 键列表\n\t * @param values 值列表\n\t * @return Map\n\t */\n\tpublic static <T, K> Map<T, K> zip(Collection<T> keys, Collection<K> values) {\n\t\tif(isEmpty(keys) || isEmpty(values)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal List<T> keyList = new ArrayList<T>(keys);\n\t\tfinal List<K> valueList = new ArrayList<K>(values);\n\n\t\tfinal int size = Math.min(keys.size(), values.size());\n\t\tfinal Map<T, K> map = new HashMap<T, K>((int)(size / 0.75));\n\t\tfor(int i = 0; i < size; i++) {\n\t\t\tmap.put(keyList.get(i), valueList.get(i));\n\t\t}\n\n\t\treturn map;\n\t}\n\n\t/**\n\t * 数组中是否包含元素\n\t * @param array 数组\n\t * @param value 被检查的元素\n\t * @return 是否包含\n\t */\n\tpublic static <T> boolean contains(T[] array, T value) {\n\t\tfinal Class<?> componetType = array.getClass().getComponentType();\n\t\tboolean isPrimitive = false;\n\t\tif(null != componetType) {\n\t\t\tisPrimitive = componetType.isPrimitive();\n\t\t}\n\t\tfor (T t : array) {\n\t\t\tif(t == value) {\n\t\t\t\treturn true;\n\t\t\t}else if(false == isPrimitive && null != value && value.equals(t)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 将Entry集合转换为HashMap\n\t * @param entryCollection entry集合\n\t * @return Map\n\t */\n\tpublic static <T, K> HashMap<T, K> toMap(Collection<Entry<T, K>> entryCollection) {\n\t\tHashMap<T,K> map = new HashMap<T, K>();\n\t\tfor (Entry<T, K> entry : entryCollection) {\n\t\t\tmap.put(entry.getKey(), entry.getValue());\n\t\t}\n\t\treturn map;\n\t}\n\n\t/**\n\t * 将集合转换为排序后的TreeSet\n\t * @param collection 集合\n\t * @param comparator 比较器\n\t * @return treeSet\n\t */\n\tpublic static <T> TreeSet<T> toTreeSet(Collection<T> collection, Comparator<T> comparator){\n\t\tfinal TreeSet<T> treeSet = new TreeSet<T>(comparator);\n\t\tfor (T t : collection) {\n\t\t\ttreeSet.add(t);\n\t\t}\n\t\treturn treeSet;\n\t}\n\n\t/**\n\t * 排序集合\n\t * @param collection 集合\n\t * @param comparator 比较器\n\t * @return treeSet\n\t */\n\tpublic static <T> List<T> sort(Collection<T> collection, Comparator<T> comparator){\n\t\tList<T> list = new ArrayList<T>(collection);\n\t\tCollections.sort(list, comparator);\n\t\treturn list;\n\t}\n\n\t//------------------------------------------------------------------- 基本类型的数组转换为包装类型数组\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Integer[] wrap(int... values){\n\t\tfinal int length = values.length;\n\t\tInteger[] array = new Integer[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Long[] wrap(long... values){\n\t\tfinal int length = values.length;\n\t\tLong[] array = new Long[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Character[] wrap(char... values){\n\t\tfinal int length = values.length;\n\t\tCharacter[] array = new Character[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Byte[] wrap(byte... values){\n\t\tfinal int length = values.length;\n\t\tByte[] array = new Byte[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Short[] wrap(short... values){\n\t\tfinal int length = values.length;\n\t\tShort[] array = new Short[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Float[] wrap(float... values){\n\t\tfinal int length = values.length;\n\t\tFloat[] array = new Float[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Double[] wrap(double... values){\n\t\tfinal int length = values.length;\n\t\tDouble[] array = new Double[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Boolean[] wrap(boolean... values){\n\t\tfinal int length = values.length;\n\t\tBoolean[] array = new Boolean[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\n\t/**\n\t * 判定给定对象是否为数组类型\n\t * @param obj 对象\n\t * @return 是否为数组类型\n\t */\n\tpublic static boolean isArray(Object obj){\n\t\treturn obj.getClass().isArray();\n\t}\n\n\t/**\n\t * 数组或集合转String\n\t *\n\t * @param obj 集合或数组对象\n\t * @return 数组字符串，与集合转字符串格式相同\n\t */\n\tpublic static String toString(Object obj) {\n\t\tif (null == obj) {\n\t\t\treturn null;\n\t\t}\n\t\tif (isArray(obj)) {\n\t\t\ttry {\n\t\t\t\treturn Arrays.deepToString((Object[]) obj);\n\t\t\t} catch (Exception e) {\n\t\t\t\tfinal String className = obj.getClass().getComponentType().getName();\n\t\t\t\tswitch (className) {\n\t\t\t\t\tcase \"long\":\n\t\t\t\t\t\treturn Arrays.toString((long[]) obj);\n\t\t\t\t\tcase \"int\":\n\t\t\t\t\t\treturn Arrays.toString((int[]) obj);\n\t\t\t\t\tcase \"short\":\n\t\t\t\t\t\treturn Arrays.toString((short[]) obj);\n\t\t\t\t\tcase \"char\":\n\t\t\t\t\t\treturn Arrays.toString((char[]) obj);\n\t\t\t\t\tcase \"byte\":\n\t\t\t\t\t\treturn Arrays.toString((byte[]) obj);\n\t\t\t\t\tcase \"boolean\":\n\t\t\t\t\t\treturn Arrays.toString((boolean[]) obj);\n\t\t\t\t\tcase \"float\":\n\t\t\t\t\t\treturn Arrays.toString((float[]) obj);\n\t\t\t\t\tcase \"double\":\n\t\t\t\t\t\treturn Arrays.toString((double[]) obj);\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new ToolBoxException(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn obj.toString();\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/Constants.java",
    "content": "package cn.enilu.material.utils;\n\npublic interface Constants {\n    String SEPARATOR = \";;;\";\n    long SYSTEM_USER_ID=-1;\n\n    /**\n     * 用户密码加密key\n     */\n    String CRYPT_DES_KEY = \"sc123456\";\n\n\n    /**\n     * 微信获取token url\n     */\n    String ACCESS_TOKEN_URL = \"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s\";\n    /**\n     * 微信获取JsapiTicket url\n     */\n    String JSAPI_TICKET_URL = \"https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi\";\n    /**\n     * 微信下载多媒体文件 url\n     */\n    String MEDIA_URL = \"http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s\";\n    /**\n     * 微信群发信息 url\n     */\n    String WX_MESSAGE_URL = \"https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=%s\";\n\n\n\n\n    /**\n     * ===================================================================JSON\n     * 返回JSON结果的前后缀,jquery1.4x以上版本的json校验比较严格,不能使用单引号,但是可以将jquery的json解析器还原为eval\n     * (\"(\"+xx+\")\")\n     */\n    String JSON_PRE = \"{'state':'\", JSON_END = \"'}\";\n\n    /**\n     * 定义JSON形式的业务处理结果\n     */\n    String FAIL = JSON_PRE + \"fail\" + JSON_END, ERROR = JSON_PRE + \"error\" + JSON_END, SUCCESS = JSON_PRE + \"success\" + JSON_END,\n            TRUE = JSON_PRE + \"true\" + JSON_END, FALSE = JSON_PRE + \"false\" + JSON_END, LOCKED = JSON_PRE + \"locked\" + JSON_END, EXIST = JSON_PRE + \"exist\" + JSON_END;\n\n    /**\n     * 定义JSON形式的业务处理结果----附加上信息\n     */\n    static String msg(String state, Object info) {\n        return state.replace(\"}\", \", 'info': '\" + info + \"'}\");\n    }\n\n    /**\n     * ===================================================================日志类型\n     * 访问日志、操作日志\n     */\n    int ACCESS = 0, OPERATION = 1;\n\n    String MAIL_ACTION_KEY = \"fqufyasiduvqeouirtfu\";\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/Convert.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport cn.enilu.material.utils.cache.exception.ToolBoxException;\n\nimport java.io.UnsupportedEncodingException;\nimport java.math.BigDecimal;\nimport java.math.BigInteger;\nimport java.nio.charset.Charset;\nimport java.text.NumberFormat;\nimport java.util.Date;\nimport java.util.Set;\n\n\n/**\n * 类型转换器\n * \n * @author xiaoleilu\n * \n */\npublic class Convert {\n\t\n\n\tprivate Convert() {\n\t\t// 静态类不可实例化\n\t}\n\n\t/**\n\t * 强制转换类型\n\t * \n\t * @param clazz 被转换成的类型\n\t * @param value 需要转换的对象\n\t * @return 转换后的对象\n\t */\n\tpublic static Object parse(Class<?> clazz, Object value) {\n\t\ttry {\n\t\t\tif (clazz.isAssignableFrom(String.class)) {\n\t\t\t\t// ----2016-12-19---zhuangqian----防止beetlsql对空字符串不检测导致无法入库的问题----\n\t\t\t\tif (StrKit.isBlank(String.valueOf(value)))\n\t\t\t\t\treturn \" \";\n\t\t\t\telse\n\t\t\t\t\treturn String.valueOf(value);\n\t\t\t}\n\t\t\treturn clazz.cast(value);\n\t\t} catch (ClassCastException e) {\n\t\t\tString valueStr = String.valueOf(value);\n\n\t\t\tObject result = parseBasic(clazz, valueStr);\n\t\t\tif (result != null) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tif (Date.class.isAssignableFrom(clazz)) {\n\t\t\t\t// 判断标准日期\n\t\t\t\t// ----2016-11-24---zhuangqian----需要加toDate(),不然beetlsql转换date类型的时候会报错----\n\t\t\t\treturn DateTimeKit.parse(valueStr).toDate();\n\t\t\t} else if (clazz == BigInteger.class) {\n\t\t\t\t// 数学计算数字\n\t\t\t\treturn new BigInteger(valueStr);\n\t\t\t} else if (clazz == BigDecimal.class) {\n\t\t\t\t// 数学计算数字\n\t\t\t\treturn new BigDecimal(valueStr);\n\t\t\t} else if (clazz == byte[].class) {\n\t\t\t\t// 流，由于有字符编码问题，在此使用系统默认\n\t\t\t\treturn valueStr.getBytes();\n\t\t\t}\n\t\t\t// 未找到可转换的类型，返回原值\n\t\t\treturn (StrKit.isBlank(valueStr)) ? null : value;\n\t\t}\n\t}\n\n\t/**\n\t * 转换基本类型<br>\n\t * 将字符串转换为原始类型或包装类型\n\t * \n\t * @param clazz 转换到的类，可以是原始类型类，也可以是包装类型类\n\t * @param valueStr 被转换的字符串\n\t * @return 转换后的对象，如果非基本类型，返回null\n\t */\n\tpublic static Object parseBasic(Class<?> clazz, String valueStr) {\n\t\tif (null == clazz || null == valueStr) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (StrKit.isBlank(valueStr)) return null;\n\t\t\n\t\tBasicType basicType = null;\n\t\ttry {\n\t\t\tbasicType = BasicType.valueOf(clazz.getSimpleName().toUpperCase());\n\t\t} catch (Exception e) {\n\t\t\t// 非基本类型数据\n\t\t\treturn null;\n\t\t}\n\n\t\tswitch (basicType) {\n\t\t\tcase BYTE:\n\t\t\t\tif (clazz == byte.class) {\n\t\t\t\t\treturn Byte.parseByte(valueStr);\n\t\t\t\t}\n\t\t\t\treturn Byte.valueOf(valueStr);\n\t\t\tcase SHORT:\n\t\t\t\tif (clazz == short.class) {\n\t\t\t\t\treturn Short.parseShort(valueStr);\n\t\t\t\t}\n\t\t\t\treturn Short.valueOf(valueStr);\n\t\t\tcase INT:\n\t\t\t\treturn Integer.parseInt(valueStr);\n\t\t\tcase INTEGER:\n\t\t\t\treturn Integer.valueOf(valueStr);\n\t\t\tcase LONG:\n\t\t\t\tif (clazz == long.class) {\n\t\t\t\t\treturn new BigDecimal(valueStr).longValue();\n\t\t\t\t}\n\t\t\t\treturn Long.valueOf(valueStr);\n\t\t\tcase DOUBLE:\n\t\t\t\tif (clazz == double.class) {\n\t\t\t\t\treturn new BigDecimal(valueStr).doubleValue();\n\t\t\t\t}\n\t\t\tcase FLOAT:\n\t\t\t\tif (clazz == float.class) {\n\t\t\t\t\treturn Float.parseFloat(valueStr);\n\t\t\t\t}\n\t\t\t\treturn Float.valueOf(valueStr);\n\t\t\tcase BOOLEAN:\n\t\t\t\tif (clazz == boolean.class) {\n\t\t\t\t\treturn Boolean.parseBoolean(valueStr);\n\t\t\t\t}\n\t\t\t\treturn Boolean.valueOf(valueStr);\n\t\t\tcase CHAR:\n\t\t\t\treturn valueStr.charAt(0);\n\t\t\tcase CHARACTER:\n\t\t\t\treturn Character.valueOf(valueStr.charAt(0));\n\t\t\tdefault:\n\t\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为字符串<br>\n\t * 如果给定的值为null，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static String toStr(Object value, String defaultValue) {\n\t\tif (null == value) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof String) {\n\t\t\treturn (String) value;\n\t\t} else if (CollectionKit.isArray(value)) {\n\t\t\treturn CollectionKit.toString(value);\n\t\t}\n\t\treturn value.toString();\n\t}\n\n\t/**\n\t * 转换为字符串<br>\n\t * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static String toStr(Object value) {\n\t\treturn toStr(value, null);\n\t}\n\n\t/**\n\t * 转换为字符<br>\n\t * 如果给定的值为null，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Character toChar(Object value, Character defaultValue) {\n\t\tif (null == value) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Character) {\n\t\t\treturn (Character) value;\n\t\t}\n\n\t\tfinal String valueStr = toStr(value, null);\n\t\treturn StrKit.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);\n\t}\n\n\t/**\n\t * 转换为字符<br>\n\t * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Character toChar(Object value) {\n\t\treturn toChar(value, null);\n\t}\n\n\t/**\n\t * 转换为byte<br>\n\t * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Byte toByte(Object value, Byte defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Byte) {\n\t\t\treturn (Byte) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).byteValue();\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\treturn Byte.parseByte(valueStr);\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为byte<br>\n\t * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Byte toByte(Object value) {\n\t\treturn toByte(value, null);\n\t}\n\n\t/**\n\t * 转换为Short<br>\n\t * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Short toShort(Object value, Short defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Short) {\n\t\t\treturn (Short) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).shortValue();\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\treturn Short.parseShort(valueStr.trim());\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为Short<br>\n\t * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Short toShort(Object value) {\n\t\treturn toShort(value, null);\n\t}\n\n\t/**\n\t * 转换为Number<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Number toNumber(Object value, Number defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn (Number) value;\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\treturn NumberFormat.getInstance().parse(valueStr);\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为Number<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Number toNumber(Object value) {\n\t\treturn toNumber(value, null);\n\t}\n\n\t/**\n\t * 转换为int<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Integer toInt(Object value, Integer defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Integer) {\n\t\t\treturn (Integer) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).intValue();\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\treturn Integer.parseInt(valueStr.trim());\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为int<br>\n\t * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Integer toInt(Object value) {\n\t\treturn toInt(value, null);\n\t}\n\n\t/**\n\t * 转换为Integer数组<br>\n\t * \n\t * @param isIgnoreConvertError 是否忽略转换错误，忽略则给值null\n\t * @param values 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Integer[] toIntArray(boolean isIgnoreConvertError, Object... values) {\n\t\tif (CollectionKit.isEmpty(values)) {\n\t\t\treturn new Integer[] {};\n\t\t}\n\t\tfinal Integer[] ints = new Integer[values.length];\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tfinal Integer v = toInt(values[i], null);\n\t\t\tif (null == v && isIgnoreConvertError == false) {\n\t\t\t\tthrow new ToolBoxException(StrKit.format(\"Convert [{}] to Integer error!\", values[i]));\n\t\t\t}\n\t\t\tints[i] = v;\n\t\t}\n\t\treturn ints;\n\t}\n\t\n\t\n\t/**\n\t * 转换为Integer数组<br>\n\t * \n\t * @param str 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Integer[] toIntArray(String str) {\n\t\treturn toIntArray(\",\", str);\n\t}\n\t\n\t/**\n\t * 转换为Integer数组<br>\n\t * \n\t * @param split 分隔符\n\t * @param split 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Integer[] toIntArray(String split, String str) {\n\t\tif (StrKit.isEmpty(str)) {\n\t\t\treturn new Integer[] {};\n\t\t}\n\t\tString[] arr = str.split(split);\n\t\tfinal Integer[] ints = new Integer[arr.length];\n\t\tfor (int i = 0; i < arr.length; i++) {\n\t\t\tfinal Integer v = toInt(arr[i], 0);\n\t\t\tints[i] = v;\n\t\t}\n\t\treturn ints;\n\t}\n\tpublic static Long[] toLongArray(String split, String str) {\n\t\tif (StrKit.isEmpty(str)) {\n\t\t\treturn new Long[] {};\n\t\t}\n\t\tString[] arr = str.split(split);\n\t\tfinal Long[] ints = new Long[arr.length];\n\t\tfor (int i = 0; i < arr.length; i++) {\n\t\t\tfinal Long v = StringUtils.isNotEmpty(arr[i])?Long.valueOf(arr[i]):0L;\n\t\t\tints[i] = v;\n\t\t}\n\t\treturn ints;\n\t}\n\t\n\t/**\n\t * 转换为String数组<br>\n\t * \n\t * @param str 被转换的值\n\t * @return 结果\n\t */\n\tpublic static String[] toStrArray(String str) {\n\t\treturn toStrArray(\"\", str);\n\t}\n\t\n\t/**\n\t * 转换为String数组<br>\n\t * \n\t * @param split 分隔符\n\t * @param split 被转换的值\n\t * @return 结果\n\t */\n\tpublic static String[] toStrArray(String split, String str) {\n\t\treturn str.split(split);\n\t}\n\n\t/**\n\t * 转换为long<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Long toLong(Object value, Long defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Long) {\n\t\t\treturn (Long) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).longValue();\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\t// 支持科学计数法\n\t\t\treturn new BigDecimal(valueStr.trim()).longValue();\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为long<br>\n\t * 如果给定的值为<code>null</code>，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Long toLong(Object value) {\n\t\treturn toLong(value, null);\n\t}\n\n\t/**\n\t * 转换为Long数组<br>\n\t * \n\t * @param isIgnoreConvertError 是否忽略转换错误，忽略则给值null\n\t * @param values 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Long[] toLongArray(boolean isIgnoreConvertError, Object... values) {\n\t\tif (CollectionKit.isEmpty(values)) {\n\t\t\treturn new Long[] {};\n\t\t}\n\t\tfinal Long[] longs = new Long[values.length];\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tfinal Long v = toLong(values[i], null);\n\t\t\tif (null == v && isIgnoreConvertError == false) {\n\t\t\t\tthrow new ToolBoxException(StrKit.format(\"Convert [{}] to Long error!\", values[i]));\n\t\t\t}\n\t\t\tlongs[i] = v;\n\t\t}\n\t\treturn longs;\n\t}\n\n\t/**\n\t * 转换为double<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Double toDouble(Object value, Double defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Double) {\n\t\t\treturn (Double) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).doubleValue();\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\t// 支持科学计数法\n\t\t\treturn new BigDecimal(valueStr.trim()).doubleValue();\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为double<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Double toDouble(Object value) {\n\t\treturn toDouble(value, null);\n\t}\n\n\t/**\n\t * 转换为Double数组<br>\n\t * \n\t * @param isIgnoreConvertError 是否忽略转换错误，忽略则给值null\n\t * @param values 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Double[] toDoubleArray(boolean isIgnoreConvertError, Object... values) {\n\t\tif (CollectionKit.isEmpty(values)) {\n\t\t\treturn new Double[] {};\n\t\t}\n\t\tfinal Double[] doubles = new Double[values.length];\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tfinal Double v = toDouble(values[i], null);\n\t\t\tif (null == v && isIgnoreConvertError == false) {\n\t\t\t\tthrow new ToolBoxException(StrKit.format(\"Convert [{}] to Double error!\", values[i]));\n\t\t\t}\n\t\t\tdoubles[i] = v;\n\t\t}\n\t\treturn doubles;\n\t}\n\n\t/**\n\t * 转换为Float<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Float toFloat(Object value, Float defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Float) {\n\t\t\treturn (Float) value;\n\t\t}\n\t\tif (value instanceof Number) {\n\t\t\treturn ((Number) value).floatValue();\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\treturn Float.parseFloat(valueStr.trim());\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为Float<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Float toFloat(Object value) {\n\t\treturn toFloat(value, null);\n\t}\n\n\t/**\n\t * 转换为Float数组<br>\n\t * \n\t * @param isIgnoreConvertError 是否忽略转换错误，忽略则给值null\n\t * @param values 被转换的值\n\t * @return 结果\n\t */\n\tpublic static <T> Float[] toFloatArray(boolean isIgnoreConvertError, Object... values) {\n\t\tif (CollectionKit.isEmpty(values)) {\n\t\t\treturn new Float[] {};\n\t\t}\n\t\tfinal Float[] floats = new Float[values.length];\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tfinal Float v = toFloat(values[i], null);\n\t\t\tif (null == v && isIgnoreConvertError == false) {\n\t\t\t\tthrow new ToolBoxException(StrKit.format(\"Convert [{}] to Float error!\", values[i]));\n\t\t\t}\n\t\t\tfloats[i] = v;\n\t\t}\n\t\treturn floats;\n\t}\n\n\t/**\n\t * 转换为boolean<br>\n\t * String支持的值为：true、false、yes、ok、no，1,0 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static Boolean toBool(Object value, Boolean defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof Boolean) {\n\t\t\treturn (Boolean) value;\n\t\t}\n\t\tString valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tvalueStr = valueStr.trim().toLowerCase();\n\t\tswitch (valueStr) {\n\t\t\tcase \"true\":\n\t\t\t\treturn true;\n\t\t\tcase \"false\":\n\t\t\t\treturn false;\n\t\t\tcase \"yes\":\n\t\t\t\treturn true;\n\t\t\tcase \"ok\":\n\t\t\t\treturn true;\n\t\t\tcase \"no\":\n\t\t\t\treturn false;\n\t\t\tcase \"1\":\n\t\t\t\treturn true;\n\t\t\tcase \"0\":\n\t\t\t\treturn false;\n\t\t\tdefault:\n\t\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为boolean<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Boolean toBool(Object value) {\n\t\treturn toBool(value, null);\n\t}\n\n\t/**\n\t * 转换为Boolean数组<br>\n\t * \n\t * @param isIgnoreConvertError 是否忽略转换错误，忽略则给值null\n\t * @param values 被转换的值\n\t * @return 结果\n\t */\n\tpublic static Boolean[] toBooleanArray(boolean isIgnoreConvertError, Object... values) {\n\t\tif (CollectionKit.isEmpty(values)) {\n\t\t\treturn new Boolean[] {};\n\t\t}\n\t\tfinal Boolean[] bools = new Boolean[values.length];\n\t\tfor (int i = 0; i < values.length; i++) {\n\t\t\tfinal Boolean v = toBool(values[i], null);\n\t\t\tif (null == v && isIgnoreConvertError == false) {\n\t\t\t\tthrow new ToolBoxException(StrKit.format(\"Convert [{}] to Boolean error!\", values[i]));\n\t\t\t}\n\t\t\tbools[i] = v;\n\t\t}\n\t\treturn bools;\n\t}\n\n\t/**\n\t * 转换为Enum对象<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * \n\t * @param clazz Enum的Class\n\t * @param value 值\n\t * @param defaultValue 默认值\n\t * @return Enum\n\t */\n\tpublic static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (clazz.isAssignableFrom(value.getClass())) {\n\t\t\t@SuppressWarnings(\"unchecked\")\n\t\t\tE myE = (E) value;\n\t\t\treturn myE;\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\treturn Enum.valueOf(clazz, valueStr);\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为Enum对象<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\n\t * \n\t * @param clazz Enum的Class\n\t * @param value 值\n\t * @return Enum\n\t */\n\tpublic static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) {\n\t\treturn toEnum(clazz, value, null);\n\t}\n\n\t/**\n\t * 转换为BigInteger<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static BigInteger toBigInteger(Object value, BigInteger defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof BigInteger) {\n\t\t\treturn (BigInteger) value;\n\t\t}\n\t\tif (value instanceof Long) {\n\t\t\treturn BigInteger.valueOf((Long) value);\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\treturn new BigInteger(valueStr);\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为BigInteger<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<code>null</code><br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static BigInteger toBigInteger(Object value) {\n\t\treturn toBigInteger(value, null);\n\t}\n\n\t/**\n\t * 转换为BigDecimal<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @param defaultValue 转换错误时的默认值\n\t * @return 结果\n\t */\n\tpublic static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) {\n\t\tif (value == null) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tif (value instanceof BigDecimal) {\n\t\t\treturn (BigDecimal) value;\n\t\t}\n\t\tif (value instanceof Long) {\n\t\t\treturn new BigDecimal((Long) value);\n\t\t}\n\t\tif (value instanceof Double) {\n\t\t\treturn new BigDecimal((Double) value);\n\t\t}\n\t\tif (value instanceof Integer) {\n\t\t\treturn new BigDecimal((Integer) value);\n\t\t}\n\t\tfinal String valueStr = toStr(value, null);\n\t\tif (StrKit.isBlank(valueStr)) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\ttry {\n\t\t\treturn new BigDecimal(valueStr);\n\t\t} catch (Exception e) {\n\t\t\treturn defaultValue;\n\t\t}\n\t}\n\n\t/**\n\t * 转换为BigDecimal<br>\n\t * 如果给定的值为空，或者转换失败，返回默认值<br>\n\t * 转换失败不会报错\n\t * \n\t * @param value 被转换的值\n\t * @return 结果\n\t */\n\tpublic static BigDecimal toBigDecimal(Object value) {\n\t\treturn toBigDecimal(value, null);\n\t}\n\n\t// ----------------------------------------------------------------------- 全角半角转换\n\t/**\n\t * 半角转全角\n\t * \n\t * @param input String.\n\t * @return 全角字符串.\n\t */\n\tpublic static String toSBC(String input) {\n\t\treturn toSBC(input, null);\n\t}\n\n\t/**\n\t * 半角转全角\n\t * \n\t * @param input String\n\t * @param notConvertSet 不替换的字符集合\n\t * @return 全角字符串.\n\t */\n\tpublic static String toSBC(String input, Set<Character> notConvertSet) {\n\t\tchar c[] = input.toCharArray();\n\t\tfor (int i = 0; i < c.length; i++) {\n\t\t\tif (null != notConvertSet && notConvertSet.contains(c[i])) {\n\t\t\t\t// 跳过不替换的字符\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (c[i] == ' ') {\n\t\t\t\tc[i] = '\\u3000';\n\t\t\t} else if (c[i] < '\\177') {\n\t\t\t\tc[i] = (char) (c[i] + 65248);\n\n\t\t\t}\n\t\t}\n\t\treturn new String(c);\n\t}\n\n\t/**\n\t * 全角转半角\n\t * \n\t * @param input String.\n\t * @return 半角字符串\n\t */\n\tpublic static String toDBC(String input) {\n\t\treturn toDBC(input, null);\n\t}\n\n\t/**\n\t * 替换全角为半角\n\t * \n\t * @param text 文本\n\t * @param notConvertSet 不替换的字符集合\n\t * @return 替换后的字符\n\t */\n\tpublic static String toDBC(String text, Set<Character> notConvertSet) {\n\t\tchar c[] = text.toCharArray();\n\t\tfor (int i = 0; i < c.length; i++) {\n\t\t\tif (null != notConvertSet && notConvertSet.contains(c[i])) {\n\t\t\t\t// 跳过不替换的字符\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (c[i] == '\\u3000') {\n\t\t\t\tc[i] = ' ';\n\t\t\t} else if (c[i] > '\\uFF00' && c[i] < '\\uFF5F') {\n\t\t\t\tc[i] = (char) (c[i] - 65248);\n\t\t\t}\n\t\t}\n\t\tString returnString = new String(c);\n\n\t\treturn returnString;\n\t}\n\n\t// --------------------------------------------------------------------- hex\n\t/**\n\t * 字符串转换成十六进制字符串\n\t * \n\t * @param str 待转换的ASCII字符串\n\t * @return 16进制字符串\n\t */\n\tpublic static String toHex(String str) {\n\t\treturn HexKit.encodeHexStr(str.getBytes());\n\t}\n\n\t/**\n\t * byte数组转16进制串\n\t * \n\t * @param bytes 被转换的byte数组\n\t * @return 转换后的值\n\t */\n\tpublic static String toHex(byte[] bytes) {\n\t\treturn HexKit.encodeHexStr(bytes);\n\t}\n\n\t/**\n\t * Hex字符串转换为Byte值\n\t * \n\t * @param src Byte字符串，每个Byte之间没有分隔符\n\t * @return byte[]\n\t */\n\tpublic static byte[] hexToBytes(String src) {\n\t\treturn HexKit.decodeHex(src.toCharArray());\n\t}\n\n\t/**\n\t * 十六进制转换字符串\n\t * \n\t * @param hexStr Byte字符串(Byte之间无分隔符 如:[616C6B])\n\t * @param charset 编码 {@link Charset}\n\t * @return 对应的字符串\n\t */\n\tpublic static String hexStrToStr(String hexStr, Charset charset) {\n\t\treturn HexKit.decodeHexStr(hexStr, charset);\n\t}\n\n\t/**\n\t * String的字符串转换成unicode的String\n\t * \n\t * @param strText 全角字符串\n\t * @return String 每个unicode之间无分隔符\n\t * @throws Exception\n\t */\n\tpublic static String strToUnicode(String strText) throws Exception {\n\t\tchar c;\n\t\tStringBuilder str = new StringBuilder();\n\t\tint intAsc;\n\t\tString strHex;\n\t\tfor (int i = 0; i < strText.length(); i++) {\n\t\t\tc = strText.charAt(i);\n\t\t\tintAsc = (int) c;\n\t\t\tstrHex = Integer.toHexString(intAsc);\n\t\t\tif (intAsc > 128)\n\t\t\t\tstr.append(\"\\\\u\" + strHex);\n\t\t\telse // 低位在前面补00\n\t\t\t\tstr.append(\"\\\\u00\" + strHex);\n\t\t}\n\t\treturn str.toString();\n\t}\n\n\t/**\n\t * unicode的String转换成String的字符串\n\t * \n\t * @param hex 16进制值字符串 （一个unicode为2byte）\n\t * @return String 全角字符串\n\t */\n\tpublic static String unicodeToStr(String hex) {\n\t\tint t = hex.length() / 6;\n\t\tStringBuilder str = new StringBuilder();\n\t\tfor (int i = 0; i < t; i++) {\n\t\t\tString s = hex.substring(i * 6, (i + 1) * 6);\n\t\t\t// 高位需要补上00再转\n\t\t\tString s1 = s.substring(2, 4) + \"00\";\n\t\t\t// 低位直接转\n\t\t\tString s2 = s.substring(4);\n\t\t\t// 将16进制的string转为int\n\t\t\tint n = Integer.valueOf(s1, 16) + Integer.valueOf(s2, 16);\n\t\t\t// 将int转换为字符\n\t\t\tchar[] chars = Character.toChars(n);\n\t\t\tstr.append(new String(chars));\n\t\t}\n\t\treturn str.toString();\n\t}\n\n\t/**\n\t * 给定字符串转换字符编码<br/>\n\t * 如果参数为空，则返回原字符串，不报错。\n\t * \n\t * @param str 被转码的字符串\n\t * @param sourceCharset 原字符集\n\t * @param destCharset 目标字符集\n\t * @return 转换后的字符串\n\t */\n\tpublic static String convertCharset(String str, String sourceCharset, String destCharset) {\n\t\tif (StrKit.hasBlank(str, sourceCharset, destCharset)) {\n\t\t\treturn str;\n\t\t}\n\n\t\ttry {\n\t\t\treturn new String(str.getBytes(sourceCharset), destCharset);\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\treturn str;\n\t\t}\n\t}\n\n\t/**\n\t * 数字金额大写转换 先写个完整的然后将如零拾替换成零\n\t * \n\t * @param n 数字\n\t * @return 中文大写数字\n\t */\n\tpublic static String digitUppercase(double n) {\n\t\tString fraction[] = { \"角\", \"分\" };\n\t\tString digit[] = { \"零\", \"壹\", \"贰\", \"叁\", \"肆\", \"伍\", \"陆\", \"柒\", \"捌\", \"玖\" };\n\t\tString unit[][] = { { \"元\", \"万\", \"亿\" }, { \"\", \"拾\", \"佰\", \"仟\" } };\n\n\t\tString head = n < 0 ? \"负\" : \"\";\n\t\tn = Math.abs(n);\n\n\t\tString s = \"\";\n\t\tfor (int i = 0; i < fraction.length; i++) {\n\t\t\ts += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll(\"(零.)+\", \"\");\n\t\t}\n\t\tif (s.length() < 1) {\n\t\t\ts = \"整\";\n\t\t}\n\t\tint integerPart = (int) Math.floor(n);\n\n\t\tfor (int i = 0; i < unit[0].length && integerPart > 0; i++) {\n\t\t\tString p = \"\";\n\t\t\tfor (int j = 0; j < unit[1].length && n > 0; j++) {\n\t\t\t\tp = digit[integerPart % 10] + unit[1][j] + p;\n\t\t\t\tintegerPart = integerPart / 10;\n\t\t\t}\n\t\t\ts = p.replaceAll(\"(零.)*零$\", \"\").replaceAll(\"^$\", \"零\") + unit[0][i] + s;\n\t\t}\n\t\treturn head + s.replaceAll(\"(零.)*零元\", \"元\").replaceFirst(\"(零.)+\", \"\").replaceAll(\"(零.)+\", \"零\").replaceAll(\"^整$\", \"零元整\");\n\t}\n\t\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/CryptUtils.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport cn.enilu.material.bean.constant.Const;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.SecretKey;\nimport javax.crypto.SecretKeyFactory;\nimport javax.crypto.spec.DESKeySpec;\nimport java.io.*;\nimport java.security.MessageDigest;\nimport java.security.SecureRandom;\nimport java.text.SimpleDateFormat;\nimport java.util.Arrays;\nimport java.util.Base64;\nimport java.util.Date;\n\n/**\n * 加密工具类\n * @author  enilu\n */\npublic class CryptUtils {\n\n\tprivate static final String DES = \"DES\";\n\n\t/**\n\t * 加密\n\t *\n\t * @param src 数据源\n\t * @param key 密钥，长度必须是8的倍数\n\t * @return 返回加密后的数据\n\t * @throws Exception\n\t */\n\tprivate static byte[] encrypt(byte[] src, byte[] key) {\n\t\t// DES算法要求有一个可信任的随机数源\n\t\ttry {\n\t\t\tSecureRandom sr = new SecureRandom();\n\t\t\t// 从原始密匙数据创建DESKeySpec对象\n\t\t\tDESKeySpec dks = new DESKeySpec(key);\n\t\t\t// 创建一个密匙工厂，然后用它把DESKeySpec转换成\n\t\t\t// 一个SecretKey对象\n\t\t\tSecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);\n\t\t\tSecretKey securekey = keyFactory.generateSecret(dks);\n\t\t\t// Cipher对象实际完成加密操作\n\t\t\tCipher cipher = Cipher.getInstance(DES);\n\t\t\t// 用密匙初始化Cipher对象\n\t\t\tcipher.init(Cipher.ENCRYPT_MODE, securekey, sr);\n\t\t\t// 现在，获取数据并加密\n\t\t\t// 正式执行加密操作\n\t\t\treturn cipher.doFinal(src);\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t/**\n\t * 解密\n\t *\n\t * @param src 数据源\n\t * @param key 密钥，长度必须是8的倍数\n\t * @return 返回解密后的原始数据\n\t * @throws Exception\n\t */\n\tprivate static byte[] decrypt(byte[] src, byte[] key) {\n\t\ttry {\n\t\t\t// DES算法要求有一个可信任的随机数源\n\t\t\tSecureRandom sr = new SecureRandom();\n\t\t\t// 从原始密匙数据创建一个DESKeySpec对象\n\t\t\tDESKeySpec dks = new DESKeySpec(key);\n\t\t\t// 创建一个密匙工厂，然后用它把DESKeySpec对象转换成\n\t\t\t// 一个SecretKey对象\n\t\t\tSecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);\n\t\t\tSecretKey securekey = keyFactory.generateSecret(dks);\n\t\t\t// Cipher对象实际完成解密操作\n\t\t\tCipher cipher = Cipher.getInstance(DES);\n\t\t\t// 用密匙初始化Cipher对象\n\t\t\tcipher.init(Cipher.DECRYPT_MODE, securekey, sr);\n\t\t\t// 现在，获取数据并解密\n\t\t\t// 正式执行解密操作\n\t\t\treturn cipher.doFinal(src);\n\t\t} catch (Exception e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\t/**\n\t * 数据解密\n\t *\n\t * @param data\n\t * @param key  密钥\n\t * @return String\n\t * @throws Exception\n\t */\n\tprivate final static String decrypt(String data, String key) {\n\t\tif (data != null) {\n\t\t\treturn new String(decrypt(hex2byte(data.getBytes()), key.getBytes()));\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 数据加密\n\t *\n\t * @param data\n\t * @param key  密钥\n\t * @return\n\t * @throws Exception\n\t */\n\tpublic final static String encrypt(String data, String key) {\n\t\tif (data != null) {\n\t\t\ttry {\n\t\t\t\treturn byte2hex(encrypt(data.getBytes(), key.getBytes()));\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 二行制转字符串\n\t *\n\t * @param b\n\t * @return\n\t */\n\tprivate static String byte2hex(byte[] b) {\n\t\tStringBuilder hs = new StringBuilder();\n\t\tString stmp;\n\t\tfor (int n = 0; b != null && n < b.length; n++) {\n\t\t\tstmp = Integer.toHexString(b[n] & 0XFF);\n\t\t\tif (stmp.length() == 1) {\n\t\t\t\ths.append('0');\n\t\t\t}\n\t\t\ths.append(stmp);\n\t\t}\n\t\treturn hs.toString().toUpperCase();\n\t}\n\n\tprivate static byte[] hex2byte(byte[] b) {\n\t\tif ((b.length % 2) != 0) {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t\tbyte[] b2 = new byte[b.length / 2];\n\t\tfor (int n = 0; n < b.length; n += 2) {\n\t\t\tString item = new String(b, n, 2);\n\t\t\tb2[n / 2] = (byte) Integer.parseInt(item, 16);\n\t\t}\n\t\treturn b2;\n\t}\n\n\t/**\n\t * 对字符串按密钥进行DES加密\n\t */\n\tpublic static String encode(String data) {\n\t\treturn encrypt(data, Const.CRYPT_DES_KEY);\n\t}\n\n\t/**\n\t * 对字符串按密钥进行DES解密\n\t */\n\tpublic static String decode(String data) {\n\t\treturn decrypt(data, Const.CRYPT_DES_KEY);\n\t}\n\n\t/**\n\t * 对字符串按密钥进行DES加密\n\t */\n\tpublic static String encode(String data, String key) {\n\t\tif (data != null && key != null) {\n\t\t\ttry {\n\t\t\t\tSecretKey secretKey = generateSecretKey(key);\n\t\t\t\tCipher cipher = Cipher.getInstance(DES);\n\t\t\t\tcipher.init(Cipher.ENCRYPT_MODE, secretKey);\n\t\t\t\treturn encryptBASE64(cipher.doFinal(data.getBytes()));\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 对字符串按密钥进行DES解密\n\t */\n\tpublic static String decode(String data, String key) {\n\t\tif (data != null && key != null) {\n\t\t\ttry {\n\t\t\t\tSecretKey secretKey = generateSecretKey(key);\n\t\t\t\tCipher cipher = Cipher.getInstance(DES); // Get the cipher\n\t\t\t\tcipher.init(Cipher.DECRYPT_MODE, secretKey);\n\t\t\t\treturn new String(cipher.doFinal(decryptBASE64(data)));\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 根据密码和keyGenerator生成密钥。\n\t * @param key\n\t * @return\n\t */\n\tprivate static SecretKey generateSecretKey(String key) {\n\t\tSecretKey secretKey = null;\n\t\ttry {\n\t\t\tMessageDigest md = MessageDigest.getInstance(\"MD5\");\n\t\t\tbyte[] bytes = key.getBytes();\n\t\t\tmd.update(bytes, 0, bytes.length);\n\t\t\t// Generate 16 bytes\n\t\t\tbyte[] mdBytes = md.digest();\n\t\t\t// Fetch 8 bytes for DESKeySpec\n\t\t\tbyte[] truncatedBytes = Arrays.copyOf(mdBytes, 8);\n\t\t\tDESKeySpec keySpec = new DESKeySpec(truncatedBytes);\n\t\t\tSecretKeyFactory keyFactory = SecretKeyFactory.getInstance(\"DES\");\n\t\t\tsecretKey = keyFactory.generateSecret(keySpec);\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\treturn secretKey;\n\t}\n\n\t/**\n\t * 转换成字符串\n\t */\n\tpublic static String convertToHexString(byte[] data) {\n\t\tStringBuffer strBuffer = new StringBuffer();\n\t\tfor (int i = 0; i < data.length; i++) {\n\t\t\tString hex = Integer.toHexString(0xff & data[i]);\n\t\t\tif (hex.length() == 1) {\n\t\t\t\thex = '0' + hex;\n\t\t\t}\n\t\t\tstrBuffer.append(hex.toUpperCase());\n\t\t}\n\t\treturn strBuffer.toString();\n\t}\n\n\t/**\n\t * BASE64加密\n\t */\n\tpublic static String encryptBASE64(byte[] key) throws Exception {\n\t\treturn (Base64.getEncoder()).encodeToString(key);\n\t}\n\n\t/**\n\t * BASE64解密\n\t */\n\tpublic static byte[] decryptBASE64(String key) throws Exception {\n\t\treturn Base64.getDecoder().decode(key);\n\t}\n\tpublic static String encodeBASE64(byte[] bytes) {\n\n\t\tString encode = Base64.getEncoder().encodeToString(bytes);\n\t\tencode = encode.replaceAll(\"\\n\", \"\");\n\t\treturn encode;\n\t}\n\n\t/**\n\t * 文件内容生成BASE64编码的字符串\n\t */\n\tpublic static String encodeBASE64(File file) {\n\t\tBase64.Encoder encoder =  Base64.getEncoder();\n\t\tStringBuilder sb = new StringBuilder();\n\t\tInputStream input = null;\n\t\ttry {\n\t\t\tinput = new FileInputStream(file);\n\t\t\tByteArrayOutputStream out = new ByteArrayOutputStream();\n\t\t\tbyte[] temp = new byte[1024];\n\t\t\tfor (int len = input.read(temp); len != -1; len = input.read(temp)) {\n\t\t\t\tout.write(temp, 0, len);\n\t\t\t\tsb.append(encoder.encode(out.toByteArray()));\n\t\t\t\tout.reset();\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (input != null) {\n\t\t\t\t\tinput.close();\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * BASE64编码的字符串解码为文件\n\t */\n\tpublic static void decodeBASE64(String encoder, File file) {\n\t\tBase64.Decoder decoder = Base64.getDecoder();\n\t\tFileOutputStream fos = null;\n\t\ttry {\n\t\t\tfos = new FileOutputStream(file);\n\t\t\tbyte[] decoderBytes = decoder.decode(encoder);\n\t\t\tfos.write(decoderBytes);\n\t\t\tfos.flush();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (fos != null) {\n\t\t\t\t\tfos.close();\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static byte[] decodeBASE64(String encoder) {\n\t\tBase64.Decoder decoder = Base64.getDecoder();\n\n\t\treturn decoder.decode(encoder);\n\n\t}\n\tpublic static String getSign(String privateKey) {\n\t\treturn getSign(privateKey, new Date());\n\t}\n\tpublic static String getMD5ofStr(String inStr) {\n\t\tMessageDigest md5 = null;\n\t\ttry {\n\t\t\t// 获得MD5摘要算法的 MessageDigest 对象\n\t\t\tmd5 = MessageDigest.getInstance(\"MD5\");\n\t\t\tbyte[] byteArray = inStr.getBytes(\"UTF-8\");\n\t\t\t// 获得密文\n\t\t\tbyte[] md5Bytes = md5.digest(byteArray);\n\t\t\t// 把密文转换成十六进制的字符串形式\n\t\t\tStringBuffer hexValue = new StringBuffer();\n\t\t\tfor (int i = 0; i < md5Bytes.length; i++) {\n\t\t\t\tint val = ((int) md5Bytes[i]) & 0xff;\n\t\t\t\tif (val < 16) {\n\t\t\t\t\thexValue.append(\"0\");\n\t\t\t\t}\n\t\t\t\thexValue.append(Integer.toHexString(val));\n\t\t\t}\n\t\t\treturn hexValue.toString().toUpperCase();\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\treturn \"\";\n\t}\n\tpublic static String getSign(String privateKey, Date date) {\n\t\tSimpleDateFormat sdf = new SimpleDateFormat(\"yyyyMMdd\");\n\t\tString sign = getMD5ofStr(privateKey + sdf.format(date));\n\n\t\treturn sign;\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/DateTime.java",
    "content": "package cn.enilu.material.utils;\n\nimport java.util.Date;\n\n/**\n * 封装java.util.Date\n * @author xiaoleilu\n *\n */\npublic class DateTime extends Date{\n\tprivate static final long serialVersionUID = -5395712593979185936L;\n\t\n\t/**\n\t * 转换JDK date为 DateTime\n\t * @param date JDK Date\n\t * @return DateTime\n\t */\n\tpublic static DateTime parse(Date date) {\n\t\treturn new DateTime(date);\n\t}\n\t\n\t/**\n\t * 当前时间\n\t */\n\tpublic DateTime() {\n\t\tsuper();\n\t}\n\t\n\t/**\n\t * 给定日期的构造\n\t * @param date 日期\n\t */\n\tpublic DateTime(Date date) {\n\t\tthis(date.getTime());\n\t}\n\t\n\t/**\n\t * 给定日期毫秒数的构造\n\t * @param timeMillis 日期毫秒数\n\t */\n\tpublic DateTime(long timeMillis) {\n\t\tsuper(timeMillis);\n\t}\n\t\n\t@Override\n\tpublic String toString() {\n\t\treturn DateTimeKit.formatDateTime(this);\n\t}\n\t\n\tpublic String toString(String format) {\n\t\treturn DateTimeKit.format(this, format);\n\t}\n\t\n\t/**\n\t * @return 输出精确到毫秒的标准日期形式\n\t */\n\tpublic String toMsStr() {\n\t\treturn DateTimeKit.format(this, DateTimeKit.NORM_DATETIME_MS_PATTERN);\n\t}\n\t\n\t/**   \n\t * @return java.util.Date\n\t*/\n\tpublic Date toDate() {\n\t\treturn new Date(this.getTime());\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/DateTimeKit.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport cn.enilu.material.utils.cache.exception.ToolBoxException;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.LinkedHashSet;\nimport java.util.Locale;\n\n/**\n * 时间工具类\n * @author xiaoleilu\n */\npublic class DateTimeKit {\n\t/** 毫秒 */\n\tpublic final static long MS = 1;\n\t/** 每秒钟的毫秒数 */\n\tpublic final static long SECOND_MS = MS * 1000;\n\t/** 每分钟的毫秒数 */\n\tpublic final static long MINUTE_MS = SECOND_MS * 60;\n\t/** 每小时的毫秒数 */\n\tpublic final static long HOUR_MS = MINUTE_MS * 60;\n\t/** 每天的毫秒数 */\n\tpublic final static long DAY_MS = HOUR_MS * 24;\n\n\t/** 标准日期格式 */\n\tpublic final static String NORM_DATE_PATTERN = \"yyyy-MM-dd\";\n\t/** 标准时间格式 */\n\tpublic final static String NORM_TIME_PATTERN = \"HH:mm:ss\";\n\t/** 标准日期时间格式，精确到分 */\n\tpublic final static String NORM_DATETIME_MINUTE_PATTERN = \"yyyy-MM-dd HH:mm\";\n\t/** 标准日期时间格式，精确到秒 */\n\tpublic final static String NORM_DATETIME_PATTERN = \"yyyy-MM-dd HH:mm:ss\";\n\t/** 标准日期时间格式，精确到毫秒 */\n\tpublic final static String NORM_DATETIME_MS_PATTERN = \"yyyy-MM-dd HH:mm:ss.SSS\";\n\t/** HTTP头中日期时间格式 */\n\tpublic final static String HTTP_DATETIME_PATTERN = \"EEE, dd MMM yyyy HH:mm:ss z\";\n\n\t/** 标准日期（不含时间）格式化器 */\n\t// private final static SimpleDateFormat NORM_DATE_FORMAT = new SimpleDateFormat(NORM_DATE_PATTERN);\n\tprivate static ThreadLocal<SimpleDateFormat> NORM_DATE_FORMAT = new ThreadLocal<SimpleDateFormat>(){\n\t\tsynchronized protected SimpleDateFormat initialValue() {\n\t\t\treturn new SimpleDateFormat(NORM_DATE_PATTERN);\n\t\t};\n\t};\n\t/** 标准时间格式化器 */\n\t// private final static SimpleDateFormat NORM_TIME_FORMAT = new SimpleDateFormat(NORM_TIME_PATTERN);\n\tprivate static ThreadLocal<SimpleDateFormat> NORM_TIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){\n\t\tsynchronized protected SimpleDateFormat initialValue() {\n\t\t\treturn new SimpleDateFormat(NORM_TIME_PATTERN);\n\t\t};\n\t};\n\t/** 标准日期时间格式化器 */\n\t// private final static SimpleDateFormat NORM_DATETIME_FORMAT = new SimpleDateFormat(NORM_DATETIME_PATTERN);\n\tprivate static ThreadLocal<SimpleDateFormat> NORM_DATETIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){\n\t\tsynchronized protected SimpleDateFormat initialValue() {\n\t\t\treturn new SimpleDateFormat(NORM_DATETIME_PATTERN);\n\t\t};\n\t};\n\t/** HTTP日期时间格式化器 */\n\t// private final static SimpleDateFormat HTTP_DATETIME_FORMAT = new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US);\n\tprivate static ThreadLocal<SimpleDateFormat> HTTP_DATETIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){\n\t\tsynchronized protected SimpleDateFormat initialValue() {\n\t\t\treturn new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US);\n\t\t};\n\t};\n\n\t/**\n\t * 当前时间，格式 yyyy-MM-dd HH:mm:ss\n\t * \n\t * @return 当前时间的标准形式字符串\n\t */\n\tpublic static String now() {\n\t\treturn formatDateTime(new DateTime());\n\t}\n\n\t/**\n\t * 当前时间long\n\t *\n\t * @param isNano 是否为高精度时间\n\t * @return 时间\n\t */\n\tpublic static long current(boolean isNano) {\n\t\treturn isNano ? System.nanoTime() : System.currentTimeMillis();\n\t}\n\n\t/**\n\t * 当前日期，格式 yyyy-MM-dd\n\t *\n\t * @return 当前日期的标准形式字符串\n\t */\n\tpublic static String today() {\n\t\treturn formatDate(new DateTime());\n\t}\n\n\t/**\n\t * @return 当前月份\n\t */\n\tpublic static int thisMonth() {\n\t\treturn month(date());\n\t}\n\n\t/**\n\t * @return 今年\n\t */\n\tpublic static int thisYear() {\n\t\treturn year(date());\n\t}\n\n\t/**\n\t * @return 当前时间\n\t */\n\tpublic static DateTime date() {\n\t\treturn new DateTime();\n\t}\n\n\t/**\n\t * Long类型时间转为Date\n\t *\n\t * @param date Long类型Date（Unix时间戳）\n\t * @return 时间对象\n\t */\n\tpublic static DateTime date(long date) {\n\t\treturn new DateTime(date);\n\t}\n\n\t/**\n\t * 转换为Calendar对象\n\t *\n\t * @param date 日期对象\n\t * @return Calendar对象\n\t */\n\tpublic static Calendar toCalendar(Date date) {\n\t\tfinal Calendar cal = Calendar.getInstance();\n\t\tcal.setTime(date);\n\t\treturn cal;\n\t}\n\n\t/**\n\t * 获得月份，从1月开始计数\n\t *\n\t * @param date 日期\n\t * @return 月份\n\t */\n\tpublic static int month(Date date) {\n\t\treturn toCalendar(date).get(Calendar.MONTH) + 1;\n\t}\n\n\t/**\n\t * 获得年\n\t *\n\t * @param date 日期\n\t * @return 年\n\t */\n\tpublic static int year(Date date) {\n\t\treturn toCalendar(date).get(Calendar.YEAR);\n\t}\n\n\t/**\n\t * 获得季节\n\t *\n\t * @param date 日期\n\t * @return 第几个季节\n\t */\n\tpublic static int season(Date date) {\n\t\treturn toCalendar(date).get(Calendar.MONTH) / 3 + 1;\n\t}\n\n\t/**\n\t * 获得指定日期年份和季节<br>\n\t * 格式：[20131]表示2013年第一季度\n\t *\n\t * @param date 日期\n\t * @return Season ，类似于 20132\n\t */\n\tpublic static String yearAndSeason(Date date) {\n\t\treturn yearAndSeason(toCalendar(date));\n\t}\n\n\t/**\n\t * 获得指定日期区间内的年份和季节<br>\n\t *\n\t * @param startDate 其实日期（包含）\n\t * @param endDate 结束日期（包含）\n\t * @return Season列表 ，元素类似于 20132\n\t */\n\tpublic static LinkedHashSet<String> yearAndSeasons(Date startDate, Date endDate) {\n\t\tfinal LinkedHashSet<String> seasons = new LinkedHashSet<String>();\n\t\tif (startDate == null || endDate == null) {\n\t\t\treturn seasons;\n\t\t}\n\n\t\tfinal Calendar cal = Calendar.getInstance();\n\t\tcal.setTime(startDate);\n\t\twhile (true) {\n\t\t\t// 如果开始时间超出结束时间，让结束时间为开始时间，处理完后结束循环\n\t\t\tif (startDate.after(endDate)) {\n\t\t\t\tstartDate = endDate;\n\t\t\t}\n\n\t\t\tseasons.add(yearAndSeason(cal));\n\n\t\t\tif (startDate.equals(endDate)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcal.add(Calendar.MONTH, 3);\n\t\t\tstartDate = cal.getTime();\n\t\t}\n\n\t\treturn seasons;\n\t}\n\n\t// ------------------------------------ Format start ----------------------------------------------\n\t/**\n\t * 根据特定格式格式化日期\n\t *\n\t * @param date 被格式化的日期\n\t * @param format 格式\n\t * @return 格式化后的字符串\n\t */\n\tpublic static String format(Date date, String format) {\n\t\treturn new SimpleDateFormat(format).format(date);\n\t}\n\n\t/**\n\t * 格式 yyyy-MM-dd HH:mm:ss\n\t *\n\t * @param date 被格式化的日期\n\t * @return 格式化后的日期\n\t */\n\tpublic static String formatDateTime(Date date) {\n\t\tif(null == date){\n\t\t\treturn null;\n\t\t}\n\t\treturn NORM_DATETIME_FORMAT.get().format(date);\n\t}\n\n\t/**\n\t * 格式 yyyy-MM-dd\n\t *\n\t * @param date 被格式化的日期\n\t * @return 格式化后的字符串\n\t */\n\tpublic static String formatDate(Date date) {\n\t\tif(null == date){\n\t\t\treturn null;\n\t\t}\n\t\treturn NORM_DATE_FORMAT.get().format(date);\n\t}\n\n\t/**\n\t * 格式化为Http的标准日期格式\n\t *\n\t * @param date 被格式化的日期\n\t * @return HTTP标准形式日期字符串\n\t */\n\tpublic static String formatHttpDate(Date date) {\n\t\tif(null == date){\n\t\t\treturn null;\n\t\t}\n\t\treturn HTTP_DATETIME_FORMAT.get().format(date);\n\t}\n\t// ------------------------------------ Format end ----------------------------------------------\n\n\t// ------------------------------------ Parse start ----------------------------------------------\n\n\t/**\n\t * 构建DateTime对象\n\t *\n\t * @param dateStr Date字符串\n\t * @param simpleDateFormat 格式化器\n\t * @return DateTime对象\n\t */\n\tpublic static DateTime parse(String dateStr, SimpleDateFormat simpleDateFormat) {\n\t\ttry {\n\t\t\treturn new DateTime(simpleDateFormat.parse(dateStr));\n\t\t} catch (Exception e) {\n\t\t\tthrow new ToolBoxException(StrKit.format(\"Parse [{}] with format [{}] error!\", dateStr, simpleDateFormat.toPattern()), e);\n\t\t}\n\t}\n\n\t/**\n\t * 将特定格式的日期转换为Date对象\n\t *\n\t * @param dateString 特定格式的日期\n\t * @param format 格式，例如yyyy-MM-dd\n\t * @return 日期对象\n\t */\n\tpublic static DateTime parse(String dateString, String format) {\n\t\treturn parse(dateString, new SimpleDateFormat(format));\n\t}\n\n\t/**\n\t * 格式yyyy-MM-dd HH:mm:ss\n\t *\n\t * @param dateString 标准形式的时间字符串\n\t * @return 日期对象\n\t */\n\tpublic static DateTime parseDateTime(String dateString) {\n\t\treturn parse(dateString, NORM_DATETIME_FORMAT.get());\n\t}\n\n\t/**\n\t * 格式yyyy-MM-dd\n\t *\n\t * @param dateString 标准形式的日期字符串\n\t * @return 日期对象\n\t */\n\tpublic static DateTime parseDate(String dateString) {\n\t\treturn parse(dateString, NORM_DATE_FORMAT.get());\n\t}\n\n\t/**\n\t * 格式HH:mm:ss\n\t *\n\t * @param timeString 标准形式的日期字符串\n\t * @return 日期对象\n\t */\n\tpublic static DateTime parseTime(String timeString) {\n\t\treturn parse(timeString, NORM_TIME_FORMAT.get());\n\t}\n\n\t/**\n\t * 格式：<br>\n\t * 1、yyyy-MM-dd HH:mm:ss<br>\n\t * 2、yyyy-MM-dd<br>\n\t * 3、HH:mm:ss<br>\n\t * 4、yyyy-MM-dd HH:mm 5、yyyy-MM-dd HH:mm:ss.SSS\n\t *\n\t * @param dateStr 日期字符串\n\t * @return 日期\n\t */\n\tpublic static DateTime parse(String dateStr) {\n\t\tif (null == dateStr) {\n\t\t\treturn null;\n\t\t}\n\t\tdateStr = dateStr.trim();\n\t\tint length = dateStr.length();\n\t\ttry {\n\t\t\tif (length == NORM_DATETIME_PATTERN.length()) {\n\t\t\t\treturn parseDateTime(dateStr);\n\t\t\t} else if (length == NORM_DATE_PATTERN.length()) {\n\t\t\t\treturn parseDate(dateStr);\n\t\t\t} else if (length == NORM_TIME_PATTERN.length()) {\n\t\t\t\treturn parseTime(dateStr);\n\t\t\t} else if (length == NORM_DATETIME_MINUTE_PATTERN.length()) {\n\t\t\t\treturn parse(dateStr, NORM_DATETIME_MINUTE_PATTERN);\n\t\t\t} else if (length >= NORM_DATETIME_MS_PATTERN.length() - 2) {\n\t\t\t\treturn parse(dateStr, NORM_DATETIME_MS_PATTERN);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new ToolBoxException(StrKit.format(\"Parse [{}] with format normal error!\", dateStr));\n\t\t}\n\n\t\t// 没有更多匹配的时间格式\n\t\tthrow new ToolBoxException(StrKit.format(\" [{}] format is not fit for date pattern!\", dateStr));\n\t}\n\t// ------------------------------------ Parse end ----------------------------------------------\n\n\t// ------------------------------------ Offset start ----------------------------------------------\n\t/**\n\t * 获取某天的开始时间\n\t *\n\t * @param date 日期\n\t * @return 某天的开始时间\n\t */\n\tpublic static DateTime getBeginTimeOfDay(Date date) {\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tcalendar.setTime(date);\n\t\tcalendar.set(Calendar.HOUR_OF_DAY, 0);\n\t\tcalendar.set(Calendar.MINUTE, 0);\n\t\tcalendar.set(Calendar.SECOND, 0);\n\t\tcalendar.set(Calendar.MILLISECOND, 0);\n\t\treturn new DateTime(calendar.getTime());\n\t}\n\n\t/**\n\t * 获取某天的结束时间\n\t *\n\t * @param date 日期\n\t * @return 某天的结束时间\n\t */\n\tpublic static DateTime getEndTimeOfDay(Date date) {\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tcalendar.setTime(date);\n\t\tcalendar.set(Calendar.HOUR_OF_DAY, 23);\n\t\tcalendar.set(Calendar.MINUTE, 59);\n\t\tcalendar.set(Calendar.SECOND, 59);\n\t\tcalendar.set(Calendar.MILLISECOND, 999);\n\t\treturn new DateTime(calendar.getTime());\n\t}\n\n\t/**\n\t * 昨天\n\t *\n\t * @return 昨天\n\t */\n\tpublic static DateTime yesterday() {\n\t\treturn offsiteDay(new DateTime(), -1);\n\t}\n\n\t/**\n\t * 上周\n\t *\n\t * @return 上周\n\t */\n\tpublic static DateTime lastWeek() {\n\t\treturn offsiteWeek(new DateTime(), -1);\n\t}\n\n\t/**\n\t * 上个月\n\t *\n\t * @return 上个月\n\t */\n\tpublic static DateTime lastMouth() {\n\t\treturn offsiteMonth(new DateTime(), -1);\n\t}\n\n\t/**\n\t * 偏移天\n\t *\n\t * @param date 日期\n\t * @param offsite 偏移天数，正数向未来偏移，负数向历史偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static DateTime offsiteDay(Date date, int offsite) {\n\t\treturn offsiteDate(date, Calendar.DAY_OF_YEAR, offsite);\n\t}\n\n\t/**\n\t * 偏移周\n\t *\n\t * @param date 日期\n\t * @param offsite 偏移周数，正数向未来偏移，负数向历史偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static DateTime offsiteWeek(Date date, int offsite) {\n\t\treturn offsiteDate(date, Calendar.WEEK_OF_YEAR, offsite);\n\t}\n\n\t/**\n\t * 偏移月\n\t *\n\t * @param date 日期\n\t * @param offsite 偏移月数，正数向未来偏移，负数向历史偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static DateTime offsiteMonth(Date date, int offsite) {\n\t\treturn offsiteDate(date, Calendar.MONTH, offsite);\n\t}\n\n\t/**\n\t * 获取指定日期偏移指定时间后的时间\n\t *\n\t * @param date 基准日期\n\t * @param calendarField 偏移的粒度大小（小时、天、月等）使用Calendar中的常数\n\t * @param offsite 偏移量，正数为向后偏移，负数为向前偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static DateTime offsiteDate(Date date, int calendarField, int offsite) {\n\t\tCalendar cal = Calendar.getInstance();\n\t\tcal.setTime(date);\n\t\tcal.add(calendarField, offsite);\n\t\treturn new DateTime(cal.getTime());\n\t}\n\t// ------------------------------------ Offset end ----------------------------------------------\n\n\t/**\n\t * 判断两个日期相差的时长<br/>\n\t * 返回 minuend - subtrahend 的差\n\t * \n\t * @param subtrahend 减数日期\n\t * @param minuend 被减数日期\n\t * @param diffField 相差的选项：相差的天、小时\n\t * @return 日期差\n\t */\n\tpublic static long diff(Date subtrahend, Date minuend, long diffField) {\n\t\tlong diff = minuend.getTime() - subtrahend.getTime();\n\t\treturn diff / diffField;\n\t}\n\n\t/**\n\t * 计时，常用于记录某段代码的执行时间，单位：纳秒\n\t * \n\t * @param preTime 之前记录的时间\n\t * @return 时间差，纳秒\n\t */\n\tpublic static long spendNt(long preTime) {\n\t\treturn System.nanoTime() - preTime;\n\t}\n\n\t/**\n\t * 计时，常用于记录某段代码的执行时间，单位：毫秒\n\t * \n\t * @param preTime 之前记录的时间\n\t * @return 时间差，毫秒\n\t */\n\tpublic static long spendMs(long preTime) {\n\t\treturn System.currentTimeMillis() - preTime;\n\t}\n\n\t/**\n\t * 格式化成yyMMddHHmm后转换为int型\n\t * \n\t * @param date 日期\n\t * @return int\n\t */\n\tpublic static int toIntSecond(Date date) {\n\t\treturn Integer.parseInt(format(date, \"yyMMddHHmm\"));\n\t}\n\n\t/**\n\t * 计算指定指定时间区间内的周数\n\t * \n\t * @param start 开始时间\n\t * @param end 结束时间\n\t * @return 周数\n\t */\n\tpublic static int weekCount(Date start, Date end) {\n\t\tfinal Calendar startCalendar = Calendar.getInstance();\n\t\tstartCalendar.setTime(start);\n\t\tfinal Calendar endCalendar = Calendar.getInstance();\n\t\tendCalendar.setTime(end);\n\n\t\tfinal int startWeekofYear = startCalendar.get(Calendar.WEEK_OF_YEAR);\n\t\tfinal int endWeekofYear = endCalendar.get(Calendar.WEEK_OF_YEAR);\n\n\t\tint count = endWeekofYear - startWeekofYear + 1;\n\n\t\tif (Calendar.SUNDAY != startCalendar.get(Calendar.DAY_OF_WEEK)) {\n\t\t\tcount--;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * 计时器<br>\n\t * 计算某个过程话费的时间，精确到毫秒\n\t * \n\t * @return Timer\n\t */\n\tpublic static Timer timer() {\n\t\treturn new Timer();\n\n\t}\n\t\n\t/**\n\t * 生日转为年龄，计算法定年龄\n\t * @param birthDay 生日，标准日期字符串\n\t * @return 年龄\n\t * @throws Exception\n\t */\n\tpublic static int ageOfNow(String birthDay) {\n\t\treturn ageOfNow(parse(birthDay));\n\t}\n\n\t/**\n\t * 生日转为年龄，计算法定年龄\n\t * @param birthDay 生日\n\t * @return 年龄\n\t * @throws Exception\n\t */\n\tpublic static int ageOfNow(Date birthDay) {\n\t\treturn age(birthDay,date());\n\t}\n\t\n\t/**\n\t * 计算相对于dateToCompare的年龄，长用于计算指定生日在某年的年龄\n\t * @param birthDay 生日\n\t * @param dateToCompare 需要对比的日期\n\t * @return 年龄\n\t * @throws Exception\n\t */\n\tpublic static int age(Date birthDay, Date dateToCompare) {\n\t\tCalendar cal = Calendar.getInstance();\n\t\tcal.setTime(dateToCompare);\n\n\t\tif (cal.before(birthDay)) {\n\t\t\tthrow new IllegalArgumentException(StrKit.format(\"Birthday is after date {}!\", formatDate(dateToCompare)));\n\t\t}\n\n\t\tint year = cal.get(Calendar.YEAR);\n\t\tint month = cal.get(Calendar.MONTH);\n\t\tint dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);\n\n\t\tcal.setTime(birthDay);\n\t\tint age = year - cal.get(Calendar.YEAR);\n\t\t\n\t\tint monthBirth = cal.get(Calendar.MONTH);\n\t\tif (month == monthBirth) {\n\t\t\tint dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);\n\t\t\tif (dayOfMonth < dayOfMonthBirth) {\n\t\t\t\t//如果生日在当月，但是未达到生日当天的日期，年龄减一\n\t\t\t\tage--;\n\t\t\t}\n\t\t} else if (month < monthBirth){\n\t\t\t//如果当前月份未达到生日的月份，年龄计算减一\n\t\t\tage--;\n\t\t}\n\n\t\treturn age;\n\t}\n\n\t/**\n\t * 计时器<br>\n\t * 计算某个过程话费的时间，精确到毫秒\n\t * \n\t * @author Looly\n\t *\n\t */\n\tpublic static class Timer {\n\t\tprivate long time;\n\t\tprivate boolean isNano;\n\n\t\tpublic Timer() {\n\t\t\tthis(false);\n\t\t}\n\n\t\tpublic Timer(boolean isNano) {\n\t\t\tthis.isNano = isNano;\n\t\t\tstart();\n\t\t}\n\n\t\t/**\n\t\t * @return 开始计时并返回当前时间\n\t\t */\n\t\tpublic long start() {\n\t\t\ttime = current(isNano);\n\t\t\treturn time;\n\t\t}\n\n\t\t/**\n\t\t * @return 重新计时并返回从开始到当前的持续时间\n\t\t */\n\t\tpublic long durationRestart() {\n\t\t\tlong now = current(isNano);\n\t\t\tlong d = now - time;\n\t\t\ttime = now;\n\t\t\treturn d;\n\t\t}\n\n\t\t/**\n\t\t * @return 从开始到当前的持续时间\n\t\t */\n\t\tpublic long duration() {\n\t\t\treturn current(isNano) - time;\n\t\t}\n\t}\n\n\t// ------------------------------------------------------------------------ Private method start\n\t/**\n\t * 获得指定日期年份和季节<br>\n\t * 格式：[20131]表示2013年第一季度\n\t * \n\t * @param cal 日期\n\t */\n\tprivate static String yearAndSeason(Calendar cal) {\n\t\treturn new StringBuilder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString();\n\t}\n\t// ------------------------------------------------------------------------ Private method end\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/DateUtil.java",
    "content": "/**\n * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.utils;\n\n\nimport org.apache.commons.lang3.time.DateFormatUtils;\n\nimport java.sql.Timestamp;\nimport java.text.DateFormat;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class DateUtil {\n\n\n\tprivate static final Object lock = new Object();\n\n\tprivate static final Map<String, ThreadLocal<SimpleDateFormat>> pool = new HashMap<String, ThreadLocal<SimpleDateFormat>>();\n\t/**\n\t * 获取YYYY格式\n\t *\n\t * @return\n\t */\n\tpublic static String getYear() {\n\t\treturn formatDate(new Date(), \"yyyy\");\n\t}\n\n\t/**\n\t * 获取YYYY格式\n\t *\n\t * @return\n\t */\n\tpublic static String getYear(Date date) {\n\t\treturn formatDate(date, \"yyyy\");\n\t}\n\n\t/**\n\t * 获取YYYY-MM-DD格式\n\t *\n\t * @return\n\t */\n\tpublic static String getDay() {\n\t\treturn formatDate(new Date(), \"yyyy-MM-dd\");\n\t}\n\n\t/**\n\t * 获取YYYY-MM-DD格式\n\t *\n\t * @return\n\t */\n\tpublic static String getDay(Date date) {\n\t\treturn formatDate(date, \"yyyy-MM-dd\");\n\t}\n\n\t/**\n\t * 获取YYYYMMDD格式\n\t *\n\t * @return\n\t */\n\tpublic static String getDays() {\n\t\treturn formatDate(new Date(), \"yyyyMMdd\");\n\t}\n\n\t/**\n\t * 获取YYYYMMDD格式\n\t *\n\t * @return\n\t */\n\tpublic static String getDays(Date date) {\n\t\treturn formatDate(date, \"yyyyMMdd\");\n\t}\n\n\t/**\n\t * 获取YYYY-MM-DD HH:mm:ss格式\n\t *\n\t * @return\n\t */\n\tpublic static String getTime() {\n\t\treturn formatDate(new Date(), \"yyyy-MM-dd HH:mm:ss\");\n\t}\n\n\t/**\n\t * 获取YYYY-MM-DD HH:mm:ss.SSS格式\n\t *\n\t * @return\n\t */\n\tpublic static String getMsTime() {\n\t\treturn formatDate(new Date(), \"yyyy-MM-dd HH:mm:ss.SSS\");\n\t}\n\n\t/**\n\t * 获取YYYYMMDDHHmmss格式\n\t *\n\t * @return\n\t */\n\tpublic static String getAllTime() {\n\t\treturn formatDate(new Date(), \"yyyyMMddHHmmss\");\n\t}\n\n\t/**\n\t * 获取YYYY-MM-DD HH:mm:ss格式\n\t *\n\t * @return\n\t */\n\tpublic static String getTime(Date date) {\n\t\treturn formatDate(date, \"yyyy-MM-dd HH:mm:ss\");\n\t}\n\n\tpublic static String formatDate(Date date, String pattern) {\n\t\tString formatDate = null;\n\t\tif (StringUtils.isNotEmpty(pattern)) {\n\t\t\tformatDate = DateFormatUtils.format(date, pattern);\n\t\t} else {\n\t\t\tformatDate = DateFormatUtils.format(date, \"yyyy-MM-dd\");\n\t\t}\n\t\treturn formatDate;\n\t}\n\n\t/**\n\t * @Title: compareDate\n\t * @Description:(日期比较，如果s>=e 返回true 否则返回false)\n\t * @param s\n\t * @param e\n\t * @return boolean\n\t * @throws\n\t * @author luguosui\n\t */\n\tpublic static boolean compareDate(String s, String e) {\n\t\tif (parseDate(s) == null || parseDate(e) == null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn parseDate(s).getTime() >= parseDate(e).getTime();\n\t}\n\n\t/**\n\t * 格式化日期\n\t *\n\t * @return\n\t */\n\tpublic static Date parseDate(String date) {\n\t\treturn parse(date,\"yyyy-MM-dd\");\n\t}\n\n\t/**\n\t * 格式化日期\n\t *\n\t * @return\n\t */\n\tpublic static Date parseTime(String date) {\n\t\treturn parse(date,\"yyyy-MM-dd HH:mm:ss\");\n\t}\n\n\t/**\n\t * 格式化日期\n\t *\n\t * @return\n\t */\n\tpublic static Date parse(String date, String pattern) {\n\t\tif (StringUtils.isNotEmpty(date)) {\n\t\t\tif (pattern == null || \"\".equals(pattern)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tDateFormat format = getDFormat(pattern);\n\t\t\ttry {\n\t\t\t\treturn format.parse(date);\n\t\t\t} catch (ParseException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\tpublic static SimpleDateFormat getDFormat(String pattern) {\n\t\tThreadLocal<SimpleDateFormat> tl = pool.get(pattern);\n\t\tif (tl == null) {\n\t\t\tsynchronized (lock) {\n\t\t\t\ttl = pool.get(pattern);\n\t\t\t\tif (tl == null) {\n\t\t\t\t\tfinal String p = pattern;\n\t\t\t\t\ttl = new ThreadLocal<SimpleDateFormat>() {\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tprotected synchronized SimpleDateFormat initialValue() {\n\t\t\t\t\t\t\treturn new SimpleDateFormat(p);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\tpool.put(p, tl);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn tl.get();\n\t}\n\n\t/**\n\t * 格式化日期\n\t *\n\t * @return\n\t */\n\tpublic static String format(Date date, String pattern) {\n\t\treturn DateFormatUtils.format(date, pattern);\n\t}\n\n\t/**\n\t * 把日期转换为Timestamp\n\t *\n\t * @param date\n\t * @return\n\t */\n\tpublic static Timestamp format(Date date) {\n\t\treturn new Timestamp(date.getTime());\n\t}\n\n\t/**\n\t * 校验日期是否合法\n\t *\n\t * @return\n\t */\n\tpublic static boolean isValidDate(String s) {\n\t\treturn parse(s, \"yyyy-MM-dd HH:mm:ss\") != null;\n\t}\n\n\t/**\n\t * 校验日期是否合法\n\t *\n\t * @return\n\t */\n\tpublic static boolean isValidDate(String s, String pattern) {\n        return parse(s, pattern) != null;\n\t}\n\n\tpublic static int getDiffYear(String startTime, String endTime) {\n\t\tDateFormat fmt = new SimpleDateFormat(\"yyyy-MM-dd\");\n\t\ttry {\n\t\t\tint years = (int) (((fmt.parse(endTime).getTime() - fmt.parse(\n\t\t\t\t\tstartTime).getTime()) / (1000 * 60 * 60 * 24)) / 365);\n\t\t\treturn years;\n\t\t} catch (Exception e) {\n\t\t\t// 如果throw java.text.ParseException或者NullPointerException，就说明格式不对\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/**\n\t * <li>功能描述：时间相减得到天数\n\t *\n\t * @param beginDateStr\n\t * @param endDateStr\n\t * @return long\n\t * @author Administrator\n\t */\n\tpublic static long getDaySub(String beginDateStr, String endDateStr) {\n\t\tlong day = 0;\n\t\tSimpleDateFormat format = new SimpleDateFormat(\n\t\t\t\t\"yyyy-MM-dd\");\n\t\tDate beginDate = null;\n\t\tDate endDate = null;\n\n\t\ttry {\n\t\t\tbeginDate = format.parse(beginDateStr);\n\t\t\tendDate = format.parse(endDateStr);\n\t\t} catch (ParseException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\t\tday = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);\n\t\t// System.out.println(\"相隔的天数=\"+day);\n\n\t\treturn day;\n\t}\n\n\t/**\n\t * 得到n天之后的日期\n\t *\n\t * @param days\n\t * @return\n\t */\n\tpublic static String getAfterDayDate(String days) {\n\t\tint daysInt = Integer.parseInt(days);\n\n\t\tCalendar canlendar = Calendar.getInstance(); // java.util包\n\t\tcanlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动\n\t\tDate date = canlendar.getTime();\n\n\t\tSimpleDateFormat sdfd = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n\t\tString dateStr = sdfd.format(date);\n\n\t\treturn dateStr;\n\t}\n\n\t/**\n\t * 得到n天之后是周几\n\t *\n\t * @param days\n\t * @return\n\t */\n\tpublic static String getAfterDayWeek(String days) {\n\t\tint daysInt = Integer.parseInt(days);\n\n\t\tCalendar canlendar = Calendar.getInstance(); // java.util包\n\t\tcanlendar.add(Calendar.DATE, daysInt); // 日期减 如果不够减会将月变动\n\t\tDate date = canlendar.getTime();\n\n\t\tSimpleDateFormat sdf = new SimpleDateFormat(\"E\");\n\t\tString dateStr = sdf.format(date);\n\n\t\treturn dateStr;\n\t}\n\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(getTime(new Date()));\n\t\tSystem.out.println(getAfterDayWeek(\"3\"));\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/HexKit.java",
    "content": "package cn.enilu.material.utils;\n\nimport java.nio.charset.Charset;\n\n/**\n * 十六进制（简写为hex或下标16）在数学中是一种逢16进1的进位制，一般用数字0到9和字母A到F表示（其中:A~F即10~15）。<br>\n * 例如十进制数57，在二进制写作111001，在16进制写作39。<br>\n * 像java,c这样的语言为了区分十六进制和十进制数值,会在十六进制数的前面加上 0x,比如0x20是十进制的32,而不是十进制的20<br>\n * \n * 参考：https://my.oschina.net/xinxingegeya/blog/287476\n * \n * @author Looly\n *\n */\npublic class HexKit {\n\n\t/**\n\t * 用于建立十六进制字符的输出的小写字符数组\n\t */\n\tprivate static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n\t/**\n\t * 用于建立十六进制字符的输出的大写字符数组\n\t */\n\tprivate static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n\n\t//---------------------------------------------------------------------------------------------------- encode\n\t/**\n\t * 将字节数组转换为十六进制字符数组\n\t *\n\t * @param data byte[]\n\t * @return 十六进制char[]\n\t */\n\tpublic static char[] encodeHex(byte[] data) {\n\t\treturn encodeHex(data, true);\n\t}\n\t\n\t/**\n\t * 将字节数组转换为十六进制字符数组\n\t *\n\t * @param str 字符串\n\t * @param charset 编码\n\t * @return 十六进制char[]\n\t */\n\tpublic static char[] encodeHex(String str, Charset charset) {\n\t\treturn encodeHex(StrKit.getBytes(str, charset), true);\n\t}\n\n\t/**\n\t * 将字节数组转换为十六进制字符数组\n\t *\n\t * @param data byte[]\n\t * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式\n\t * @return 十六进制char[]\n\t */\n\tpublic static char[] encodeHex(byte[] data, boolean toLowerCase) {\n\t\treturn encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);\n\t}\n\n\t/**\n\t * 将字节数组转换为十六进制字符串\n\t *\n\t * @param data byte[]\n\t * @return 十六进制String\n\t */\n\tpublic static String encodeHexStr(byte[] data) {\n\t\treturn encodeHexStr(data, true);\n\t}\n\n\t/**\n\t * 将字节数组转换为十六进制字符串\n\t *\n\t * @param data byte[]\n\t * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式\n\t * @return 十六进制String\n\t */\n\tpublic static String encodeHexStr(byte[] data, boolean toLowerCase) {\n\t\treturn encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);\n\t}\n\t\n\t//---------------------------------------------------------------------------------------------------- decode\n\t/**\n\t * 将十六进制字符数组转换为字符串\n\t *\n\t * @param hexStr 十六进制String\n\t * @param charset 编码\n\t * @return 字符串\n\t */\n\tpublic static String decodeHexStr(String hexStr, Charset charset) {\n\t\tif(StrKit.isEmpty(hexStr)){\n\t\t\treturn hexStr;\n\t\t}\n\t\treturn decodeHexStr(hexStr.toCharArray(), charset);\n\t}\n\t\n\t/**\n\t * 将十六进制字符数组转换为字符串\n\t *\n\t * @param hexData 十六进制char[]\n\t * @param charset 编码\n\t * @return 字符串\n\t */\n\tpublic static String decodeHexStr(char[] hexData, Charset charset) {\n\t\treturn StrKit.str(decodeHex(hexData), charset);\n\t}\n\n\t/**\n\t * 将十六进制字符数组转换为字节数组\n\t *\n\t * @param hexData 十六进制char[]\n\t * @return byte[]\n\t * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度，将抛出运行时异常\n\t */\n\tpublic static byte[] decodeHex(char[] hexData) {\n\n\t\tint len = hexData.length;\n\n\t\tif ((len & 0x01) != 0) {\n\t\t\tthrow new RuntimeException(\"Odd number of characters.\");\n\t\t}\n\n\t\tbyte[] out = new byte[len >> 1];\n\n\t\t// two characters form the hex value.\n\t\tfor (int i = 0, j = 0; j < len; i++) {\n\t\t\tint f = toDigit(hexData[j], j) << 4;\n\t\t\tj++;\n\t\t\tf = f | toDigit(hexData[j], j);\n\t\t\tj++;\n\t\t\tout[i] = (byte) (f & 0xFF);\n\t\t}\n\n\t\treturn out;\n\t}\n\t\n\t//---------------------------------------------------------------------------------------- Private method start\n\t/**\n\t * 将字节数组转换为十六进制字符串\n\t *\n\t * @param data byte[]\n\t * @param toDigits 用于控制输出的char[]\n\t * @return 十六进制String\n\t */\n\tprivate static String encodeHexStr(byte[] data, char[] toDigits) {\n\t\treturn new String(encodeHex(data, toDigits));\n\t}\n\t\n\t/**\n\t * 将字节数组转换为十六进制字符数组\n\t *\n\t * @param data byte[]\n\t * @param toDigits 用于控制输出的char[]\n\t * @return 十六进制char[]\n\t */\n\tprivate static char[] encodeHex(byte[] data, char[] toDigits) {\n\t\tint l = data.length;\n\t\tchar[] out = new char[l << 1];\n\t\t// two characters form the hex value.\n\t\tfor (int i = 0, j = 0; i < l; i++) {\n\t\t\tout[j++] = toDigits[(0xF0 & data[i]) >>> 4];\n\t\t\tout[j++] = toDigits[0x0F & data[i]];\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * 将十六进制字符转换成一个整数\n\t *\n\t * @param ch 十六进制char\n\t * @param index 十六进制字符在字符数组中的位置\n\t * @return 一个整数\n\t * @throws RuntimeException 当ch不是一个合法的十六进制字符时，抛出运行时异常\n\t */\n\tprivate static int toDigit(char ch, int index) {\n\t\tint digit = Character.digit(ch, 16);\n\t\tif (digit == -1) {\n\t\t\tthrow new RuntimeException(\"Illegal hexadecimal character \" + ch + \" at index \" + index);\n\t\t}\n\t\treturn digit;\n\t}\n\t//---------------------------------------------------------------------------------------- Private method end\n\t\n\t\n\t\n\t/**\n\t * 2进制转16进制\n\t * @param bString 2进制字符串\n\t * @return\n\t */\n\tpublic static String binary2Hex(String bString) {\n\t\tif (bString == null || bString.equals(\"\") || bString.length() % 8 != 0)\n\t\t\treturn null;\n\t\tStringBuffer tmp = new StringBuffer();\n\t\tint iTmp = 0;\n\t\tfor (int i = 0; i < bString.length(); i += 4) {\n\t\t\tiTmp = 0;\n\t\t\tfor (int j = 0; j < 4; j++) {\n\t\t\t\tiTmp += Integer.parseInt(bString.substring(i + j, i + j + 1)) << (4 - j - 1);\n\t\t\t}\n\t\t\ttmp.append(Integer.toHexString(iTmp));\n\t\t}\n\t\treturn tmp.toString();\n\t}\n\n\t/**\n\t * 16进制转2进制\n\t * @param hexString\n\t * @return\n\t */\n\tpublic static String hex2Binary(String hexString) {\n\t\tif (hexString == null || hexString.length() % 2 != 0)\n\t\t\treturn null;\n\t\tString bString = \"\", tmp;\n\t\tfor (int i = 0; i < hexString.length(); i++) {\n\t\t\ttmp = \"0000\" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16));\n\t\t\tbString += tmp.substring(tmp.length() - 4);\n\t\t}\n\t\treturn bString;\n\t}\n\n\t/**\n\t * 将二进制转换成16进制\n\t * @param buf\n\t * @return\n\t */\n\tpublic static String binary2Hex(byte buf[]) {\n\t\tStringBuffer sb = new StringBuffer();\n\t\tfor (int i = 0; i < buf.length; i++) {\n\t\t\tString hex = Integer.toHexString(buf[i] & 0xFF);\n\t\t\tif (hex.length() == 1) {\n\t\t\t\thex = '0' + hex;\n\t\t\t}\n\t\t\tsb.append(hex.toUpperCase());\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将16进制转换为二进制\n\t * @param hexStr\n\t * @return\n\t */\n\tpublic static byte[] hex2Byte(String hexStr) {\n\t\tif (hexStr.length() < 1)\n\t\t\treturn null;\n\t\tbyte[] result = new byte[hexStr.length() / 2];\n\t\tfor (int i = 0; i < hexStr.length() / 2; i++) {\n\t\t\tint high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);\n\t\t\tint low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);\n\t\t\tresult[i] = (byte) (high * 16 + low);\n\t\t}\n\t\treturn result;\n\t}\n\t\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/HttpKit.java",
    "content": "/**\n * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.utils;\n\nimport org.springframework.web.context.request.RequestContextHolder;\nimport org.springframework.web.context.request.ServletRequestAttributes;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.*;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.net.URLConnection;\nimport java.util.Enumeration;\nimport java.net.URLEncoder;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class HttpKit {\n\n    public static String getIp(){\n       return HttpKit.getRequest().getRemoteHost();\n    }\n\n    /**\n     * 获取所有请求的值\n     */\n    public static Map<String, String> getRequestParameters() {\n        HashMap<String, String> values = new HashMap<>();\n        HttpServletRequest request = HttpKit.getRequest();\n        Enumeration enums = request.getParameterNames();\n        while ( enums.hasMoreElements()){\n            String paramName = (String) enums.nextElement();\n            String paramValue = request.getParameter(paramName);\n            values.put(paramName, paramValue);\n        }\n        return values;\n    }\n\n    /**\n     * 获取 HttpServletRequest\n     */\n    public static HttpServletResponse getResponse() {\n        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();\n        return response;\n    }\n\n    /**\n     * 获取 包装防Xss Sql注入的 HttpServletRequest\n     * @return request\n     */\n    public static HttpServletRequest getRequest() {\n        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();\n        return new WafRequestWrapper(request);\n    }\n    public static  String getToken(){\n        return  getRequest().getHeader(\"Authorization\");\n    }\n\n    /**\n     * 向指定URL发送GET方法的请求\n     *\n     * @param url 发送请求的URL\n     * @param param 请求参数\n     * @return URL 所代表远程资源的响应结果\n     */\n    public static String sendGet(String url, Map<String, String> param) {\n        String result = \"\";\n        BufferedReader in = null;\n        try {\n            StringBuffer query = new StringBuffer();\n\n            for (Map.Entry<String, String> kv : param.entrySet()) {\n                query.append(URLEncoder.encode(kv.getKey(), \"UTF-8\") + \"=\");\n                query.append(URLEncoder.encode(kv.getValue(), \"UTF-8\") + \"&\");\n            }\n            if (query.lastIndexOf(\"&\") > 0) {\n                query.deleteCharAt(query.length() - 1);\n            }\n\n            String urlNameString = url + \"?\" + query.toString();\n            URL realUrl = new URL(urlNameString);\n            // 打开和URL之间的连接\n            URLConnection connection = realUrl.openConnection();\n            // 设置通用的请求属性\n            connection.setRequestProperty(\"accept\", \"*/*\");\n            connection.setRequestProperty(\"connection\", \"Keep-Alive\");\n            connection.setRequestProperty(\"user-agent\", \"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)\");\n            // 建立实际的连接\n            connection.connect();\n            // 获取所有响应头字段\n            Map<String, List<String>> map = connection.getHeaderFields();\n            // 遍历所有的响应头字段\n            for (String key : map.keySet()) {\n                System.out.println(key + \"--->\" + map.get(key));\n            }\n            // 定义 BufferedReader输入流来读取URL的响应\n            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));\n            String line;\n            while ((line = in.readLine()) != null) {\n                result += line;\n            }\n        } catch (Exception e) {\n            System.out.println(\"发送GET请求出现异常！\" + e);\n            e.printStackTrace();\n        }\n        // 使用finally块来关闭输入流\n        finally {\n            try {\n                if (in != null) {\n                    in.close();\n                }\n            } catch (Exception e2) {\n                e2.printStackTrace();\n            }\n        }\n        return result;\n    }\n\n    /**\n     * 向指定 URL 发送POST方法的请求\n     *\n     * @param url 发送请求的 URL\n     * @param param  请求参数\n     * @return 所代表远程资源的响应结果\n     */\n    public static String sendPost(String url, Map<String, String> param) {\n        PrintWriter out = null;\n        BufferedReader in = null;\n        String result = \"\";\n        try {\n            String para = \"\";\n            for (String key : param.keySet()) {\n                para += (key + \"=\" + param.get(key) + \"&\");\n            }\n            if (para.lastIndexOf(\"&\") > 0) {\n                para = para.substring(0, para.length() - 1);\n            }\n            String urlNameString = url + \"?\" + para;\n            URL realUrl = new URL(urlNameString);\n            // 打开和URL之间的连接\n            HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();\n            // 设置通用的请求属性\n            conn.setRequestProperty(\"accept\", \"*/*\");\n            conn.setRequestProperty(\"connection\", \"Keep-Alive\");\n            conn.setRequestProperty(\"user-agent\", \"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)\");\n            // 发送POST请求必须设置如下两行\n            conn.setDoOutput(true);\n            conn.setDoInput(true);\n            // 获取URLConnection对象对应的输出流\n            out = new PrintWriter(conn.getOutputStream());\n            // 发送请求参数\n            out.print(param);\n            // flush输出流的缓冲\n            out.flush();\n            int status = conn.getResponseCode();\n            InputStream inputStream = null;\n            if (status != HttpURLConnection.HTTP_OK){\n                inputStream = conn.getErrorStream();\n            }else{\n                inputStream = conn.getInputStream();\n            }\n            // 定义 BufferedReader输入流来读取URL的响应\n            in = new BufferedReader(new InputStreamReader(inputStream));\n            String line;\n            while ((line = in.readLine()) != null) {\n                result += line;\n            }\n        } catch (Exception e) {\n            System.out.println(\"发送 POST 请求出现异常！\" + e);\n            e.printStackTrace();\n        }\n        // 使用finally块来关闭输出流、输入流\n        finally {\n            try {\n                if (out != null) {\n                    out.close();\n                }\n                if (in != null) {\n                    in.close();\n                }\n            } catch (IOException ex) {\n                ex.printStackTrace();\n            }\n        }\n        return result;\n    }\n\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/Lists.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport net.sf.ehcache.hibernate.management.impl.BeanUtils;\n\nimport java.util.*;\n\n/**\n * 集合工具类\n *\n * @author enilu\n */\npublic final class Lists {\n\n    private Lists() {\n    }\n\n\n    /**\n     * 碾平集合咯，主要针对集合元素为集合的情况有效果\n     *\n     * @param list\n     * @param <T>\n     * @return\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> List<T> flatten(List<?> list) {\n        List<T> result = new ArrayList<T>();\n        for (Object o : list) {\n            if (o instanceof List) {\n                List<T> subResult = flatten((List<?>) o);\n                result.addAll(subResult);\n            } else {\n                result.add((T) o);\n            }\n        }\n        return result;\n    }\n\n    /**\n     * 压缩集合，去掉集合中的null记录\n     *\n     * @param list\n     * @param <T>\n     * @return\n     */\n    public static <T> List<T> compact(List<T> list) {\n        List<T> result = new ArrayList<T>();\n        for (T t : list) {\n            if (t != null) {\n                result.add(t);\n            }\n        }\n        return result;\n    }\n\n    /**\n     * 提取集合中指定属性值\n     *\n     * @param list\n     * @param property\n     * @param <T>\n     * @param <R>\n     * @return\n     */\n    public static <T, R> List<R> map(List<T> list, String property) {\n        List<R> result = new ArrayList<R>();\n        for (T t : list) {\n\n            try {\n                R r = (R) getProperty(t, property);\n                result.add(r);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n\n        }\n        return result;\n    }\n\n    /**\n     * 将集合转换为map\n     *\n     * @param list\n     * @param keyProperty\n     * @param <K>\n     * @param <V>\n     * @return\n     */\n    public static <K, V> Map<K, V> toMap(List<V> list, String keyProperty) {\n        Map<K, V> map = new HashMap<K, V>();\n        for (V v : list) {\n\n            try {\n                K k = (K) getProperty(v, keyProperty);\n                map.put(k, v);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n\n        }\n        return map;\n    }\n\n    /**\n     * 移除与value不想等的值，原集合不发生变化\n     *\n     * @param list\n     * @param property\n     * @param value\n     * @param <T>\n     * @return\n     */\n    public static <T> List<T> filter(List<T> list, String property, Object value) {\n        List<T> result = new ArrayList<T>();\n        for (T t : list) {\n            try {\n                Object v = getProperty(t, property);\n                if ((v == null && value == null) || (v != null && v.equals(value))) {\n                    result.add(t);\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n\n        }\n        return result;\n    }\n\n    /**\n     * 移除与value相等的值, 原数组不发生变化.\n     *\n     * @param list\n     * @param value\n     * @return\n     */\n    public static <T> List<T> without(List<T> list, T value) {\n        List<T> result = new ArrayList<T>();\n        for (T t : list) {\n            if ((value == null && t == null)\n                    || (value != null && value.equals(t))) {\n                continue;\n            }\n            result.add(t);\n        }\n        return result;\n    }\n\n    /**\n     * 对集合去重，原集合不发生变化\n     *\n     * @param input\n     * @param <T>\n     * @return\n     */\n    public static <T> List<T> uniq(List<T> input) {\n        LinkedHashMap<T, T> map = new LinkedHashMap<>();\n        for (T t : input) {\n            map.put(t, t);\n        }\n        return new ArrayList<T>(map.values());\n    }\n\n    /**\n     * 按照给定的集合（keys）进行排序\n     *\n     * @param input       要排序的集合\n     * @param keyProperty 排序的属性\n     * @param keys        给定的键值集合\n     * @param <K>\n     * @param <T>\n     * @return\n     */\n    public static <K, T> List<T> sortBy(List<T> input, String keyProperty,\n                                        List<K> keys) {\n        if (input.isEmpty()) {\n            return new ArrayList();\n        }\n\n        Map<K, T> map = toMap(input, keyProperty);\n        List<T> result = new ArrayList<T>();\n        for (K k : keys) {\n            T t = map.get(k);\n            if (t != null) {\n                result.add(t);\n            }\n        }\n        return result;\n    }\n\n    /**\n     * 对集合进行分组\n     *\n     * @param input\n     * @param keyProperty\n     * @param <K>\n     * @param <V>\n     * @return\n     */\n    public static <K, V> Map<K, List<V>> group(List<V> input, String keyProperty) {\n        Map<K, List<V>> result = new HashMap<>();\n\n        for (V v : input) {\n\n            try {\n                K k = (K) getProperty(v, keyProperty);\n                List<V> list = result.get(k);\n                if (list == null) {\n                    list = new ArrayList<>();\n                    result.put(k, list);\n                }\n                list.add(v);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n\n        }\n\n        return result;\n    }\n\n    /**\n     * 将数组按n个一份拆分.\n     *\n     * @param <T>\n     * @param input\n     * @param n\n     * @return\n     */\n    public static <T> List<List<T>> group(List<T> input, int n) {\n        if (n <= 0) {\n            throw new IllegalArgumentException(\"n must > 0\");\n        }\n\n        int size = input.size();\n        int m = (size + n - 1) / n;\n        List<List<T>> result = new ArrayList<>(m);\n        for (int i = 0; i < m; i++) {\n            List<T> items = new ArrayList(n);\n            int end = i < m - 1 ? n : size - i * n;\n            for (int j = 0; j < end; j++) {\n                items.add(input.get(i * n + j));\n            }\n            result.add(items);\n        }\n        return result;\n    }\n\n\n\n    public static boolean containAny(Set parent, Set child) {\n        if (parent == null || child == null) {\n            return false;\n        }\n        Iterator iter = child.iterator();\n        while (iter.hasNext()) {\n            return parent.contains(iter.next());\n        }\n        return false;\n    }\n\n    public static <V> List<V> newArrayList(V... vs) {\n        List<V> list = new ArrayList<V>();\n        for (V v : vs) {\n            list.add(v);\n        }\n        return list;\n    }\n\n    private static Object getProperty(Object bean,String name){\n        return BeanUtils.getBeanProperty(bean,name);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/Log.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\n/**\n * @author deanyule\n */\npublic class Log {\n\n    public static Logger get(Class<?> clazz) {\n        return LoggerFactory.getLogger(clazz);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/MD5.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport com.google.common.base.Strings;\nimport org.apache.commons.io.IOUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\n\n/**\n * MD5加密工具类\n */\npublic class MD5 {\n\n\tpublic static final Logger LOG = LoggerFactory.getLogger(MD5.class);\n\n\t/**\n\t * 16进制字符集\n\t */\n\tprivate static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\n\t/**\n\t * 循环次数\n\t */\n\tpublic final static int HASH_ITERATIONS = 1024;\n\t/**\n\t * 加盐参数\n\t */\n\tpublic final static String HASH_ALGORITHM_NAME = \"MD5\";\n\n\n\t/**\n\t * * MD5加密字符串\n\t *\n\t * @param str 目标字符串\n\t * @return MD5加密后的字符串\n\t */\n\n\tpublic static String getMD5String(String str) {\n\t\tif (Strings.isNullOrEmpty(str)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn getMD5String(str.getBytes());\n\t}\n\n\t/**\n\t * * MD5加密以byte数组表示的字符串\n\t *\n\t * @param bytes 目标byte数组\n\t * @return MD5加密后的字符串\n\t */\n\n\tpublic static String getMD5String(byte[] bytes) {\n\t\ttry {\n\t\t\tMessageDigest MESSAGE_DIGEST = MessageDigest.getInstance(HASH_ALGORITHM_NAME);\n\t\t\tMESSAGE_DIGEST.update(bytes);\n\t\t\treturn bytesToHex(MESSAGE_DIGEST.digest());\n\t\t}catch (Exception e){\n\t\t\tLOG.error(e.getMessage(), e);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * 获取文件的MD5值\n\t *\n\t * @param file 目标文件\n\t * @return MD5字符串\n\t */\n\tpublic static String getFileMD5String(File file) {\n\t\tString ret = \"\";\n\t\tFileInputStream in = null;\n\t\tFileChannel ch = null;\n\t\ttry {\n\t\t\tMessageDigest MESSAGE_DIGEST = MessageDigest.getInstance(HASH_ALGORITHM_NAME);\n\t\t\tin = new FileInputStream(file);\n\t\t\tch = in.getChannel();\n\t\t\tByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length());\n\t\t\tMESSAGE_DIGEST.update(byteBuffer);\n\t\t\tret = bytesToHex(MESSAGE_DIGEST.digest());\n\t\t} catch (Exception e) {\n\t\t\tLOG.error(e.getMessage(), e);\n\t\t} finally {\n\t\t\tIOUtils.closeQuietly(in);\n\t\t\tIOUtils.closeQuietly(ch);\n\t\t}\n\t\treturn ret;\n\t}\n\n\t/**\n\t * * 获取文件的MD5值\n\t *\n\t * @param fileName 目标文件的完整名称\n\t * @return MD5字符串\n\t */\n\tpublic static String getFileMD5String(String fileName) {\n\t\treturn getFileMD5String(new File(fileName));\n\t}\n\n\n\t/**\n\t * * 将字节数组转换成16进制字符串\n\t *\n\t * @param bytes 目标字节数组\n\t * @return 转换结果\n\t */\n\tpublic static String bytesToHex(byte[] bytes) {\n\t\treturn bytesToHex(bytes, 0, bytes.length);\n\t}\n\n\t/**\n\t * * 将字节数组中指定区间的子数组转换成16进制字符串\n\t *\n\t * @param bytes 目标字节数组\n\t * @param start 起始位置（包括该位置）\n\t * @param end   结束位置（不包括该位置）\n\t * @return 转换结果\n\t */\n\tpublic static String bytesToHex(byte[] bytes, int start, int end) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tfor (int i = start; i < start + end; i++) {\n\t\t\tsb.append(byteToHex(bytes[i]));\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * * 将单个字节码转换成16进制字符串\n\t *\n\t * @param bt 目标字节\n\t * @return 转换结果\n\t */\n\tpublic static String byteToHex(byte bt) {\n\t\treturn HEX_DIGITS[(bt & 0xf0) >> 4] + \"\" + HEX_DIGITS[bt & 0xf];\n\t}\n\n\n\t/**\n\t * shiro密码加密工具类\n\t *\n\t * @param credentials 密码\n\t * @param salt        密码盐\n\t * @return\n\t */\n\tpublic static String md5(String credentials, String salt) {\n\t\tMessageDigest messageDigest = null;\n\t\ttry {\n\t\t\tmessageDigest = MessageDigest.getInstance(\"MD5\");\n\t\t\tmessageDigest.reset();\n\t\t\t//先加盐\n\t\t\tmessageDigest.update(salt.getBytes(\"UTF-8\"));\n\t\t\t//再放需要被加密的数据\n\t\t\tmessageDigest.update(credentials.getBytes(\"UTF-8\"));\n\t\t} catch (NoSuchAlgorithmException e) {\n\t\t\tSystem.out.println(\"NoSuchAlgorithmException caught!\");\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\te.printStackTrace();\n\t\t}\n\n\t\tbyte[] byteArray = messageDigest.digest();\n\n\t\tStringBuffer md5StrBuff = new StringBuffer();\n\n\t\tfor (int i = 0; i < byteArray.length; i++) {\n\t\t\tif (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {\n\t\t\t\tmd5StrBuff.append(\"0\").append(Integer.toHexString(0xFF & byteArray[i]));\n\t\t\t} else {\n\t\t\t\tmd5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));\n\t\t\t}\n\t\t}\n\n\t\treturn md5StrBuff.toString();\n\t}\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(MD5.md5(\"admin\", \"8pgby\"));\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/Maps.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport java.util.HashMap;\n\n/**\n * Map 工具类\n *\n * @author enilu\n *\n */\npublic final class Maps {\n\n    private Maps() {\n    }\n\n    public static <K, V> HashMap<K, V> newHashMap() {\n        return new HashMap<K, V>();\n    }\n\n    public static <K, V> HashMap<K, V> newHashMap(K k, V v) {\n        HashMap<K, V> map = new HashMap<K, V>();\n        map.put(k, v);\n        return map;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public static <K, V> HashMap<K, V> newHashMap(K k, V v,\n                                                  Object... extraKeyValues) {\n        if (extraKeyValues.length % 2 != 0) {\n            throw new IllegalArgumentException();\n        }\n        HashMap<K, V> map = new HashMap<K, V>();\n        map.put(k, v);\n        for (int i = 0; i < extraKeyValues.length; i += 2) {\n            k = (K) extraKeyValues[i];\n            v = (V) extraKeyValues[i + 1];\n            map.put(k, v);\n        }\n        return map;\n    }\n}"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/MobileUtil.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport com.google.common.base.Strings;\n\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class MobileUtil {\n\tpublic static final Set<String> prefixIds = new HashSet<String>();\n\n    final static Pattern PHONE_START_WITH_ZERO = Pattern.compile(\"^01(3[0-9]|4[579]|5[0-35-9]|7[0135678]|8[0-9])[0-9]{8}$\");\n\n\tstatic {\n\t\tprefixIds.add(\"12590\");\n\t\tprefixIds.add(\"12593\");\n\t\tprefixIds.add(\"17901\");\n\t\tprefixIds.add(\"17911\");\n\t\tprefixIds.add(\"17951\");\n        prefixIds.add(\"10193\");\n\t}\n\n\tpublic enum MobileType {ChinaTelecom, ChinaUnicom, ChinaMobile, UnKnow}\n\n\tfinal static String chinaTelecomRegex = \"(133|153|180|181|189|177|173)\\\\d{8}|1700\\\\d{7}\";\n\tfinal static String chinaUnicomRegex = \"(130|131|132|155|156|145|185|186|176)\\\\d{8}|1709\\\\d{7}\";\n\tfinal static String chinaMobileRegex = \"(13[5-9]|15[0-2|7-9]|18[2-4|7-8]|147|178)\\\\d{8}|(134[0-8]|1705)\\\\d{7}\";\n\n\tpublic static final Pattern P_RULE_1 = Pattern.compile(\"^((10)|(2[1-9])).*\");\n\tpublic static final Pattern P_RULE_2 = Pattern.compile(\"^[3-9].*\");\n\n\tpublic static MobileType type(String mobile) {\n\t\tif (mobile.matches(chinaTelecomRegex)) {\n\t\t\treturn MobileType.ChinaTelecom;\n\t\t} else if (mobile.matches(chinaUnicomRegex)) {\n\t\t\treturn MobileType.ChinaUnicom;\n\t\t} else if (mobile.matches(chinaMobileRegex)) {\n\t\t\treturn MobileType.ChinaMobile;\n\t\t}\n\n\t\treturn MobileType.UnKnow;\n\t}\n\n\tpublic static String cleanPhone(String value) {\n\t\tvalue = strClean(value);\n\n\t\tif (value.startsWith(\"+86\")) {\n\t\t\tvalue = value.substring(3);\n\t\t}\n\n\t\tif (value.length() == 13) {\n\t\t\t// 8613800210500\n\t\t\tif (value.startsWith(\"86\")) {\n\t\t\t\tvalue = value.substring(2);\n\t\t\t}\n\t\t} else if (value.length() >= 14 && value.length() <= 16) {\n\t\t\t// 008613637037976\n\t\t\tif (value.startsWith(\"0086\")) {\n\t\t\t\tvalue = value.substring(4);\n\t\t\t}\n\t\t}\n\n        if (PHONE_START_WITH_ZERO.matcher(value).matches()) {\n            value = value.substring(1);\n\n        }\n\n\t\t// 如果号码是10位，且前2位是10,21,22,23,24,25,26,27,28,29，应该是固话，在第一位补上0\n\t\t// 如果号码是10位，且第1位是3,4,5,6,7,8,9（非400、800开头），应该也是固话，在第一位补上0\n\t\t// 如果号码是11位，且第1位是3,4,5,6,7,8,9，应该也是固话，在第一位补上0\n\t\tif (value.length() == 10) {\n\t\t\tMatcher m = P_RULE_1.matcher(value);\n\t\t\tif (m.find()) {\n\t\t\t\tvalue = \"0\" + value;\n\t\t\t} else {\n\t\t\t\tm = P_RULE_2.matcher(value);\n\t\t\t\tif (m.find()) {\n\t\t\t\t\tif (!value.startsWith(\"400\") && !value.startsWith(\"800\")) {\n\t\t\t\t\t\tvalue = \"0\" + value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (value.length() == 11) {\n\t\t\tMatcher m = P_RULE_2.matcher(value);\n\t\t\tif (m.find()) {\n\t\t\t\tvalue = \"0\" + value;\n\t\t\t}\n\t\t} else if (value.length() == 12) {\n\t\t\tif (value.startsWith(\"01\")) {\n\t\t\t\tvalue = value.substring(1);\n\t\t\t}\n\t\t} else if (value.length() == 16) {\n\t\t\tfor (String id : prefixIds) {\n\t\t\t\tif (value.startsWith(id)) {\n\t\t\t\t\tvalue = value.substring(5);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t}\n\n\tpublic static String strClean(String value) {\n\t\tif (Strings.isNullOrEmpty(value)) {\n\t\t\treturn \"\";\n\t\t}\n\n\t\t// 去除首尾空白字符、全角空格等\n\t\treturn value.trim().replaceAll(\"[\\\\s\\\\u00A0\\\\u3000]+$\", \"\").replaceAll(\"^[\\\\s\\\\u00A0\\\\u3000]+\", \"\");\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/PageKit.java",
    "content": "package cn.enilu.material.utils;\n\n/**\n * 分页工具类\n * \n * @author xiaoleilu\n * \n */\npublic class PageKit {\n\n\t/**\n\t * 将页数和每页条目数转换为开始位置和结束位置<br>\n\t * 此方法用于不包括结束位置的分页方法<br>\n\t * 例如：<br>\n\t * 页码：1，每页10 -> [0, 10]<br>\n\t * 页码：2，每页10 -> [10, 20]<br>\n\t * 。。。<br>\n\t * \n\t * @param pageNo\n\t *            页码（从1计数）\n\t * @param countPerPage\n\t *            每页条目数\n\t * @return 第一个数为开始位置，第二个数为结束位置\n\t */\n\tpublic static int[] transToStartEnd(int pageNo, int countPerPage) {\n\t\tif (pageNo < 1) {\n\t\t\tpageNo = 1;\n\t\t}\n\n\t\tif (countPerPage < 1) {\n\t\t\tcountPerPage = 0;\n//\t\t\tLogKit.warn(\"Count per page  [\" + countPerPage + \"] is not valid!\");\n\t\t}\n\n\t\tint start = (pageNo - 1) * countPerPage;\n\t\tint end = start + countPerPage;\n\n\t\treturn new int[] { start, end };\n\t}\n\n\t/**\n\t * 根据总数计算总页数\n\t * \n\t * @param totalCount\n\t *            总数\n\t * @param numPerPage\n\t *            每页数\n\t * @return 总页数\n\t */\n\tpublic static int totalPage(int totalCount, int numPerPage) {\n\t\tif (numPerPage == 0) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn totalCount % numPerPage == 0 ? (totalCount / numPerPage)\n\t\t\t\t: (totalCount / numPerPage + 1);\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/RSAUtil.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport org.apache.commons.codec.binary.Base64;\n\nimport javax.crypto.Cipher;\nimport java.security.*;\nimport java.security.interfaces.RSAPrivateKey;\nimport java.security.interfaces.RSAPublicKey;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.security.spec.X509EncodedKeySpec;\nimport java.util.HashMap;\nimport java.util.Map;\n\n\n/**\n * 非对称加密算法RSA算法组件\n * 非对称算法一般是用来传送对称加密算法的密钥来使用的，相对于DH算法，RSA算法只需要一方构造密钥，不需要\n * 大费周章的构造各自本地的密钥对了。DH算法只能算法非对称算法的底层实现。而RSA算法算法实现起来较为简单\n *\n * @author mayanyun\n */\npublic class RSAUtil {\n    //非对称密钥算法\n    public static final String KEY_ALGORITHM = \"RSA\";\n\n\n    /**\n     * 密钥长度，DH算法的默认密钥长度是1024\n     * 密钥长度必须是64的倍数，在512到65536位之间\n     */\n    private static final int KEY_SIZE = 512;\n    //公钥\n    private static final String PUBLIC_KEY = \"RSAPublicKey\";\n\n    //私钥\n    private static final String PRIVATE_KEY = \"RSAPrivateKey\";\n\n    /**\n     * 初始化密钥对\n     *\n     * @return Map 甲方密钥的Map\n     */\n    public static Map<String, Object> initKey() throws Exception {\n        //实例化密钥生成器\n        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);\n        //初始化密钥生成器\n        keyPairGenerator.initialize(KEY_SIZE);\n        //生成密钥对\n        KeyPair keyPair = keyPairGenerator.generateKeyPair();\n        //甲方公钥\n        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();\n        //甲方私钥\n        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();\n        //将密钥存储在map中\n        Map<String, Object> keyMap = new HashMap<String, Object>();\n        keyMap.put(PUBLIC_KEY, publicKey);\n        keyMap.put(PRIVATE_KEY, privateKey);\n        return keyMap;\n\n    }\n\n\n    /**\n     * 私钥加密\n     *\n     * @param data 待加密数据\n     * @param key       密钥\n     * @return byte[] 加密数据\n     */\n    public static byte[] encryptByPrivateKey(byte[] data, byte[] key) throws Exception {\n\n        //取得私钥\n        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);\n        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);\n        //生成私钥\n        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);\n        //数据加密\n        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());\n        cipher.init(Cipher.ENCRYPT_MODE, privateKey);\n        return cipher.doFinal(data);\n    }\n\n    /**\n     * 公钥加密\n     *\n     * @param data 待加密数据\n     * @param key       密钥\n     * @return byte[] 加密数据\n     */\n    public static byte[] encryptByPublicKey(byte[] data, byte[] key) throws Exception {\n\n        //实例化密钥工厂\n        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);\n        //初始化公钥\n        //密钥材料转换\n        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);\n        //产生公钥\n        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);\n\n        //数据加密\n        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());\n        cipher.init(Cipher.ENCRYPT_MODE, pubKey);\n        return cipher.doFinal(data);\n    }\n\n    /**\n     * 私钥解密\n     *\n     * @param data 待解密数据\n     * @param key  密钥\n     * @return byte[] 解密数据\n     */\n    public static byte[] decryptByPrivateKey(byte[] data, byte[] key) throws Exception {\n        //取得私钥\n        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);\n        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);\n        //生成私钥\n        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);\n        //数据解密\n        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());\n        cipher.init(Cipher.DECRYPT_MODE, privateKey);\n        return cipher.doFinal(data);\n    }\n\n    /**\n     * 公钥解密\n     *\n     * @param data 待解密数据\n     * @param key  密钥\n     * @return byte[] 解密数据\n     */\n    public static byte[] decryptByPublicKey(byte[] data, byte[] key) throws Exception {\n\n        //实例化密钥工厂\n        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);\n        //初始化公钥\n        //密钥材料转换\n        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);\n        //产生公钥\n        PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);\n        //数据解密\n        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());\n        cipher.init(Cipher.DECRYPT_MODE, pubKey);\n        return cipher.doFinal(data);\n    }\n\n    /**\n     * 取得私钥\n     *\n     * @param keyMap 密钥map\n     * @return byte[] 私钥\n     */\n    public static byte[] getPrivateKey(Map<String, Object> keyMap) {\n        Key key = (Key) keyMap.get(PRIVATE_KEY);\n        return key.getEncoded();\n    }\n\n    /**\n     * 取得公钥\n     *\n     * @param keyMap 密钥map\n     * @return byte[] 公钥\n     */\n    public static byte[] getPublicKey(Map<String, Object> keyMap) throws Exception {\n        Key key = (Key) keyMap.get(PUBLIC_KEY);\n        return key.getEncoded();\n    }\n\n    /**\n     * @param args\n     * @throws Exception\n     */\n    public static void main(String[] args) throws Exception {\n        //初始化密钥\n        //生成密钥对\n        Map<String, Object> keyMap = RSAUtil.initKey();\n        //公钥\n        byte[] publicKey = RSAUtil.getPublicKey(keyMap);\n\n        //私钥\n        byte[] privateKey = RSAUtil.getPrivateKey(keyMap);\n        System.out.println(\"公钥：/n\" + Base64.encodeBase64String(publicKey));\n        System.out.println(\"私钥：/n\" + Base64.encodeBase64String(privateKey));\n\n        System.out.println(\"================密钥对构造完毕,甲方将公钥公布给乙方，开始进行加密数据的传输=============\");\n        String str = \"RSA密码交换算法\";\n        System.out.println(\"/n===========甲方向乙方发送加密数据==============\");\n        System.out.println(\"原文:\" + str);\n        //甲方进行数据的加密\n        byte[] code1 = RSAUtil.encryptByPrivateKey(str.getBytes(), privateKey);\n        System.out.println(\"加密后的数据：\" + Base64.encodeBase64String(code1));\n        System.out.println(\"===========乙方使用甲方提供的公钥对数据进行解密==============\");\n        //乙方进行数据的解密\n        byte[] decode1 = RSAUtil.decryptByPublicKey(code1, publicKey);\n        System.out.println(\"乙方解密后的数据：\" + new String(decode1) + \"/n/n\");\n\n        System.out.println(\"===========反向进行操作，乙方向甲方发送数据==============/n/n\");\n\n        str = \"乙方向甲方发送数据RSA算法\";\n\n        System.out.println(\"原文:\" + str);\n\n        //乙方使用公钥对数据进行加密\n        byte[] code2 = RSAUtil.encryptByPublicKey(str.getBytes(), publicKey);\n        System.out.println(\"===========乙方使用公钥对数据进行加密==============\");\n        System.out.println(\"加密后的数据：\" + Base64.encodeBase64String(code2));\n\n        System.out.println(\"=============乙方将数据传送给甲方======================\");\n        System.out.println(\"===========甲方使用私钥对数据进行解密==============\");\n\n        //甲方使用私钥对数据进行解密\n        byte[] decode2 = RSAUtil.decryptByPrivateKey(code2, privateKey);\n\n        System.out.println(\"甲方解密后的数据：\" + new String(decode2));\n    }\n}"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/RandomUtils.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport java.text.DecimalFormat;\nimport java.util.*;\n\n/**\n * 随机数工具\n */\npublic class RandomUtils {\n\n    private static char[] alpha = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',\n            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};\n\n    private static Random ran;\n\n    static {\n        ran = new Random();\n        ran.setSeed(System.currentTimeMillis());\n    }\n\n    public static char nextChar() {\n        return alpha[Math.abs(ran.nextInt()) % 36];\n    }\n\n    public static String nextChar(int i) {\n        StringBuffer sb = new StringBuffer();\n        for (int j = 0; j < i; j++) {\n            sb.append(nextChar());\n        }\n\n        return sb.toString();\n    }\n\n\n    /**\n     * 产生普通的随机数\n     * fmt: #0.00 数值格式\n     */\n    public static String getNormalRandom(int range, String fmt) {\n        DecimalFormat format = new DecimalFormat(fmt);\n        double randomNum = Math.random() * 20;\n        return format.format(randomNum);\n    }\n\n    /**\n     * 产生指定位数的字符随机字符串\n     */\n    public static String getCharacterRandom(int length) {\n        return getRandom(\"a-z,A-Z\", length);\n    }\n\n    /**\n     * 产生指定位数的数字随机字符串\n     */\n    public static String getNumberRandom(int length) {\n        return getRandom(\"1-9\", length);\n    }\n\n    /**\n     * 产生指定范围和位数的随机字符串\n     * range:a-z,A-Z,0-9\n     */\n    public static String getRandom(String range, int length) {\n        StringBuffer result = new StringBuffer();\n        List<Character> randomRange = new ArrayList<Character>();\n        try {\n            if (range != null && range.trim().length() > 0) {\n                String[] rangeGroup = range.split(\",\");\n                for (String group : rangeGroup) {\n                    String[] charStr = group.split(\"-\");\n                    for (char i = charStr[0].charAt(0); i <= charStr[1].charAt(0); i++) {\n                        randomRange.add(i);\n                    }\n                }\n            }\n            for (int i = 0; i < length; i++) {\n                Object randomObj = randomRange.get(new Random().nextInt(randomRange.size()));\n                result.append(randomObj);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        return result.toString();\n    }\n\n    /**\n     * 产生36位的UUID随机字符串\n     */\n    public static String getUUIDRandom() {\n        return UUID.randomUUID().toString();\n    }\n\n    /**\n     * 产生可定制的时间戳随机字符串\n     */\n    public static String getTimestampRandom(String head, String tail, int tailBit) {\n        return head + DateUtil.getAllTime() + tail + RandomUtils.getNumberRandom(tailBit);\n    }\n\n    public static String randomCode() {\n        String[] beforeShuffle = new String[]{\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\"};\n        List<String> list = Arrays.asList(beforeShuffle);\n        Collections.shuffle(list);\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < list.size(); i++) {\n            sb.append(list.get(i));\n        }\n        String afterShuffle = sb.toString();\n        String result = afterShuffle.substring(5, 9);\n        return result;\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/StrKit.java",
    "content": "package cn.enilu.material.utils;\n\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n/**\n * 字符串工具类\n * \n * @author xiaoleilu\n *\n */\npublic class StrKit {\n\n\tpublic static final String SPACE = \" \";\n\tpublic static final String DOT = \".\";\n\tpublic static final String SLASH = \"/\";\n\tpublic static final String BACKSLASH = \"\\\\\";\n\tpublic static final String EMPTY = \"\";\n\tpublic static final String CRLF = \"\\r\\n\";\n\tpublic static final String NEWLINE = \"\\n\";\n\tpublic static final String UNDERLINE = \"_\";\n\tpublic static final String COMMA = \",\";\n\n\tpublic static final String HTML_NBSP = \"&nbsp;\";\n\tpublic static final String HTML_AMP = \"&amp\";\n\tpublic static final String HTML_QUOTE = \"&quot;\";\n\tpublic static final String HTML_LT = \"&lt;\";\n\tpublic static final String HTML_GT = \"&gt;\";\n\n\tpublic static final String EMPTY_JSON = \"{}\";\n\n\n\t/**\n\t * 首字母变小写\n\t */\n\tpublic static String firstCharToLowerCase(String str) {\n\t\tchar firstChar = str.charAt(0);\n\t\tif (firstChar >= 'A' && firstChar <= 'Z') {\n\t\t\tchar[] arr = str.toCharArray();\n\t\t\tarr[0] += ('a' - 'A');\n\t\t\treturn new String(arr);\n\t\t}\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 首字母变大写\n\t */\n\tpublic static String firstCharToUpperCase(String str) {\n\t\tchar firstChar = str.charAt(0);\n\t\tif (firstChar >= 'a' && firstChar <= 'z') {\n\t\t\tchar[] arr = str.toCharArray();\n\t\t\tarr[0] -= ('a' - 'A');\n\t\t\treturn new String(arr);\n\t\t}\n\t\treturn str;\n\t}\n\n\t// ------------------------------------------------------------------------ Blank\n\t/**\n\t * 字符串是否为空白 空白的定义如下： <br>\n\t * 1、为null <br>\n\t * 2、为不可见字符（如空格）<br>\n\t * 3、\"\"<br>\n\t * \n\t * @param str 被检测的字符串\n\t * @return 是否为空\n\t */\n\tpublic static boolean isBlank(String str) {\n\t\tint length;\n\t\tif ((str == null) || ((length = str.length()) == 0)) {\n\t\t\treturn true;\n\t\t}\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\t// 只要有一个非空字符即为非空字符串\n\t\t\tif (false == Character.isWhitespace(str.charAt(i))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * 字符串是否为非空白 空白的定义如下： <br>\n\t * 1、不为null <br>\n\t * 2、不为不可见字符（如空格）<br>\n\t * 3、不为\"\"<br>\n\t * \n\t * @param str 被检测的字符串\n\t * @return 是否为非空\n\t */\n\tpublic static boolean notBlank(String str) {\n\t\treturn false == isBlank(str);\n\t}\n\n\t/**\n\t * 是否包含空字符串\n\t * \n\t * @param strs 字符串列表\n\t * @return 是否包含空字符串\n\t */\n\tpublic static boolean hasBlank(String... strs) {\n\t\tif (CollectionKit.isEmpty(strs)) {\n\t\t\treturn true;\n\t\t}\n\t\tfor (String str : strs) {\n\t\t\tif (isBlank(str)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 给定所有字符串是否为空白\n\t * \n\t * @param strs 字符串\n\t * @return 所有字符串是否为空白\n\t */\n\tpublic static boolean isAllBlank(String... strs) {\n\t\tif (CollectionKit.isEmpty(strs)) {\n\t\t\treturn true;\n\t\t}\n\t\tfor (String str : strs) {\n\t\t\tif (notBlank(str)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t// ------------------------------------------------------------------------ Empty\n\t/**\n\t * 字符串是否为空，空的定义如下 1、为null <br>\n\t * 2、为\"\"<br>\n\t * \n\t * @param str 被检测的字符串\n\t * @return 是否为空\n\t */\n\tpublic static boolean isEmpty(String str) {\n\t\treturn str == null || str.length() == 0;\n\t}\n\n\t/**\n\t * 字符串是否为非空白 空白的定义如下： <br>\n\t * 1、不为null <br>\n\t * 2、不为\"\"<br>\n\t * \n\t * @param str 被检测的字符串\n\t * @return 是否为非空\n\t */\n\tpublic static boolean isNotEmpty(String str) {\n\t\treturn false == isEmpty(str);\n\t}\n\n\t/**\n\t * 当给定字符串为null时，转换为Empty\n\t * \n\t * @param str 被转换的字符串\n\t * @return 转换后的字符串\n\t */\n\tpublic static String nullToEmpty(String str) {\n\t\treturn nullToDefault(str, EMPTY);\n\t}\n\n\t/**\n\t * 如果字符串是<code>null</code>，则返回指定默认字符串，否则返回字符串本身。\n\t * \n\t * <pre>\n\t * nullToDefault(null, &quot;default&quot;)  = &quot;default&quot;\n\t * nullToDefault(&quot;&quot;, &quot;default&quot;)    = &quot;&quot;\n\t * nullToDefault(&quot;  &quot;, &quot;default&quot;)  = &quot;  &quot;\n\t * nullToDefault(&quot;bat&quot;, &quot;default&quot;) = &quot;bat&quot;\n\t * </pre>\n\t * \n\t * @param str 要转换的字符串\n\t * @param defaultStr 默认字符串\n\t * \n\t * @return 字符串本身或指定的默认字符串\n\t */\n\tpublic static String nullToDefault(String str, String defaultStr) {\n\t\treturn (str == null) ? defaultStr : str;\n\t}\n\n\t/**\n\t * 当给定字符串为空字符串时，转换为<code>null</code>\n\t * \n\t * @param str 被转换的字符串\n\t * @return 转换后的字符串\n\t */\n\tpublic static String emptyToNull(String str) {\n\t\treturn isEmpty(str) ? null : str;\n\t}\n\n\t/**\n\t * 是否包含空字符串\n\t * \n\t * @param strs 字符串列表\n\t * @return 是否包含空字符串\n\t */\n\tpublic static boolean hasEmpty(String... strs) {\n\t\tif (CollectionKit.isEmpty(strs)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tfor (String str : strs) {\n\t\t\tif (isEmpty(str)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 是否全部为空字符串\n\t * \n\t * @param strs 字符串列表\n\t * @return 是否全部为空字符串\n\t */\n\tpublic static boolean isAllEmpty(String... strs) {\n\t\tif (CollectionKit.isEmpty(strs)) {\n\t\t\treturn true;\n\t\t}\n\n\t\tfor (String str : strs) {\n\t\t\tif (isNotEmpty(str)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t// ------------------------------------------------------------------------ Trim\n\t/**\n\t * 除去字符串头尾部的空白，如果字符串是<code>null</code>，依然返回<code>null</code>。\n\t * \n\t * <p>\n\t * 注意，和<code>String.trim</code>不同，此方法使用<code>Character.isWhitespace</code> 来判定空白， 因而可以除去英文字符集之外的其它空白，如中文空格。\n\t * \n\t * <pre>\n\t * trim(null)          = null\n\t * trim(&quot;&quot;)            = &quot;&quot;\n\t * trim(&quot;     &quot;)       = &quot;&quot;\n\t * trim(&quot;abc&quot;)         = &quot;abc&quot;\n\t * trim(&quot;    abc    &quot;) = &quot;abc&quot;\n\t * </pre>\n\t * \n\t * </p>\n\t * \n\t * @param str 要处理的字符串\n\t * \n\t * @return 除去空白的字符串，如果原字串为<code>null</code>，则返回<code>null</code>\n\t */\n\tpublic static String trim(String str) {\n\t\treturn (null == str) ? null : trim(str, 0);\n\t}\n\n\t/**\n\t * 给定字符串数组全部做去首尾空格\n\t * \n\t * @param strs 字符串数组\n\t */\n\tpublic static void trim(String[] strs) {\n\t\tif (null == strs) {\n\t\t\treturn;\n\t\t}\n\t\tString str;\n\t\tfor (int i = 0; i < strs.length; i++) {\n\t\t\tstr = strs[i];\n\t\t\tif (null != str) {\n\t\t\t\tstrs[i] = str.trim();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * 除去字符串头部的空白，如果字符串是<code>null</code>，则返回<code>null</code>。\n\t * \n\t * <p>\n\t * 注意，和<code>String.trim</code>不同，此方法使用<code>Character.isWhitespace</code> 来判定空白， 因而可以除去英文字符集之外的其它空白，如中文空格。\n\t * \n\t * <pre>\n\t * trimStart(null)         = null\n\t * trimStart(&quot;&quot;)           = &quot;&quot;\n\t * trimStart(&quot;abc&quot;)        = &quot;abc&quot;\n\t * trimStart(&quot;  abc&quot;)      = &quot;abc&quot;\n\t * trimStart(&quot;abc  &quot;)      = &quot;abc  &quot;\n\t * trimStart(&quot; abc &quot;)      = &quot;abc &quot;\n\t * </pre>\n\t * \n\t * </p>\n\t * \n\t * @param str 要处理的字符串\n\t * \n\t * @return 除去空白的字符串，如果原字串为<code>null</code>或结果字符串为<code>\"\"</code>，则返回 <code>null</code>\n\t */\n\tpublic static String trimStart(String str) {\n\t\treturn trim(str, -1);\n\t}\n\n\t/**\n\t * 除去字符串尾部的空白，如果字符串是<code>null</code>，则返回<code>null</code>。\n\t * \n\t * <p>\n\t * 注意，和<code>String.trim</code>不同，此方法使用<code>Character.isWhitespace</code> 来判定空白， 因而可以除去英文字符集之外的其它空白，如中文空格。\n\t * \n\t * <pre>\n\t * trimEnd(null)       = null\n\t * trimEnd(&quot;&quot;)         = &quot;&quot;\n\t * trimEnd(&quot;abc&quot;)      = &quot;abc&quot;\n\t * trimEnd(&quot;  abc&quot;)    = &quot;  abc&quot;\n\t * trimEnd(&quot;abc  &quot;)    = &quot;abc&quot;\n\t * trimEnd(&quot; abc &quot;)    = &quot; abc&quot;\n\t * </pre>\n\t * \n\t * </p>\n\t * \n\t * @param str 要处理的字符串\n\t * \n\t * @return 除去空白的字符串，如果原字串为<code>null</code>或结果字符串为<code>\"\"</code>，则返回 <code>null</code>\n\t */\n\tpublic static String trimEnd(String str) {\n\t\treturn trim(str, 1);\n\t}\n\n\t/**\n\t * 除去字符串头尾部的空白符，如果字符串是<code>null</code>，依然返回<code>null</code>。\n\t * \n\t * @param str 要处理的字符串\n\t * @param mode <code>-1</code>表示trimStart，<code>0</code>表示trim全部， <code>1</code>表示trimEnd\n\t * \n\t * @return 除去指定字符后的的字符串，如果原字串为<code>null</code>，则返回<code>null</code>\n\t */\n\tpublic static String trim(String str, int mode) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tint length = str.length();\n\t\tint start = 0;\n\t\tint end = length;\n\n\t\t// 扫描字符串头部\n\t\tif (mode <= 0) {\n\t\t\twhile ((start < end) && (Character.isWhitespace(str.charAt(start)))) {\n\t\t\t\tstart++;\n\t\t\t}\n\t\t}\n\n\t\t// 扫描字符串尾部\n\t\tif (mode >= 0) {\n\t\t\twhile ((start < end) && (Character.isWhitespace(str.charAt(end - 1)))) {\n\t\t\t\tend--;\n\t\t\t}\n\t\t}\n\n\t\tif ((start > 0) || (end < length)) {\n\t\t\treturn str.substring(start, end);\n\t\t}\n\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 是否以指定字符串开头\n\t * @param str 被监测字符串\n\t * @param prefix 开头字符串\n\t * @param isIgnoreCase 是否忽略大小写\n\t * @return 是否以指定字符串开头\n\t */\n\tpublic static boolean startWith(String str, String prefix, boolean isIgnoreCase){\n\t\tif(isIgnoreCase){\n\t\t\treturn str.toLowerCase().startsWith(prefix.toLowerCase());\n\t\t}else{\n\t\t\treturn str.startsWith(prefix);\n\t\t}\n\t}\n\t\n\t/**\n\t * 是否以指定字符串结尾\n\t * @param str 被监测字符串\n\t * @param suffix 结尾字符串\n\t * @param isIgnoreCase 是否忽略大小写\n\t * @return 是否以指定字符串结尾\n\t */\n\tpublic static boolean endWith(String str, String suffix, boolean isIgnoreCase){\n\t\tif(isIgnoreCase){\n\t\t\treturn str.toLowerCase().endsWith(suffix.toLowerCase());\n\t\t}else{\n\t\t\treturn str.endsWith(suffix);\n\t\t}\n\t}\n\t\n\t/**\n\t * 是否包含特定字符，忽略大小写，如果给定两个参数都为<code>null</code>，返回true\n\t * @param str 被检测字符串\n\t * @param testStr 被测试是否包含的字符串\n\t * @return 是否包含\n\t */\n\tpublic static boolean containsIgnoreCase(String str, String testStr){\n\t\tif(null == str){\n\t\t\t//如果被监测字符串和 \n\t\t\treturn null == testStr;\n\t\t}\n\t\treturn str.toLowerCase().contains(testStr.toLowerCase());\n\t}\n\n\t/**\n\t * 获得set或get方法对应的标准属性名<br/>\n\t * 例如：setName 返回 name\n\t * \n\t * @param getOrSetMethodName\n\t * @return 如果是set或get方法名，返回field， 否则null\n\t */\n\tpublic static String getGeneralField(String getOrSetMethodName) {\n\t\tif (getOrSetMethodName.startsWith(\"get\") || getOrSetMethodName.startsWith(\"set\")) {\n\t\t\treturn cutPreAndLowerFirst(getOrSetMethodName, 3);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 生成set方法名<br/>\n\t * 例如：name 返回 setName\n\t * \n\t * @param fieldName 属性名\n\t * @return setXxx\n\t */\n\tpublic static String genSetter(String fieldName) {\n\t\treturn upperFirstAndAddPre(fieldName, \"set\");\n\t}\n\n\t/**\n\t * 生成get方法名\n\t * \n\t * @param fieldName 属性名\n\t * @return getXxx\n\t */\n\tpublic static String genGetter(String fieldName) {\n\t\treturn upperFirstAndAddPre(fieldName, \"get\");\n\t}\n\n\t/**\n\t * 去掉首部指定长度的字符串并将剩余字符串首字母小写<br/>\n\t * 例如：str=setName, preLength=3 -> return name\n\t * \n\t * @param str 被处理的字符串\n\t * @param preLength 去掉的长度\n\t * @return 处理后的字符串，不符合规范返回null\n\t */\n\tpublic static String cutPreAndLowerFirst(String str, int preLength) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (str.length() > preLength) {\n\t\t\tchar first = Character.toLowerCase(str.charAt(preLength));\n\t\t\tif (str.length() > preLength + 1) {\n\t\t\t\treturn first + str.substring(preLength + 1);\n\t\t\t}\n\t\t\treturn String.valueOf(first);\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 原字符串首字母大写并在其首部添加指定字符串 例如：str=name, preString=get -> return getName\n\t * \n\t * @param str 被处理的字符串\n\t * @param preString 添加的首部\n\t * @return 处理后的字符串\n\t */\n\tpublic static String upperFirstAndAddPre(String str, String preString) {\n\t\tif (str == null || preString == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn preString + upperFirst(str);\n\t}\n\n\t/**\n\t * 大写首字母<br>\n\t * 例如：str = name, return Name\n\t * \n\t * @param str 字符串\n\t * @return 字符串\n\t */\n\tpublic static String upperFirst(String str) {\n\t\treturn Character.toUpperCase(str.charAt(0)) + str.substring(1);\n\t}\n\n\t/**\n\t * 小写首字母<br>\n\t * 例如：str = Name, return name\n\t * \n\t * @param str 字符串\n\t * @return 字符串\n\t */\n\tpublic static String lowerFirst(String str) {\n\t\tif(isBlank(str)){\n\t\t\treturn str;\n\t\t}\n\t\treturn Character.toLowerCase(str.charAt(0)) + str.substring(1);\n\t}\n\n\t/**\n\t * 去掉指定前缀\n\t * \n\t * @param str 字符串\n\t * @param prefix 前缀\n\t * @return 切掉后的字符串，若前缀不是 preffix， 返回原字符串\n\t */\n\tpublic static String removePrefix(String str, String prefix) {\n\t\tif(isEmpty(str) || isEmpty(prefix)){\n\t\t\treturn str;\n\t\t}\n\t\t\n\t\tif (str.startsWith(prefix)) {\n\t\t\treturn str.substring(prefix.length());\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * 忽略大小写去掉指定前缀\n\t * \n\t * @param str 字符串\n\t * @param prefix 前缀\n\t * @return 切掉后的字符串，若前缀不是 prefix， 返回原字符串\n\t */\n\tpublic static String removePrefixIgnoreCase(String str, String prefix) {\n\t\tif(isEmpty(str) || isEmpty(prefix)){\n\t\t\treturn str;\n\t\t}\n\t\t\n\t\tif (str.toLowerCase().startsWith(prefix.toLowerCase())) {\n\t\t\treturn str.substring(prefix.length());\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * 去掉指定后缀\n\t * \n\t * @param str 字符串\n\t * @param suffix 后缀\n\t * @return 切掉后的字符串，若后缀不是 suffix， 返回原字符串\n\t */\n\tpublic static String removeSuffix(String str, String suffix) {\n\t\tif(isEmpty(str) || isEmpty(suffix)){\n\t\t\treturn str;\n\t\t}\n\t\t\n\t\tif (str.endsWith(suffix)) {\n\t\t\treturn str.substring(0, str.length() - suffix.length());\n\t\t}\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 获得字符串对应byte数组\n\t * @param str 字符串\n\t * @param charset 编码，如果为<code>null</code>使用系统默认编码\n\t * @return bytes\n\t */\n\tpublic static byte[] getBytes(String str, Charset charset){\n\t\tif(null == str){\n\t\t\treturn null;\n\t\t}\n\t\treturn null == charset ? str.getBytes() : str.getBytes(charset);\n\t}\n\n\t/**\n\t * 忽略大小写去掉指定后缀\n\t * \n\t * @param str 字符串\n\t * @param suffix 后缀\n\t * @return 切掉后的字符串，若后缀不是 suffix， 返回原字符串\n\t */\n\tpublic static String removeSuffixIgnoreCase(String str, String suffix) {\n\t\tif(isEmpty(str) || isEmpty(suffix)){\n\t\t\treturn str;\n\t\t}\n\t\t\n\t\tif (str.toLowerCase().endsWith(suffix.toLowerCase())) {\n\t\t\treturn str.substring(0, str.length() - suffix.length());\n\t\t}\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 如果给定字符串不是以prefix开头的，在开头补充 prefix\n\t * @param str 字符串\n\t * @param prefix 前缀\n\t * @return 补充后的字符串\n\t */\n\tpublic static String addPrefixIfNot(String str, String prefix){\n\t\tif(isEmpty(str) || isEmpty(prefix)){\n\t\t\treturn str;\n\t\t}\n\t\tif(false == str.startsWith(prefix)){\n\t\t\tstr = prefix + str;\n\t\t}\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 如果给定字符串不是以suffix结尾的，在尾部补充 suffix\n\t * @param str 字符串\n\t * @param suffix 后缀\n\t * @return 补充后的字符串\n\t */\n\tpublic static String addSuffixIfNot(String str, String suffix){\n\t\tif(isEmpty(str) || isEmpty(suffix)){\n\t\t\treturn str;\n\t\t}\n\t\tif(false == str.endsWith(suffix)){\n\t\t\tstr += suffix;\n\t\t}\n\t\treturn str;\n\t}\n\n\t/**\n\t * 清理空白字符\n\t * \n\t * @param str 被清理的字符串\n\t * @return 清理后的字符串\n\t */\n\tpublic static String cleanBlank(String str) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn str.replaceAll(\"\\\\s*\", EMPTY);\n\t}\n\n\t/**\n\t * 切分字符串<br>\n\t * a#b#c -> [a,b,c] <br>\n\t * a##b#c -> [a,\"\",b,c]\n\t * \n\t * @param str 被切分的字符串\n\t * @param separator 分隔符字符\n\t * @return 切分后的集合\n\t */\n\tpublic static List<String> split(String str, char separator) {\n\t\treturn split(str, separator, 0);\n\t}\n\n\t/**\n\t * 切分字符串\n\t * \n\t * @param str 被切分的字符串\n\t * @param separator 分隔符字符\n\t * @param limit 限制分片数\n\t * @return 切分后的集合\n\t */\n\tpublic static List<String> split(String str, char separator, int limit) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\t\tList<String> list = new ArrayList<String>(limit == 0 ? 16 : limit);\n\t\tif (limit == 1) {\n\t\t\tlist.add(str);\n\t\t\treturn list;\n\t\t}\n\n\t\tboolean isNotEnd = true; // 未结束切分的标志\n\t\tint strLen = str.length();\n\t\tStringBuilder sb = new StringBuilder(strLen);\n\t\tfor (int i = 0; i < strLen; i++) {\n\t\t\tchar c = str.charAt(i);\n\t\t\tif (isNotEnd && c == separator) {\n\t\t\t\tlist.add(sb.toString());\n\t\t\t\t// 清空StringBuilder\n\t\t\t\tsb.delete(0, sb.length());\n\n\t\t\t\t// 当达到切分上限-1的量时，将所剩字符全部作为最后一个串\n\t\t\t\tif (limit != 0 && list.size() == limit - 1) {\n\t\t\t\t\tisNotEnd = false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsb.append(c);\n\t\t\t}\n\t\t}\n\t\tlist.add(sb.toString());// 加入尾串\n\t\treturn list;\n\t}\n\n\t/**\n\t * 切分字符串<br>\n\t * from jodd\n\t * \n\t * @param str 被切分的字符串\n\t * @param delimiter 分隔符\n\t * @return 字符串\n\t */\n\tpublic static String[] split(String str, String delimiter) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (str.trim().length() == 0) {\n\t\t\treturn new String[] { str };\n\t\t}\n\n\t\tint dellen = delimiter.length(); // del length\n\t\tint maxparts = (str.length() / dellen) + 2; // one more for the last\n\t\tint[] positions = new int[maxparts];\n\n\t\tint i, j = 0;\n\t\tint count = 0;\n\t\tpositions[0] = -dellen;\n\t\twhile ((i = str.indexOf(delimiter, j)) != -1) {\n\t\t\tcount++;\n\t\t\tpositions[count] = i;\n\t\t\tj = i + dellen;\n\t\t}\n\t\tcount++;\n\t\tpositions[count] = str.length();\n\n\t\tString[] result = new String[count];\n\n\t\tfor (i = 0; i < count; i++) {\n\t\t\tresult[i] = str.substring(positions[i] + dellen, positions[i + 1]);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * 改进JDK subString<br>\n\t * index从0开始计算，最后一个字符为-1<br>\n\t * 如果from和to位置一样，返回 \"\" <br>\n\t * 如果from或to为负数，则按照length从后向前数位置，如果绝对值大于字符串长度，则from归到0，to归到length<br>\n\t * 如果经过修正的index中from大于to，则互换from和to\n\t * example: <br>\n\t * \tabcdefgh 2 3 -> c <br>\n\t * \tabcdefgh 2 -3 -> cde <br>\n\t * \n\t * @param string String\n\t * @param fromIndex 开始的index（包括）\n\t * @param toIndex 结束的index（不包括）\n\t * @return 字串\n\t */\n\tpublic static String sub(String string, int fromIndex, int toIndex) {\n\t\tint len = string.length();\n\t\tif (fromIndex < 0) {\n\t\t\tfromIndex = len + fromIndex;\n\t\t\tif(fromIndex < 0 ) { \n\t\t\t\tfromIndex = 0;\n\t\t\t}\n\t\t} else if(fromIndex >= len) {\n\t\t\tfromIndex = len -1;\n\t\t}\n\t\tif (toIndex < 0) {\n\t\t\ttoIndex = len + toIndex;\n\t\t\tif(toIndex < 0) {\n\t\t\t\ttoIndex = len;\n\t\t\t}\n\t\t} else if(toIndex > len) {\n\t\t\ttoIndex = len;\n\t\t}\n\t\tif (toIndex < fromIndex) {\n\t\t\tint tmp = fromIndex;\n\t\t\tfromIndex = toIndex;\n\t\t\ttoIndex = tmp;\n\t\t}\n\t\tif (fromIndex == toIndex) {\n\t\t\treturn EMPTY;\n\t\t}\n\t\tchar[] strArray = string.toCharArray();\n\t\tchar[] newStrArray = Arrays.copyOfRange(strArray, fromIndex, toIndex);\n\t\treturn new String(newStrArray);\n\t}\n\n\t/**\n\t * 切割前部分\n\t * \n\t * @param string 字符串\n\t * @param toIndex 切割到的位置（不包括）\n\t * @return 切割后的字符串\n\t */\n\tpublic static String subPre(String string, int toIndex) {\n\t\treturn sub(string, 0, toIndex);\n\t}\n\n\t/**\n\t * 切割后部分\n\t * \n\t * @param string 字符串\n\t * @param fromIndex 切割开始的位置（包括）\n\t * @return 切割后的字符串\n\t */\n\tpublic static String subSuf(String string, int fromIndex) {\n\t\tif (isEmpty(string)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn sub(string, fromIndex, string.length());\n\t}\n\n\t/**\n\t * 给定字符串是否被字符包围\n\t * \n\t * @param str 字符串\n\t * @param prefix 前缀\n\t * @param suffix 后缀\n\t * @return 是否包围，空串不包围\n\t */\n\tpublic static boolean isSurround(String str, String prefix, String suffix) {\n\t\tif (StrKit.isBlank(str)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (str.length() < (prefix.length() + suffix.length())) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn str.startsWith(prefix) && str.endsWith(suffix);\n\t}\n\n\t/**\n\t * 给定字符串是否被字符包围\n\t * \n\t * @param str 字符串\n\t * @param prefix 前缀\n\t * @param suffix 后缀\n\t * @return 是否包围，空串不包围\n\t */\n\tpublic static boolean isSurround(String str, char prefix, char suffix) {\n\t\tif (StrKit.isBlank(str)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (str.length() < 2) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn str.charAt(0) == prefix && str.charAt(str.length() - 1) == suffix;\n\t}\n\n\t/**\n\t * 重复某个字符\n\t * \n\t * @param c 被重复的字符\n\t * @param count 重复的数目\n\t * @return 重复字符字符串\n\t */\n\tpublic static String repeat(char c, int count) {\n\t\tchar[] result = new char[count];\n\t\tfor (int i = 0; i < count; i++) {\n\t\t\tresult[i] = c;\n\t\t}\n\t\treturn new String(result);\n\t}\n\n\t/**\n\t * 重复某个字符串\n\t * \n\t * @param str 被重复的字符\n\t * @param count 重复的数目\n\t * @return 重复字符字符串\n\t */\n\tpublic static String repeat(String str, int count) {\n\n\t\t// 检查\n\t\tfinal int len = str.length();\n\t\tfinal long longSize = (long) len * (long) count;\n\t\tfinal int size = (int) longSize;\n\t\tif (size != longSize) {\n\t\t\tthrow new ArrayIndexOutOfBoundsException(\"Required String length is too large: \" + longSize);\n\t\t}\n\n\t\tfinal char[] array = new char[size];\n\t\tstr.getChars(0, len, array, 0);\n\t\tint n;\n\t\tfor (n = len; n < size - n; n <<= 1) {// n <<= 1相当于n *2\n\t\t\tSystem.arraycopy(array, 0, array, n, n);\n\t\t}\n\t\tSystem.arraycopy(array, 0, array, n, size - n);\n\t\treturn new String(array);\n\t}\n\n\t/**\n\t * 比较两个字符串（大小写敏感）。\n\t * \n\t * <pre>\n\t * equals(null, null)   = true\n\t * equals(null, &quot;abc&quot;)  = false\n\t * equals(&quot;abc&quot;, null)  = false\n\t * equals(&quot;abc&quot;, &quot;abc&quot;) = true\n\t * equals(&quot;abc&quot;, &quot;ABC&quot;) = false\n\t * </pre>\n\t * \n\t * @param str1 要比较的字符串1\n\t * @param str2 要比较的字符串2\n\t * \n\t * @return 如果两个字符串相同，或者都是<code>null</code>，则返回<code>true</code>\n\t */\n\tpublic static boolean equals(String str1, String str2) {\n\t\tif (str1 == null) {\n\t\t\treturn str2 == null;\n\t\t}\n\n\t\treturn str1.equals(str2);\n\t}\n\n\t/**\n\t * 比较两个字符串（大小写不敏感）。\n\t * \n\t * <pre>\n\t * equalsIgnoreCase(null, null)   = true\n\t * equalsIgnoreCase(null, &quot;abc&quot;)  = false\n\t * equalsIgnoreCase(&quot;abc&quot;, null)  = false\n\t * equalsIgnoreCase(&quot;abc&quot;, &quot;abc&quot;) = true\n\t * equalsIgnoreCase(&quot;abc&quot;, &quot;ABC&quot;) = true\n\t * </pre>\n\t * \n\t * @param str1 要比较的字符串1\n\t * @param str2 要比较的字符串2\n\t * \n\t * @return 如果两个字符串相同，或者都是<code>null</code>，则返回<code>true</code>\n\t */\n\tpublic static boolean equalsIgnoreCase(String str1, String str2) {\n\t\tif (str1 == null) {\n\t\t\treturn str2 == null;\n\t\t}\n\n\t\treturn str1.equalsIgnoreCase(str2);\n\t}\n\n\t/**\n\t * 格式化文本, {} 表示占位符<br>\n\t * 例如：format(\"aaa {} ccc\", \"bbb\")   ---->    aaa bbb ccc\n\t * \n\t * @param template 文本模板，被替换的部分用 {} 表示\n\t * @param values 参数值\n\t * @return 格式化后的文本\n\t */\n\tpublic static String format(String template, Object... values) {\n\t\tif (CollectionKit.isEmpty(values) || isBlank(template)) {\n\t\t\treturn template;\n\t\t}\n\n\t\tfinal StringBuilder sb = new StringBuilder();\n\t\tfinal int length = template.length();\n\n\t\tint valueIndex = 0;\n\t\tchar currentChar;\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tif (valueIndex >= values.length) {\n\t\t\t\tsb.append(sub(template, i, length));\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcurrentChar = template.charAt(i);\n\t\t\tif (currentChar == '{') {\n\t\t\t\tfinal char nextChar = template.charAt(++i);\n\t\t\t\tif (nextChar == '}') {\n\t\t\t\t\tsb.append(values[valueIndex++]);\n\t\t\t\t} else {\n\t\t\t\t\tsb.append('{').append(nextChar);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tsb.append(currentChar);\n\t\t\t}\n\n\t\t}\n\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 格式化文本，使用 {varName} 占位<br>\n\t * map = {a: \"aValue\", b: \"bValue\"}\n\t * format(\"{a} and {b}\", map)    ---->    aValue and bValue\n\t * \n\t * @param template 文本模板，被替换的部分用 {key} 表示\n\t * @param map 参数值对\n\t * @return 格式化后的文本\n\t */\n\tpublic static String format(String template, Map<?, ?> map) {\n\t\tif (null == map || map.isEmpty()) {\n\t\t\treturn template;\n\t\t}\n\n\t\tfor (Entry<?, ?> entry : map.entrySet()) {\n\t\t\ttemplate = template.replace(\"{\" + entry.getKey() + \"}\", entry.getValue().toString());\n\t\t}\n\t\treturn template;\n\t}\n\t\n\t/**\n\t * 编码字符串\n\t * \n\t * @param str 字符串\n\t * @param charset 字符集，如果此字段为空，则解码的结果取决于平台\n\t * @return 编码后的字节码\n\t */\n\tpublic static byte[] bytes(String str, String charset) {\n\t\treturn bytes(str, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset));\n\t}\n\n\t/**\n\t * 编码字符串\n\t * \n\t * @param str 字符串\n\t * @param charset 字符集，如果此字段为空，则解码的结果取决于平台\n\t * @return 编码后的字节码\n\t */\n\tpublic static byte[] bytes(String str, Charset charset) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (null == charset) {\n\t\t\treturn str.getBytes();\n\t\t}\n\t\treturn str.getBytes(charset);\n\t}\n\t\n\t/**\n\t * 将byte数组转为字符串\n\t * \n\t * @param bytes byte数组\n\t * @param charset 字符集\n\t * @return 字符串\n\t */\n\tpublic static String str(byte[] bytes, String charset) {\n\t\treturn str(bytes, isBlank(charset) ? Charset.defaultCharset() : Charset.forName(charset));\n\t}\n\n\t/**\n\t * 解码字节码\n\t * \n\t * @param data 字符串\n\t * @param charset 字符集，如果此字段为空，则解码的结果取决于平台\n\t * @return 解码后的字符串\n\t */\n\tpublic static String str(byte[] data, Charset charset) {\n\t\tif (data == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (null == charset) {\n\t\t\treturn new String(data);\n\t\t}\n\t\treturn new String(data, charset);\n\t}\n\t\n\t/**\n\t * 将编码的byteBuffer数据转换为字符串\n\t * @param data 数据\n\t * @param charset 字符集，如果为空使用当前系统字符集\n\t * @return 字符串\n\t */\n\tpublic static String str(ByteBuffer data, String charset){\n\t\tif(data == null) {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\treturn str(data, Charset.forName(charset));\n\t}\n\t\n\t/**\n\t * 将编码的byteBuffer数据转换为字符串\n\t * @param data 数据\n\t * @param charset 字符集，如果为空使用当前系统字符集\n\t * @return 字符串\n\t */\n\tpublic static String str(ByteBuffer data, Charset charset){\n\t\tif(null == charset) {\n\t\t\tcharset = Charset.defaultCharset();\n\t\t}\n\t\treturn charset.decode(data).toString();\n\t}\n\t\n\t/**\n\t * 字符串转换为byteBuffer\n\t * @param str 字符串\n\t * @param charset 编码\n\t * @return byteBuffer\n\t */\n\tpublic static ByteBuffer byteBuffer(String str, String charset) {\n\t\treturn ByteBuffer.wrap(StrKit.bytes(str, charset));\n\t}\n\n\t/**\n\t * 以 conjunction 为分隔符将多个对象转换为字符串\n\t * \n\t * @param conjunction 分隔符\n\t * @param objs 数组\n\t * @return 连接后的字符串\n\t */\n\tpublic static String join(String conjunction, Object... objs) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tboolean isFirst = true;\n\t\tfor (Object item : objs) {\n\t\t\tif (isFirst) {\n\t\t\t\tisFirst = false;\n\t\t\t} else {\n\t\t\t\tsb.append(conjunction);\n\t\t\t}\n\t\t\tsb.append(item);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n\t/**\n\t * 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空，则返回空字符串。</br>\n\t * 例如：HelloWorld->hello_world\n\t *\n\t * @param camelCaseStr 转换前的驼峰式命名的字符串\n\t * @return 转换后下划线大写方式命名的字符串\n\t */\n\tpublic static String toUnderlineCase(String camelCaseStr) {\n\t\tif (camelCaseStr == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal int length = camelCaseStr.length();\n\t\tStringBuilder sb = new StringBuilder();\n\t\tchar c;\n\t\tboolean isPreUpperCase = false;\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tc = camelCaseStr.charAt(i);\n\t\t\tboolean isNextUpperCase = true;\n\t\t\tif (i < (length - 1)) {\n\t\t\t\tisNextUpperCase = Character.isUpperCase(camelCaseStr.charAt(i + 1));\n\t\t\t}\n\t\t\tif (Character.isUpperCase(c)) {\n\t\t\t\tif (!isPreUpperCase || !isNextUpperCase) {\n\t\t\t\t\tif (i > 0) sb.append(UNDERLINE);\n\t\t\t\t}\n\t\t\t\tisPreUpperCase = true;\n\t\t\t} else {\n\t\t\t\tisPreUpperCase = false;\n\t\t\t}\n\t\t\tsb.append(Character.toLowerCase(c));\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。</br>\n\t * 例如：hello_world->HelloWorld\n\t *\n\t * @param name 转换前的下划线大写方式命名的字符串\n\t * @return 转换后的驼峰式命名的字符串\n\t */\n\tpublic static String toCamelCase(String name) {\n\t\tif (name == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (name.contains(UNDERLINE)) {\n\t\t\tname = name.toLowerCase();\n\n\t\t\tStringBuilder sb = new StringBuilder(name.length());\n\t\t\tboolean upperCase = false;\n\t\t\tfor (int i = 0; i < name.length(); i++) {\n\t\t\t\tchar c = name.charAt(i);\n\n\t\t\t\tif (c == '_') {\n\t\t\t\t\tupperCase = true;\n\t\t\t\t} else if (upperCase) {\n\t\t\t\t\tsb.append(Character.toUpperCase(c));\n\t\t\t\t\tupperCase = false;\n\t\t\t\t} else {\n\t\t\t\t\tsb.append(c);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn sb.toString();\n\t\t} else\n\t\t\treturn name;\n\t}\n\n\t/**\n\t * 包装指定字符串\n\t * \n\t * @param str 被包装的字符串\n\t * @param prefix 前缀\n\t * @param suffix 后缀\n\t * @return 包装后的字符串\n\t */\n\tpublic static String wrap(String str, String prefix, String suffix) {\n\t\treturn format(\"{}{}{}\", prefix, str, suffix);\n\t}\n\n\t/**\n\t * 指定字符串是否被包装\n\t * \n\t * @param str 字符串\n\t * @param prefix 前缀\n\t * @param suffix 后缀\n\t * @return 是否被包装\n\t */\n\tpublic static boolean isWrap(String str, String prefix, String suffix) {\n\t\treturn str.startsWith(prefix) && str.endsWith(suffix);\n\t}\n\n\t/**\n\t * 指定字符串是否被同一字符包装（前后都有这些字符串）\n\t * \n\t * @param str 字符串\n\t * @param wrapper 包装字符串\n\t * @return 是否被包装\n\t */\n\tpublic static boolean isWrap(String str, String wrapper) {\n\t\treturn isWrap(str, wrapper, wrapper);\n\t}\n\n\t/**\n\t * 指定字符串是否被同一字符包装（前后都有这些字符串）\n\t * \n\t * @param str 字符串\n\t * @param wrapper 包装字符\n\t * @return 是否被包装\n\t */\n\tpublic static boolean isWrap(String str, char wrapper) {\n\t\treturn isWrap(str, wrapper, wrapper);\n\t}\n\n\t/**\n\t * 指定字符串是否被包装\n\t * \n\t * @param str 字符串\n\t * @param prefixChar 前缀\n\t * @param suffixChar 后缀\n\t * @return 是否被包装\n\t */\n\tpublic static boolean isWrap(String str, char prefixChar, char suffixChar) {\n\t\treturn str.charAt(0) == prefixChar && str.charAt(str.length() - 1) == suffixChar;\n\t}\n\n\t/**\n\t * 补充字符串以满足最小长度 StrUtil.padPre(\"1\", 3, '0');//\"001\"\n\t * \n\t * @param str 字符串\n\t * @param minLength 最小长度\n\t * @param padChar 补充的字符\n\t * @return 补充后的字符串\n\t */\n\tpublic static String padPre(String str, int minLength, char padChar) {\n\t\tif (str.length() >= minLength) {\n\t\t\treturn str;\n\t\t}\n\t\tStringBuilder sb = new StringBuilder(minLength);\n\t\tfor (int i = str.length(); i < minLength; i++) {\n\t\t\tsb.append(padChar);\n\t\t}\n\t\tsb.append(str);\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 补充字符串以满足最小长度 StrUtil.padEnd(\"1\", 3, '0');//\"100\"\n\t * \n\t * @param str 字符串\n\t * @param minLength 最小长度\n\t * @param padChar 补充的字符\n\t * @return 补充后的字符串\n\t */\n\tpublic static String padEnd(String str, int minLength, char padChar) {\n\t\tif (str.length() >= minLength) {\n\t\t\treturn str;\n\t\t}\n\t\tStringBuilder sb = new StringBuilder(minLength);\n\t\tsb.append(str);\n\t\tfor (int i = str.length(); i < minLength; i++) {\n\t\t\tsb.append(padChar);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 创建StringBuilder对象\n\t * \n\t * @return StringBuilder对象\n\t */\n\tpublic static StringBuilder builder() {\n\t\treturn new StringBuilder();\n\t}\n\n\t/**\n\t * 创建StringBuilder对象\n\t * \n\t * @return StringBuilder对象\n\t */\n\tpublic static StringBuilder builder(int capacity) {\n\t\treturn new StringBuilder(capacity);\n\t}\n\n\t/**\n\t * 创建StringBuilder对象\n\t * \n\t * @return StringBuilder对象\n\t */\n\tpublic static StringBuilder builder(String... strs) {\n\t\tfinal StringBuilder sb = new StringBuilder();\n\t\tfor (String str : strs) {\n\t\t\tsb.append(str);\n\t\t}\n\t\treturn sb;\n\t}\n\n\t/**\n\t * 获得StringReader\n\t * \n\t * @param str 字符串\n\t * @return StringReader\n\t */\n\tpublic static StringReader getReader(String str) {\n\t\treturn new StringReader(str);\n\t}\n\n\t/**\n\t * 获得StringWriter\n\t * \n\t * @return StringWriter\n\t */\n\tpublic static StringWriter getWriter() {\n\t\treturn new StringWriter();\n\t}\n\n\t\t/**\n\t * 编码字符串\n\t * \n\t * @param str 字符串\n\t * @param charset 字符集，如果此字段为空，则解码的结果取决于平台\n\t * @return 编码后的字节码\n\t */\n\tpublic static byte[] encode(String str, String charset) {\n\t\tif (str == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif(isBlank(charset)) {\n\t\t\treturn str.getBytes();\n\t\t}\n\t\ttry {\n\t\t\treturn str.getBytes(charset);\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\tthrow new RuntimeException(format(\"Charset [{}] unsupported!\", charset));\n\t\t}\n\t}\n\n\t/**\n\t * 解码字节码\n\t * \n\t * @param data 字符串\n\t * @param charset 字符集，如果此字段为空，则解码的结果取决于平台\n\t * @return 解码后的字符串\n\t */\n\tpublic static String decode(byte[] data, String charset) {\n\t\tif (data == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif(isBlank(charset)) {\n\t\t\treturn new String(data);\n\t\t}\n\t\ttry {\n\t\t\treturn new String(data, charset);\n\t\t} catch (UnsupportedEncodingException e) {\n\t\t\tthrow new RuntimeException(format(\"Charset [{}] unsupported!\", charset));\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/StringUtils.java",
    "content": "package cn.enilu.material.utils;\n\n\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.regex.Pattern;\n\npublic class StringUtils {\n\n    public static final String EMPTY = \"\";\n    private static final AtomicLong ORDER_SEQ = new AtomicLong(1);\n    private static final Pattern PATERN_IP = Pattern.compile(\"((2[0-4]\\\\d|25[0-5]|[01]?\\\\d\\\\d?)\\\\.){3}(2[0-4]\\\\d|25[0-5]|[01]?\\\\d\\\\d?)\");\n\n    /**\n     * 是否为空字符\n     */\n    public static boolean isEmpty(String str) {\n        if (str == null || str.trim().length() == 0) {\n            return true;\n        }\n        if (\"null\".equalsIgnoreCase(str) || \"undefined\".equalsIgnoreCase(str)) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 是否包含空字符串\n     *\n     * @param strs 字符串列表\n     * @return 是否包含空字符串\n     */\n    public static boolean hasBlank(String... strs) {\n        if (CollectionKit.isEmpty(strs)) {\n            return true;\n        }\n        for (String str : strs) {\n            if (isEmpty(str)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 是否为非空字符\n     */\n    public static boolean isNotEmpty(String str) {\n        return (!isEmpty(str));\n    }\n\n    /**\n     * 判断是否为null或空字符\n     */\n    public static boolean isNullOrEmpty(Object o) {\n        if (o == null) {\n            return true;\n        }\n        if (String.valueOf(o).replace((char) 12288, ' ').trim().length() == 0) {\n            return true;\n        }\n        if (\"null\".equals(o)) {\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * 判断是否不为null或非空字符\n     */\n    public static boolean isNotNullOrEmpty(Object o) {\n        return !isNullOrEmpty(o);\n    }\n\n    // 根据Unicode编码完美的判断中文汉字和符号\n    private static boolean isChinese(char c) {\n        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);\n        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS\n                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B\n                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS\n                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {\n            return true;\n        }\n        return false;\n    }\n\n\n    public static String sNull(Object obj) {\n        return obj == null ? \"\" : obj.toString();\n    }\n\n\n    /**\n     * 格式化文本, {} 表示占位符<br>\n     * 例如：format(\"aaa {} ccc\", \"bbb\")   ---->    aaa bbb ccc\n     *\n     * @param template 文本模板，被替换的部分用 {} 表示\n     * @param values   参数值\n     * @return 格式化后的文本\n     */\n    public static String format(String template, Object... values) {\n        if (CollectionKit.isEmpty(values) || isEmpty(template)) {\n            return template;\n        }\n\n        final StringBuilder sb = new StringBuilder();\n        final int length = template.length();\n\n        int valueIndex = 0;\n        char currentChar;\n        for (int i = 0; i < length; i++) {\n            if (valueIndex >= values.length) {\n                sb.append(sub(template, i, length));\n                break;\n            }\n\n            currentChar = template.charAt(i);\n            if (currentChar == '{') {\n                final char nextChar = template.charAt(++i);\n                if (nextChar == '}') {\n                    sb.append(values[valueIndex++]);\n                } else {\n                    sb.append('{').append(nextChar);\n                }\n            } else {\n                sb.append(currentChar);\n            }\n\n        }\n\n        return sb.toString();\n    }\n\n    /**\n     * 格式化文本，使用 {varName} 占位<br>\n     * map = {a: \"aValue\", b: \"bValue\"}\n     * format(\"{a} and {b}\", map)    ---->    aValue and bValue\n     *\n     * @param template 文本模板，被替换的部分用 {key} 表示\n     * @param map      参数值对\n     * @return 格式化后的文本\n     */\n    public static String format(String template, Map<?, ?> map) {\n        if (null == map || map.isEmpty()) {\n            return template;\n        }\n\n        for (Map.Entry<?, ?> entry : map.entrySet()) {\n            template = template.replace(\"{\" + entry.getKey() + \"}\", entry.getValue().toString());\n        }\n        return template;\n    }\n\n    /**\n     * 改进JDK subString<br>\n     * index从0开始计算，最后一个字符为-1<br>\n     * 如果from和to位置一样，返回 \"\" <br>\n     * 如果from或to为负数，则按照length从后向前数位置，如果绝对值大于字符串长度，则from归到0，to归到length<br>\n     * 如果经过修正的index中from大于to，则互换from和to\n     * example: <br>\n     * abcdefgh 2 3 -> c <br>\n     * abcdefgh 2 -3 -> cde <br>\n     *\n     * @param string    String\n     * @param fromIndex 开始的index（包括）\n     * @param toIndex   结束的index（不包括）\n     * @return 字串\n     */\n    public static String sub(String string, int fromIndex, int toIndex) {\n        int len = string.length();\n        if (fromIndex < 0) {\n            fromIndex = len + fromIndex;\n            if (fromIndex < 0) {\n                fromIndex = 0;\n            }\n        } else if (fromIndex >= len) {\n            fromIndex = len - 1;\n        }\n        if (toIndex < 0) {\n            toIndex = len + toIndex;\n            if (toIndex < 0) {\n                toIndex = len;\n            }\n        } else if (toIndex > len) {\n            toIndex = len;\n        }\n        if (toIndex < fromIndex) {\n            int tmp = fromIndex;\n            fromIndex = toIndex;\n            toIndex = tmp;\n        }\n        if (fromIndex == toIndex) {\n            return EMPTY;\n        }\n        char[] strArray = string.toCharArray();\n        char[] newStrArray = Arrays.copyOfRange(strArray, fromIndex, toIndex);\n        return new String(newStrArray);\n    }\n\n\n    /**\n     * 首字母变小写\n     */\n    public static String firstCharToLowerCase(String str) {\n        char firstChar = str.charAt(0);\n        if (firstChar >= 'A' && firstChar <= 'Z') {\n            char[] arr = str.toCharArray();\n            arr[0] += ('a' - 'A');\n            return new String(arr);\n        }\n        return str;\n    }\n\n    /**\n     * 首字母变大写\n     */\n    public static String firstCharToUpperCase(String str) {\n        char firstChar = str.charAt(0);\n        if (firstChar >= 'a' && firstChar <= 'z') {\n            char[] arr = str.toCharArray();\n            arr[0] -= ('a' - 'A');\n            return new String(arr);\n        }\n        return str;\n    }\n\n\n    /**\n     * 去掉指定前缀\n     *\n     * @param str    字符串\n     * @param prefix 前缀\n     * @return 切掉后的字符串，若前缀不是 preffix， 返回原字符串\n     */\n    public static String removePrefix(String str, String prefix) {\n        if (isEmpty(str) || isEmpty(prefix)) {\n            return str;\n        }\n\n        if (str.startsWith(prefix)) {\n            return str.substring(prefix.length());\n        }\n        return str;\n    }\n\n\n    /**\n     * 去掉指定后缀\n     *\n     * @param str    字符串\n     * @param suffix 后缀\n     * @return 切掉后的字符串，若后缀不是 suffix， 返回原字符串\n     */\n    public static String removeSuffix(String str, String suffix) {\n        if (isEmpty(str) || isEmpty(suffix)) {\n            return str;\n        }\n\n        if (str.endsWith(suffix)) {\n            return str.substring(0, str.length() - suffix.length());\n        }\n        return str;\n    }\n\n    /**\n     * 获得字符串对应byte数组\n     *\n     * @param str     字符串\n     * @param charset 编码，如果为<code>null</code>使用系统默认编码\n     * @return bytes\n     */\n    public static byte[] getBytes(String str, Charset charset) {\n        if (null == str) {\n            return null;\n        }\n        return null == charset ? str.getBytes() : str.getBytes(charset);\n    }\n\n\n    /**\n     * 切分字符串<br>\n     * from jodd\n     *\n     * @param str       被切分的字符串\n     * @param delimiter 分隔符\n     * @return 字符串\n     */\n    public static String[] split(String str, String delimiter) {\n        if (str == null) {\n            return null;\n        }\n        if (str.trim().length() == 0) {\n            return new String[]{str};\n        }\n\n        int dellen = delimiter.length(); // del length\n        int maxparts = (str.length() / dellen) + 2; // one more for the last\n        int[] positions = new int[maxparts];\n\n        int i, j = 0;\n        int count = 0;\n        positions[0] = -dellen;\n        while ((i = str.indexOf(delimiter, j)) != -1) {\n            count++;\n            positions[count] = i;\n            j = i + dellen;\n        }\n        count++;\n        positions[count] = str.length();\n\n        String[] result = new String[count];\n\n        for (i = 0; i < count; i++) {\n            result[i] = str.substring(positions[i] + dellen, positions[i + 1]);\n        }\n        return result;\n    }\n\n\n    /**\n     * 比较两个字符串（大小写敏感）。\n     *\n     * <pre>\n     * equals(null, null)   = true\n     * equals(null, &quot;abc&quot;)  = false\n     * equals(&quot;abc&quot;, null)  = false\n     * equals(&quot;abc&quot;, &quot;abc&quot;) = true\n     * equals(&quot;abc&quot;, &quot;ABC&quot;) = false\n     * </pre>\n     *\n     * @param str1 要比较的字符串1\n     * @param str2 要比较的字符串2\n     * @return 如果两个字符串相同，或者都是<code>null</code>，则返回<code>true</code>\n     */\n    public static boolean equals(String str1, String str2) {\n        if (str1 == null) {\n            return str2 == null;\n        }\n\n        return str1.equals(str2);\n    }\n\n\n    /**\n     * 编码字符串\n     *\n     * @param str     字符串\n     * @param charset 字符集，如果此字段为空，则解码的结果取决于平台\n     * @return 编码后的字节码\n     */\n    public static byte[] bytes(String str, Charset charset) {\n        if (str == null) {\n            return null;\n        }\n\n        if (null == charset) {\n            return str.getBytes();\n        }\n        return str.getBytes(charset);\n    }\n\n\n    /**\n     * 解码字节码\n     *\n     * @param data    字符串\n     * @param charset 字符集，如果此字段为空，则解码的结果取决于平台\n     * @return 解码后的字符串\n     */\n    public static String str(byte[] data, Charset charset) {\n        if (data == null) {\n            return null;\n        }\n\n        if (null == charset) {\n            return new String(data);\n        }\n        return new String(data, charset);\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/ToolUtil.java",
    "content": "/**\n * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.utils;\n\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.lang.reflect.Array;\nimport java.math.BigDecimal;\nimport java.net.URISyntaxException;\nimport java.util.*;\nimport java.util.Map.Entry;\n\n/**\n * 高频方法集合类\n */\npublic class ToolUtil {\n\n    /**\n     * 获取随机位数的字符串\n     *\n     * @author fengshuonan\n     * @Date 2017/8/24 14:09\n     */\n    public static String getRandomString(int length) {\n        String base = \"abcdefghijklmnopqrstuvwxyz0123456789\";\n        Random random = new Random();\n        StringBuffer sb = new StringBuffer();\n        for (int i = 0; i < length; i++) {\n            int number = random.nextInt(base.length());\n            sb.append(base.charAt(number));\n        }\n        return sb.toString();\n    }\n\n    /**\n     * 判断一个对象是否是时间类型\n     *\n     * @author enilu.cn\n     * @Date 2017/4/18 12:55\n     */\n    public static String dateType(Object o) {\n        if (o instanceof Date) {\n            return DateUtil.getDay((Date) o);\n        } else {\n            return o.toString();\n        }\n    }\n\n    /**\n     * 获取异常的具体信息\n     *\n     * @author fengshuonan\n     * @Date 2017/3/30 9:21\n     * @version 2.0\n     */\n    public static String getExceptionMsg(Exception e) {\n        StringWriter sw = new StringWriter();\n        try {\n            e.printStackTrace(new PrintWriter(sw));\n        } finally {\n            try {\n                sw.close();\n            } catch (IOException e1) {\n                e1.printStackTrace();\n            }\n        }\n        return sw.getBuffer().toString().replaceAll(\"\\\\$\", \"T\");\n    }\n\n    /**\n     * 比较两个对象是否相等。<br>\n     * 相同的条件有两个，满足其一即可：<br>\n     * 1. obj1 == null && obj2 == null; 2. obj1.equals(obj2)\n     *\n     * @param obj1 对象1\n     * @param obj2 对象2\n     * @return 是否相等\n     */\n    public static boolean equals(Object obj1, Object obj2) {\n        return (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null);\n    }\n\n    /**\n     * 计算对象长度，如果是字符串调用其length函数，集合类调用其size函数，数组调用其length属性，其他可遍历对象遍历计算长度\n     *\n     * @param obj 被计算长度的对象\n     * @return 长度\n     */\n    public static int length(Object obj) {\n        if (obj == null) {\n            return 0;\n        }\n        if (obj instanceof CharSequence) {\n            return ((CharSequence) obj).length();\n        }\n        if (obj instanceof Collection) {\n            return ((Collection<?>) obj).size();\n        }\n        if (obj instanceof Map) {\n            return ((Map<?, ?>) obj).size();\n        }\n\n        int count;\n        if (obj instanceof Iterator) {\n            Iterator<?> iter = (Iterator<?>) obj;\n            count = 0;\n            while (iter.hasNext()) {\n                count++;\n                iter.next();\n            }\n            return count;\n        }\n        if (obj instanceof Enumeration) {\n            Enumeration<?> enumeration = (Enumeration<?>) obj;\n            count = 0;\n            while (enumeration.hasMoreElements()) {\n                count++;\n                enumeration.nextElement();\n            }\n            return count;\n        }\n        if (obj.getClass().isArray() == true) {\n            return Array.getLength(obj);\n        }\n        return -1;\n    }\n\n    /**\n     * 对象中是否包含元素\n     *\n     * @param obj     对象\n     * @param element 元素\n     * @return 是否包含\n     */\n    public static boolean contains(Object obj, Object element) {\n        if (obj == null) {\n            return false;\n        }\n        if (obj instanceof String) {\n            if (element == null) {\n                return false;\n            }\n            return ((String) obj).contains(element.toString());\n        }\n        if (obj instanceof Collection) {\n            return ((Collection<?>) obj).contains(element);\n        }\n        if (obj instanceof Map) {\n            return ((Map<?, ?>) obj).values().contains(element);\n        }\n\n        if (obj instanceof Iterator) {\n            Iterator<?> iter = (Iterator<?>) obj;\n            while (iter.hasNext()) {\n                Object o = iter.next();\n                if (equals(o, element)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        if (obj instanceof Enumeration) {\n            Enumeration<?> enumeration = (Enumeration<?>) obj;\n            while (enumeration.hasMoreElements()) {\n                Object o = enumeration.nextElement();\n                if (equals(o, element)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n        if (obj.getClass().isArray() == true) {\n            int len = Array.getLength(obj);\n            for (int i = 0; i < len; i++) {\n                Object o = Array.get(obj, i);\n                if (equals(o, element)) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 对象是否不为空(新增)\n     *\n     * @param obj String,List,Map,Object[],int[],long[]\n     * @return\n     */\n    public static boolean isNotEmpty(Object o) {\n        return !isEmpty(o);\n    }\n\n    /**\n     * 对象是否为空\n     *\n     * @param obj String,List,Map,Object[],int[],long[]\n     * @return\n     */\n    @SuppressWarnings(\"rawtypes\")\n    public static boolean isEmpty(Object o) {\n        if (o == null) {\n            return true;\n        }\n        if (o instanceof String) {\n            if (o.toString().trim().equals(\"\")) {\n                return true;\n            }\n        } else if (o instanceof List) {\n            if (((List) o).size() == 0) {\n                return true;\n            }\n        } else if (o instanceof Map) {\n            if (((Map) o).size() == 0) {\n                return true;\n            }\n        } else if (o instanceof Set) {\n            if (((Set) o).size() == 0) {\n                return true;\n            }\n        } else if (o instanceof Object[]) {\n            if (((Object[]) o).length == 0) {\n                return true;\n            }\n        } else if (o instanceof int[]) {\n            if (((int[]) o).length == 0) {\n                return true;\n            }\n        } else if (o instanceof long[]) {\n            if (((long[]) o).length == 0) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 对象组中是否存在 Empty Object\n     *\n     * @param os 对象组\n     * @return\n     */\n    public static boolean isOneEmpty(Object... os) {\n        for (Object o : os) {\n            if (isEmpty(o)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 对象组中是否全是 Empty Object\n     *\n     * @param os\n     * @return\n     */\n    public static boolean isAllEmpty(Object... os) {\n        for (Object o : os) {\n            if (!isEmpty(o)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 是否为数字\n     *\n     * @param obj\n     * @return\n     */\n    public static boolean isNum(Object obj) {\n        try {\n            Integer.parseInt(obj.toString());\n        } catch (Exception e) {\n            return false;\n        }\n        return true;\n    }\n\n    /**\n     * 如果为空, 则调用默认值\n     *\n     * @param str\n     * @return\n     */\n    public static Object getValue(Object str, Object defaultValue) {\n        if (isEmpty(str)) {\n            return defaultValue;\n        }\n        return str;\n    }\n\n    /**\n     * 格式化文本\n     *\n     * @param template 文本模板，被替换的部分用 {} 表示\n     * @param values   参数值\n     * @return 格式化后的文本\n     */\n    public static String format(String template, Object... values) {\n        return StrKit.format(template, values);\n    }\n\n    /**\n     * 格式化文本\n     *\n     * @param template 文本模板，被替换的部分用 {key} 表示\n     * @param map      参数值对\n     * @return 格式化后的文本\n     */\n    public static String format(String template, Map<?, ?> map) {\n        return StrKit.format(template, map);\n    }\n\n    /**\n     * 强转->string,并去掉多余空格\n     *\n     * @param str\n     * @return\n     */\n    public static String toStr(Object str) {\n        return toStr(str, \"\");\n    }\n\n    /**\n     * 强转->string,并去掉多余空格\n     *\n     * @param str\n     * @param defaultValue\n     * @return\n     */\n    public static String toStr(Object str, String defaultValue) {\n        if (null == str) {\n            return defaultValue;\n        }\n        return str.toString().trim();\n    }\n\n    /**\n     * 强转->int\n     *\n     * @param obj\n     * @return\n     */\n//\tpublic static int toInt(Object value) {\n//\t\treturn toInt(value, -1);\n//\t}\n\n    /**\n     * 强转->int\n     *\n     * @param obj\n     * @param defaultValue\n     * @return\n     */\n//\tpublic static int toInt(Object value, int defaultValue) {\n//\t\treturn Convert.toInt(value, defaultValue);\n//\t}\n\n    /**\n     * 强转->long\n     *\n     * @param obj\n     * @return\n     */\n//\tpublic static long toLong(Object value) {\n//\t\treturn toLong(value, -1);\n//\t}\n\n    /**\n     * 强转->long\n     *\n     * @param obj\n     * @param defaultValue\n     * @return\n     */\n//\tpublic static long toLong(Object value, long defaultValue) {\n//\t\treturn Convert.toLong(value, defaultValue);\n//\t}\n//\n//\tpublic static String encodeUrl(String url) {\n//\t\treturn URLKit.encode(url, CharsetKit.UTF_8);\n//\t}\n//\n//\tpublic static String decodeUrl(String url) {\n//\t\treturn URLKit.decode(url, CharsetKit.UTF_8);\n//\t}\n\n    /**\n     * map的key转为小写\n     *\n     * @param map\n     * @return Map<String,Object>\n     */\n    public static Map<String, Object> caseInsensitiveMap(Map<String, Object> map) {\n        Map<String, Object> tempMap = new HashMap<>();\n        for (String key : map.keySet()) {\n            tempMap.put(key.toLowerCase(), map.get(key));\n        }\n        return tempMap;\n    }\n\n    /**\n     * 获取map中第一个数据值\n     *\n     * @param <K> Key的类型\n     * @param <V> Value的类型\n     * @param map 数据源\n     * @return 返回的值\n     */\n    public static <K, V> V getFirstOrNull(Map<K, V> map) {\n        V obj = null;\n        for (Entry<K, V> entry : map.entrySet()) {\n            obj = entry.getValue();\n            if (obj != null) {\n                break;\n            }\n        }\n        return obj;\n    }\n\n    /**\n     * 创建StringBuilder对象\n     *\n     * @return StringBuilder对象\n     */\n    public static StringBuilder builder(String... strs) {\n        final StringBuilder sb = new StringBuilder();\n        for (String str : strs) {\n            sb.append(str);\n        }\n        return sb;\n    }\n\n    /**\n     * 创建StringBuilder对象\n     *\n     * @return StringBuilder对象\n     */\n    public static void builder(StringBuilder sb, String... strs) {\n        for (String str : strs) {\n            sb.append(str);\n        }\n    }\n\n    /**\n     * 去掉指定后缀\n     *\n     * @param str    字符串\n     * @param suffix 后缀\n     * @return 切掉后的字符串，若后缀不是 suffix， 返回原字符串\n     */\n    public static String removeSuffix(String str, String suffix) {\n        if (isEmpty(str) || isEmpty(suffix)) {\n            return str;\n        }\n\n        if (str.endsWith(suffix)) {\n            return str.substring(0, str.length() - suffix.length());\n        }\n        return str;\n    }\n\n    /**\n     * 当前时间\n     *\n     * @author enilu.cn\n     * @Date 2017/5/7 21:56\n     */\n    public static String currentTime() {\n        return DateUtil.getTime();\n    }\n\n    /**\n     * 首字母大写\n     *\n     * @author enilu.cn\n     * @Date 2017/5/7 22:01\n     */\n    public static String firstLetterToUpper(String val) {\n        return StrKit.firstCharToUpperCase(val);\n    }\n\n    /**\n     * 首字母小写\n     *\n     * @author enilu.cn\n     * @Date 2017/5/7 22:02\n     */\n    public static String firstLetterToLower(String val) {\n        return StrKit.firstCharToLowerCase(val);\n    }\n\n    /**\n     * 判断是否是windows操作系统\n     *\n     * @author enilu.cn\n     * @Date 2017/5/24 22:34\n     */\n    public static Boolean isWinOs() {\n        String os = System.getProperty(\"os.name\");\n        if (os.toLowerCase().startsWith(\"win\")) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * 获取临时目录\n     *\n     * @author enilu.cn\n     * @Date 2017/5/24 22:35\n     */\n    public static String getTempPath() {\n        return System.getProperty(\"java.io.tmpdir\");\n    }\n\n    /**\n     * 把一个数转化为int\n     *\n     * @author fengshuonan\n     * @Date 2017/11/15 下午11:10\n     */\n    public static Integer toInt(Object val) {\n        if (val instanceof Double) {\n            BigDecimal bigDecimal = new BigDecimal((Double) val);\n            return bigDecimal.intValue();\n        } else {\n            return Integer.valueOf(val.toString());\n        }\n\n    }\n\n    /**\n     * 获取项目路径\n     */\n    public static String getWebRootPath(String filePath) {\n        try {\n            String path = ToolUtil.class.getClassLoader().getResource(\"\").toURI().getPath();\n            path = path.replace(\"/WEB-INF/classes/\", \"\");\n            path = path.replace(\"/target/classes/\", \"\");\n            path = path.replace(\"file:/\", \"\");\n            if (ToolUtil.isEmpty(filePath)) {\n                return path;\n            } else {\n                return path + \"/\" + filePath;\n            }\n        } catch (URISyntaxException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/WafKit.java",
    "content": "/**\n * Copyright (c) 2011-2014, hubin (jobob@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.utils;\n\nimport java.util.regex.Pattern;\n\n/**\n * Web防火墙工具类\n * <p>\n * @author   hubin\n * @Date\t 2014-5-8 \t \n */\npublic class WafKit {\n\n\t/**\n\t * @Description 过滤XSS脚本内容\n\t * @param value\n\t * \t\t\t\t待处理内容\n\t * @return\n\t */\n\tpublic static String stripXSS(String value) {\n\t\tString rlt = null;\n\n\t\tif (null != value) {\n\t\t\t// NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to\n\t\t\t// avoid encoded attacks.\n\t\t\t// value = ESAPI.encoder().canonicalize(value);\n\n\t\t\t// Avoid null characters\n\t\t\trlt = value.replaceAll(\"\", \"\");\n\n\t\t\t// Avoid anything between script tags\n\t\t\tPattern scriptPattern = Pattern.compile(\"<script>(.*?)</script>\", Pattern.CASE_INSENSITIVE);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\n\t\t\t// Avoid anything in a src='...' type of expression\n\t\t\t/*scriptPattern = Pattern.compile(\"src[\\r\\n]*=[\\r\\n]*\\\\\\'(.*?)\\\\\\'\", Pattern.CASE_INSENSITIVE\n\t\t\t\t\t| Pattern.MULTILINE | Pattern.DOTALL);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\n\t\t\tscriptPattern = Pattern.compile(\"src[\\r\\n]*=[\\r\\n]*\\\\\\\"(.*?)\\\\\\\"\", Pattern.CASE_INSENSITIVE\n\t\t\t\t\t| Pattern.MULTILINE | Pattern.DOTALL);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");*/\n\n\t\t\t// Remove any lonesome </script> tag\n\t\t\tscriptPattern = Pattern.compile(\"</script>\", Pattern.CASE_INSENSITIVE);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\n\t\t\t// Remove any lonesome <script ...> tag\n\t\t\tscriptPattern = Pattern.compile(\"<script(.*?)>\", Pattern.CASE_INSENSITIVE\n\t\t\t\t\t| Pattern.MULTILINE | Pattern.DOTALL);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\n\t\t\t// Avoid eval(...) expressions\n\t\t\tscriptPattern = Pattern.compile(\"eval\\\\((.*?)\\\\)\", Pattern.CASE_INSENSITIVE\n\t\t\t\t\t| Pattern.MULTILINE | Pattern.DOTALL);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\n\t\t\t// Avoid expression(...) expressions\n\t\t\tscriptPattern = Pattern.compile(\"expression\\\\((.*?)\\\\)\", Pattern.CASE_INSENSITIVE\n\t\t\t\t\t| Pattern.MULTILINE | Pattern.DOTALL);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\n\t\t\t// Avoid javascript:... expressions\n\t\t\tscriptPattern = Pattern.compile(\"javascript:\", Pattern.CASE_INSENSITIVE);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\n\t\t\t// Avoid vbscript:... expressions\n\t\t\tscriptPattern = Pattern.compile(\"vbscript:\", Pattern.CASE_INSENSITIVE);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\n\t\t\t// Avoid onload= expressions\n\t\t\tscriptPattern = Pattern.compile(\"onload(.*?)=\", Pattern.CASE_INSENSITIVE\n\t\t\t\t\t| Pattern.MULTILINE | Pattern.DOTALL);\n\t\t\trlt = scriptPattern.matcher(rlt).replaceAll(\"\");\n\t\t}\n\t\t\n\t\treturn rlt;\n\t}\n\n\t/**\n\t * @Description 过滤SQL注入内容\n\t * @param value\n\t * \t\t\t\t待处理内容\n\t * @return\n\t */\n\tpublic static String stripSqlInjection(String value) {\n\t\treturn (null == value) ? null : value.replaceAll(\"('.+--)|(--)|(%7C)\", \"\"); //value.replaceAll(\"('.+--)|(--)|(\\\\|)|(%7C)\", \"\");\n\t}\n\n\t/**\n\t * @Description 过滤SQL/XSS注入内容\n\t * @param value\n\t * \t\t\t\t待处理内容\n\t * @return\n\t */\n\tpublic static String stripSqlXSS(String value) {\n\t\treturn stripXSS(stripSqlInjection(value));\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/WafRequestWrapper.java",
    "content": "/**\n * Copyright (c) 2011-2014, hubin (jobob@qq.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\npackage cn.enilu.material.utils;\n\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletRequestWrapper;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Request请求过滤包装\n * <p>\n * @author   hubin\n * @Date\t 2014-5-8 \t \n */\npublic class WafRequestWrapper extends HttpServletRequestWrapper {\n\n\tprivate boolean filterXSS = true;\n\n\tprivate boolean filterSQL = true;\n\n\n\tpublic WafRequestWrapper(HttpServletRequest request, boolean filterXSS, boolean filterSQL) {\n\t\tsuper(request);\n\t\tthis.filterXSS = filterXSS;\n\t\tthis.filterSQL = filterSQL;\n\t}\n\n\n\tpublic WafRequestWrapper(HttpServletRequest request) {\n\t\tthis(request, true, true);\n\t}\n\n\n\t/**\n\t * @Description 数组参数过滤\n\t * @param parameter\n\t * \t\t\t\t过滤参数\n\t * @return\n\t */\n\t@Override\n\tpublic String[] getParameterValues(String parameter) {\n\t\tString[] values = super.getParameterValues(parameter);\n\t\tif ( values == null ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tint count = values.length;\n\t\tString[] encodedValues = new String[count];\n\t\tfor ( int i = 0 ; i < count ; i++ ) {\n\t\t\tencodedValues[i] = filterParamString(values[i]);\n\t\t}\n\n\t\treturn encodedValues;\n\t}\n\n\t@Override\n\t@SuppressWarnings({ \"rawtypes\", \"unchecked\" })\n\tpublic Map getParameterMap() {\n\t\tMap<String, String[]> primary = super.getParameterMap();\n\t\tMap<String, String[]> result = new HashMap<String, String[]>(primary.size());\n\t\tfor ( Map.Entry<String, String[]> entry : primary.entrySet() ) {\n\t\t\tresult.put(entry.getKey(), filterEntryString(entry.getValue()));\n\t\t}\n\t\treturn result;\n\n\t}\n\t\n\tprotected String[] filterEntryString(String[] rawValue) {\n\t\tfor ( int i = 0 ; i < rawValue.length ; i++ ) {\n\t\t\trawValue[i] = filterParamString(rawValue[i]);\n\t\t}\n\t\treturn rawValue;\n\t}\n\n\t/**\n\t * @Description 参数过滤\n\t * @param parameter\n\t * \t\t\t\t过滤参数\n\t * @return\n\t */\n\t@Override\n\tpublic String getParameter(String parameter) {\n\t\treturn filterParamString(super.getParameter(parameter));\n\t}\n\n\n\t/**\n\t * @Description 请求头过滤 \n\t * @param name\n\t * \t\t\t\t过滤内容\n\t * @return\n\t */\n\t@Override\n\tpublic String getHeader(String name) {\n\t\treturn filterParamString(super.getHeader(name));\n\t}\n\n\n\t/**\n\t * @Description Cookie内容过滤\n\t * @return\n\t */\n\t@Override\n\tpublic Cookie[] getCookies() {\n\t\tCookie[] existingCookies = super.getCookies();\n\t\tif (existingCookies != null) {\n\t\t\tfor (int i = 0 ; i < existingCookies.length ; ++i) {\n\t\t\t\tCookie cookie = existingCookies[i];\n\t\t\t\tcookie.setValue(filterParamString(cookie.getValue()));\n\t\t\t}\n\t\t}\n\t\treturn existingCookies;\n\t}\n\n\t/**\n\t * @Description 过滤字符串内容\n\t * @param rawValue\n\t * \t\t\t\t待处理内容\n\t * @return\n\t */\n\tprotected String filterParamString(String rawValue) {\n\t\tif (null == rawValue) {\n\t\t\treturn null;\n\t\t}\n\t\tString tmpStr = rawValue;\n\t\tif (this.filterXSS) {\n\t\t\ttmpStr = WafKit.stripXSS(rawValue);\n\t\t}\n\t\tif (this.filterSQL) {\n\t\t\ttmpStr = WafKit.stripSqlInjection(tmpStr);\n\t\t}\n\t\treturn tmpStr;\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/XmlHelper.java",
    "content": "package cn.enilu.material.utils;\n\nimport org.apache.commons.io.IOUtils;\nimport org.w3c.dom.Document;\nimport org.w3c.dom.Element;\nimport org.w3c.dom.Node;\nimport org.w3c.dom.NodeList;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.SAXException;\n\nimport javax.xml.namespace.QName;\nimport javax.xml.parsers.DocumentBuilder;\nimport javax.xml.parsers.DocumentBuilderFactory;\nimport javax.xml.parsers.ParserConfigurationException;\nimport javax.xml.xpath.XPath;\nimport javax.xml.xpath.XPathConstants;\nimport javax.xml.xpath.XPathExpressionException;\nimport javax.xml.xpath.XPathFactory;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.StringReader;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Created by huan on 2017/1/7.\n */\npublic class XmlHelper {\n\n    private final XPath path;\n    private final Document doc;\n\n    private XmlHelper(InputSource inputSource) throws ParserConfigurationException, SAXException, IOException {\n        DocumentBuilderFactory dbf = getDocumentBuilderFactory();\n        DocumentBuilder db = dbf.newDocumentBuilder();\n        doc = db.parse(inputSource);\n        path = getXPathFactory().newXPath();\n    }\n\n    private static XmlHelper create(InputSource inputSource) {\n        try {\n            return new XmlHelper(inputSource);\n        } catch (ParserConfigurationException e) {\n            throw new RuntimeException(e);\n        } catch (SAXException e) {\n            throw new RuntimeException(e);\n        } catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static XmlHelper of(InputStream is) {\n        InputSource inputSource = new InputSource(is);\n        return create(inputSource);\n    }\n\n    public static XmlHelper of(String xmlStr) {\n        StringReader sr = new StringReader(xmlStr.trim());\n        InputSource inputSource = new InputSource(sr);\n        XmlHelper xmlHelper = create(inputSource);\n        IOUtils.closeQuietly(sr);\n        return xmlHelper;\n    }\n\n    private Object evalXPath(String expression, Object item, QName returnType) {\n        item = null == item ? doc : item;\n        try {\n            return path.evaluate(expression, item, returnType);\n        } catch (XPathExpressionException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * 获取String\n     * @param expression 路径\n     * @return String\n     */\n    public String getString(String expression) {\n        return (String) evalXPath(expression, null, XPathConstants.STRING);\n    }\n\n    /**\n     * 获取Boolean\n     * @param expression 路径\n     * @return String\n     */\n    public Boolean getBoolean(String expression) {\n        return (Boolean) evalXPath(expression, null, XPathConstants.BOOLEAN);\n    }\n\n    /**\n     * 获取Number\n     * @param expression 路径\n     * @return {Number}\n     */\n    public Number getNumber(String expression) {\n        return (Number) evalXPath(expression, null, XPathConstants.NUMBER);\n    }\n\n    /**\n     * 获取某个节点\n     * @param expression 路径\n     * @return {Node}\n     */\n    public Node getNode(String expression) {\n        return (Node) evalXPath(expression, null, XPathConstants.NODE);\n    }\n\n    /**\n     * 获取子节点\n     * @param expression 路径\n     * @return NodeList\n     */\n    public NodeList getNodeList(String expression) {\n        return (NodeList) evalXPath(expression, null, XPathConstants.NODESET);\n    }\n\n\n    /**\n     * 获取String\n     * @param node 节点\n     * @param expression 相对于node的路径\n     * @return String\n     */\n    public String getString(Object node, String expression) {\n        return (String) evalXPath(expression, node, XPathConstants.STRING);\n    }\n\n    /**\n     * 获取\n     * @param node 节点\n     * @param expression 相对于node的路径\n     * @return String\n     */\n    public Boolean getBoolean(Object node, String expression) {\n        return (Boolean) evalXPath(expression, node, XPathConstants.BOOLEAN);\n    }\n\n    /**\n     * 获取\n     * @param node 节点\n     * @param expression 相对于node的路径\n     * @return {Number}\n     */\n    public Number getNumber(Object node, String expression) {\n        return (Number) evalXPath(expression, node, XPathConstants.NUMBER);\n    }\n\n    /**\n     * 获取某个节点\n     * @param node 节点\n     * @param expression 路径\n     * @return {Node}\n     */\n    public Node getNode(Object node, String expression) {\n        return (Node) evalXPath(expression, node, XPathConstants.NODE);\n    }\n\n    /**\n     * 获取子节点\n     * @param node 节点\n     * @param expression 相对于node的路径\n     * @return NodeList\n     */\n    public NodeList getNodeList(Object node, String expression) {\n        return (NodeList) evalXPath(expression, node, XPathConstants.NODESET);\n    }\n\n    /**\n     * 针对没有嵌套节点的简单处理\n     * @return map集合\n     */\n    public Map<String, String> toMap() {\n        Element root = doc.getDocumentElement();\n        Map<String, String> params = new HashMap<String, String>();\n\n        // 将节点封装成map形式\n        NodeList list = root.getChildNodes();\n        for (int i = 0; i < list.getLength(); i++) {\n            Node node = list.item(i);\n            if (node instanceof Element) {\n                params.put(node.getNodeName(), node.getTextContent());\n            }\n        }\n        return params;\n    }\n\n    private static DocumentBuilderFactory getDocumentBuilderFactory(){\n        return XmlHelper.XmlHelperHolder.documentBuilderFactory;\n    }\n\n    private static XPathFactory getXPathFactory() {\n        return  XmlHelper.XmlHelperHolder.xPathFactory;\n    }\n\n    /**\n     * 内部类单例\n     */\n    private static class XmlHelperHolder {\n        private static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();\n        private static XPathFactory xPathFactory = XPathFactory.newInstance();\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/ZipUtils.java",
    "content": "package cn.enilu.material.utils;\n\nimport java.io.*;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.List;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\nimport java.util.zip.ZipOutputStream;\n\n\n/**\n * 压缩和解压缩\n * \n * @author\n * */\npublic class ZipUtils {\n\t/**\n\t * 日志记录，为静态变量，防止多次实例化\n\t * \n\t * */\n//\tprivate static Logger log = Logger.getLogger(ZipUtils.class);\n\t/**\n\t * 每次读入大小\n\t */\n\tprivate static final int BUFFER = 4096;\n\n\t/**\n\t * 做成压缩文件\n\t * \n\t * @param baseDir\n\t *            压缩文件夹\n\t * @param zipFileName\n\t *            生成压缩文件名\n\t * @return 是否成功\n\t */\n\tpublic static boolean zipFile(String baseDir, String zipFileName) {\n\t\ttry {\n\t\t\t// 获取文件夹下所有文件\n\t\t\tList<File> fileList = getSubFiles(new File(baseDir));\n\t\t\tZipOutputStream zos;\n\t\t\tzos = new ZipOutputStream(new FileOutputStream(zipFileName));\n\t\t\tfor (int i = 0; i < fileList.size(); i++) {\n\t\t\t\tFile f = fileList.get(i);\n\t\t\t\tzipAddFile(zos, f, getAbsFileName(baseDir, f));\n\t\t\t}\n\t\t\tzos.close();\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n//\t\t\tlog.error(\"生成压缩文件错误:错误原因如下:\" + e.getMessage());\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 做成压缩文件\n\t * \n\t * @param baseDir\n\t *            压缩文件夹\n\t * @return 是否成功\n\t */\n\tpublic static String zipFile(String baseDir) {\n\t\tZipOutputStream zos = null;\n\t\ttry {\n\t\t\tFile base = new File(baseDir);\n\t\t\tString target = base.getPath() + \".zip\";\n\t\t\t// 获取文件夹下所有文件\n\t\t\tList<File> fileList = getSubFiles(base);\n\t\t\tzos = new ZipOutputStream(new FileOutputStream(target));\n\t\t\tfor (int i = 0; i < fileList.size(); i++) {\n\t\t\t\tFile f = fileList.get(i);\n\t\t\t\tzipAddFile(zos, f, getAbsFileName(baseDir, f));\n\t\t\t}\n\t\t\treturn target;\n\t\t} catch (Exception e) {\n//\t\t\tlog.error(\"生成压缩文件错误:错误原因如下:\" + e.getMessage());\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tif (zos != null) {\n\t\t\t\t\tzos.close();\n\t\t\t\t}\n\t\t\t} catch (IOException e) {\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 压缩包中添加文件\n\t * \n\t * @param zos\n\t *            压缩包对象\n\t * @param file\n\t *            文件对象\n\t * @param filePath\n\t *            在压缩包中的路径\n\t * @return 是否成功\n\t */\n\tprivate static boolean zipAddFile(ZipOutputStream zos, File file,\n\t\t\t\t\t\t\t\t\t  String filePath) throws FileNotFoundException, IOException {\n\t\tZipEntry ze = new ZipEntry(filePath);\n\t\tze.setSize(file.length());\n\t\tze.setTime(file.lastModified());\n\t\tzos.putNextEntry(ze);\n\n\t\tInputStream is = new BufferedInputStream(new FileInputStream(file));\n\t\tint readLen = 0;\n\t\tbyte[] buf = new byte[BUFFER];\n\t\twhile ((readLen = is.read(buf, 0, BUFFER)) != -1) {\n\t\t\tzos.write(buf, 0, readLen);\n\t\t}\n\t\t// zos.setEncoding(\"GBK\");\n\t\tis.close();\n\t\treturn true;\n\t}\n\n\t/**\n\t * 解压缩文件\n\t * \n\t * @param zipName\n\t *            包的文件名\n\t * @param targetDirName\n\t *            需解压到的目录\n\t * @return 是否成功\n\t */\n\tpublic static boolean upZipFile(String zipName, String targetDirName) {\n\t\tZipFile zipFile =null;\n\t\ttry {\n\t\t\tzipFile = new ZipFile(zipName);\n\t\t\tif (!targetDirName.endsWith(File.separator)) {\n\t\t\t\ttargetDirName += File.separator;\n\t\t\t}\n\t\t\tZipEntry zn = null;\n\t\t\tString entryName = null;\n\t\t\tString targetFileName = null;\n\t\t\tbyte[] buffer = new byte[BUFFER];\n\t\t\tint readLen = 0;\n\t\t\t// 获取ZIP文件里所有的文件条目的名字\n\t\t\tEnumeration<?> entrys = zipFile.entries();\n\t\t\twhile (entrys.hasMoreElements()) {\n\t\t\t\tzn = (ZipEntry) entrys.nextElement();\n\t\t\t\tentryName = zn.getName();\n\t\t\t\ttargetFileName = targetDirName + entryName;\n\t\t\t\tif (zn.isDirectory()) {\n\t\t\t\t\t// 如果zn是一个目录，则创建目录\n\t\t\t\t\tnew File(targetFileName).mkdirs();\n\t\t\t\t\tcontinue;\n\t\t\t\t} else {\n\t\t\t\t\t// 如果zn是一个文件，则创建父目录\n\t\t\t\t\tnew File(targetFileName).getParentFile().mkdirs();\n\t\t\t\t}\n\t\t\t\t// 创建文件\n\t\t\t\tFile targetFile = new File(targetFileName);\n\t\t\t\tFileOutputStream os = new FileOutputStream(targetFile);\n\t\t\t\t// 从ZipFile对象中打开entry的输入流\n\t\t\t\tInputStream is = zipFile.getInputStream(zn);\n\t\t\t\twhile ((readLen = is.read(buffer)) != -1) {\n\t\t\t\t\tos.write(buffer, 0, readLen);\n\t\t\t\t}\n\t\t\t\t// 关闭流\n\t\t\t\tos.close();\n\t\t\t\tis.close();\n\t\t\t}\n\t\t\treturn true;\n\t\t} catch (Exception e) {\n//\t\t\tlog.error(\"解压缩错误:错误原因如下:\" + e.getMessage());\n\t\t}finally{\n\t\t\ttry{\n\t\t\tzipFile.close();\n\t\t\t}catch(Exception e){}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * 生成文件在压缩包中的路径\n\t * \n\t * @param baseDir\n\t *            压缩包所在文件夹路径\n\t * @param realFile\n\t *            文件对象\n\t * @return 文件在压缩包中的路径\n\t */\n\tprivate static String getAbsFileName(String baseDir, File realFile) {\n\t\tFile real = realFile;\n\t\tFile base = new File(baseDir);\n\t\tString ret = real.getName();\n\t\twhile (true) {\n\t\t\treal = real.getParentFile();\n\t\t\tif (real == null) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (real.equals(base)) {\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tret = real.getName() + \"/\" + ret;\n\t\t\t}\n\t\t}\n\t\treturn ret;\n\t}\n\n\t/**\n\t * 获取文件夹下所有文件\n\t * \n\t * @param baseDir\n\t *            文件夹路径\n\t * @return 文件集合\n\t */\n\tprivate static List<File> getSubFiles(File baseDir) {\n\t\tList<File> ret = new ArrayList<File>();\n\t\tFile[] tmp = baseDir.listFiles();\n\t\tfor (int i = 0; i < tmp.length; i++) {\n\t\t\tif (tmp[i].isFile()) {\n\t\t\t\tret.add(tmp[i]);\n\t\t\t}\n\t\t\tif (tmp[i].isDirectory()) {\n\t\t\t\tret.addAll(getSubFiles(tmp[i]));\n\t\t\t}\n\t\t}\n\t\treturn ret;\n\t}\n\t\n\tpublic static boolean isExist(String path) {\n\t\tFile file = new File(path);\n\t\treturn file.exists();\n\t}\n\t\n\tpublic static boolean createDirectory(String path) {\n\t\tFile file = new File(path);\n\t\tif (!isExist(path)) {\n\t\t\tfile.mkdirs();\n\t\t}\n\t\treturn true;\n\t}\n\t\n\tpublic static boolean deleteDirectory(String path) {\n\t\tFile f = new File(path);\n\t\tif (isExist(path)) {\n\t\t\tif (f.isDirectory()) {\n\t\t\t\tFile[] files = f.listFiles();\n\t\t\t\tfor (int i = 0; i < files.length; i++) {\n\t\t\t\t\tdeleteDirectory(files[i].getPath());\n\t\t\t\t}\n\t\t\t\tf.delete();\n\t\t\t} else if (f.isFile()) {\n\t\t\t\tf.delete();\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/cache/TimeCacheMap.java",
    "content": "package cn.enilu.material.utils.cache;\n\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.Map;\n\n/**\n * Created by zt on 2017/4/12 0012.\n */\npublic class TimeCacheMap<K, V> {\n    private static final int DEFAULT_NUM_BUCKETS = 3;\n\n\n    //回调函数实现这个接口就可以，至少可以把删掉的元素传回去\n    public static interface ExpiredCallback<K, V> {\n        public void expire(K key, V val);\n    }\n\n    //把数据分成多个桶，用链表是因为在头尾的增减操作时O（1）\n    private LinkedList<HashMap<K, V>> _buckets;\n\n    private final Object _lock = new Object();\n    private Thread _cleaner;\n    private ExpiredCallback _callback;\n\n    public TimeCacheMap(int expirationSecs, int numBuckets, ExpiredCallback<K, V> callback) {\n        if (numBuckets < 2) {\n            throw new IllegalArgumentException(\"numBuckets must be >= 2\");\n        }\n        //构造函数中，按照桶的数量，初始桶\n        _buckets = new LinkedList<HashMap<K, V>>();\n        for (int i = 0; i < numBuckets; i++) {\n            _buckets.add(new HashMap<K, V>());\n        }\n\n\n        _callback = callback;\n        final long expirationMillis = expirationSecs * 1000L;\n        final long sleepTime = expirationMillis / (numBuckets - 1);\n        _cleaner = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                while (true) {\n                    Map<K, V> dead = null;\n                    try {\n                        Thread.sleep(sleepTime);\n                    } catch (InterruptedException e) {\n\n                    }\n//                        Time.sleep(sleepTime);\n                    synchronized (_lock) {\n                        //删掉最后一个桶，在头补充一个新的桶，最后一个桶的数据是最旧的\n                        dead = _buckets.removeLast();\n                        _buckets.addFirst(new HashMap<K, V>());\n                    }\n                    if (_callback != null) {\n                        for (Map.Entry<K, V> entry : dead.entrySet()) {\n                            _callback.expire(entry.getKey(), entry.getValue());\n                        }\n                    }\n                }\n            }\n        });\n        //作为守护线程运行，一旦主线程不在，这个线程自动结束\n        _cleaner.setDaemon(true);\n        _cleaner.start();\n    }\n\n    public TimeCacheMap(int expirationSecs, ExpiredCallback<K, V> callback) {\n        this(expirationSecs, DEFAULT_NUM_BUCKETS, callback);\n    }\n\n    public TimeCacheMap(int expirationSecs) {\n        this(expirationSecs, DEFAULT_NUM_BUCKETS);\n    }\n\n    public TimeCacheMap(int expirationSecs, int numBuckets) {\n        this(expirationSecs, numBuckets, null);\n    }\n\n\n    public boolean containsKey(K key) {\n        if (_buckets.getFirst().containsKey(key)) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public V get(K key) {\n        return _buckets.getFirst().get(key);\n    }\n\n    public void put(K key, V value) {\n        _buckets.getFirst().put(key, value);\n\n    }\n\n    public Object remove(K key) {\n        return _buckets.getFirst().remove(key);\n    }\n\n    public int size() {\n        return _buckets.getFirst().size();\n    }\n\n\n    public void cleanup() {\n        //中断清理线程中的sleep，_cleaner线程会抛出异常，然后_cleaner线程就死了，不再清理过期数据了\n        _cleaner.interrupt();  //调用了interrupt后，再跑sleep就会抛InterruptedException异常\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/utils/cache/exception/ToolBoxException.java",
    "content": "package cn.enilu.material.utils.cache.exception;\n\n\nimport cn.enilu.material.utils.StrKit;\n\n/**\n * 工具类初始化异常\n */\npublic class ToolBoxException extends RuntimeException{\n\tprivate static final long serialVersionUID = 8247610319171014183L;\n\n\tpublic ToolBoxException(Throwable e) {\n\t\tsuper(e.getMessage(), e);\n\t}\n\t\n\tpublic ToolBoxException(String message) {\n\t\tsuper(message);\n\t}\n\t\n\tpublic ToolBoxException(String messageTemplate, Object... params) {\n\t\tsuper(StrKit.format(messageTemplate, params));\n\t}\n\t\n\tpublic ToolBoxException(String message, Throwable throwable) {\n\t\tsuper(message, throwable);\n\t}\n\t\n\tpublic ToolBoxException(Throwable throwable, String messageTemplate, Object... params) {\n\t\tsuper(StrKit.format(messageTemplate, params), throwable);\n\t}\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/warpper/BaseControllerWarpper.java",
    "content": "package cn.enilu.material.warpper;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 控制器查询结果的包装类基类\n *\n * @author fengshuonan\n * @date 2017年2月13日 下午10:49:36\n */\npublic abstract class BaseControllerWarpper {\n\n    public Object obj = null;\n    public BaseControllerWarpper(Object obj) {\n        this.obj = obj;\n    }\n\n        @SuppressWarnings(\"unchecked\")\n    public Object warp() {\n\n        if (this.obj instanceof List) {\n            List<Map<String, Object>> list = (List<Map<String, Object>>) this.obj;\n            for (Map<String, Object> map : list) {\n                warpTheMap(map);\n            }\n            return list;\n        } else if (this.obj instanceof Map) {\n            Map<String, Object> map = (Map<String, Object>) this.obj;\n            warpTheMap(map);\n            return map;\n        } else {\n            return this.obj;\n        }\n    }\n\n    protected abstract void warpTheMap(Map<String, Object> map);\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/warpper/DeptWarpper.java",
    "content": "package cn.enilu.material.warpper;\n\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.ToolUtil;\n\nimport java.util.Map;\n\n/**\n * 部门列表的包装\n *\n * @author fengshuonan\n * @date 2017年4月25日 18:10:31\n */\npublic class DeptWarpper extends BaseControllerWarpper {\n\n    public DeptWarpper(Object list) {\n        super(list);\n    }\n\n    @Override\n    public void warpTheMap(Map<String, Object> map) {\n\n        Long pid = (Long) map.get(\"pid\");\n\n        if (ToolUtil.isEmpty(pid) || pid.equals(0)) {\n            map.put(\"pName\", \"--\");\n        } else {\n            map.put(\"pName\", ConstantFactory.me().getDeptName(pid));\n        }\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/warpper/DictWarpper.java",
    "content": "package cn.enilu.material.warpper;\n\nimport cn.enilu.material.bean.entity.system.Dict;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.ToolUtil;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 字典列表的包装\n *\n * @author fengshuonan\n * @date 2017年4月25日 18:10:31\n */\npublic class DictWarpper extends BaseControllerWarpper {\n\n    public DictWarpper(Object list) {\n        super(list);\n    }\n\n    @Override\n    public void warpTheMap(Map<String, Object> map) {\n        StringBuffer detail = new StringBuffer();\n        Long id = (Long) map.get(\"id\");\n        List<Dict> dicts = ConstantFactory.me().findInDict(id);\n        if(dicts != null){\n            for (Dict dict : dicts) {\n                detail.append(dict.getValue() + \":\" +dict.getName() + \",\");\n            }\n            map.put(\"detail\", ToolUtil.removeSuffix(detail.toString(),\",\"));\n        }\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/warpper/LogWarpper.java",
    "content": "package cn.enilu.material.warpper;\n\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.Constants;\nimport cn.enilu.material.utils.DateUtil;\nimport cn.enilu.material.utils.ToolUtil;\n\nimport java.util.Date;\nimport java.util.Map;\n\n/**\n * 日志列表的包装类\n *\n * @author fengshuonan\n * @date 2017年4月5日22:56:24\n */\npublic class LogWarpper extends BaseControllerWarpper {\n\n    public LogWarpper(Object list) {\n        super(list);\n    }\n\n    @Override\n    public void warpTheMap(Map<String, Object> map) {\n        String message = (String) map.get(\"message\");\n\n        Long userid = Long.valueOf(map.get(\"userid\").toString());\n        map.put(\"userName\", ConstantFactory.me().getUserNameById(userid));\n\n        //如果信息过长,则只截取前100位字符串\n        if (ToolUtil.isNotEmpty(message) && message.length() >= 100) {\n            String subMessage = message.substring(0, 100) + \"...\";\n            map.put(\"message\", subMessage);\n        }\n        map.put(\"createTime\",DateUtil.format((Date) map.get(\"createTime\"),\"yyyy-MM-dd hh:MM:ss\"));\n        //如果信息中包含分割符号;;;   则分割字符串返给前台\n        if (ToolUtil.isNotEmpty(message) && message.indexOf(Constants.SEPARATOR) != -1) {\n            String[] msgs = message.split(Constants.SEPARATOR);\n            map.put(\"regularMessage\",msgs);\n        }else{\n            map.put(\"regularMessage\",message);\n        }\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/warpper/MenuWarpper.java",
    "content": "package cn.enilu.material.warpper;\n\nimport cn.enilu.material.bean.vo.node.IsMenu;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 菜单列表的包装类\n *\n * @author fengshuonan\n * @date 2017年2月19日15:07:29\n */\npublic class MenuWarpper extends BaseControllerWarpper {\n\n    public MenuWarpper(List<Map<String, Object>> list) {\n        super(list);\n    }\n\n    @Override\n    public void warpTheMap(Map<String, Object> map) {\n        map.put(\"statusName\", ConstantFactory.me().getMenuStatusName((Integer) map.get(\"status\")));\n        map.put(\"isMenuName\", IsMenu.valueOf((Integer) map.get(\"ismenu\")));\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/warpper/NoticeWrapper.java",
    "content": "package cn.enilu.material.warpper;\n\nimport cn.enilu.material.service.system.impl.ConstantFactory;\n\nimport java.util.Map;\n\n/**\n * 部门列表的包装\n *\n * @author fengshuonan\n * @date 2017年4月25日 18:10:31\n */\npublic class NoticeWrapper extends BaseControllerWarpper {\n\n    public NoticeWrapper(Object list) {\n        super(list);\n    }\n\n    @Override\n    public void warpTheMap(Map<String, Object> map) {\n        Long creater = (Long) map.get(\"createBy\");\n        map.put(\"createrName\", ConstantFactory.me().getUserNameById(creater));\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/warpper/RoleWarpper.java",
    "content": "package cn.enilu.material.warpper;\n\nimport cn.enilu.material.service.system.impl.ConstantFactory;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 角色列表的包装类\n *\n * @author fengshuonan\n * @date 2017年2月19日10:59:02\n */\npublic class RoleWarpper extends BaseControllerWarpper {\n\n    public RoleWarpper(List<Map<String, Object>> list) {\n        super(list);\n    }\n\n    @Override\n    public void warpTheMap(Map<String, Object> map) {\n        map.put(\"pName\", ConstantFactory.me().getSingleRoleName((Long) map.get(\"pid\")));\n        map.put(\"deptName\", ConstantFactory.me().getDeptName((Long) map.get(\"deptid\")));\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/warpper/UserWarpper.java",
    "content": "package cn.enilu.material.warpper;\n\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.StringUtils;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 用户管理的包装类\n *\n * @author fengshuonan\n * @date 2017年2月13日 下午10:47:03\n */\npublic class UserWarpper extends BaseControllerWarpper {\n\n    public UserWarpper(List<Map<String, Object>> list) {\n        super(list);\n    }\n\n    @Override\n    public void warpTheMap(Map<String, Object> map) {\n        map.put(\"sexName\", ConstantFactory.me().getSexName((Integer) map.get(\"sex\")));\n        if(StringUtils.isNotNullOrEmpty(map.get(\"roleid\"))) {\n            map.put(\"roleName\", ConstantFactory.me().getRoleName((String) map.get(\"roleid\")));\n        }\n        if(StringUtils.isNotNullOrEmpty(map.get(\"deptid\"))) {\n            map.put(\"deptName\", ConstantFactory.me().getDeptName((Long) map.get(\"deptid\")));\n        }\n        map.put(\"statusName\", ConstantFactory.me().getStatusName((Integer) map.get(\"status\")));\n\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/web/listener/CacheListener.java",
    "content": "package cn.enilu.material.web.listener;\n\nimport cn.enilu.material.dao.cache.ConfigCache;\nimport cn.enilu.material.dao.cache.DictCache;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.stereotype.Component;\n\n/**\n * 系统监听器<br>\n * 系统启动时加载全局参数(t_sys_cfg标中的数据)到缓存中\n *\n * @author enilu\n * @version 2018-12-23\n */\n@Component\npublic class CacheListener implements CommandLineRunner {\n\n    @Autowired\n    private ConfigCache configCache;\n    @Autowired\n    private DictCache dictCache;\n\n    private Logger logger = LoggerFactory.getLogger(CacheListener.class);\n\n    public void loadCache() {\n        configCache.cache();\n        dictCache.cache();\n    }\n\n    @Override\n    public void run(String... strings) throws Exception {\n        Thread thread = new Thread(new Runnable() {\n            @Override\n            public void run() {\n                loadCache();\n            }\n        });\n        thread.start();\n\n    }\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/web/listener/ConfigListener.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.web.listener;\n\nimport javax.servlet.ServletContext;\nimport javax.servlet.ServletContextEvent;\nimport javax.servlet.ServletContextListener;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ConfigListener implements ServletContextListener {\n\n    private static Map<String, String> conf = new HashMap<>();\n\n    public static Map<String, String> getConf() {\n        return conf;\n    }\n\n    @Override\n    public void contextDestroyed(ServletContextEvent arg0) {\n        conf.clear();\n    }\n\n    @Override\n    public void contextInitialized(ServletContextEvent evt) {\n        ServletContext sc = evt.getServletContext();\n        // 项目路径\n        conf.put(\"realPath\", sc.getRealPath(\"/\").replaceFirst(\"/\", \"\"));\n        conf.put(\"contextPath\", sc.getContextPath());\n    }\n\n}\n"
  },
  {
    "path": "material-core/src/main/java/cn/enilu/material/web/package-info.java",
    "content": "/**\n * package-info\n *\n * @version 2018/11/27 0027\n * @author enilu\n */\npackage cn.enilu.material.web;"
  },
  {
    "path": "material-core/src/main/resources/code/code.json",
    "content": "{\n  \"codeConfig\": {\n    \"type\": \"cn.enilu.flash.code.CodeConfig\",\n    \"fields\": {\n      entityModel: \"material-core\",\n      daoModel: \"material-core\",\n      serviceModel: \"material-core\",\n      controllerModel: \"material-manage\",\n      viewModel: \"material-manage\"\n    }\n  }\n}"
  },
  {
    "path": "material-generator/README.md",
    "content": "English | [简体中文](./README.zh-CN.md)\n\n# Code generation\n\n## Useage\n- Add dependencies in material-core/pom.xml\n```xml\n        <dependency>\n            <groupId>cn.enilu</groupId>\n            <artifactId>material-generator</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n```\n- Download the IDEA Intellij plugin: Search and install the plugin in the plugin center: 'webflash-generator'\n\n- Prepare an entity class,E.g:\n```java\npackage cn.enilu.material.bean.entity.test;\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\n \n@Entity(name=\"t_test_boy\")\n@Table(appliesTo = \"t_test_boy\",comment = \"男孩\")\n@Data\n\npublic class Boy extends BaseEntity {\n    @Column(columnDefinition = \"VARCHAR(32) COMMENT '姓名'\")\n    private String userName;\n    @Column(columnDefinition = \"INT COMMENT '年龄'\")\n    private Integer age;\n    @Column(columnDefinition = \"VARCHAR(12) COMMENT '生日'\")\n    private String birthday;\n    @Column(name = \"has_girl_friend\",columnDefinition = \"TINYINT COMMENT '是否有女朋友'\")\n    private Boolean hasGirFriend;\n}\n\n``` \n- Precautions:\n    - @Table: Use @org.hibernate.annotations.Table don't use @javax.persistence.Table\n    - @Table annotations must be configured with the table name (applyiesTo) and comments (comment)\n    - @Column annotations must be configured with columnDefinition to describe column information (all uppercase in English): include type, comment\n    - Entity classes must inherit BaseEntity\n- After the entity class is ready, open the entity class, right click on \"Generator\"-->\"web-flash-mvc\", and the following content will pop up.\n![code-generator](./doc/code-generate.jpg)    \n**Note**No need to change the configuration in the dialog (most of them have no effect)\n- After running the generated code, it will generate the controller, service, repository, and add and delete the change page and js. Take the example of Boy, the generated code is as follows:\n![generate-result](./doc/generate-result.png)\n- After the code is generated, configure menus and permissions in the system\n![菜单配置](./doc/menu.png)\n\n![功能预览](./doc/boy-list.png)\n\n"
  },
  {
    "path": "material-generator/README.zh-CN.md",
    "content": "[English](./README.md) | 简体中文\n\n# 代码生成\n\n## 用法\n- 在material-core/pom.xml中添加依赖\n```xml\n        <dependency>\n            <groupId>cn.enilu</groupId>\n            <artifactId>material-generator</artifactId>\n            <version>${project.version}</version>\n            <scope>provided</scope>\n        </dependency>\n```\n- 下载intellij代码生成插件，在插件中心搜索并安装插件:webflash-generator\n\n- 写好实体类，例如：\n```java\npackage cn.enilu.material.bean.entity.test;\nimport cn.enilu.material.bean.entity.BaseEntity;\nimport lombok.Data;\nimport org.hibernate.annotations.Table;\nimport javax.persistence.Column;\nimport javax.persistence.Entity;\n \n@Entity(name=\"t_test_boy\")\n@Table(appliesTo = \"t_test_boy\",comment = \"男孩\")\n@Data\n\npublic class Boy extends BaseEntity {\n    @Column(columnDefinition = \"VARCHAR(32) COMMENT '姓名'\")\n    private String name;\n    @Column(columnDefinition = \"INT COMMENT '年龄'\")\n    private Integer age;\n    @Column(columnDefinition = \"VARCHAR(12) COMMENT '生日'\")\n    private String birthday;\n    @Column(name = \"has_girl_friend\",columnDefinition = \"TINYINT COMMENT '是否有女朋友'\")\n    private Boolean hasGirFriend;\n}\n\n``` \n- 上面实体类注意事项\n    - @Table注解要使用org.hibernate.annotations.Table 不要使用javax.persistence.Table\n    - @Table注解 必须配置表名(applyiesTo)和注释(comment)\n    - @Column注解必须配置columnDefinition来表述列信息(英文全部大写)：包括类型,注释COMMENT\n    - 实体类必须继承BaseEntity\n- 实体类准备好了后,打开实体类，右键点击“Generator\"-->\"web-flash-mvc\"，弹出如下图所示对话框\n![code-generator](./doc/code-generate.jpg)    \n**注意**不用更改对话框中的配置(大部分没有什么作用)\n- 运行生成代码后，将会生成controller,service,repository，以及对应的增上改查页面和js,以TestBoy为例,生成的代码如下所示：\n![generate-result](./doc/generate-result.png)\n- 代码生成后，在系统中配置对应的菜单和权限，即可使用\n![菜单配置](./doc/menu.png)\n\n![功能预览](./doc/boy-list.png)\n\n"
  },
  {
    "path": "material-generator/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>material-admin</artifactId>\n        <groupId>cn.enilu</groupId>\n        <version>0.1</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>material-generator</artifactId>\n    <properties>\n        <java-version>1.8</java-version>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <evo-inflector-version>1.0.1</evo-inflector-version>\n        <velocity-version>1.7</velocity-version>\n        <commons-cli-version>1.2</commons-cli-version>\n        <spring.boot.version>2.1.1.RELEASE</spring.boot.version>\n    </properties>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-data-jpa</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.atteo</groupId>\n            <artifactId>evo-inflector</artifactId>\n            <version>${evo-inflector-version}</version>\n        </dependency>\n        <dependency>\n            <groupId>commons-cli</groupId>\n            <artifactId>commons-cli</artifactId>\n            <version>${commons-cli-version}</version>\n        </dependency>\n\n        <dependency>\n            <groupId>org.apache.velocity</groupId>\n            <artifactId>velocity</artifactId>\n            <version>${velocity-version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.nutz</groupId>\n            <artifactId>nutz</artifactId>\n        </dependency>\n    </dependencies>\n\n</project>"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/AbstractLoader.java",
    "content": "package cn.enilu.flash.code;\n\nimport org.nutz.ioc.Ioc;\n\nimport java.util.Map;\n\n/**\n * 基础的数据结构加载器<br>\n * @author : zhangtao <br>\n * 创建日期: 16-7-12<br>\n */\npublic abstract class AbstractLoader {\n\n    public abstract Map<String, TableDescriptor> loadTables(Ioc ioc,\n                                                   String basePackageName, String baseUri,\n                                                            String servPackageName,\n                                                            String repositoryPackageName,\n                                                            String modPackageName) throws Exception;\n\n\n    }\n"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/CodeConfig.java",
    "content": "package cn.enilu.flash.code;\n\npublic class CodeConfig {\n    private String entityModel = \"material-entity\";\n    private String daoModel = \"material-dao\";\n    private String serviceModel = \"material-service\";\n    private String controllerModel = \"material-api\";\n    private String viewModel = \"material-manage\";\n    public String getModel(String type){\n        switch (type){\n            case \"model\":\n                return entityModel;\n            case \"repository\":\n                return daoModel;\n            case \"service\":\n                return serviceModel;\n            case \"controller\":\n                return controllerModel;\n            case \"view\":\n                return viewModel;\n        }\n        return null;\n    }\n    public String getEntityModel() {\n        return entityModel;\n    }\n\n    public void setEntityModel(String entityModel) {\n        this.entityModel = entityModel;\n    }\n\n    public String getDaoModel() {\n        return daoModel;\n    }\n\n    public void setDaoModel(String daoModel) {\n        this.daoModel = daoModel;\n    }\n\n    public String getServiceModel() {\n        return serviceModel;\n    }\n\n    public void setServiceModel(String serviceModel) {\n        this.serviceModel = serviceModel;\n    }\n\n    public String getControllerModel() {\n        return controllerModel;\n    }\n\n    public void setControllerModel(String controllerModel) {\n        this.controllerModel = controllerModel;\n    }\n\n    public String getViewModel() {\n        return viewModel;\n    }\n\n    public void setViewModel(String viewModel) {\n        this.viewModel = viewModel;\n    }\n}\n"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/ColumnDescriptor.java",
    "content": "package cn.enilu.flash.code;\n\n\n\nimport org.nutz.lang.Strings;\n\nimport java.math.BigDecimal;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * 属性（数据库列）基本信息描述<br>\n * 作者: zhangtao <br>\n * 创建日期: 16-7-5<br>\n */\npublic class ColumnDescriptor {\n\tprivate static Map<String, Class<?>> typeMapping = new HashMap<String,Class<?>>();\n\n\tstatic {\n\t\ttypeMapping.put(\"varchar\", String.class);\n\t\ttypeMapping.put(\"enum\", String.class);\n\t\ttypeMapping.put(\"bigint\", Long.class);\n\t\ttypeMapping.put(\"long\", Long.class);\n\t\ttypeMapping.put(\"integer\", Integer.class);\n\t\ttypeMapping.put(\"float\", Float.class);\n\t\ttypeMapping.put(\"double\", Double.class);\n\t\ttypeMapping.put(\"int\", Integer.class);\n\t\ttypeMapping.put(\"timestamp\", Integer.class);\n\t\ttypeMapping.put(\"datetime\", Integer.class);\n\t\ttypeMapping.put(\"boolean\", boolean.class);\n\t\ttypeMapping.put(\"tinyint\",boolean.class);\n\t\ttypeMapping.put(\"bool\", boolean.class);\n\t\ttypeMapping.put(\"decimal\", BigDecimal.class);\n\t}\n\t//todo\n//\tprivate static Map<String, Class<?>> validationRules = new HashMap<String,Class<?>>();\n\n\tstatic {\n\n\t}\n\n\tprivate static Map<String, String> labelMapping = new HashMap<String,String>();\n\n\tstatic {\n\n\t\tlabelMapping.put(\"id\", \"ID\");\n\t\tlabelMapping.put(\"opAt\", \"操作时间\");\n\t\tlabelMapping.put(\"opBy\", \"操作人\");\n\t\tlabelMapping.put(\"delFlag\", \"删除标记\");\n\t}\n\n\tpublic static class Validation {\n\t\tpublic final Class<?> klass;\n\t\tprivate final String annotation;\n\n\t\tpublic Validation(Class<?> klass, String annotation) {\n\t\t\tthis.klass = klass;\n\t\t\tthis.annotation = annotation;\n\t\t}\n\n\t\tpublic String getAnnotation() {\n\t\t\treturn annotation;\n\t\t}\n\t}\n\n\tprivate static Pattern COLUMN_TYPE_PATTERN = Pattern\n\t\t\t.compile(\"^(\\\\w+)(?:\\\\((\\\\d+)\\\\))?\");\n\tprivate static Pattern ENUM_PATTERN = Pattern.compile(\"enum\\\\((.+)\\\\)\");\n\n\tpublic String columnName;\n\tprivate String label;\n\tpublic boolean primary;\n\tpublic String dataType;\n\n\tpublic String columnType;\n\tpublic int size;\n\n\tpublic boolean nullable;\n\tprivate Object defaultValue;\n\tprivate String comment;\n\tprivate  String fieldName;\n\n\tprivate List<String> enumValues = new ArrayList<String>();\n\n\tprivate List<Validation> validations = new ArrayList<Validation>();\n\tprivate boolean validationBuilt = false;\n\n\tprivate String queryOperator;\n\n\n\n\tprivate boolean containsValidation(Class<?> klass) {\n\t\tfor (Validation v : validations) {\n\t\t\tif (v.klass == klass) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic boolean hasLabel() {\n\t\treturn label != null;\n\t}\n\n\tpublic void setLabel(String label) {\n\t\tthis.label = label;\n\t}\n\n\tpublic String getLabel() {\n\t\tif (label != null) {\n\t\t\treturn label;\n\t\t}\n\t\tString defaultLabel = labelMapping.get(columnName);\n\t\tif (defaultLabel != null) {\n\t\t\treturn defaultLabel;\n\t\t}\n\t\treturn label;\n\t}\n\n\tpublic String getComment() {\n\t\treturn comment;\n\t}\n\n\tpublic void setComment(String comment) {\n\t\tthis.comment = comment;\n\t\tif (comment == null) {\n\t\t\treturn;\n\t\t}\n\n\t\textractLabel(comment);\n\t\textractSearchable(comment);\n\t}\n\n\tprivate void extractLabel(String comment) {\n\t\tPattern labelPattern = Pattern.compile(\"label:\\\\s*([^,;，]+)\");\n\t\tMatcher m = labelPattern.matcher(comment);\n\t\tif (m.find()) {\n\t\t\tthis.label = m.group(1);\n\t\t}\n\t}\n\n\tpublic String getQueryOperator() {\n\t\treturn queryOperator;\n\t}\n\n\tprivate void extractSearchable(String comment) {\n\t\t// searchable: eq\n\t\tPattern queryPattern = Pattern.compile(\"searchable:\\\\s*(\\\\w+)\");\n\t\tMatcher m = queryPattern.matcher(comment);\n\t\tif (m.find()) {\n\t\t\tqueryOperator = m.group(1);\n\t\t}\n\t}\n\n\tpublic String getColumnName() {\n\t\treturn columnName;\n\t}\n\n\tpublic String getFieldName() {\n\t\tif(Strings.isBlank(fieldName)){\n\t\t\treturn Utils.LOWER_CAMEL(columnName);\n\t\t}\n\t\treturn fieldName;\n\t}\n\tpublic void setFieldName(String fieldName){\n\t\tthis.fieldName = fieldName;\n\t}\n\n\tpublic List<String> getEnumValues() {\n\t\treturn enumValues;\n\t}\n\n\tpublic void setColumnType(String columnType) {\n\t\tMatcher m = ENUM_PATTERN.matcher(columnType);\n\t\tif (m.find()) {\n\t\t\tthis.columnType = \"enum\";\n\n\t\t\tString s = m.group(1);\n\t\t\tfor (String v : s.split(\",\")) {\n\t\t\t\tv = v.trim().replaceAll(\"'\", \"\");\n\t\t\t\tenumValues.add(v);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tm = COLUMN_TYPE_PATTERN.matcher(columnType);\n\t\tif (m.find()) {\n\t\t\tif (m.group(2) != null) {\n\t\t\t\tthis.size = Integer.parseInt(m.group(2));\n\t\t\t}\n\t\t\tthis.columnType = m.group(1);\n\t\t} else {\n\t\t\tthrow new IllegalArgumentException();\n\t\t}\n\t}\n\n\tpublic String getJavaType() {\n\t\tif (\"tinyint\".equalsIgnoreCase(dataType) && size == 1) {\n\t\t\treturn boolean.class.getName();\n\t\t}\n\t\tif (\"enum\".equalsIgnoreCase(dataType)) {\n\t\t\treturn getUpperJavaFieldName();\n\t\t}\n\t\tClass<?> type = typeMapping.get(dataType);\n\t\tif (type != null) {\n\t\t\treturn type.getName();\n\t\t}\n\n\t\treturn String.class.getName();\n\t}\n\n\tpublic String getSimpleJavaTypeName() {\n\t\treturn getJavaType().replaceFirst(\"^.*\\\\.\", \"\");\n\t}\n\n\tpublic boolean isEnum() {\n\t\treturn \"enum\".equalsIgnoreCase(dataType);\n\t}\n\n\tpublic boolean isBoolean() {\n\t\treturn boolean.class.getName().equals(getJavaType());\n\t}\n\n\tpublic boolean isTimestamp() {\n\t\treturn \"timestamp\".equalsIgnoreCase(dataType);\n\t}\n\n\tpublic String getUpperJavaFieldName() {\n\t\treturn Utils.LOWER_CAMEL(columnName);\n//\t\treturn CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL,\n//\t\t\t\tcolumnName);\n\t}\n\n\tpublic String getGetterMethodName() {\n\t\tif (isBoolean()) {\n\t\t\treturn \"is\" + getUpperJavaFieldName();\n\t\t}\n\t\treturn \"get\" + getUpperJavaFieldName();\n\t}\n\n\tpublic String getSetterMethodName() {\n\t\treturn \"set\" + getUpperJavaFieldName();\n\t}\n\n\tpublic String getColumnAnnotation() {\n\t\tif (primary) {\n//\t\t\treturn \"@Id\";\n\t\t\treturn \"@Name\\r\\n\t@Prev(els = {@EL(\\\"uuid()\\\")})\";\n\t\t}\n\t\treturn \"@Column\";\n\t}\n\n\tpublic void setDefaultValue(Object v) {\n\t\tthis.defaultValue = v;\n\t}\n\n\tpublic Object getDefaultValue() {\n\t\treturn defaultValue;\n\t}\n\n\tpublic String getDefaultValueCode() {\n\t\tif (isEnum()) {\n\t\t\treturn getSimpleJavaTypeName() + \".\" + defaultValue;\n\t\t}\n\t\tif (isBoolean()) {\n\t\t\tif (\"1\".equals(defaultValue.toString())) {\n\t\t\t\treturn \"true\";\n\t\t\t} else {\n\t\t\t\treturn \"false\";\n\t\t\t}\n\t\t}\n\t\tif (isTimestamp()) {\n\t\t\tif ((\"0000-00-00 00:00:00\".equals(defaultValue) || \"CURRENT_TIMESTAMP\"\n\t\t\t\t\t.equals(defaultValue))) {\n\t\t\t\treturn \"DateTime.now()\";\n\t\t\t}\n\t\t}\n\t\tif (defaultValue != null && Long.class.getName().equals(getJavaType())) {\n\t\t\treturn defaultValue + \"L\";\n\t\t}\n\t\tif (defaultValue != null && BigDecimal.class.getName().equals(getJavaType())) {\n\t\t\treturn \"new BigDecimal(\\\"\" + defaultValue.toString() + \"\\\")\";\n\t\t}\n\t\treturn \"\\\"\" + getDefaultValue().toString() + \"\\\"\";\n\t}\n\t//TODO\n\tpublic String getValidationFormClass() {\n\t\t return \"\";\n\t}\n\n}"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/EntityDescLoader.java",
    "content": "package cn.enilu.flash.code;\n\nimport org.hibernate.annotations.Table;\nimport org.nutz.ioc.Ioc;\nimport org.nutz.json.Json;\nimport org.nutz.lang.Files;\nimport org.nutz.lang.Mirror;\nimport org.nutz.lang.Strings;\nimport org.nutz.log.Log;\nimport org.nutz.log.Logs;\n\nimport javax.persistence.Column;\nimport javax.persistence.Id;\nimport java.io.File;\nimport java.lang.annotation.Annotation;\nimport java.lang.reflect.Field;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n/**\n * 根据java model定义生成，service，controller， <br>\n * </p> Copyright by easecredit.com<br>\n * 作者: zhangtao <br>\n * 创建日期: 16-7-10<br>\n */\npublic class EntityDescLoader extends  Loader {\n    \n    private static final Log log = Logs.get();\n    public static  final Pattern COLUMN_DEFINITION_PATTERN  =  Pattern.compile(\"([A-Za-z]+)(?:\\\\(\\\\d+\\\\))?\\\\s*(?:(?:COMMENT|[Cc]omment)\\\\s+'(.*?)')?\");\n\n    @Override\n    public Map<String, TableDescriptor> loadTables(Ioc ioc, String basePackageName,\n                                                   String baseUri,\n                                                   String servPackageName,\n                                                   String repositoryPackageName,\n                                                   String modPackageName) throws Exception {\n        String packageName = basePackageName+\".\"+modPackageName;\n\n        String filePath = packageName.replaceAll(\"\\\\.\",\"\\\\/\");\n        URL url = Loader.class.getClassLoader().getResource(filePath);\n        String path;\n        if (url != null)\n            path = url.getPath();\n        else {\n            path = \"out/\" + basePackageName.replace('.', '/');\n        }\n        File f = Files.createDirIfNoExists(path);\n        log.debug(\"output dir = \" + f.getAbsolutePath());\n        String abstractPath = URLDecoder.decode(path, \"utf8\");\n        File[] files = Files.lsFile(abstractPath, null);\n        Map<String, TableDescriptor> tables = new HashMap<String, TableDescriptor>();\n\n        for(File file:files){\n            String fileName = file.getName().split(\"\\\\.\")[0];\n            String className = packageName+\".\"+fileName;\n            Class<?> modelClass = Class.forName(className);\n            if(className.contains(\".Model\")){\n                continue;\n            }\n\n            Mirror<?> mirror = Mirror.me(modelClass);\n            Table tableAnno =   mirror.getAnnotation(Table.class);\n            if(tableAnno==null){\n                continue;\n            }\n            String tableName = tableAnno.appliesTo();\n            String entityName = modelClass.getSimpleName();\n            TableDescriptor table = new TableDescriptor(tableName,entityName,basePackageName,baseUri,servPackageName,repositoryPackageName,modPackageName);\n            if(tableAnno.comment()!=null) {\n                table.setLabel(tableAnno.comment());\n            }else{\n                table.setLabel(tableName);\n            }\n\n            tables.put(tableName, table);\n            tables.put(entityName,table);\n            Field[] fields = mirror.getFields();\n            for(Field field:fields){\n                ColumnDescriptor column = new ColumnDescriptor();\n                String fieldName = field.getName();\n                if(fieldName.equals(\"createTime\")||fieldName.equals(\"createBy\")||fieldName.equals(\"modifyTime\")||fieldName.equals(\"modifyBy\")){\n                    continue;\n                }\n                column.setFieldName(fieldName);\n                Annotation[] annotations = field.getAnnotations();\n                for(Annotation annotation :annotations){\n                    if(annotation instanceof  Column){\n                        Column columnAnno = (Column)annotation;\n                        String columnDefinition= columnAnno.columnDefinition();\n                        if(columnDefinition!=null&&!\"\".equals(columnDefinition.trim())){\n                            System.out.println(columnDefinition.trim());\n                            Matcher matcher = COLUMN_DEFINITION_PATTERN.matcher(columnDefinition.trim());\n                            if(matcher.find()){\n                                String type = matcher.group(1);\n                                String comment = matcher.group(2);\n                                if(comment!=null){\n                                    column.setLabel(comment);\n                                    column.setComment(comment);\n                                }\n                                column.setColumnType(type.toLowerCase());\n                                column.dataType =type;\n\n                            }\n                        }\n                        if(columnAnno.name()!=null){\n                            column.columnName = columnAnno.name();\n                        }else{\n                            column.columnName = StrKit.toUnderlineCase(fieldName);\n                        }\n\n                    }\n                    if(annotation instanceof Id){\n                        column.primary=true;\n                        table.setPkType(column.getSimpleJavaTypeName());\n                        column.columnName =fieldName;\n                    }\n\n\n                }\n                if(Strings.isEmpty(column.getLabel())){\n                    column.setLabel(fieldName);\n                }\n                table.addColumn(column);\n            }\n            System.out.println(Json.toJson(table));\n\n        }\n        return tables;\n    }\n}\n"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/Generator.java",
    "content": "package cn.enilu.flash.code;\n\nimport org.apache.commons.cli.*;\nimport org.apache.velocity.VelocityContext;\nimport org.apache.velocity.app.VelocityEngine;\nimport org.nutz.ioc.Ioc;\nimport org.nutz.ioc.impl.NutIoc;\nimport org.nutz.ioc.loader.json.JsonLoader;\nimport org.nutz.json.Json;\nimport org.nutz.lang.*;\nimport org.nutz.log.Log;\nimport org.nutz.log.Logs;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.nio.charset.Charset;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.regex.Pattern;\n\n/**\n * 入口类<br>\n * 作者: enilu <br>\n * 创建日期: 16-7-5<br>\n */\npublic class Generator {\n    private static final Log log = Logs.get();\n    private final TableDescriptor table;\n\n    public Generator(  TableDescriptor table) {\n        this.table = table;\n    }\n\n    public void generate(String packageName, String templatePath, File file, boolean force)\n            throws IOException {\n        if (file.exists() && !force) {\n            log.debug(\"file \" + file + \" exists, skipped\");\n            return;\n        }\n\n        String code = generateCode(packageName, templatePath);\n        file.getParentFile().mkdirs();\n        Files.write(file, code.getBytes(Charset.forName(\"utf8\")));\n\n    }\n\n    public String generateCode(String packageName, String templatePath) throws IOException {\n        VelocityContext context = new VelocityContext();\n        context.put(\"table\", table);\n        context.put(\"packageName\", packageName);\n        StringWriter writer = new StringWriter();\n\n        String template = new String(Streams.readBytes(ClassLoader.getSystemResourceAsStream(templatePath)),\n                                     Charset.forName(\"utf8\"));\n        VelocityEngine engine = new VelocityEngine();\n        engine.setProperty(\"runtime.references.strict\", false);\n        engine.init();\n        engine.evaluate(context, writer, \"generator\", template);\n        return writer.toString();\n\n    }\n\n    public static void main(String[] args) throws Exception {\n\n        String configPath = \"code/code.json\";\n        String basePath = \"\";\n        Pattern includePattern = Pattern.compile(\".*\");\n        Pattern excludePattern = null;\n        String module = \"test\";\n        String basePackageName = \"cn.enilu.material\";\n        String controllerPackageName = \"admin.modular.\"+module;\n        String servicePackageName = \"service.\"+module;\n        String repositoryPackageName = \"dao.\"+module;\n        String modelPackageName = \"bean.entity.\"+module;\n        String _loader = \"entity\";\n\n        String outputDir = \"src/main/java\";\n        boolean force = false;\n        String baseUri = \"/\";\n        String types[] = {\"all\"};\n        String pages[] = {\"index\", \"add\", \"edit\"};\n        Options options = new Options();\n        options.addOption(\"i\", \"include\", true, \"include table pattern\");\n        options.addOption(\"x\", \"exclude\", true, \"exclude table pattern\");\n        options.addOption(\"basePath\", \"basePath\", true, \"base uri\");\n        options.addOption(\"module\", \"module\", true, \"current module name\");\n        options.addOption(\"p\", \"package\", true, \"base package name,default:cn.enilu.material\");\n        options.addOption(\"ctr\",\n                          \"package\",\n                          true,\n                          \"controller base package name,default:controllers/${package}\");\n        options.addOption(\"mod\",\n                          \"package\",\n                          true,\n                          \"model base package name,default:models/${package}\");\n        options.addOption(\"repo\",\n                \"package\",\n                true,\n                \"repository base package name,default:repository/${package}\");\n        options.addOption(\"sev\",\n                          \"package\",\n                          true,\n                          \"service base package name,default:services/${package}\");\n        options.addOption(\"v\",\n                          \"views\",\n                          true,\n                          \"for generator pages,default:all pages,eg: -v index_detail will generate index.html and detail.html\");\n\n        options.addOption(\"u\", \"base-uri\", true, \"base uri prefix, default is /\");\n        options.addOption(\"f\", \"force\", false, \"force generate file even if file exists\");\n        options.addOption(\"h\", \"help\", false, \"show help message\");\n        CommandLineParser parser = new GnuParser();\n        try {\n            CommandLine commandLine = parser.parse(options, args);\n            if(commandLine.hasOption(\"basePath\")){\n                basePath =commandLine.getOptionValue(\"basePath\")+File.separator;\n            }\n            if (commandLine.hasOption(\"i\")) {\n                includePattern = Pattern.compile(commandLine.getOptionValue(\"i\"),\n                                                 Pattern.CASE_INSENSITIVE);\n            }\n            if (commandLine.hasOption(\"x\")) {\n                excludePattern = Pattern.compile(commandLine.getOptionValue(\"x\"),\n                                                 Pattern.CASE_INSENSITIVE);\n            }\n            if(commandLine.hasOption(\"mod\")){\n                module =  commandLine.getOptionValue(\"mod\");\n                module = module.split(\"\\\\.\")[module.split(\"\\\\.\").length-1];\n                controllerPackageName = \"admin.modular.\"+module;\n                servicePackageName = \"service.\"+module;\n                repositoryPackageName = \"dao.\"+module;\n                modelPackageName = \"bean.entity.\"+module;\n            }\n            if (commandLine.hasOption(\"p\")) {\n                basePackageName = commandLine.getOptionValue(\"p\");\n            }\n\t\t\tif(commandLine.hasOption(\"u\")){\n                baseUri = commandLine.getOptionValue(\"u\");\n            }\n            force = commandLine.hasOption(\"f\");\n            if (commandLine.hasOption(\"h\")) {\n                usage(options);\n            }\n            String[] extraArgs = commandLine.getArgs();\n            if (extraArgs.length > 0) {\n                types = extraArgs;\n            }\n            if (commandLine.hasOption(\"loader\")) {\n                _loader = commandLine.getOptionValue(\"loader\");\n            }\n        }\n        catch (Exception e) {\n            e.printStackTrace();\n            usage(options);\n        }\n        Ioc ioc = new NutIoc(new JsonLoader(configPath));\n        CodeConfig codeConfig = ioc.get(CodeConfig.class);\n\n        log.debug(\"=================================================\");\n        log.debug(\"=================================================\");\n        log.debug(\"=================================================\");\n\n        Loader loader = (Loader) Mirror.me(Lang.loadClassQuite(\"cn.enilu.flash.code.\" + Strings.upperFirst(_loader) + \"DescLoader\")).born();\n        Map<String, TableDescriptor> tables = loader.loadTables(ioc,\n                                                                basePackageName,\n                                                                baseUri,\n                                                                servicePackageName,\n                                                                repositoryPackageName,\n                                                                modelPackageName);\n\n        System.out.println(Json.toJson(tables));\n        for (Map.Entry<String, TableDescriptor> entry : tables.entrySet()) {\n            String tableName = entry.getKey();\n            if (excludePattern != null) {\n                if (excludePattern.matcher(tableName).find()) {\n                    log.debug(\"skip \" + tableName);\n                    continue;\n                }\n            }\n            if (includePattern != null) {\n                if (!includePattern.matcher(tableName).find()) {\n                    log.debug(\"skip \" + tableName);\n                    continue;\n                }\n            }\n\n            TableDescriptor table = entry.getValue();\n            log.debug(\"generate \" + tableName + \" ...\");\n            Generator generator = new Generator(table);\n            Map<String, String> typeMap = new HashMap<String, String>();\n            typeMap.put(\"model\", modelPackageName);\n            typeMap.put(\"service\", servicePackageName);\n            typeMap.put(\"controller\", controllerPackageName);\n            typeMap.put(\"repository\",repositoryPackageName);\n\n            for (String type : new String[]{\"model\",\"repository\", \"service\", \"controller\", \"view\"}) {\n                if (!isTypeMatch(types, type)) {\n                    continue;\n                }\n                if (type.equals(\"view\")) {\n                    generateViews(basePath,codeConfig,force, table, generator, pages);\n                } else {\n                    if (loader instanceof EntityDescLoader && type.equals(\"model\")) {\n                        continue;\n                    }\n                    String packageName = basePackageName + \".\" + typeMap.get(type);\n                    String templatePath = \"code/\" + type + \".vm\";\n\n                    String packagePath = packageName.replace('.', '/');\n                    String className = table.getEntityClassName();\n                    if (!\"model\".equals(type)) {\n                        className = Utils.UPPER_CAMEL(className) + Strings.upperFirst(type);\n                    }\n                    File file = new File(basePath+codeConfig.getModel(type)+File.separator+outputDir, packagePath + \"/\" + className + \".java\");\n                    log.debug(\"generate \" + file.getName());\n                    generator.generate(packageName, templatePath, file, force);\n                }\n            }\n        }\n        ioc.depose();\n        log.debug(\"done!\");\n    }\n\n    private static boolean isTypeMatch(String[] types, String type) {\n        for (String t : types) {\n            if (t.equalsIgnoreCase(type) || \"all\".equalsIgnoreCase(t)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private static void generateViews(String basePath,CodeConfig codeConfig,boolean force,\n                                      TableDescriptor table,\n                                      Generator generator,\n                                      String[] pages)\n            throws IOException {\n            //生成传统html文件\n        for (String view : pages) {\n            String templatePath = \"code/view/\" + view + \".html.vm\";\n            File file = new File(basePath+codeConfig.getViewModel()+\"/src/main/webapp/WEB-INF/view/\"\n                                 + table.getViewBasePath()\n                                 + \"/\"\n                                 + view\n                                 + \".html\");\n            log.debug(\"generate html:\" + file.getName());\n            generator.generate(null, templatePath, file, force);\n\n        }\n        //生成传统js：index.js，info.js\n        String indexTplPath = \"code/view/index.js.vm\";\n        String infoTplPath = \"code/view/info.js.vm\";\n        File indexFile = new File(basePath+codeConfig.getViewModel()+\"/src/main/webapp/static/modular/\"\n                + table.getViewBasePath()\n                + \"/\"+table.getEntityNameLowerFirstChar()+\".js\");\n        File infoFile = new File(basePath+codeConfig.getViewModel()+\"/src/main/webapp/static/modular/\"\n                + table.getViewBasePath()\n                + \"/\"+table.getEntityNameLowerFirstChar()+\"_info.js\");\n\n        generator.generate(null, indexTplPath, indexFile, force);\n        generator.generate(null, infoTplPath, infoFile, force);\n    }\n\n    private static void usage(Options options) {\n        HelpFormatter formatter = new HelpFormatter();\n        formatter.printHelp(\"Generator [options] [all|entity|service|controller|view]\", options);\n        System.exit(1);\n    }\n\n}\n"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/Loader.java",
    "content": "package cn.enilu.flash.code;\n\nimport org.nutz.ioc.Ioc;\n\nimport java.util.Map;\n\n/**\n * 基础的数据结构加载器<br>\n * 作者: zhangtao <br>\n * 创建日期: 16-7-12<br>\n */\npublic abstract class Loader {\n\n    public abstract Map<String, TableDescriptor> loadTables(Ioc ioc,\n                                                   String basePackageName, String baseUri,\n                                                            String servPackageName,\n                                                            String repositoryPackageName,\n                                                            String modPackageName) throws Exception;\n\n\n    }\n"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/StrKit.java",
    "content": "package cn.enilu.flash.code;\n\nimport java.io.StringReader;\nimport java.io.StringWriter;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n/**\n * 字符串工具类\n * \n * @author xiaoleilu\n *\n */\npublic class StrKit {\n\n\tpublic static final String SPACE = \" \";\n\tpublic static final String DOT = \".\";\n\tpublic static final String SLASH = \"/\";\n\tpublic static final String BACKSLASH = \"\\\\\";\n\tpublic static final String EMPTY = \"\";\n\tpublic static final String CRLF = \"\\r\\n\";\n\tpublic static final String NEWLINE = \"\\n\";\n\tpublic static final String UNDERLINE = \"_\";\n\tpublic static final String COMMA = \",\";\n\n\tpublic static final String HTML_NBSP = \"&nbsp;\";\n\tpublic static final String HTML_AMP = \"&amp\";\n\tpublic static final String HTML_QUOTE = \"&quot;\";\n\tpublic static final String HTML_LT = \"&lt;\";\n\tpublic static final String HTML_GT = \"&gt;\";\n\n\tpublic static final String EMPTY_JSON = \"{}\";\n\n\n\t/**\n\t * 首字母变小写\n\t */\n\tpublic static String firstCharToLowerCase(String str) {\n\t\tchar firstChar = str.charAt(0);\n\t\tif (firstChar >= 'A' && firstChar <= 'Z') {\n\t\t\tchar[] arr = str.toCharArray();\n\t\t\tarr[0] += ('a' - 'A');\n\t\t\treturn new String(arr);\n\t\t}\n\t\treturn str;\n\t}\n\t\n\t/**\n\t * 首字母变大写\n\t */\n\tpublic static String firstCharToUpperCase(String str) {\n\t\tchar firstChar = str.charAt(0);\n\t\tif (firstChar >= 'a' && firstChar <= 'z') {\n\t\t\tchar[] arr = str.toCharArray();\n\t\t\tarr[0] -= ('a' - 'A');\n\t\t\treturn new String(arr);\n\t\t}\n\t\treturn str;\n\t}\n\n\n\n\t// ------------------------------------------------------------------------ Empty\n\t/**\n\t * 字符串是否为空，空的定义如下 1、为null <br>\n\t * 2、为\"\"<br>\n\t * \n\t * @param str 被检测的字符串\n\t * @return 是否为空\n\t */\n\tpublic static boolean isEmpty(String str) {\n\t\treturn str == null || str.length() == 0;\n\t}\n\n\t/**\n\t * 字符串是否为非空白 空白的定义如下： <br>\n\t * 1、不为null <br>\n\t * 2、不为\"\"<br>\n\t * \n\t * @param str 被检测的字符串\n\t * @return 是否为非空\n\t */\n\tpublic static boolean isNotEmpty(String str) {\n\t\treturn false == isEmpty(str);\n\t}\n\n\t/**\n\t * 当给定字符串为null时，转换为Empty\n\t * \n\t * @param str 被转换的字符串\n\t * @return 转换后的字符串\n\t */\n\tpublic static String nullToEmpty(String str) {\n\t\treturn nullToDefault(str, EMPTY);\n\t}\n\n\t/**\n\t * 如果字符串是<code>null</code>，则返回指定默认字符串，否则返回字符串本身。\n\t * \n\t * <pre>\n\t * nullToDefault(null, &quot;default&quot;)  = &quot;default&quot;\n\t * nullToDefault(&quot;&quot;, &quot;default&quot;)    = &quot;&quot;\n\t * nullToDefault(&quot;  &quot;, &quot;default&quot;)  = &quot;  &quot;\n\t * nullToDefault(&quot;bat&quot;, &quot;default&quot;) = &quot;bat&quot;\n\t * </pre>\n\t * \n\t * @param str 要转换的字符串\n\t * @param defaultStr 默认字符串\n\t * \n\t * @return 字符串本身或指定的默认字符串\n\t */\n\tpublic static String nullToDefault(String str, String defaultStr) {\n\t\treturn (str == null) ? defaultStr : str;\n\t}\n\n\n\t\n\t/**\n\t * 将驼峰式命名的字符串转换为下划线方式。如果转换前的驼峰式命名的字符串为空，则返回空字符串。</br>\n\t * 例如：HelloWorld->hello_world\n\t *\n\t * @param camelCaseStr 转换前的驼峰式命名的字符串\n\t * @return 转换后下划线大写方式命名的字符串\n\t */\n\tpublic static String toUnderlineCase(String camelCaseStr) {\n\t\tif (camelCaseStr == null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal int length = camelCaseStr.length();\n\t\tStringBuilder sb = new StringBuilder();\n\t\tchar c;\n\t\tboolean isPreUpperCase = false;\n\t\tfor (int i = 0; i < length; i++) {\n\t\t\tc = camelCaseStr.charAt(i);\n\t\t\tboolean isNextUpperCase = true;\n\t\t\tif (i < (length - 1)) {\n\t\t\t\tisNextUpperCase = Character.isUpperCase(camelCaseStr.charAt(i + 1));\n\t\t\t}\n\t\t\tif (Character.isUpperCase(c)) {\n\t\t\t\tif (!isPreUpperCase || !isNextUpperCase) {\n\t\t\t\t\tif (i > 0) sb.append(UNDERLINE);\n\t\t\t\t}\n\t\t\t\tisPreUpperCase = true;\n\t\t\t} else {\n\t\t\t\tisPreUpperCase = false;\n\t\t\t}\n\t\t\tsb.append(Character.toLowerCase(c));\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将下划线方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。</br>\n\t * 例如：hello_world->HelloWorld\n\t *\n\t * @param name 转换前的下划线大写方式命名的字符串\n\t * @return 转换后的驼峰式命名的字符串\n\t */\n\tpublic static String toCamelCase(String name) {\n\t\tif (name == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (name.contains(UNDERLINE)) {\n\t\t\tname = name.toLowerCase();\n\n\t\t\tStringBuilder sb = new StringBuilder(name.length());\n\t\t\tboolean upperCase = false;\n\t\t\tfor (int i = 0; i < name.length(); i++) {\n\t\t\t\tchar c = name.charAt(i);\n\n\t\t\t\tif (c == '_') {\n\t\t\t\t\tupperCase = true;\n\t\t\t\t} else if (upperCase) {\n\t\t\t\t\tsb.append(Character.toUpperCase(c));\n\t\t\t\t\tupperCase = false;\n\t\t\t\t} else {\n\t\t\t\t\tsb.append(c);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn sb.toString();\n\t\t} else\n\t\t\treturn name;\n\t}\n\n\n\n\n\n}\n"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/TableDescLoader.java",
    "content": "package cn.enilu.flash.code;\n\nimport org.nutz.dao.Dao;\nimport org.nutz.dao.Sqls;\nimport org.nutz.dao.impl.NutDao;\nimport org.nutz.dao.sql.Sql;\nimport org.nutz.dao.sql.SqlCallback;\nimport org.nutz.ioc.Ioc;\n\nimport javax.sql.DataSource;\nimport java.sql.Connection;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 根据数据库结构生成model,service,controller,views<br>\n * 作者: zhangtao <br>\n * 创建日期: 16-7-10<br>\n */\npublic class TableDescLoader extends Loader{\n\n\n    @Override\n    public   Map<String, TableDescriptor> loadTables(Ioc ioc,\n                                                     String basePackageName,\n                                                     String baseUri,\n                                                     String servPackageName,\n                                                     String repositoryPackageName,\n                                                     String modPackageName) throws SQLException {\n\n\n        DataSource ds = ioc.get(DataSource.class);\n        Dao dao = new NutDao(ds);\n        Sql sql = Sqls.create(\"select database()\");\n\n        sql.setCallback(new SqlCallback() {\n            @Override\n            public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {\n                if (rs.next()) {\n                    return rs.getString(1);\n                }\n                return null;\n            }\n        });\n        dao.execute(sql);\n        String database = sql.getString();\n\n\n        Sql tableSchemaSql = Sqls.create(\"select * from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '\"\n                + database + \"'\");\n\n        tableSchemaSql.setCallback(new SqlCallback() {\n            @Override\n            public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {\n                ResultSetMetaData metaData = rs.getMetaData();\n                int columnCount = metaData.getColumnCount();\n\n                List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();\n                while (rs.next()) {\n                    Map<String, Object> record = new HashMap<String, Object>();\n                    for (int i = 1; i <= columnCount; i++) {\n                        String columnName = metaData.getColumnName(i);\n                        record.put(columnName, rs.getObject(columnName));\n                    }\n                    result.add(record);\n\n\n                }\n                return result;\n            }\n        });\n        dao.execute(tableSchemaSql);\n\n\n        List<Map> columns =tableSchemaSql.getList(Map.class);\n\n        Map<String, TableDescriptor> tables = new HashMap<String, TableDescriptor>();\n        for (Map<String, Object> columnInfo : columns) {\n            String tableName = (String) columnInfo.get(\"TABLE_NAME\");\n\n            ColumnDescriptor column = new ColumnDescriptor();\n            column.columnName = (String) columnInfo.get(\"COLUMN_NAME\");\n            if(\"opAt\".equals(column.columnName)||\"opBy\".equals(column.columnName)||\"delFlag\".equals(column.columnName)){\n                continue;\n            }\n            column.setDefaultValue(columnInfo.get(\"COLUMN_DEFAULT\"));\n            column.dataType = (String) columnInfo.get(\"DATA_TYPE\");\n            column.nullable = \"YES\".equals(columnInfo.get(\"IS_NULLABLE\"));\n            column.primary = \"PRI\".equals(columnInfo.get(\"COLUMN_KEY\"));\n\n            String columnType = (String) columnInfo.get(\"COLUMN_TYPE\");\n            column.setColumnType(columnType);\n            column.setComment((String) columnInfo.get(\"COLUMN_COMMENT\"));\n\n            TableDescriptor table = tables.get(tableName);\n            if (table == null) {\n                table = new TableDescriptor(tableName,null, basePackageName, baseUri,servPackageName,repositoryPackageName,modPackageName);\n                tables.put(tableName, table);\n            }\n            if(column.primary){\n                table.setPkType(column.getSimpleJavaTypeName());\n            }\n            table.addColumn(column);\n        }\n        Sql infomationSchemaSql = Sqls.create(\"select * from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA = '\"\n                + database + \"'\");\n        infomationSchemaSql.setCallback(new SqlCallback() {\n            @Override\n            public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {\n                ResultSetMetaData metaData = rs.getMetaData();\n                int columnCount = metaData.getColumnCount();\n\n                List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();\n                while (rs.next()) {\n                    Map<String, Object> record = new HashMap<String, Object>();\n                    for (int i = 1; i <= columnCount; i++) {\n                        String columnName = metaData.getColumnName(i);\n                        record.put(columnName, rs.getObject(columnName));\n                    }\n                    result.add(record);\n\n\n                }\n                return result;\n            }\n        });\n        dao.execute(infomationSchemaSql);\n\n\n        List<Map> tableInfos =infomationSchemaSql.getList(Map.class);\n\n        for (Map<String, Object> tableInfo : tableInfos) {\n            String tableName = (String) tableInfo.get(\"TABLE_NAME\");\n            String comment = (String) tableInfo.get(\"TABLE_COMMENT\");\n\n            TableDescriptor table = tables.get(tableName);\n            if (table != null) {\n                table.setComment(comment);\n            }\n        }\n\n\n        return tables;\n    }\n}\n"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/TableDescriptor.java",
    "content": "package cn.enilu.flash.code;\n\n\nimport org.atteo.evo.inflector.English;\nimport org.nutz.lang.Strings;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\n/**\n * 实体（表）基本信息描述类<br>\n * 作者: zhangtao <br>\n * 创建日期: 16-7-10<br>\n */\npublic class TableDescriptor {\n    private final String basePackageName;\n    private final String baseUri;\n    private final List<ColumnDescriptor> columns = new ArrayList<ColumnDescriptor>();\n    //表名称\n    public final String name;\n    //实体类名称\n    private String entityName;\n    //实体类名称（首字母小写）\n    private String entityNameLowerFirstChar;\n    //主键类型\n    private String pkType;\n    //注释\n    private String comment;\n    private String label = \"项\";\n    //service包名\n    private String serPackageName;\n    //models包名\n    private String modPackageName;\n    //repository报名\n    private String repoPackageName;\n\n\n    public TableDescriptor(String name, String entityName, String basePackageName, String baseUri, String serPackageName,\n                           String repoPackageName,\n                           String modPackageName) {\n        this.name = name;\n        this.entityName = entityName;\n        this.basePackageName = basePackageName;\n        this.serPackageName = serPackageName;\n        this.repoPackageName = repoPackageName;\n        this.modPackageName = modPackageName;\n\n        if (!baseUri.endsWith(\"/\")) {\n            baseUri = baseUri + \"/\";\n        }\n        this.baseUri = baseUri;\n    }\n\n    public String getBaseUri() {\n        return baseUri;\n    }\n\n    public String getName() {\n        return name;\n    }\n\n    public String getPlural() {\n        return English.plural(name);\n    }\n\n    public String getPkType() {\n        return pkType;\n    }\n\n    public void setPkType(String pkType) {\n        this.pkType = pkType;\n    }\n\n    public String getBasePackageName() {\n        return basePackageName;\n    }\n\n    public List<ColumnDescriptor> getColumns() {\n        return columns;\n    }\n\n    public void addColumn(ColumnDescriptor column) {\n        columns.add(column);\n    }\n\n    public String getClassName() {\n        return getEntityClassName();\n    }\n\n    public String getUriPrefix() {\n        if (getName().contains(\"_\")) {\n            return baseUri + getName().substring(getName().indexOf(\"_\") + 1).replace(\"_\", \"/\");\n        }\n        return baseUri + getName();\n    }\n\n    public String getViewBasePath() {\n        if (getName().contains(\"_\")) {\n            return baseUri.replaceFirst(\"/\", \"\") + getName().substring(getName().indexOf(\"_\") + 1).replace(\"_\", \"/\");\n        }\n        return baseUri.replaceFirst(\"/\", \"\") + getName().replace(\"_\", \"/\");\n    }\n\n    public String getModPackageName() {\n        return modPackageName;\n    }\n\n    public void setModPackageName(String modPackageName) {\n        this.modPackageName = modPackageName;\n    }\n\n    public String getSerPackageName() {\n        return serPackageName;\n    }\n\n    public void setSerPackageName(String serPackageName) {\n        this.serPackageName = serPackageName;\n    }\n\n    public String getRepoPackageName() {\n        return repoPackageName;\n    }\n\n    public void setRepoPackageName(String repoPackageName) {\n        this.repoPackageName = repoPackageName;\n    }\n\n    public String getEntityClassName() {\n        if (Strings.isBlank(entityName)) {\n            return Utils.UPPER_CAMEL(name);\n        }\n        return entityName;\n    }\n    public String getEntityNameLowerFirstChar(){\n        String ret = getEntityClassName();\n        return ret.substring(0,1).toLowerCase()+ret.substring(1);\n    }\n    public String getEntityFullClassName() {\n        return basePackageName + \".\" + getModPackageName() + \".\" + getEntityClassName();\n    }\n\n    public String getServiceFullClassName() {\n        return basePackageName + \".\" + getSerPackageName() + \".\" + getServiceClassName();\n    }\n    public String getRepositoryFullClassName(){\n        return basePackageName + \".\" + getRepoPackageName() + \".\" + getRepositoryClassName();\n    }\n\n\n    public String getEntityInstanceName() {\n        return Utils.LOWER_CAMEL(name);\n    }\n\n    public String getEntityInstancesName() {\n        return getEntityInstanceName() + \"s\";\n    }\n\n    public String getServiceInstanceName() {\n        return Strings.lowerFirst(getServiceClassName());\n    }\n\n    public String getServiceClassName() {\n        return Utils.UPPER_CAMEL(getEntityClassName()) + \"Service\";\n    }\n    public String getRepositoryClassName(){\n        return Utils.UPPER_CAMEL(getEntityClassName()) + \"Repository\";\n    }\n\n    public String getControllerClassName() {\n        return Utils.UPPER_CAMEL(getEntityClassName()) + \"Controller\";\n    }\n\n    public void addPrimaryKeyColumn(String columnName) {\n        for (ColumnDescriptor column : columns) {\n            if (column.columnName.equals(columnName)) {\n                column.primary = true;\n                break;\n            }\n        }\n    }\n\n    public ColumnDescriptor getPrimaryColumn() {\n        for (ColumnDescriptor column : columns) {\n            if (column.primary) {\n                return column;\n            }\n        }\n        return null;\n    }\n\n    public String getPrimaryType() {\n        ColumnDescriptor columnDescriptor = getPrimaryColumn();\n        if (columnDescriptor == null) {\n            return null;\n        }\n\n        return columnDescriptor.getSimpleJavaTypeName();\n    }\n\n    public String getTableAnnotation() {\n        return \"@Table\";\n    }\n\n    public List<String> getImports() {\n        Set<String> klasses = new LinkedHashSet<String>();\n\n        for (ColumnDescriptor column : columns) {\n            String klass = column.getJavaType();\n            if (klass.startsWith(\"java.lang\") || klass.indexOf('.') == -1) {\n                continue;\n            }\n            klasses.add(column.getJavaType());\n        }\n\n        List<String> imports = new ArrayList<String>();\n        imports.addAll(klasses);\n        imports.add(null);\n\n        imports.add(Serializable.class.getName());\n        imports.add(null);\n\n        klasses.clear();\n        if (klasses.size() > 0) {\n            imports.addAll(klasses);\n            imports.add(null);\n        }\n\n        return imports;\n    }\n\n    public List<ColumnDescriptor> getEnumColumns() {\n        List<ColumnDescriptor> result = new ArrayList<ColumnDescriptor>();\n        for (ColumnDescriptor column : columns) {\n            if (column.isEnum()) {\n                result.add(column);\n            }\n        }\n        return result;\n    }\n\n    //todo\n    public String getQueryColumns(String op) {\n        List<String> result = new ArrayList<String>();\n        for (ColumnDescriptor column : columns) {\n            if (op.equals(column.getQueryOperator())) {\n                result.add(\"\\\"\" + column.columnName + \"\\\"\");\n            }\n        }\n\n        if (result.isEmpty()) {\n            return null;\n        }\n        return \"\";\n    }\n\n    public List<ColumnDescriptor> getSearchableColumns() {\n        List<ColumnDescriptor> result = new ArrayList<ColumnDescriptor>();\n\n        for (ColumnDescriptor column : columns) {\n            if (!Strings.isBlank(column.getQueryOperator())) {\n                result.add(column);\n            }\n        }\n\n        return result;\n    }\n\n    public List<ColumnDescriptor> getLabeledColumns() {\n        List<ColumnDescriptor> result = new ArrayList<ColumnDescriptor>();\n\n        for (ColumnDescriptor column : columns) {\n            if (column.getComment() != null && !column.primary) {\n                result.add(column);\n            }\n        }\n        return result;\n    }\n\n    public String[] getLabeledColumnNames() {\n        List<ColumnDescriptor> columnDescriptors = getLabeledColumns();\n        List<String> result = new ArrayList<String>();\n        for (ColumnDescriptor descriptor : columnDescriptors) {\n            result.add(descriptor.getFieldName());\n        }\n        return result.toArray(new String[0]);\n\n    }\n\n    public String getLabeledColumnNamesString() {\n        StringBuilder buf = new StringBuilder();\n        for (String name : getLabeledColumnNames()) {\n            buf.append(\"\\\"\").append(name).append(\"\\\"\").append(\", \");\n        }\n        if (buf.length() > 2) {\n            buf.setLength(buf.length() - 2);\n        }\n        return buf.toString();\n    }\n\n    public List<ColumnDescriptor> getIndexColumns() {\n        List<ColumnDescriptor> result = new ArrayList<ColumnDescriptor>();\n\n        for (ColumnDescriptor column : columns) {\n            if (!Strings.isBlank(column.getLabel())\n                    && !\"id\".equalsIgnoreCase(column.columnName)) {\n                result.add(column);\n            }\n        }\n\n        return result;\n    }\n\n    public void setLabel(String label) {\n        this.label = label;\n    }\n\n    public String getLabel() {\n        return label;\n    }\n\n    public String getComment() {\n        return comment;\n    }\n\n    public void setComment(String comment) {\n        this.comment = comment;\n    }\n\n}"
  },
  {
    "path": "material-generator/src/main/java/cn/enilu/flash/code/Utils.java",
    "content": "package cn.enilu.flash.code;\n\nimport org.nutz.lang.Strings;\n\n/**\n * 工具类<br>\n * </p> Copyright by easecredit.com<br>\n * 作者: zhangtao <br>\n * 创建日期: 16-7-27<br>\n */\npublic class Utils {\n    /**\n     * 将以“_”分割的单词转换为首字母小写驼峰格式\n     * @param src\n     * @return\n     */\n    public static String  LOWER_CAMEL(String src){\n        src = src.toLowerCase();\n        StringBuilder result = new StringBuilder();\n        for(String sitem:src.split(\"_\")){\n            if(result.toString().length()==0){\n                result.append(sitem);\n            }else{\n                result.append(Strings.upperFirst(sitem));\n            }\n        }\n        return result.toString();\n    }\n\n    /**\n     * 以“_”分割的单词转换为首字母大写驼峰格式\n     * @param src\n     * @return\n     */\n    public static String  UPPER_CAMEL(String src){\n        if(!src.contains(\"_\")){\n            return src;\n        }\n        src = src.toLowerCase();\n        StringBuilder result = new StringBuilder();\n        for(String sitem:src.split(\"_\")){\n            if(result.toString().length()==0){\n                result.append(Strings.upperFirst(sitem));\n            }else{\n                result.append(Strings.upperFirst(sitem));\n            }\n        }\n        return result.toString();\n    }\n    public static  void main(String[] args){\n        System.out.println(UPPER_CAMEL(\"AAAA_BBBB\"));\n    }\n}\n"
  },
  {
    "path": "material-generator/src/main/resources/code/code.json",
    "content": "{\n  \"codeConfig\": {\n    \"type\": \"cn.enilu.flash.code.CodeConfig\",\n    \"fields\": {\n      entityModel: \"material-core\",\n      daoModel: \"material-core\",\n      serviceModel: \"material-core\",\n      controllerModel: \"material-manage\",\n      viewModel: \"material-manage\"\n    }\n  }\n}"
  },
  {
    "path": "material-generator/src/main/resources/code/controller.vm",
    "content": "package ${packageName};\n\nimport ${table.EntityFullClassName};\nimport ${table.ServiceFullClassName};\n\nimport ${table.basePackageName}.bean.core.BussinessLog;\nimport ${table.basePackageName}.bean.constant.factory.PageFactory;\nimport ${table.basePackageName}.bean.dictmap.CommonDict;\nimport ${table.basePackageName}.admin.core.base.controller.BaseController;\nimport ${table.basePackageName}.bean.exception.ApplicationException;\n\nimport ${table.basePackageName}.bean.vo.query.Page;\nimport ${table.basePackageName}.bean.vo.query.SearchFilter;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.ui.Model;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.*;\n\n@Controller\n@RequestMapping(\"${table.UriPrefix}\")\npublic class ${table.ControllerClassName} extends BaseController {\n\tprivate  Logger logger = LoggerFactory.getLogger(getClass());\n\t@Autowired\n\tprivate ${table.ServiceClassName} ${table.ServiceInstanceName};\n\n\tprivate static String PREFIX = \"${table.UriPrefix}/\";\n\n\t/**\n\t* 跳转到首页\n\t*/\n\t@RequestMapping(value=\"\",method = RequestMethod.GET)\n\t\tpublic String index() {\n\t\treturn PREFIX + \"index.html\";\n\t}\n\n\t/**\n\t* 跳转到添加页面\n\t*/\n\t@RequestMapping(value = \"/add\",method = RequestMethod.GET)\n\t\tpublic String add() {\n\t\treturn PREFIX + \"add.html\";\n\t}\n\n\t/**\n\t* 跳转到修改页面\n\t*/\n\t@RequestMapping(\"/edit/{id}\")\n\tpublic String edit(@PathVariable Long id, Model model) {\n\t\t${table.EntityClassName} entity = ${table.ServiceInstanceName}.get(id);\n\t\tmodel.addAttribute(\"item\",entity);\n\t\treturn PREFIX + \"edit.html\";\n\t}\n\t@RequestMapping(value = \"/list\",method = RequestMethod.POST)\n\t@ResponseBody\n\tpublic Object list(@RequestParam(name=\"name\",required = false) String name) {\n\t\tPage<${table.EntityClassName}> page = new PageFactory<${table.EntityClassName}>().defaultPage();\n\t\tpage.addFilter(\"name\", SearchFilter.Operator.EQ,name);\n\t\tpage = ${table.ServiceInstanceName}.queryPage(page);\n\t\treturn super.packForBT(page);\n\t}\n\t/**\n\t* 新增${table.label}\n\t*/\n\t@RequestMapping(value = \"/add\",method = RequestMethod.POST)\n\t@ResponseBody\n\t@BussinessLog(value = \"新增${table.label}\", key = \"name\",dict= CommonDict.class)\n\tpublic Object add(${table.EntityClassName} ${table.entityNameLowerFirstChar}) {\n\t\t${table.ServiceInstanceName}.insert(${table.entityNameLowerFirstChar});\n\t\treturn SUCCESS_TIP;\n\t}\n\n\t/**\n\t* 删除${table.label}\n\t*/\n\t@RequestMapping(value = \"/delete\")\n\t@ResponseBody\n\t@BussinessLog(value = \"删除${table.label}\", key = \"id\",dict= CommonDict.class)\n\tpublic Object delete(@RequestParam Long id) {\n\t\t${table.ServiceInstanceName}.delete(id);\n\t\treturn SUCCESS_TIP;\n\t}\n\n\t/**\n\t* 修改${table.label}\n\t*/\n\t@RequestMapping(value = \"/update\")\n\t@ResponseBody\n\t@BussinessLog(value = \"修改${table.label}\", key = \"name\",dict= CommonDict.class)\n\tpublic Object update(${table.EntityClassName} ${table.entityNameLowerFirstChar}) {\n\t\t${table.ServiceInstanceName}.update(${table.entityNameLowerFirstChar});\n\t\treturn SUCCESS_TIP;\n\t}\n\n}\n"
  },
  {
    "path": "material-generator/src/main/resources/code/repository.vm",
    "content": "package ${packageName};\n\n\nimport ${table.EntityFullClassName};\nimport ${table.basePackageName}.dao.BaseRepository;\n\n\npublic interface ${table.RepositoryClassName} extends BaseRepository<${table.EntityClassName},Long>{\n\n}\n\n"
  },
  {
    "path": "material-generator/src/main/resources/code/service.vm",
    "content": "package ${packageName};\n\n\nimport ${table.EntityFullClassName};\nimport ${table.basePackageName}.${table.repoPackageName}.${table.EntityClassName}Repository;\n\nimport ${table.basePackageName}.service.BaseService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Service;\n\n@Service\npublic class ${table.ServiceClassName} extends BaseService<${table.EntityClassName},Long,${table.RepositoryClassName}>  {\n    private Logger logger = LoggerFactory.getLogger(getClass());\n    @Autowired\n    private ${table.RepositoryClassName} ${table.entityNameLowerFirstChar}Repository;\n\n}\n\n"
  },
  {
    "path": "material-generator/src/main/resources/code/view/add.html.vm",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"\">\n\n            <div class=\"row\">\n#foreach ($column in $table.LabeledColumns)\n                <div class=\"col-sm-4 b-r\">\n                    <#input id=\"${column.FieldName}\" name=\"${column.label}\"/>\n                </div>\n#end\n            </div>\n\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"${table.entityClassName}InfoDlg.addSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"${table.entityClassName}InfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular${table.UriPrefix}/${table.entityNameLowerFirstChar}_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-generator/src/main/resources/code/view/edit.html.vm",
    "content": "@layout(\"/common/include.html\"){\n#set($item_id='${item.id}')\n#set($itemLeft = '${item')\n#set($itemRight = '}')\n\n<div class=\"card\">\n    <div class=\"ibox-content\">\n        <div class=\"form-horizontal\">\n\n            <input type=\"hidden\" id=\"id\" value=\"$item_id\">\n\n            <div class=\"row\">\n                <div class=\"col-sm-4 b-r\">\n                    <#input id=\"id\" name=\"自增主键\" value=\"$item_id\" readonly=\"true\" underline=\"true\"/>\n                </div>\n#foreach ($column in $table.LabeledColumns)\n                <div class=\"col-sm-4 b-r\">\n                    <#input id=\"${column.FieldName}\" name=\"${column.label}\" value=\"$itemLeft.${column.FieldName}$itemRight\" />\n                </div>\n#end\n            </div>\n\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"${table.entityClassName}InfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"${table.entityClassName}InfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular${table.UriPrefix}/${table.entityNameLowerFirstChar}_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-generator/src/main/resources/code/view/index.html.vm",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>${table.Label}管理</h2>\n</div>\n#set($ctxPath = '${ctxPath}')\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"hidden-xs\" id=\"${table.entityClassName}TableToolbar\" role=\"group\">\n                    <div class=\"col-sm-3\">\n                        <#NameCon id=\"name\" name=\"名称\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"${table.entityClassName}.search()\"/>\n                    <#button name=\"重置\" icon=\"fa-refresh\" clickFun=\"${table.entityClassName}.reset()\" space=\"true\"/>\n\n                    @if(shiro.hasPermission(\"${table.UriPrefix}/add\")){\n                    <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"${table.entityClassName}.openAdd${table.entityClassName}()\" space=\"true\"/>\n                    @}\n                </div>\n                <#table id=\"${table.entityClassName}Table\"/>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"$ctxPath/static/modular${table.UriPrefix}/${table.entityNameLowerFirstChar}.js\"></script>\n@}\n"
  },
  {
    "path": "material-generator/src/main/resources/code/view/index.js.vm",
    "content": "/**\n * ${table.Label}管理初始化\n */\nvar ${table.entityClassName} = {\n    id: \"${table.entityClassName}Table\",\n    seItem: null,\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\n${table.entityClassName}.initColumn = function () {\n    return [\n        {field: 'selectItem', checkbox: true},\n        {title: 'ID', field: 'id', visible: true, align: 'center', valign: 'middle',sortable:true},\n#foreach ($column in $table.LabeledColumns)\n    #if($velocityCount==1)\n        {title: '${column.label}', field: '${column.FieldName}', visible: true, align: 'center', valign: 'middle',sortable:true,formatter:function(data,row){\n                return '<a href=\"javascript:;\" onclick=\"${table.entityClassName}.open${table.entityClassName}Detail('+row.id+')\">'+data+'</a>';\n         }},\n    #else\n        {title: '${column.label}', field: '${column.FieldName}', visible: true, align: 'center', valign: 'middle',sortable:true},\n    #end\n#end\n        {title: '操作',formatter:function(data,row){\n                return '<button type=\"button\" class=\"btn btn-info btn-icon waves-effect waves-circle\" onclick=\"${table.entityClassName}.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n        }}\n    ];\n};\n\n/**\n * 点击添加${table.Label}\n */\n${table.entityClassName}.openAdd${table.entityClassName} = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加${table.Label}',\n        area: ['65%', '65%'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '${table.UriPrefix}/add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 打开查看${table.Label}详情\n */\n${table.entityClassName}.open${table.entityClassName}Detail = function (id) {\n    var index = layer.open({\n        type: 2,\n        title: '系统参数详情',\n        area: ['65%', '65%'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '${table.UriPrefix}/edit/' + id\n    });\n    this.layerIndex = index;\n\n};\n\n/**\n * 删除${table.Label}\n */\n${table.entityClassName}.delete = function (id) {\n    var operation = function() {\n        var ajax = new $ax(Feng.ctxPath + \"${table.UriPrefix}/delete\", function (data) {\n            Feng.success(\"删除成功!\");\n            ${table.entityClassName}.\n            table.refresh();\n        }, function (data) {\n            Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n        });\n        ajax.set(\"id\", id);\n        ajax.start();\n    }\n    Feng.confirm(\"确认删除该记录?\", operation);\n\n};\n\n/**\n * 查询${table.Label}列表\n */\n${table.entityClassName}.search = function () {\n    var queryData = {};\n    queryData['name'] = $(\"#name\").val();\n    ${table.entityClassName}.table.refresh({query: queryData});\n};\n/**\n * 重置查询条件\n */\n${table.entityClassName}.reset = function () {\n    $('#name').val('');\n    this.search();\n};\n\n$(function () {\n    var defaultColunms = ${table.entityClassName}.initColumn();\n    var table = new BSTable(${table.entityClassName}.id, \"${table.UriPrefix}/list\", defaultColunms);\n    table.setPaginationType(\"server\");\n    ${table.entityClassName}.table = table.init();\n});\n"
  },
  {
    "path": "material-generator/src/main/resources/code/view/info.js.vm",
    "content": "/**\n * 初始化系统参数详情对话框\n */\nvar ${table.entityClassName}InfoDlg = {\n    ${table.entityNameLowerFirstChar}InfoData : {}\n};\n\n/**\n * 清除数据\n */\n${table.entityClassName}InfoDlg.clearData = function() {\n    this.${table.entityNameLowerFirstChar}InfoData = {};\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\n${table.entityClassName}InfoDlg.set = function(key, val) {\n    this.${table.entityNameLowerFirstChar}InfoData[key] = (typeof val == \"undefined\") ? $(\"#\" + key).val() : val;\n    return this;\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\n${table.entityClassName}InfoDlg.get = function(key) {\n    return $(\"#\" + key).val();\n}\n\n/**\n * 关闭此对话框\n */\n${table.entityClassName}InfoDlg.close = function() {\n    parent.layer.close(window.parent.${table.entityClassName}.layerIndex);\n}\n\n/**\n * 收集数据\n */\n${table.entityClassName}InfoDlg.collectData = function() {\n    this\n        .set('id')\n#foreach ($column in ${table.LabeledColumns})\n        .set('${column.FieldName}')\n#end\n    ;\n}\n\n/**\n * 提交添加\n */\n${table.entityClassName}InfoDlg.addSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"${table.UriPrefix}/add\", function(data){\n        Feng.success(\"添加成功!\");\n        window.parent.${table.entityClassName}.table.refresh();\n        ${table.entityClassName}InfoDlg.close();\n    },function(data){\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.${table.entityNameLowerFirstChar}InfoData);\n    ajax.start();\n}\n\n/**\n * 提交修改\n */\n${table.entityClassName}InfoDlg.editSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"${table.UriPrefix}/update\", function(data){\n        Feng.success(\"修改成功!\");\n        window.parent.${table.entityClassName}.table.refresh();\n        ${table.entityClassName}InfoDlg.close();\n    },function(data){\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.${table.entityNameLowerFirstChar}InfoData);\n    ajax.start();\n}\n\n$(function() {\n\n});\n"
  },
  {
    "path": "material-lab/README.md",
    "content": "# material-lab\n该模块包含一些实验特性的模块，主要探索spring boot的各种功能\n\n## 集成actuator监控\n- 使用actuator可以方便的对spring boot应用做监控\n- 本引用之前的ehcache-core版本过低，需要升级：\n    ```javascript\n     <dependency>\n        <groupId>net.sf.ehcache</groupId>\n        <artifactId>ehcache-core</artifactId>\n        <version>2.6.11</version>\n      </dependency>\n    调整为：\n      <dependency>\n          <groupId>net.sf.ehcache.internal</groupId>\n          <artifactId>ehcache-core</artifactId>\n          <version>2.10.5</version>\n       </dependency>\n    ```\n- 启用该功能后 访问http://localhost:8000/actuator/env"
  },
  {
    "path": "material-lab/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>material-admin</artifactId>\n        <groupId>cn.enilu</groupId>\n        <version>0.1</version>\n    </parent>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>material-lab</artifactId>\n\n    <dependencies>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-actuator</artifactId>\n        </dependency>\n    </dependencies>\n</project>"
  },
  {
    "path": "material-lab/src/main/resources/application.properties",
    "content": "#actuator ع\n##صַ˿\nmanagement.server.port=8000\n##springboot2.0֮Http½ĬϵendpointֻΪinfohealthҪ뿪ļعܣҪֶ\nmanagement.endpoints.web.exposure.include=*\n##ǰ׺ Ĭ/actuator\nmanagement.endpoints.web.base-path=/actuator"
  },
  {
    "path": "material-manage/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <parent>\n        <artifactId>material-admin</artifactId>\n        <groupId>cn.enilu</groupId>\n        <version>0.1</version>\n    </parent>\n    <packaging>war</packaging>\n    <modelVersion>4.0.0</modelVersion>\n\n    <artifactId>material-manage</artifactId>\n    <dependencies>\n        <!-- 一些实验特性的功能 商业应用开发中可以有选择的删减-->\n        <dependency>\n            <groupId>cn.enilu</groupId>\n            <artifactId>material-lab</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>cn.enilu</groupId>\n            <artifactId>material-core</artifactId>\n            <version>${project.version}</version>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-tomcat</artifactId>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.ibeetl</groupId>\n            <artifactId>beetl</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.springfox</groupId>\n            <artifactId>springfox-swagger2</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>io.springfox</groupId>\n            <artifactId>springfox-swagger-ui</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.github.penggle</groupId>\n            <artifactId>kaptcha</artifactId>\n        </dependency>\n\n\n        <dependency>\n            <groupId>com.google.zxing</groupId>\n            <artifactId>core</artifactId>\n        </dependency>\n\n        <dependency>\n            <groupId>org.springframework.boot</groupId>\n            <artifactId>spring-boot-starter-test</artifactId>\n            <scope>test</scope>\n        </dependency>\n    </dependencies>\n    <build>\n\n        <plugins>\n            <plugin>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-maven-plugin</artifactId>\n                <configuration>\n                    <fork>true</fork>\n                </configuration>\n            </plugin>\n            <plugin>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <configuration>\n                    <source>1.8</source>\n                    <target>1.8</target>\n                </configuration>\n            </plugin>\n            <!--以war包形式部署到tomcat中-->\n            <plugin>\n            <artifactId>maven-war-plugin</artifactId>\n            <version>2.6</version>\n            <configuration>\n            <warName>material</warName>\n            <failOnMissingWebXml>false</failOnMissingWebXml>\n            </configuration>\n            </plugin>\n\n            <!--以jar包形式单独部署开始-->\n            <!--<plugin>-->\n                <!--<groupId>org.springframework.boot</groupId>-->\n                <!--<artifactId>spring-boot-maven-plugin</artifactId>-->\n                <!--<configuration>-->\n                    <!--<mainClass>cn.enilu.material.admin.AdminApplication</mainClass>-->\n                    <!--<layout>ZIP</layout>-->\n                    <!--<finalName>material</finalName>-->\n                <!--</configuration>-->\n                <!--<executions>-->\n                    <!--<execution>-->\n                        <!--<goals>-->\n                            <!--<goal>repackage</goal>-->\n                        <!--</goals>-->\n                    <!--</execution>-->\n                <!--</executions>-->\n            <!--</plugin>-->\n\n        </plugins>\n        <resources>\n            <resource>\n                <directory>src/main/webapp</directory>\n            </resource>\n            <resource>\n                <directory>src/main/resources</directory>\n            </resource>\n            <resource>\n                <directory>src/main/java</directory>\n                <includes>\n                    <include>**/*.xml</include>\n                </includes>\n            </resource>\n        </resources>\n    </build>\n\n</project>"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/AdminApplication.java",
    "content": "package cn.enilu.material.admin;\n\nimport cn.enilu.material.admin.config.properties.AppProperties;\nimport cn.enilu.material.dao.BaseRepositoryFactoryBean;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.SpringApplication;\nimport org.springframework.boot.autoconfigure.SpringBootApplication;\nimport org.springframework.boot.autoconfigure.domain.EntityScan;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.context.annotation.ComponentScan;\nimport org.springframework.data.jpa.repository.config.EnableJpaAuditing;\nimport org.springframework.data.jpa.repository.config.EnableJpaRepositories;\nimport org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;\nimport org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;\n\n/**\n * SpringBoot方式启动类\n *\n * @author enilu.cn\n * @Date 2017/5/21 12:06\n */\n@SpringBootApplication\n@EnableCaching\n@ComponentScan(basePackages = \"cn.enilu.material\")\n@EntityScan(basePackages=\"cn.enilu.material.bean.entity\")\n@EnableJpaRepositories(basePackages= \"cn.enilu.material.dao\", repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class)\n@EnableJpaAuditing\npublic class AdminApplication extends WebMvcConfigurerAdapter {\n\n    protected final static Logger logger = LoggerFactory.getLogger(AdminApplication.class);\n\n    @Autowired\n    AppProperties appProperties;\n\n    /**\n     * 增加swagger的支持\n     */\n    @Override\n    public void addResourceHandlers(ResourceHandlerRegistry registry) {\n        if (appProperties.getSwaggerOpen()) {\n            registry.addResourceHandler(\"swagger-ui.html\").addResourceLocations(\"classpath:/META-INF/resources/\");\n            registry.addResourceHandler(\"/webjars/**\").addResourceLocations(\"classpath:/META-INF/resources/webjars/\");\n        }\n    }\n\n    public static void main(String[] args) {\n        SpringApplication.run(AdminApplication.class, args);\n        logger.info(\"materail-admin is success!\");\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/AdminServletInitializer.java",
    "content": "package cn.enilu.material.admin;\n\nimport org.springframework.boot.builder.SpringApplicationBuilder;\nimport org.springframework.boot.web.servlet.support.SpringBootServletInitializer;\n\n/**\n * Web程序启动类\n *\n * @author fengshuonan\n * @date 2017-05-21 9:43\n */\npublic class AdminServletInitializer extends SpringBootServletInitializer {\n\n    @Override\n    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {\n        return builder.sources(AdminApplication.class);\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/common/constant/enums/Status.java",
    "content": "package cn.enilu.material.admin.common.constant.enums;\n\nimport java.io.Serializable;\n\n/**\n * 通用的业务状态\n *\n * @author zhfish\n */\npublic enum Status    {\n    未启用(0),\n    启用(1);\n\n    private int value;\n\n    Status(final int value) {\n        this.value = value;\n    }\n\n\n    public Serializable getValue() {\n        return this.value;\n    }\n\n    @Override\n    public String toString(){\n        switch (this.value) {\n            case 0:\n                return \"未启用\";\n            case 1:\n                return \"启用\";\n        }\n        return \"未启用\";\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/common/constant/state/ExpenseState.java",
    "content": "package cn.enilu.material.admin.common.constant.state;\n\n/**\n * 是否是菜单的枚举\n *\n * @author fengshuonan\n * @date 2017年6月1日22:50:11\n */\npublic enum ExpenseState {\n\n    SUBMITING(1, \"待提交\"),\n    CHECKING(2, \"待审核\"),\n    PASS(3, \"审核通过\"),\n    UN_PASS(4, \"未通过\");\n\n    int code;\n    String message;\n\n    ExpenseState(int code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public static String valueOf(Integer status) {\n        if (status == null) {\n            return \"\";\n        } else {\n            for (ExpenseState s : ExpenseState.values()) {\n                if (s.getCode() == status) {\n                    return s.getMessage();\n                }\n            }\n            return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/common/constant/state/IsMenu.java",
    "content": "package cn.enilu.material.admin.common.constant.state;\n\n/**\n * 是否是菜单的枚举\n *\n * @author fengshuonan\n * @date 2017年6月1日22:50:11\n */\npublic enum IsMenu {\n\n    YES(1, \"是\"),\n    NO(0, \"不是\");//不是菜单的是按钮\n\n    int code;\n    String message;\n\n    IsMenu(int code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public static String valueOf(Integer status) {\n        if (status == null) {\n            return \"\";\n        } else {\n            for (IsMenu s : IsMenu.values()) {\n                if (s.getCode() == status) {\n                    return s.getMessage();\n                }\n            }\n            return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/common/constant/state/MenuOpenStatus.java",
    "content": "package cn.enilu.material.admin.common.constant.state;\n\n/**\n * 菜单是否打开的状态\n *\n * @author fengshuonan\n * @Date 2017年4月8日10:12:15\n */\npublic enum MenuOpenStatus {\n\n    OPEN(1, \"打开\"),\n    CLOSE(0, \"关闭\");\n\n    int code;\n    String message;\n\n    MenuOpenStatus(int code, String message) {\n        this.code = code;\n        this.message = message;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public static String valueOf(Integer status) {\n        if (status == null) {\n            return \"\";\n        } else {\n            for (MenuOpenStatus s : MenuOpenStatus.values()) {\n                if (s.getCode() == status) {\n                    return s.getMessage();\n                }\n            }\n            return \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/DefaultFastjsonConfig.java",
    "content": "package cn.enilu.material.admin.config;\n\nimport com.alibaba.fastjson.serializer.SerializeConfig;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport com.alibaba.fastjson.serializer.ToStringSerializer;\nimport com.alibaba.fastjson.serializer.ValueFilter;\nimport com.alibaba.fastjson.support.config.FastJsonConfig;\nimport com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.http.MediaType;\n\nimport java.math.BigInteger;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * fastjson配置类\n *\n * @author fengshuonan\n * @date 2017-05-23 22:56\n */\n@Configuration(\"defaultFastjsonConfig\")\n@ConditionalOnClass(com.alibaba.fastjson.JSON.class)\n@ConditionalOnMissingBean(FastJsonHttpMessageConverter.class)\n@ConditionalOnWebApplication\npublic class DefaultFastjsonConfig {\n\n    @Bean\n    public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {\n        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();\n        converter.setFastJsonConfig(fastjsonConfig());\n        converter.setSupportedMediaTypes(getSupportedMediaType());\n        return converter;\n    }\n\n    /**\n     * fastjson的配置\n     */\n    public FastJsonConfig fastjsonConfig() {\n        FastJsonConfig fastJsonConfig = new FastJsonConfig();\n        fastJsonConfig.setSerializerFeatures(\n                SerializerFeature.PrettyFormat,\n                SerializerFeature.WriteMapNullValue,\n                SerializerFeature.WriteEnumUsingToString,\n                SerializerFeature.DisableCircularReferenceDetect\n        );\n        fastJsonConfig.setDateFormat(\"yyyy-MM-dd HH:mm:ss\");\n        ValueFilter valueFilter = new ValueFilter() {\n            public Object process(Object o, String s, Object o1) {\n                if (null == o1) {\n                    o1 = \"\";\n                }\n                return o1;\n            }\n        };\n        fastJsonConfig.setCharset(Charset.forName(\"utf-8\"));\n        fastJsonConfig.setSerializeFilters(valueFilter);\n\n        //解决Long转json精度丢失的问题\n        SerializeConfig serializeConfig = SerializeConfig.globalInstance;\n        serializeConfig.put(BigInteger.class, ToStringSerializer.instance);\n        serializeConfig.put(Long.class, ToStringSerializer.instance);\n        serializeConfig.put(Long.TYPE, ToStringSerializer.instance);\n        fastJsonConfig.setSerializeConfig(serializeConfig);\n        return fastJsonConfig;\n    }\n\n    /**\n     * 支持的mediaType类型\n     */\n    public List<MediaType> getSupportedMediaType() {\n        ArrayList<MediaType> mediaTypes = new ArrayList<>();\n        mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);\n        return mediaTypes;\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/DruidConfig.java",
    "content": "package cn.enilu.material.admin.config;\n\nimport cn.enilu.material.admin.core.xss.XssFilter;\nimport com.alibaba.druid.pool.DruidDataSource;\nimport com.alibaba.druid.support.http.StatViewServlet;\nimport com.alibaba.druid.support.http.WebStatFilter;\nimport com.alibaba.druid.support.spring.stat.BeanTypeAutoProxyCreator;\nimport com.alibaba.druid.support.spring.stat.DruidStatInterceptor;\nimport com.google.code.kaptcha.impl.DefaultKaptcha;\nimport com.google.code.kaptcha.util.Config;\nimport cn.enilu.material.web.listener.ConfigListener;\nimport org.springframework.aop.Advisor;\nimport org.springframework.aop.support.DefaultPointcutAdvisor;\nimport org.springframework.aop.support.JdkRegexpMethodPointcut;\nimport org.springframework.boot.web.servlet.FilterRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletListenerRegistrationBean;\nimport org.springframework.boot.web.servlet.ServletRegistrationBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.web.context.request.RequestContextListener;\n\nimport java.util.Arrays;\nimport java.util.Properties;\n\n/**\n * web 配置类\n *\n * @author fengshuonan\n * @date 2016年11月12日 下午5:03:32\n */\n@Configuration\npublic class DruidConfig {\n\n    /**\n     * druidServlet注册\n     */\n    @Bean\n    public ServletRegistrationBean druidServletRegistration() {\n        ServletRegistrationBean registration = new ServletRegistrationBean(new StatViewServlet());\n        registration.addUrlMappings(\"/druid/*\");\n        return registration;\n    }\n\n    /**\n     * druid监控 配置URI拦截策略\n     * @return\n     */\n    @Bean\n    public FilterRegistrationBean druidStatFilter(){\n        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());\n        //添加过滤规则.\n        filterRegistrationBean.addUrlPatterns(\"/*\");\n        //添加不需要忽略的格式信息.\n        filterRegistrationBean.addInitParameter(\n                \"exclusions\",\"/static/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid,/druid/*\");\n        //用于session监控页面的用户名显示 需要登录后主动将username注入到session里\n        filterRegistrationBean.addInitParameter(\"principalSessionName\",\"username\");\n        return filterRegistrationBean;\n    }\n\n    /**\n     * druid数据库连接池监控\n     */\n    @Bean\n    public DruidStatInterceptor druidStatInterceptor() {\n        return new DruidStatInterceptor();\n    }\n\n\n    @Bean\n    public JdkRegexpMethodPointcut druidStatPointcut(){\n        JdkRegexpMethodPointcut druidStatPointcut = new JdkRegexpMethodPointcut();\n        String patterns = \"cn.enilu.material.admin.modular.*.code.*\";\n        //可以set多个\n        druidStatPointcut.setPatterns(patterns);\n        return druidStatPointcut;\n    }\n\n    /**\n     * druid数据库连接池监控\n     */\n    @Bean\n    public BeanTypeAutoProxyCreator beanTypeAutoProxyCreator() {\n        BeanTypeAutoProxyCreator beanTypeAutoProxyCreator = new BeanTypeAutoProxyCreator();\n        beanTypeAutoProxyCreator.setTargetBeanType(DruidDataSource.class);\n        beanTypeAutoProxyCreator.setInterceptorNames(\"druidStatInterceptor\");\n        return beanTypeAutoProxyCreator;\n    }\n\n    /**\n     * druid 为druidStatPointcut添加拦截\n     * @return\n     */\n    @Bean\n    public Advisor druidStatAdvisor() {\n        return new DefaultPointcutAdvisor(druidStatPointcut(), druidStatInterceptor());\n    }\n\n    /**\n     * xssFilter注册\n     */\n    @Bean\n    public FilterRegistrationBean xssFilterRegistration() {\n        XssFilter xssFilter = new XssFilter();\n        xssFilter.setUrlExclusion(Arrays.asList(\"/notice/update\",\"/notice/add\"));\n        FilterRegistrationBean registration = new FilterRegistrationBean(xssFilter);\n        registration.addUrlPatterns(\"/*\");\n        return registration;\n    }\n\n    /**\n     * RequestContextListener注册\n     */\n    @Bean\n    public ServletListenerRegistrationBean<RequestContextListener> requestContextListenerRegistration() {\n        return new ServletListenerRegistrationBean<>(new RequestContextListener());\n    }\n\n    /**\n     * ConfigListener注册\n     */\n    @Bean\n    public ServletListenerRegistrationBean<ConfigListener> configListenerRegistration() {\n        return new ServletListenerRegistrationBean<>(new ConfigListener());\n    }\n\n    /**\n     * 验证码生成相关\n     */\n    @Bean\n    public DefaultKaptcha kaptcha() {\n        Properties properties = new Properties();\n        properties.put(\"kaptcha.border\", \"no\");\n        properties.put(\"kaptcha.border.color\", \"105,179,90\");\n        properties.put(\"kaptcha.textproducer.font.color\", \"blue\");\n        properties.put(\"kaptcha.image.width\", \"125\");\n        properties.put(\"kaptcha.image.height\", \"45\");\n        properties.put(\"kaptcha.textproducer.font.size\", \"45\");\n        properties.put(\"kaptcha.session.key\", \"code\");\n        properties.put(\"kaptcha.textproducer.char.length\", \"4\");\n        properties.put(\"kaptcha.textproducer.font.names\", \"宋体,楷体,微软雅黑\");\n        Config config = new Config(properties);\n        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();\n        defaultKaptcha.setConfig(config);\n        return defaultKaptcha;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/EhCacheConfig.java",
    "content": "package cn.enilu.material.admin.config;\n\nimport net.sf.ehcache.CacheManager;\nimport org.springframework.cache.annotation.EnableCaching;\nimport org.springframework.cache.ehcache.EhCacheCacheManager;\nimport org.springframework.cache.ehcache.EhCacheManagerFactoryBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.core.io.ClassPathResource;\n\n/**\n * ehcache配置\n *\n * @author fengshuonan\n * @date 2017-05-20 23:11\n */\n@Configuration\n@EnableCaching\npublic class EhCacheConfig {\n\n    /**\n     * EhCache的配置\n     */\n    @Bean\n    public EhCacheCacheManager cacheManager(CacheManager cacheManager) {\n        return new EhCacheCacheManager(cacheManager);\n    }\n\n    /**\n     * EhCache的配置\n     */\n    @Bean\n    public EhCacheManagerFactoryBean ehcache() {\n        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();\n        ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource(\"ehcache.xml\"));\n        return ehCacheManagerFactoryBean;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/SpringSessionConfig.java",
    "content": "package cn.enilu.material.admin.config;\n\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\n\n/**\n * spring session配置\n *\n * @author fengshuonan\n * @date 2017-07-13 21:05\n */\n//@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1800)  //session过期时间  如果部署多机环境,需要打开注释\n@ConditionalOnProperty(prefix = \"apps\", name = \"spring-session-open\", havingValue = \"true\")\npublic class SpringSessionConfig {\n\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/SwaggerConfig.java",
    "content": "package cn.enilu.material.admin.config;\n\nimport io.swagger.annotations.ApiOperation;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\nimport springfox.documentation.builders.ApiInfoBuilder;\nimport springfox.documentation.builders.PathSelectors;\nimport springfox.documentation.builders.RequestHandlerSelectors;\nimport springfox.documentation.service.ApiInfo;\nimport springfox.documentation.spi.DocumentationType;\nimport springfox.documentation.spring.web.plugins.Docket;\nimport springfox.documentation.swagger2.annotations.EnableSwagger2;\n\n/**\n * swagger配置类\n *\n * @author fengshuonan\n * @date 2017年6月1日19:42:59\n */\n@Configuration\n@EnableSwagger2\n@ConditionalOnProperty(prefix = \"apps\", name = \"swagger-open\", havingValue = \"true\")\npublic class SwaggerConfig {\n\n    @Bean\n    public Docket createRestApi() {\n        return new Docket(DocumentationType.SWAGGER_2)\n                .apiInfo(apiInfo())\n                .select()\n                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))                         //这里采用包含注解的方式来确定要显示的接口\n                .apis(RequestHandlerSelectors.basePackage(\"cn.enilu.material.admin.modular\"))    //这里采用包扫描的方式来确定要显示的接口\n                .paths(PathSelectors.any())\n                .build();\n    }\n\n    private ApiInfo apiInfo() {\n        return new ApiInfoBuilder()\n                .title(\"material-admin Doc\")\n                .description(\"material-admin Api文档\")\n                .termsOfServiceUrl(\"https://enilu.gitee.io/material-admin\")\n                .contact(\"www.enilu.cn\")\n                .version(\"2.0\")\n                .build();\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/UserIDAuditorConfig.java",
    "content": "package cn.enilu.material.admin.config;\n\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.shiro.ShiroKit;\nimport org.springframework.context.annotation.Configuration;\nimport org.springframework.data.domain.AuditorAware;\n\nimport java.util.Optional;\n\n/**\n * UserIDAuditorBean\n *\n * @author zt\n * @version 2019/1/8 0008\n */\n@Configuration\npublic class UserIDAuditorConfig implements AuditorAware<Long> {\n    @Override\n    public Optional<Long> getCurrentAuditor() {\n        ShiroUser shiroUser = ShiroKit.getUser();\n        if(shiroUser!=null){\n            return Optional.of(shiroUser.getId());\n        }\n        return Optional.of(Const.SYSTEM_USER_ID);\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/properties/AppProperties.java",
    "content": "package cn.enilu.material.admin.config.properties;\n\nimport cn.enilu.material.utils.ToolUtil;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.io.File;\n\n/**\n * 项目配置\n *\n * @author enilu.cn\n * @Date 2017/5/23 22:31\n */\n@Component\n@ConfigurationProperties(prefix = AppProperties.PREFIX)\npublic class AppProperties {\n\n    public static final String PREFIX = \"apps\";\n\n    private Boolean kaptchaOpen = false;\n\n    private Boolean swaggerOpen = false;\n\n    private String fileUploadPath;\n\n    private Boolean haveCreatePath = false;\n\n    private Boolean springSessionOpen = false;\n\n    private Integer sessionInvalidateTime = 30 * 60;  //session 失效时间（默认为30分钟 单位：秒）\n\n    private Integer sessionValidationInterval = 15 * 60;  //session 验证失效时间（默认为15分钟 单位：秒）\n\n    public String getFileUploadPath() {\n        //如果没有写文件上传路径,保存到临时目录\n        if (ToolUtil.isEmpty(fileUploadPath)) {\n            return ToolUtil.getTempPath();\n        } else {\n            //判断有没有结尾符,没有得加上\n            if (!fileUploadPath.endsWith(File.separator)) {\n                fileUploadPath = fileUploadPath + File.separator;\n            }\n            //判断目录存不存在,不存在得加上\n            if (haveCreatePath == false) {\n                File file = new File(fileUploadPath);\n                file.mkdirs();\n                haveCreatePath = true;\n            }\n            return fileUploadPath;\n        }\n    }\n\n    public void setFileUploadPath(String fileUploadPath) {\n        this.fileUploadPath = fileUploadPath;\n    }\n\n    public Boolean getKaptchaOpen() {\n        return kaptchaOpen;\n    }\n\n    public void setKaptchaOpen(Boolean kaptchaOpen) {\n        this.kaptchaOpen = kaptchaOpen;\n    }\n\n    public Boolean getSwaggerOpen() {\n        return swaggerOpen;\n    }\n\n    public void setSwaggerOpen(Boolean swaggerOpen) {\n        this.swaggerOpen = swaggerOpen;\n    }\n\n    public Boolean getSpringSessionOpen() {\n        return springSessionOpen;\n    }\n\n    public void setSpringSessionOpen(Boolean springSessionOpen) {\n        this.springSessionOpen = springSessionOpen;\n    }\n\n    public Integer getSessionInvalidateTime() {\n        return sessionInvalidateTime;\n    }\n\n    public void setSessionInvalidateTime(Integer sessionInvalidateTime) {\n        this.sessionInvalidateTime = sessionInvalidateTime;\n    }\n\n    public Integer getSessionValidationInterval() {\n        return sessionValidationInterval;\n    }\n\n    public void setSessionValidationInterval(Integer sessionValidationInterval) {\n        this.sessionValidationInterval = sessionValidationInterval;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/properties/BeetlProperties.java",
    "content": "package cn.enilu.material.admin.config.properties;\n\nimport cn.enilu.material.utils.ToolUtil;\nimport org.springframework.beans.factory.annotation.Value;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.util.Properties;\n\n/**\n * beetl配置(如果需要配置别的配置可参照这个形式自己添加)\n *\n * @author fengshuonan\n * @date 2017-05-24 20:37\n */\n@Configuration\n@ConfigurationProperties(prefix = BeetlProperties.BEETLCONF_PREFIX)\npublic class BeetlProperties {\n\n    public static final String BEETLCONF_PREFIX = \"beetl\";\n\n    private String delimiterStatementStart;\n\n    private String delimiterStatementEnd;\n\n    private String resourceTagroot;\n\n    private String resourceTagsuffix;\n\n    private String resourceAutoCheck;\n\n    @Value(\"${spring.mvc.view.prefix}\")\n    private String prefix;\n\n    public Properties getProperties(){\n        Properties properties = new Properties();\n        if(ToolUtil.isNotEmpty(delimiterStatementStart)){\n            if(delimiterStatementStart.startsWith(\"\\\\\")){\n                delimiterStatementStart = delimiterStatementStart.substring(1);\n            }\n            properties.setProperty(\"DELIMITER_STATEMENT_START\",delimiterStatementStart);\n        }\n        if(ToolUtil.isNotEmpty(delimiterStatementEnd)){\n            properties.setProperty(\"DELIMITER_STATEMENT_END\",delimiterStatementEnd);\n        }else{\n            properties.setProperty(\"DELIMITER_STATEMENT_END\",\"null\");\n        }\n        if(ToolUtil.isNotEmpty(resourceTagroot)){\n            properties.setProperty(\"RESOURCE.tagRoot\",resourceTagroot);\n        }\n        if(ToolUtil.isNotEmpty(resourceTagsuffix)){\n            properties.setProperty(\"RESOURCE.tagSuffix\",resourceTagsuffix);\n        }\n        if(ToolUtil.isNotEmpty(resourceAutoCheck)){\n            properties.setProperty(\"RESOURCE.autoCheck\",resourceAutoCheck);\n        }\n        return properties;\n    }\n\n    public String getPrefix() {\n        return prefix;\n    }\n\n    public String getDelimiterStatementStart() {\n        return delimiterStatementStart;\n    }\n\n    public void setDelimiterStatementStart(String delimiterStatementStart) {\n        this.delimiterStatementStart = delimiterStatementStart;\n    }\n\n    public String getDelimiterStatementEnd() {\n        return delimiterStatementEnd;\n    }\n\n    public void setDelimiterStatementEnd(String delimiterStatementEnd) {\n        this.delimiterStatementEnd = delimiterStatementEnd;\n    }\n\n    public String getResourceTagroot() {\n        return resourceTagroot;\n    }\n\n    public void setResourceTagroot(String resourceTagroot) {\n        this.resourceTagroot = resourceTagroot;\n    }\n\n    public String getResourceTagsuffix() {\n        return resourceTagsuffix;\n    }\n\n    public void setResourceTagsuffix(String resourceTagsuffix) {\n        this.resourceTagsuffix = resourceTagsuffix;\n    }\n\n    public String getResourceAutoCheck() {\n        return resourceAutoCheck;\n    }\n\n    public void setResourceAutoCheck(String resourceAutoCheck) {\n        this.resourceAutoCheck = resourceAutoCheck;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/web/BeetlConfig.java",
    "content": "package cn.enilu.material.admin.config.web;\n\nimport cn.enilu.material.admin.config.properties.BeetlProperties;\nimport cn.enilu.material.admin.core.beetl.BeetlConfiguration;\nimport org.beetl.core.resource.ClasspathResourceLoader;\nimport org.beetl.ext.spring.BeetlSpringViewResolver;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\n/**\n * web 配置类\n *\n * @author fengshuonan\n * @date 2016年11月12日 下午5:03:32\n */\n@Configuration\npublic class BeetlConfig {\n\n    @Autowired\n    BeetlProperties beetlProperties;\n\n    /**\n     * beetl的配置\n     */\n    @Bean(initMethod = \"init\")\n    public BeetlConfiguration beetlConfiguration() {\n        BeetlConfiguration beetlConfiguration = new BeetlConfiguration();\n        beetlConfiguration.setResourceLoader(new ClasspathResourceLoader(BeetlConfig.class.getClassLoader(), beetlProperties.getPrefix()));\n        beetlConfiguration.setConfigProperties(beetlProperties.getProperties());\n        return beetlConfiguration;\n    }\n\n    /**\n     * beetl的视图解析器\n     */\n    @Bean\n    public BeetlSpringViewResolver beetlViewResolver() {\n        BeetlSpringViewResolver beetlSpringViewResolver = new BeetlSpringViewResolver();\n        beetlSpringViewResolver.setConfig(beetlConfiguration());\n        beetlSpringViewResolver.setContentType(\"text/html;charset=UTF-8\");\n        beetlSpringViewResolver.setOrder(0);\n        return beetlSpringViewResolver;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/config/web/ShiroConfig.java",
    "content": "package cn.enilu.material.admin.config.web;\n\nimport cn.enilu.material.admin.config.properties.AppProperties;\nimport cn.enilu.material.shiro.ShiroDbRealm;\nimport org.apache.shiro.cache.CacheManager;\nimport org.apache.shiro.cache.ehcache.EhCacheManager;\nimport org.apache.shiro.codec.Base64;\nimport org.apache.shiro.session.mgt.SessionManager;\nimport org.apache.shiro.spring.LifecycleBeanPostProcessor;\nimport org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;\nimport org.apache.shiro.spring.web.ShiroFilterFactoryBean;\nimport org.apache.shiro.web.mgt.CookieRememberMeManager;\nimport org.apache.shiro.web.mgt.DefaultWebSecurityManager;\nimport org.apache.shiro.web.servlet.Cookie;\nimport org.apache.shiro.web.servlet.ShiroHttpSession;\nimport org.apache.shiro.web.servlet.SimpleCookie;\nimport org.apache.shiro.web.session.mgt.DefaultWebSessionManager;\nimport org.apache.shiro.web.session.mgt.ServletContainerSessionManager;\nimport org.springframework.beans.factory.config.MethodInvokingFactoryBean;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.cache.ehcache.EhCacheManagerFactoryBean;\nimport org.springframework.context.annotation.Bean;\nimport org.springframework.context.annotation.Configuration;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\n/**\n * shiro权限管理的配置\n *\n * @author fengshuonan\n * @date 2016年11月14日 下午3:03:44\n */\n@Configuration\npublic class ShiroConfig {\n\n    /**\n     * 安全管理器\n     */\n    @Bean\n    public DefaultWebSecurityManager securityManager(CookieRememberMeManager rememberMeManager, CacheManager cacheShiroManager, SessionManager sessionManager) {\n        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();\n        securityManager.setRealm(this.shiroDbRealm());\n        securityManager.setCacheManager(cacheShiroManager);\n        securityManager.setRememberMeManager(rememberMeManager);\n        securityManager.setSessionManager(sessionManager);\n        return securityManager;\n    }\n\n    /**\n     * spring session管理器（多机环境）\n     */\n    @Bean\n    @ConditionalOnProperty(prefix = \"apps\", name = \"spring-session-open\", havingValue = \"true\")\n    public ServletContainerSessionManager servletContainerSessionManager() {\n        return new ServletContainerSessionManager();\n    }\n\n    /**\n     * session管理器(单机环境)\n     */\n    @Bean\n    @ConditionalOnProperty(prefix = \"apps\", name = \"spring-session-open\", havingValue = \"false\")\n    public DefaultWebSessionManager defaultWebSessionManager(CacheManager cacheShiroManager, AppProperties appProperties) {\n        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();\n        sessionManager.setCacheManager(cacheShiroManager);\n        sessionManager.setSessionValidationInterval(appProperties.getSessionValidationInterval() * 1000);\n        sessionManager.setGlobalSessionTimeout(appProperties.getSessionInvalidateTime() * 1000);\n        sessionManager.setDeleteInvalidSessions(true);\n        sessionManager.setSessionValidationSchedulerEnabled(true);\n        Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);\n        cookie.setName(\"shiroCookie\");\n        cookie.setHttpOnly(true);\n        sessionManager.setSessionIdCookie(cookie);\n        return sessionManager;\n    }\n\n\n    /**\n     * 缓存管理器 使用Ehcache实现\n     */\n    @Bean\n    public CacheManager getCacheShiroManager(EhCacheManagerFactoryBean ehcache) {\n        EhCacheManager ehCacheManager = new EhCacheManager();\n        ehCacheManager.setCacheManager(ehcache.getObject());\n        return ehCacheManager;\n    }\n\n    /**\n     * 项目自定义的Realm\n     */\n    @Bean\n    public ShiroDbRealm shiroDbRealm() {\n        return new ShiroDbRealm();\n    }\n\n    /**\n     * rememberMe管理器, cipherKey生成见{@code Base64Test.java}\n     */\n    @Bean\n    public CookieRememberMeManager rememberMeManager(SimpleCookie rememberMeCookie) {\n        CookieRememberMeManager manager = new CookieRememberMeManager();\n        manager.setCipherKey(Base64.decode(\"Z3VucwAAAAAAAAAAAAAAAA==\"));\n        manager.setCookie(rememberMeCookie);\n        return manager;\n    }\n\n    /**\n     * 记住密码Cookie\n     */\n    @Bean\n    public SimpleCookie rememberMeCookie() {\n        SimpleCookie simpleCookie = new SimpleCookie(\"rememberMe\");\n        simpleCookie.setHttpOnly(true);\n        simpleCookie.setMaxAge(7 * 24 * 60 * 60);//7天\n        return simpleCookie;\n    }\n\n    /**\n     * Shiro的过滤器链\n     */\n    @Bean\n    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {\n        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();\n        shiroFilter.setSecurityManager(securityManager);\n        /**\n         * 默认的登陆访问url\n         */\n        shiroFilter.setLoginUrl(\"/login\");\n        /**\n         * 登陆成功后跳转的url\n         */\n        shiroFilter.setSuccessUrl(\"/\");\n        /**\n         * 没有权限跳转的url\n         */\n        shiroFilter.setUnauthorizedUrl(\"/global/error\");\n        /**\n         * 配置shiro拦截器链\n         *\n         * anon  不需要认证\n         * authc 需要认证\n         * user  验证通过或RememberMe登录的都可以\n         *\n         * 当应用开启了rememberMe时,用户下次访问时可以是一个user,但不会是authc,因为authc是需要重新认证的\n         *\n         * 顺序从上到下,优先级依次降低\n         *\n         */\n        Map<String, String> hashMap = new LinkedHashMap<>();\n        hashMap.put(\"/static/**\", \"anon\");\n        hashMap.put(\"/login\", \"anon\");\n        hashMap.put(\"/global/sessionError\", \"anon\");\n        hashMap.put(\"/kaptcha\", \"anon\");\n        hashMap.put(\"/**\", \"user\");\n\n        shiroFilter.setFilterChainDefinitionMap(hashMap);\n        return shiroFilter;\n    }\n\n    /**\n     * 在方法中 注入 securityManager,进行代理控制\n     */\n    @Bean\n    public MethodInvokingFactoryBean methodInvokingFactoryBean(DefaultWebSecurityManager securityManager) {\n        MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean();\n        bean.setStaticMethod(\"org.apache.shiro.SecurityUtils.setSecurityManager\");\n        bean.setArguments(new Object[]{securityManager});\n        return bean;\n    }\n\n    /**\n     * Shiro生命周期处理器:\n     * 用于在实现了Initializable接口的Shiro bean初始化时调用Initializable接口回调(例如:UserRealm)\n     * 在实现了Destroyable接口的Shiro bean销毁时调用 Destroyable接口回调(例如:DefaultSecurityManager)\n     */\n    @Bean\n    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {\n        return new LifecycleBeanPostProcessor();\n    }\n\n    /**\n     * 启用shrio授权注解拦截方式，AOP式方法级权限检查\n     */\n    @Bean\n    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {\n        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =\n                new AuthorizationAttributeSourceAdvisor();\n        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);\n        return authorizationAttributeSourceAdvisor;\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/CoreFlag.java",
    "content": "package cn.enilu.material.admin.core;\n\n/**\n * 此类用来获取core模块的包路径\n *\n * @author fengshuonan\n * @Date 2017/12/5 下午12:44\n */\npublic class CoreFlag {\n\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/aop/BaseControllerExceptionHandler.java",
    "content": "package cn.enilu.material.admin.core.aop;\n\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.admin.core.base.tips.ErrorTip;\nimport cn.enilu.material.bean.exception.ExceptionEnum;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\n/**\n * 全局的的异常拦截器（拦截所有的控制器）（带有@RequestMapping注解的方法上都会拦截）\n *\n * @author fengshuonan\n * @date 2016年11月12日 下午3:19:56\n */\npublic class BaseControllerExceptionHandler {\n\n    private Logger log = LoggerFactory.getLogger(this.getClass());\n\n    /**\n     * 拦截业务异常\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(ApplicationException.class)\n    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)\n    @ResponseBody\n    public ErrorTip notFount(ApplicationException e) {\n        log.error(\"业务异常:\", e);\n        return new ErrorTip(e.getCode(), e.getMessage());\n    }\n\n    /**\n     * 拦截未知的运行时异常\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(RuntimeException.class)\n    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)\n    @ResponseBody\n    public ErrorTip notFount(RuntimeException e) {\n        log.error(\"运行时异常:\", e);\n        return new ErrorTip(ExceptionEnum.SERVER_ERROR.getCode(), ExceptionEnum.SERVER_ERROR.getMessage());\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/aop/GlobalExceptionHandler.java",
    "content": "package cn.enilu.material.admin.core.aop;\n\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.platform.log.LogManager;\nimport cn.enilu.material.platform.log.LogTaskFactory;\nimport cn.enilu.material.shiro.ShiroKit;\nimport cn.enilu.material.utils.HttpKit;\nimport cn.enilu.material.bean.exception.InvalidKaptchaException;\nimport cn.enilu.material.admin.core.base.tips.ErrorTip;\nimport org.apache.shiro.authc.AuthenticationException;\nimport org.apache.shiro.authc.CredentialsException;\nimport org.apache.shiro.authc.DisabledAccountException;\nimport org.apache.shiro.session.InvalidSessionException;\nimport org.apache.shiro.session.UnknownSessionException;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.ControllerAdvice;\nimport org.springframework.web.bind.annotation.ExceptionHandler;\nimport org.springframework.web.bind.annotation.ResponseBody;\nimport org.springframework.web.bind.annotation.ResponseStatus;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.lang.reflect.UndeclaredThrowableException;\n\n/**\n * 全局的的异常拦截器（拦截所有的控制器）（带有@RequestMapping注解的方法上都会拦截）\n *\n * @author fengshuonan\n * @date 2016年11月12日 下午3:19:56\n */\n@ControllerAdvice\npublic class GlobalExceptionHandler {\n\n    private Logger log = LoggerFactory.getLogger(this.getClass());\n\n    /**\n     * 拦截业务异常\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(ApplicationException.class)\n    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)\n    @ResponseBody\n    public ErrorTip notFount(ApplicationException e) {\n        LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));\n        HttpKit.getRequest().setAttribute(\"tip\", e.getMessage());\n        log.error(\"业务异常:\", e);\n        return new ErrorTip(e.getCode(), e.getMessage());\n    }\n\n    /**\n     * 用户未登录\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(AuthenticationException.class)\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    public String unAuth(AuthenticationException e) {\n        log.error(\"用户未登陆：\", e);\n        return \"/login.html\";\n    }\n\n    /**\n     * 账号被冻结\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(DisabledAccountException.class)\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    public String accountLocked(DisabledAccountException e, Model model) {\n        String username = HttpKit.getRequest().getParameter(\"username\");\n        LogManager.me().executeLog(LogTaskFactory.loginLog(username, \"账号被冻结\", HttpKit.getIp()));\n        model.addAttribute(\"tips\", \"账号被冻结\");\n        return \"/login.html\";\n    }\n\n    /**\n     * 账号密码错误\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(CredentialsException.class)\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    public String credentials(CredentialsException e, Model model) {\n        String username = HttpKit.getRequest().getParameter(\"username\");\n        LogManager.me().executeLog(LogTaskFactory.loginLog(username, \"账号密码错误\", HttpKit.getIp()));\n        model.addAttribute(\"tips\", \"账号密码错误\");\n        return \"/login.html\";\n    }\n\n    /**\n     * 验证码错误\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(InvalidKaptchaException.class)\n    @ResponseStatus(HttpStatus.BAD_REQUEST)\n    public String credentials(InvalidKaptchaException e, Model model) {\n        String username = HttpKit.getRequest().getParameter(\"username\");\n        LogManager.me().executeLog(LogTaskFactory.loginLog(username, \"验证码错误\", HttpKit.getIp()));\n        model.addAttribute(\"tips\", \"验证码错误\");\n        return \"/login.html\";\n    }\n\n    /**\n     * 无权访问该资源\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(UndeclaredThrowableException.class)\n    @ResponseStatus(HttpStatus.UNAUTHORIZED)\n    @ResponseBody\n    public ErrorTip credentials(UndeclaredThrowableException e) {\n        HttpKit.getRequest().setAttribute(\"tip\", \"权限异常\");\n        log.error(\"权限异常!\", e);\n        return new ErrorTip(BizExceptionEnum.NO_PERMITION.getCode(),BizExceptionEnum.NO_PERMITION.getMessage());\n    }\n\n    /**\n     * 拦截未知的运行时异常\n     *\n     * @author fengshuonan\n     */\n    @ExceptionHandler(RuntimeException.class)\n    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)\n    @ResponseBody\n    public ErrorTip notFount(RuntimeException e) {\n        LogManager.me().executeLog(LogTaskFactory.exceptionLog(ShiroKit.getUser().getId(), e));\n        HttpKit.getRequest().setAttribute(\"tip\", \"服务器未知运行时异常\");\n        log.error(\"运行时异常:\", e);\n        return new ErrorTip(BizExceptionEnum.SERVER_ERROR.getCode(),BizExceptionEnum.SERVER_ERROR.getMessage());\n    }\n\n    /**\n     * session失效的异常拦截\n     *\n     * @author enilu.cn\n     * @Date 2017/6/7 21:02\n     */\n    @ExceptionHandler(InvalidSessionException.class)\n    @ResponseStatus(HttpStatus.BAD_REQUEST)\n    public String sessionTimeout(InvalidSessionException e, Model model, HttpServletRequest request, HttpServletResponse response) {\n        model.addAttribute(\"tips\", \"session超时\");\n        assertAjax(request, response);\n        return \"/login.html\";\n    }\n\n    /**\n     * session异常\n     *\n     * @author enilu.cn\n     * @Date 2017/6/7 21:02\n     */\n    @ExceptionHandler(UnknownSessionException.class)\n    @ResponseStatus(HttpStatus.BAD_REQUEST)\n    public String sessionTimeout(UnknownSessionException e, Model model, HttpServletRequest request, HttpServletResponse response) {\n        model.addAttribute(\"tips\", \"session超时\");\n        assertAjax(request, response);\n        return \"/login.html\";\n    }\n\n    private void assertAjax(HttpServletRequest request, HttpServletResponse response) {\n        if (request.getHeader(\"x-requested-with\") != null\n                && request.getHeader(\"x-requested-with\").equalsIgnoreCase(\"XMLHttpRequest\")) {\n            //如果是ajax请求响应头会有，x-requested-with\n            response.setHeader(\"sessionstatus\", \"timeout\");//在响应头设置session状态\n        }\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/base/controller/BaseController.java",
    "content": "package cn.enilu.material.admin.core.base.controller;\n\nimport cn.enilu.material.utils.HttpKit;\nimport cn.enilu.material.admin.core.util.FileUtil;\nimport cn.enilu.material.admin.core.base.tips.SuccessTip;\nimport cn.enilu.material.warpper.BaseControllerWarpper;\nimport cn.enilu.material.admin.core.page.PageInfoBT;\nimport cn.enilu.material.bean.vo.query.Page;\nimport org.springframework.http.HttpHeaders;\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.MediaType;\nimport org.springframework.http.ResponseEntity;\n\nimport javax.servlet.http.Cookie;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport java.io.UnsupportedEncodingException;\n\npublic class BaseController {\n\n    protected static String SUCCESS = \"SUCCESS\";\n    protected static String ERROR = \"ERROR\";\n\n    protected static String REDIRECT = \"redirect:\";\n    protected static String FORWARD = \"forward:\";\n\n    protected static SuccessTip SUCCESS_TIP = new SuccessTip();\n\n    protected HttpServletRequest getHttpServletRequest() {\n        return HttpKit.getRequest();\n    }\n\n    protected HttpServletResponse getHttpServletResponse() {\n        return HttpKit.getResponse();\n    }\n\n    protected HttpSession getSession() {\n        return HttpKit.getRequest().getSession();\n    }\n\n    protected HttpSession getSession(Boolean flag) {\n        return HttpKit.getRequest().getSession(flag);\n    }\n\n    protected String getPara(String name) {\n        return HttpKit.getRequest().getParameter(name);\n    }\n\n    protected void setAttr(String name, Object value) {\n        HttpKit.getRequest().setAttribute(name, value);\n    }\n\n    protected Integer getSystemInvokCount() {\n        return (Integer) this.getHttpServletRequest().getServletContext().getAttribute(\"systemCount\");\n    }\n\n    /**\n     * 把service层的分页信息，封装为bootstrap table通用的分页封装\n     */\n    protected <T> PageInfoBT<T> packForBT(Page<T> page) {\n        return new PageInfoBT<T>(page);\n    }\n\n    /**\n     * 包装一个list，让list增加额外属性\n     */\n    protected Object warpObject(BaseControllerWarpper warpper) {\n        return warpper.warp();\n    }\n\n    /**\n     * 删除cookie\n     */\n    protected void deleteCookieByName(String cookieName) {\n        Cookie[] cookies = this.getHttpServletRequest().getCookies();\n        for (Cookie cookie : cookies) {\n            if (cookie.getName().equals(cookieName)) {\n                Cookie temp = new Cookie(cookie.getName(), \"\");\n                temp.setMaxAge(0);\n                this.getHttpServletResponse().addCookie(temp);\n            }\n        }\n    }\n\n    /**\n     * 返回前台文件流\n     *\n     * @author fengshuonan\n     * @date 2017年2月28日 下午2:53:19\n     */\n    protected ResponseEntity<byte[]> renderFile(String fileName, String filePath) {\n        byte[] bytes = FileUtil.toByteArray(filePath);\n        return renderFile(fileName, bytes);\n    }\n\n    /**\n     * 返回前台文件流\n     *\n     * @author fengshuonan\n     * @date 2017年2月28日 下午2:53:19\n     */\n    protected ResponseEntity<byte[]> renderFile(String fileName, byte[] fileBytes) {\n        String dfileName = null;\n        try {\n            dfileName = new String(fileName.getBytes(\"gb2312\"), \"iso8859-1\");\n        } catch (UnsupportedEncodingException e) {\n            e.printStackTrace();\n        }\n        HttpHeaders headers = new HttpHeaders();\n        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);\n        headers.setContentDispositionFormData(\"attachment\", dfileName);\n        return new ResponseEntity<byte[]>(fileBytes, headers, HttpStatus.CREATED);\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/base/controller/ErrorView.java",
    "content": "package cn.enilu.material.admin.core.base.controller;\n\nimport org.springframework.stereotype.Component;\nimport org.springframework.web.servlet.View;\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport java.util.Map;\n\n/**\n * 错误页面的默认跳转(例如请求404的时候,默认走这个视图解析器)\n *\n * @author fengshuonan\n * @date 2017-05-21 11:34\n */\n@Component(\"error\")\npublic class ErrorView implements View {\n\n    @Override\n    public String getContentType() {\n        return \"text/html\";\n    }\n\n    @Override\n    public void render(Map<String, ?> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {\n        httpServletRequest.getRequestDispatcher(\"/global/error\").forward(httpServletRequest, httpServletResponse);\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/base/controller/GlobalController.java",
    "content": "package cn.enilu.material.admin.core.base.controller;\n\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\n/**\n * 全局的控制器\n *\n * @author fengshuonan\n * @date 2016年11月13日 下午11:04:45\n */\n@Controller\n@RequestMapping(\"/global\")\npublic class GlobalController {\n\n    /**\n     * 跳转到404页面\n     *\n     * @author fengshuonan\n     */\n    @RequestMapping(path = \"/error\")\n    public String errorPage() {\n        return \"/404.html\";\n    }\n\n    /**\n     * 跳转到session超时页面\n     *\n     * @author fengshuonan\n     */\n    @RequestMapping(path = \"/sessionError\")\n    public String errorPageInfo(Model model) {\n        model.addAttribute(\"tips\", \"session超时\");\n        return \"/login.html\";\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/base/tips/ErrorTip.java",
    "content": "package cn.enilu.material.admin.core.base.tips;\n\n/**\n * 返回给前台的错误提示\n *\n * @author fengshuonan\n * @date 2016年11月12日 下午5:05:22\n */\npublic class ErrorTip extends Tip {\n\n    public ErrorTip(int code, String message) {\n        super();\n        this.code = code;\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/base/tips/SuccessTip.java",
    "content": "package cn.enilu.material.admin.core.base.tips;\n\n/**\n * 返回给前台的成功提示\n *\n * @author fengshuonan\n * @date 2016年11月12日 下午5:05:22\n */\npublic class SuccessTip extends Tip {\n\t\n\tpublic SuccessTip(){\n\t\tsuper.code = 200;\n\t\tsuper.message = \"操作成功\";\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/base/tips/Tip.java",
    "content": "package cn.enilu.material.admin.core.base.tips;\n\n/**\n * 返回给前台的提示（最终转化为json形式）\n *\n * @author fengshuonan\n * @Date 2017年1月11日 下午11:58:00\n */\npublic abstract class Tip {\n\n    protected int code;\n    protected String message;\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/beetl/BeetlConfiguration.java",
    "content": "package cn.enilu.material.admin.core.beetl;\n\nimport cn.enilu.material.admin.core.util.KaptchaUtil;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.ToolUtil;\nimport org.beetl.ext.spring.BeetlGroupUtilConfiguration;\n\npublic class BeetlConfiguration extends BeetlGroupUtilConfiguration {\n\n    @Override\n    public void initOther() {\n\n        groupTemplate.registerFunctionPackage(\"shiro\", new ShiroExt());\n        groupTemplate.registerFunctionPackage(\"tool\", new ToolUtil());\n        groupTemplate.registerFunctionPackage(\"kaptcha\", new KaptchaUtil());\n        groupTemplate.registerFunctionPackage(\"constant\",ConstantFactory.me());\n\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/beetl/ShiroExt.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n * <p>\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n * <p>\n * http://www.apache.org/licenses/LICENSE-2.0\n * <p>\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.admin.core.beetl;\n\nimport cn.enilu.material.bean.vo.node.MenuNode;\nimport cn.enilu.material.utils.StringUtils;\nimport org.apache.shiro.SecurityUtils;\nimport org.apache.shiro.subject.Subject;\nimport org.beetl.core.GroupTemplate;\n\nimport cn.enilu.material.bean.core.ShiroUser;\n\nimport java.util.List;\n\npublic class ShiroExt {\n    private static final String NAMES_DELIMETER = \",\";\n\n    /**\n     * 获取当前 Subject\n     *\n     * @return Subject\n     */\n    protected static Subject getSubject() {\n        return SecurityUtils.getSubject();\n    }\n\n    /**\n     * 获取封装的 ShiroUser\n     *\n     * @return ShiroUser\n     */\n    public ShiroUser getUser() {\n        if (isGuest()) {\n            return null;\n        } else {\n            return (ShiroUser) getSubject().getPrincipals().getPrimaryPrincipal();\n        }\n    }\n\n    /**\n     * 判断指定url和菜单名称是否是父子关系\n     * @param sonUrl 子菜单url\n     * @param parentName 父菜单名称\n     * @return\n     */\n    public boolean isParent(String sonUrl,String parentName){\n        if (isGuest()) {\n            return false;\n        } else {\n            ShiroUser shiroUser = (ShiroUser) getSubject().getPrincipals().getPrimaryPrincipal();\n            List<MenuNode> list =  shiroUser.getTitles();\n            for(MenuNode parent:list){\n                List<MenuNode> children = parent.getChildren();\n                if(children==null || children.isEmpty()){\n                    continue;\n                }\n                for(MenuNode child:children){\n                    if(sonUrl.equals(child.getUrl()) && parentName.equals(parent.getName())){\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    }\n\n    /**\n     * 验证当前用户是否属于该角色？,使用时与lacksRole 搭配使用\n     *\n     * @param roleName 角色名\n     * @return 属于该角色：true，否则false\n     */\n    public boolean hasRole(String roleName) {\n        return getSubject() != null && roleName != null\n                && roleName.length() > 0 && getSubject().hasRole(roleName);\n    }\n\n    /**\n     * 与hasRole标签逻辑相反，当用户不属于该角色时验证通过。\n     *\n     * @param roleName 角色名\n     * @return 不属于该角色：true，否则false\n     */\n    public boolean lacksRole(String roleName) {\n        return !hasRole(roleName);\n    }\n\n    /**\n     * 验证当前用户是否属于以下任意一个角色。\n     *\n     * @param roleNames 角色列表\n     * @return 属于:true,否则false\n     */\n    public boolean hasAnyRoles(String roleNames) {\n        boolean hasAnyRole = false;\n        Subject subject = getSubject();\n        if (subject != null && roleNames != null && roleNames.length() > 0) {\n            for (String role : roleNames.split(NAMES_DELIMETER)) {\n                if (subject.hasRole(role.trim())) {\n                    hasAnyRole = true;\n                    break;\n                }\n            }\n        }\n        return hasAnyRole;\n    }\n\n    /**\n     * 验证当前用户是否属于以下所有角色。\n     *\n     * @param roleNames 角色列表\n     * @return 属于:true,否则false\n     */\n    public boolean hasAllRoles(String roleNames) {\n        boolean hasAllRole = true;\n        Subject subject = getSubject();\n        if (subject != null && roleNames != null && roleNames.length() > 0) {\n            for (String role : roleNames.split(NAMES_DELIMETER)) {\n                if (!subject.hasRole(role.trim())) {\n                    hasAllRole = false;\n                    break;\n                }\n            }\n        }\n        return hasAllRole;\n    }\n\n    /**\n     * 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用\n     *\n     * @param permission 权限名\n     * @return 拥有权限：true，否则false\n     */\n    public boolean hasPermission(String permission) {\n        return getSubject() != null && permission != null\n                && permission.length() > 0\n                && getSubject().isPermitted(permission);\n    }\n\n    /**\n     * 与hasPermission标签逻辑相反，当前用户没有制定权限时，验证通过。\n     *\n     * @param permission 权限名\n     * @return 拥有权限：true，否则false\n     */\n    public boolean lacksPermission(String permission) {\n        return !hasPermission(permission);\n    }\n\n    /**\n     * 已认证通过的用户。不包含已记住的用户，这是与user标签的区别所在。与notAuthenticated搭配使用\n     *\n     * @return 通过身份验证：true，否则false\n     */\n    public boolean authenticated() {\n        return getSubject() != null && getSubject().isAuthenticated();\n    }\n\n    /**\n     * 未认证通过用户，与authenticated标签相对应。与guest标签的区别是，该标签包含已记住用户。。\n     *\n     * @return 没有通过身份验证：true，否则false\n     */\n    public boolean notAuthenticated() {\n        return !authenticated();\n    }\n\n    /**\n     * 认证通过或已记住的用户。与guset搭配使用。\n     *\n     * @return 用户：true，否则 false\n     */\n    public boolean isUser() {\n        return getSubject() != null && getSubject().getPrincipal() != null;\n    }\n\n    /**\n     * 验证当前用户是否为“访客”，即未认证（包含未记住）的用户。用user搭配使用\n     *\n     * @return 访客：true，否则false\n     */\n    public boolean isGuest() {\n        return !isUser();\n    }\n\n    /**\n     * 输出当前用户信息，通常为登录帐号信息。\n     *\n     * @return 当前用户信息\n     */\n    public String principal() {\n        if (getSubject() != null) {\n            Object principal = getSubject().getPrincipal();\n            return principal.toString();\n        }\n        return \"\";\n    }\n\n    public static void main(String[] args) {\n        GroupTemplate gt = new GroupTemplate();\n        gt.registerFunctionPackage(\"shiro\", new ShiroExt());\n\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/cache/BaseCacheFactory.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.admin.core.cache;\n\n\n/**\n * 缓存工厂基类\n */\npublic abstract class BaseCacheFactory implements ICache {\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> T get(String cacheName, Object key, ILoader iLoader) {\n\t\tObject data = get(cacheName, key);\n\t\tif (data == null) {\n\t\t\tdata = iLoader.load();\n\t\t\tput(cacheName, key, data);\n\t\t}\n\t\treturn (T) data;\n\t}\n\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass) {\n\t\tObject data = get(cacheName, key);\n\t\tif (data == null) {\n\t\t\ttry {\n\t\t\t\tILoader dataLoader = iLoaderClass.newInstance();\n\t\t\t\tdata = dataLoader.load();\n\t\t\t\tput(cacheName, key, data);\n\t\t\t} catch (Exception e) {\n\t\t\t\tthrow new RuntimeException(e);\n\t\t\t}\n\t\t}\n\t\treturn (T) data;\n\t}\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/cache/CacheKit.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage cn.enilu.material.admin.core.cache;\n\nimport java.util.List;\n\n/**\n * 缓存工具类\n */\npublic class CacheKit {\n\t\n\tprivate static ICache defaultCacheFactory = new EhcacheFactory();\n\n\tpublic static void put(String cacheName, Object key, Object value) {\n\t\tdefaultCacheFactory.put(cacheName, key, value);\n\t}\n\t\n\tpublic static <T> T get(String cacheName, Object key) {\n\t\treturn defaultCacheFactory.get(cacheName, key);\n\t}\n\t\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic static List getKeys(String cacheName) {\n\t\treturn defaultCacheFactory.getKeys(cacheName);\n\t}\n\t\n\tpublic static void remove(String cacheName, Object key) {\n\t\tdefaultCacheFactory.remove(cacheName, key);\n\t}\n\t\n\tpublic static void removeAll(String cacheName) {\n\t\tdefaultCacheFactory.removeAll(cacheName);\n\t}\n\t\n\tpublic static <T> T get(String cacheName, Object key, ILoader iLoader) {\n\t\treturn defaultCacheFactory.get(cacheName, key, iLoader);\n\t}\n\t\n\tpublic static <T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass) {\n\t\treturn defaultCacheFactory.get(cacheName, key, iLoaderClass);\n\t}\n\t\n}\n\n\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/cache/EhcacheFactory.java",
    "content": "/**\n * Copyright (c) 2011-2016, James Zhan 詹波 (jfinal@126.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.admin.core.cache;\n\nimport net.sf.ehcache.Cache;\nimport net.sf.ehcache.CacheManager;\nimport net.sf.ehcache.Element;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.List;\n\n/**\n * Ehcache缓存工厂\n */\npublic class EhcacheFactory extends BaseCacheFactory {\n\t\n\tprivate static CacheManager cacheManager;\n\tprivate static volatile Object locker = new Object();\n\tprivate static final Logger log = LoggerFactory.getLogger(EhcacheFactory.class);\n\t\n\tprivate static CacheManager getCacheManager() {\n\t\tif (cacheManager == null) {\n\t\t\tsynchronized (EhcacheFactory.class) {\n\t\t\t\tif (cacheManager == null) {\n\t\t\t\t\tcacheManager = CacheManager.create();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn cacheManager;\n\t}\n\t\n\tstatic Cache getOrAddCache(String cacheName) {\n\t\tCacheManager cacheManager = getCacheManager();\n\t\tCache cache = cacheManager.getCache(cacheName);\n\t\tif (cache == null) {\n\t\t\tsynchronized(locker) {\n\t\t\t\tcache = cacheManager.getCache(cacheName);\n\t\t\t\tif (cache == null) {\n\t\t\t\t\tlog.warn(\"无法找到缓存 [\" + cacheName + \"]的配置, 使用默认配置.\");\n\t\t\t\t\tcacheManager.addCacheIfAbsent(cacheName);\n\t\t\t\t\tcache = cacheManager.getCache(cacheName);\n\t\t\t\t\tlog.debug(\"缓存 [\" + cacheName + \"] 启动.\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t}\n\t\n\tpublic void put(String cacheName, Object key, Object value) {\n\t\tgetOrAddCache(cacheName).put(new Element(key, value));\n\t}\n\t\n\t@SuppressWarnings(\"unchecked\")\n\tpublic <T> T get(String cacheName, Object key) {\n\t\tElement element = getOrAddCache(cacheName).get(key);\n\t\treturn element != null ? (T)element.getObjectValue() : null;\n\t}\n\t\n\t@SuppressWarnings(\"rawtypes\")\n\tpublic List getKeys(String cacheName) {\n\t\treturn getOrAddCache(cacheName).getKeys();\n\t}\n\t\n\tpublic void remove(String cacheName, Object key) {\n\t\tgetOrAddCache(cacheName).remove(key);\n\t}\n\t\n\tpublic void removeAll(String cacheName) {\n\t\tgetOrAddCache(cacheName).removeAll();\n\t}\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/cache/ICache.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.admin.core.cache;\n\nimport java.util.List;\n\n/**\n * 通用缓存接口\n */\npublic interface ICache {\n\t\n\tvoid put(String cacheName, Object key, Object value);\n\t\n\t<T> T get(String cacheName, Object key);\n\t\n\t@SuppressWarnings(\"rawtypes\")\n\tList getKeys(String cacheName);\n\t\n\tvoid remove(String cacheName, Object key);\n\t\n\tvoid removeAll(String cacheName);\n\t\n\t<T> T get(String cacheName, Object key, ILoader iLoader);\n\t\n\t<T> T get(String cacheName, Object key, Class<? extends ILoader> iLoaderClass);\n\t\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/cache/ILoader.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.admin.core.cache;\n\n/**\n *  数据重载\n */\npublic interface ILoader {\n\tObject load();\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/datascope/DataScope.java",
    "content": "package cn.enilu.material.admin.core.datascope;\n\nimport java.util.List;\n\n/**\n * 数据范围\n *\n * @author fengshuonan\n * @date 2017-07-23 22:19\n */\npublic class DataScope {\n\n    /**\n     * 限制范围的字段名称\n     */\n    private String scopeName = \"deptid\";\n\n    /**\n     * 具体的数据范围\n     */\n    private List<Integer> deptIds;\n\n    public DataScope() {\n    }\n\n    public DataScope(List<Integer> deptIds) {\n        this.deptIds = deptIds;\n    }\n\n    public DataScope(String scopeName, List<Integer> deptIds) {\n        this.scopeName = scopeName;\n        this.deptIds = deptIds;\n    }\n\n    public List<Integer> getDeptIds() {\n        return deptIds;\n    }\n\n    public void setDeptIds(List<Integer> deptIds) {\n        this.deptIds = deptIds;\n    }\n\n    public String getScopeName() {\n        return scopeName;\n    }\n\n    public void setScopeName(String scopeName) {\n        this.scopeName = scopeName;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/datasource/DruidProperties.java",
    "content": "package cn.enilu.material.admin.core.datasource;\n\nimport com.alibaba.druid.pool.DruidDataSource;\nimport org.springframework.boot.context.properties.ConfigurationProperties;\nimport org.springframework.stereotype.Component;\n\nimport java.sql.SQLException;\n\n/**\n * <p>数据库数据源配置</p>\n * <p>说明:这个类中包含了许多默认配置,若这些配置符合您的情况,您可以不用管,若不符合,建议不要修改本类,建议直接在\"application.yml\"中配置即可</p>\n * @author enilu.cn\n * @date 2017-05-21 11:18\n */\n@Component\n@ConfigurationProperties(prefix = \"spring.datasource\")\npublic class DruidProperties {\n\n    private String url = \"jdbc:mysql://127.0.0.1:3306/material?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull\";\n\n    private String username = \"root\";\n\n    private String password = \"root\";\n\n    private String driverClassName = \"com.mysql.jdbc.Driver\";\n\n    private Integer initialSize = 2;\n\n    private Integer minIdle = 1;\n\n    private Integer maxActive = 20;\n\n    private Integer maxWait = 60000;\n\n    private Integer timeBetweenEvictionRunsMillis = 60000;\n\n    private Integer minEvictableIdleTimeMillis = 300000;\n\n    private String validationQuery = \"SELECT 'x'\";\n\n    private Boolean testWhileIdle = true;\n\n    private Boolean testOnBorrow = false;\n\n    private Boolean testOnReturn = false;\n\n    private Boolean poolPreparedStatements = true;\n\n    private Integer maxPoolPreparedStatementPerConnectionSize = 20;\n\n    private String filters = \"stat\";\n\n    public void config(DruidDataSource dataSource) {\n\n        dataSource.setUrl(url);\n        dataSource.setUsername(username);\n        dataSource.setPassword(password);\n\n        dataSource.setDriverClassName(driverClassName);\n        dataSource.setInitialSize(initialSize);     //定义初始连接数\n        dataSource.setMinIdle(minIdle);             //最小空闲\n        dataSource.setMaxActive(maxActive);         //定义最大连接数\n        dataSource.setMaxWait(maxWait);             //最长等待时间\n\n        // 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒\n        dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);\n\n        // 配置一个连接在池中最小生存的时间，单位是毫秒\n        dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);\n        dataSource.setValidationQuery(validationQuery);\n        dataSource.setTestWhileIdle(testWhileIdle);\n        dataSource.setTestOnBorrow(testOnBorrow);\n        dataSource.setTestOnReturn(testOnReturn);\n\n        // 打开PSCache，并且指定每个连接上PSCache的大小\n        dataSource.setPoolPreparedStatements(poolPreparedStatements);\n        dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);\n\n        try {\n            dataSource.setFilters(filters);\n        } catch (SQLException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public String getUrl() {\n        return url;\n    }\n\n    public void setUrl(String url) {\n        this.url = url;\n    }\n\n    public String getUsername() {\n        return username;\n    }\n\n    public void setUsername(String username) {\n        this.username = username;\n    }\n\n    public String getPassword() {\n        return password;\n    }\n\n    public void setPassword(String password) {\n        this.password = password;\n    }\n\n    public String getDriverClassName() {\n        return driverClassName;\n    }\n\n    public void setDriverClassName(String driverClassName) {\n        this.driverClassName = driverClassName;\n    }\n\n    public Integer getInitialSize() {\n        return initialSize;\n    }\n\n    public void setInitialSize(Integer initialSize) {\n        this.initialSize = initialSize;\n    }\n\n    public Integer getMinIdle() {\n        return minIdle;\n    }\n\n    public void setMinIdle(Integer minIdle) {\n        this.minIdle = minIdle;\n    }\n\n    public Integer getMaxActive() {\n        return maxActive;\n    }\n\n    public void setMaxActive(Integer maxActive) {\n        this.maxActive = maxActive;\n    }\n\n    public Integer getMaxWait() {\n        return maxWait;\n    }\n\n    public void setMaxWait(Integer maxWait) {\n        this.maxWait = maxWait;\n    }\n\n    public Integer getTimeBetweenEvictionRunsMillis() {\n        return timeBetweenEvictionRunsMillis;\n    }\n\n    public void setTimeBetweenEvictionRunsMillis(Integer timeBetweenEvictionRunsMillis) {\n        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;\n    }\n\n    public Integer getMinEvictableIdleTimeMillis() {\n        return minEvictableIdleTimeMillis;\n    }\n\n    public void setMinEvictableIdleTimeMillis(Integer minEvictableIdleTimeMillis) {\n        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;\n    }\n\n    public String getValidationQuery() {\n        return validationQuery;\n    }\n\n    public void setValidationQuery(String validationQuery) {\n        this.validationQuery = validationQuery;\n    }\n\n    public Boolean getTestWhileIdle() {\n        return testWhileIdle;\n    }\n\n    public void setTestWhileIdle(Boolean testWhileIdle) {\n        this.testWhileIdle = testWhileIdle;\n    }\n\n    public Boolean getTestOnBorrow() {\n        return testOnBorrow;\n    }\n\n    public void setTestOnBorrow(Boolean testOnBorrow) {\n        this.testOnBorrow = testOnBorrow;\n    }\n\n    public Boolean getTestOnReturn() {\n        return testOnReturn;\n    }\n\n    public void setTestOnReturn(Boolean testOnReturn) {\n        this.testOnReturn = testOnReturn;\n    }\n\n    public Boolean getPoolPreparedStatements() {\n        return poolPreparedStatements;\n    }\n\n    public void setPoolPreparedStatements(Boolean poolPreparedStatements) {\n        this.poolPreparedStatements = poolPreparedStatements;\n    }\n\n    public Integer getMaxPoolPreparedStatementPerConnectionSize() {\n        return maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public void setMaxPoolPreparedStatementPerConnectionSize(Integer maxPoolPreparedStatementPerConnectionSize) {\n        this.maxPoolPreparedStatementPerConnectionSize = maxPoolPreparedStatementPerConnectionSize;\n    }\n\n    public String getFilters() {\n        return filters;\n    }\n\n    public void setFilters(String filters) {\n        this.filters = filters;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/intercept/SessionInterceptor.java",
    "content": "package cn.enilu.material.admin.core.intercept;\n\nimport cn.enilu.material.admin.core.util.HttpSessionHolder;\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.springframework.stereotype.Component;\n\n/**\n * 静态调用session的拦截器\n *\n * @author fengshuonan\n * @date 2016年11月13日 下午10:15:42\n */\n@Aspect\n@Component\npublic class SessionInterceptor extends BaseController {\n\n    @Pointcut(\"execution(* cn.enilu.material.admin.*..controller.*.*(..))\")\n    public void cutService() {\n    }\n\n    @Around(\"cutService()\")\n    public Object sessionKit(ProceedingJoinPoint point) throws Throwable {\n\n        HttpSessionHolder.put(super.getHttpServletRequest().getSession());\n        try {\n            return point.proceed();\n        } finally {\n            HttpSessionHolder.remove();\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/intercept/SessionTimeoutInterceptor.java",
    "content": "package cn.enilu.material.admin.core.intercept;\n\nimport cn.enilu.material.shiro.ShiroKit;\nimport cn.enilu.material.utils.HttpKit;\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport org.apache.shiro.session.InvalidSessionException;\nimport org.aspectj.lang.ProceedingJoinPoint;\nimport org.aspectj.lang.annotation.Around;\nimport org.aspectj.lang.annotation.Aspect;\nimport org.aspectj.lang.annotation.Pointcut;\nimport org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;\nimport org.springframework.stereotype.Component;\n\n/**\n * 验证session超时的拦截器\n *\n * @author fengshuonan\n * @date 2017年6月7日21:08:48\n */\n@Aspect\n@Component\n@ConditionalOnProperty(prefix = \"apps\", name = \"session-open\", havingValue = \"true\")\npublic class SessionTimeoutInterceptor extends BaseController {\n\n    @Pointcut(\"execution(* cn.enilu.material.admin.*..controller.*.*(..))\")\n    public void cutService() {\n    }\n\n    @Around(\"cutService()\")\n    public Object sessionTimeoutValidate(ProceedingJoinPoint point) throws Throwable {\n\n        String servletPath = HttpKit.getRequest().getServletPath();\n\n        if (servletPath.equals(\"/kaptcha\") || servletPath.equals(\"/login\") || servletPath.equals(\"/global/sessionError\")) {\n            return point.proceed();\n        }else{\n            if(ShiroKit.getSession().getAttribute(\"sessionFlag\") == null){\n                ShiroKit.getSubject().logout();\n                throw new InvalidSessionException();\n            }else{\n                return point.proceed();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/page/PageBT.java",
    "content": "package cn.enilu.material.admin.core.page;\n\n/**\n * 分页参数类（for BootStrap Table）\n *\n * @author fengshuonan\n * @date 2017年1月21日 下午2:21:35\n */\npublic class PageBT {\n\n    private int limit;        // 每页显示个数\n\n    private int offset;    // 查询的偏移量（查询的页数 = offset/limit + 1）\n\n    private String order;    // 排序方式\n\n\n    public PageBT() {\n        super();\n    }\n\n    public PageBT(int limit, int offset) {\n        super();\n        this.limit = limit;\n        this.offset = offset;\n    }\n\n    public int getLimit() {\n        return limit;\n    }\n\n    public void setLimit(int limit) {\n        this.limit = limit;\n    }\n\n    public int getOffset() {\n        return offset;\n    }\n\n    public void setOffset(int offset) {\n        this.offset = offset;\n    }\n\n    public String getOrder() {\n        return order;\n    }\n\n    public void setOrder(String order) {\n        this.order = order;\n    }\n\n    public int getPageSize() {\n        return this.limit;\n    }\n\n    public int getPageNumber() {\n        return this.offset / this.limit + 1;\n    }\n\n    @Override\n    public String toString() {\n        return \"PageBT [limit=\" + limit + \", offset=\" + offset + \", order=\" + order + \"]\";\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/page/PageInfoBT.java",
    "content": "package cn.enilu.material.admin.core.page;\n\n\nimport cn.enilu.material.bean.vo.query.Page;\n\nimport java.util.List;\n\n/**\n * 分页结果的封装(for Bootstrap Table)\n *\n * @author fengshuonan\n * @Date 2017年1月22日 下午11:06:41\n */\npublic class PageInfoBT<T> {\n\n    // 结果集\n    private List<T> rows;\n\n    // 总数\n    private long total;\n\n    public PageInfoBT(Page<T> page) {\n        this.rows = page.getRecords();\n        this.total = page.getTotal();\n    }\n\n    public List<T> getRows() {\n        return rows;\n    }\n\n    public void setRows(List<T> rows) {\n        this.rows = rows;\n    }\n\n    public long getTotal() {\n        return total;\n    }\n\n    public void setTotal(long total) {\n        this.total = total;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/qr/ImgQrTool.java",
    "content": "package cn.enilu.material.admin.core.qr;\n\nimport com.google.zxing.BarcodeFormat;\nimport com.google.zxing.EncodeHintType;\nimport com.google.zxing.MultiFormatWriter;\nimport com.google.zxing.WriterException;\nimport com.google.zxing.common.BitMatrix;\nimport com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport javax.imageio.ImageIO;\nimport java.awt.*;\nimport java.awt.geom.AffineTransform;\nimport java.awt.image.AffineTransformOp;\nimport java.awt.image.BufferedImage;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 内嵌图片的二维码生成器\n *\n * @author lichunxi\n */\npublic class ImgQrTool {\n\n    private static Logger log = LoggerFactory.getLogger(ImgQrTool.class);\n\n    // 镶嵌的图片宽度的一般\n    private static final int IMAGE_WIDTH = 80;\n    private static final int IMAGE_HEIGHT = 80;\n    private static final int IMAGE_HALF_WIDTH = IMAGE_WIDTH / 2;\n    private static final int FRAME_WIDTH = 2;\n\n    // 二维码写码器\n    private static MultiFormatWriter mutiWriter = new MultiFormatWriter();\n\n    /**\n     * 生成带图片的二维码\n     *\n     * @param content       二维码的内容\n     * @param width         宽度\n     * @param height        高度\n     * @param srcImagePath  被镶嵌的图片的地址\n     * @param destImagePath 生成二维码图片的地址\n     * @author fengshuonan\n     * @since 2.3.0\n     */\n    public static void encode(String content, int width, int height, String srcImagePath, String destImagePath) {\n        try {\n            ImageIO.write(genBarcode(content, width, height, srcImagePath), \"jpg\", new File(destImagePath));\n        } catch (IOException e) {\n            e.printStackTrace();\n        } catch (WriterException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 生成带图片的二维码\n     *\n     * @param content       二维码的内容\n     * @param width         宽度\n     * @param height        高度\n     * @param srcImagePath  被镶嵌的图片的地址\n     * @param destImagePath 生成二维码图片的地址\n     * @author fengshuonan\n     * @since 2.3.0\n     */\n    public static void encode(String content, int width, int height, String srcImagePath, OutputStream outputStream) {\n        try {\n            ImageIO.write(genBarcode(content, width, height, srcImagePath), \"jpg\", outputStream);\n        } catch (IOException e) {\n            e.printStackTrace();\n        } catch (WriterException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 创建不带参数的二维码\n     *\n     * @author fengshuonan\n     * @since 2.3.0\n     */\n    public static void createSimpleQr(String content, int width, int height, String destImagePath) {\n\n        FileOutputStream output = null;\n\n        try {\n            String format = \"jpg\";// 图像类型\n            Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();\n            hints.put(EncodeHintType.CHARACTER_SET, \"UTF-8\");\n            BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);// 生成矩阵\n            File dest = new File(destImagePath);\n            output = new FileOutputStream(dest);\n            MatrixToImageWriter.writeToStream(bitMatrix, format, output);// 输出图像\n        } catch (Exception e) {\n            log.error(\"生成二维码出错！ImgQrTool：createSimpleQr()\", e);\n        } finally {\n            try {\n                output.close();\n            } catch (IOException e) {\n                log.error(\"生成二维码出错！ImgQrTool：createSimpleQr()\", e);\n            }\n        }\n    }\n\n    private static BufferedImage genBarcode(String content, int width, int height, String srcImagePath)\n            throws WriterException, IOException {\n        // 读取源图像\n        BufferedImage scaleImage = scale(srcImagePath, IMAGE_WIDTH, IMAGE_HEIGHT, true);\n        int[][] srcPixels = new int[IMAGE_WIDTH][IMAGE_HEIGHT];\n        for (int i = 0; i < scaleImage.getWidth(); i++) {\n            for (int j = 0; j < scaleImage.getHeight(); j++) {\n                srcPixels[i][j] = scaleImage.getRGB(i, j);\n            }\n        }\n\n        Map<EncodeHintType, Object> hint = new HashMap<EncodeHintType, Object>();\n        hint.put(EncodeHintType.CHARACTER_SET, \"utf-8\");\n        hint.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);\n        hint.put(EncodeHintType.MARGIN, 1);// 二维码整体白框\n\n        // 生成二维码\n        BitMatrix matrix = mutiWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hint);\n\n        // 二维矩阵转为一维像素数组\n        int halfW = matrix.getWidth() / 2;\n        int halfH = matrix.getHeight() / 2;\n        int[] pixels = new int[width * height];\n\n        for (int y = 0; y < matrix.getHeight(); y++) {\n            for (int x = 0; x < matrix.getWidth(); x++) {\n                // 读取图片\n                if (x > halfW - IMAGE_HALF_WIDTH && x < halfW + IMAGE_HALF_WIDTH && y > halfH - IMAGE_HALF_WIDTH\n                        && y < halfH + IMAGE_HALF_WIDTH) {\n                    pixels[y * width + x] = srcPixels[x - halfW + IMAGE_HALF_WIDTH][y - halfH + IMAGE_HALF_WIDTH];\n                }\n                // 在图片四周形成边框\n                else if ((x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW - IMAGE_HALF_WIDTH + FRAME_WIDTH\n                        && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)\n                        || (x > halfW + IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH\n                        && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH\n                        && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)\n                        || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH\n                        && y > halfH - IMAGE_HALF_WIDTH - FRAME_WIDTH\n                        && y < halfH - IMAGE_HALF_WIDTH + FRAME_WIDTH)\n                        || (x > halfW - IMAGE_HALF_WIDTH - FRAME_WIDTH && x < halfW + IMAGE_HALF_WIDTH + FRAME_WIDTH\n                        && y > halfH + IMAGE_HALF_WIDTH - FRAME_WIDTH\n                        && y < halfH + IMAGE_HALF_WIDTH + FRAME_WIDTH)) {\n                    pixels[y * width + x] = 0xfffffff;\n                } else {\n                    // 此处可以修改二维码的颜色，可以分别制定二维码和背景的颜色；\n                    pixels[y * width + x] = matrix.get(x, y) ? 0xff000000 : 0xfffffff;\n                }\n            }\n        }\n\n        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n        image.getRaster().setDataElements(0, 0, width, height, pixels);\n\n        return image;\n    }\n\n    /**\n     * 把传入的原始图像按高度和宽度进行缩放，生成符合要求的图标\n     *\n     * @param srcImageFile 源文件地址\n     * @param height       目标高度\n     * @param width        目标宽度\n     * @param hasFiller    比例不对时是否需要补白：true为补白; false为不补白;\n     * @throws IOException\n     */\n    private static BufferedImage scale(String srcImageFile, int height, int width, boolean hasFiller)\n            throws IOException {\n        double ratio = 0.0; // 缩放比例\n        File file = new File(srcImageFile);\n        BufferedImage srcImage = ImageIO.read(file);\n        Image destImage = srcImage.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH);\n        // 计算比例\n        if ((srcImage.getHeight() > height) || (srcImage.getWidth() > width)) {\n            if (srcImage.getHeight() > srcImage.getWidth()) {\n                ratio = (new Integer(height)).doubleValue() / srcImage.getHeight();\n            } else {\n                ratio = (new Integer(width)).doubleValue() / srcImage.getWidth();\n            }\n            AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null);\n            destImage = op.filter(srcImage, null);\n        }\n        if (hasFiller) {// 补白\n            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);\n            Graphics2D graphic = image.createGraphics();\n            graphic.setColor(Color.white);\n            graphic.fillRect(0, 0, width, height);\n            if (width == destImage.getWidth(null))\n                graphic.drawImage(destImage, 0, (height - destImage.getHeight(null)) / 2, destImage.getWidth(null),\n                        destImage.getHeight(null), Color.white, null);\n            else\n                graphic.drawImage(destImage, (width - destImage.getWidth(null)) / 2, 0, destImage.getWidth(null),\n                        destImage.getHeight(null), Color.white, null);\n            graphic.dispose();\n            destImage = image;\n        }\n        return (BufferedImage) destImage;\n    }\n\n    /**\n     * 生成上方带文字的二维码\n     */\n    public static void createQrWithFontsAbove(QrImage para) {\n        try {\n            // 首先生成二维码图片\n            BufferedImage qrImage = genBarcode(para.getQrContent(), para.getQrWidth(), para.getQrHeight(), para.getQrIconFilePath());\n\n            int qrImageWidth = qrImage.getWidth();\n            int qrImageHeight = qrImage.getHeight();\n\n            String[] splitStrLines = null;\n            splitStrLines = splitStrLines(para.getWordContent(), qrImageWidth / para.getWordSize());\n            int fontsImageHeight = splitStrLines.length * para.getWordSize() + 10; //防止文字遮挡\n\n            //创建顶部文字的图片\n            BufferedImage imageWithFonts = new BufferedImage(qrImageWidth, fontsImageHeight, BufferedImage.TYPE_4BYTE_ABGR);\n            Graphics fontsImageGraphics = imageWithFonts.getGraphics();\n            fontsImageGraphics.fillRect(0, 0, qrImageWidth, fontsImageHeight);\n            fontsImageGraphics.setColor(Color.black);\n            fontsImageGraphics.setFont(new Font(\"宋体\", Font.PLAIN, para.getWordSize()));\n\n            //文字长度大于一行的长度，进行分行\n            if (para.getWordContent().length() > qrImageWidth / para.getWordSize()) {//每行限制的文字个数\n                for (int i = 0; i < splitStrLines.length; i++) {\n                    fontsImageGraphics.drawString(splitStrLines[i], 0, para.getWordSize() * (i + 1));\n                }\n            } else {\n                fontsImageGraphics.drawString(\n                        para.getWordContent(),\n                        ((qrImageWidth / para.getWordSize() - para.getWordContent().length()) / 2) * para.getWordSize() + 20, //总长度减去字长度除以2为向右偏移长度\n                        para.getWordSize());\n            }\n\n            // 从图片中读取RGB\n            int[] ImageArrayFonts = new int[qrImageWidth * fontsImageHeight];\n            ImageArrayFonts = imageWithFonts.getRGB(0, 0, qrImageWidth, fontsImageHeight, ImageArrayFonts, 0, qrImageWidth);\n\n            int[] ImageArrayQr = new int[qrImageWidth * qrImageHeight];\n            ImageArrayQr = qrImage.getRGB(0, 0, qrImageWidth, qrImageHeight, ImageArrayQr, 0, qrImageWidth);\n\n            // 生成新图片\n            BufferedImage ImageNew = new BufferedImage(qrImageWidth, qrImageHeight + fontsImageHeight, BufferedImage.TYPE_INT_RGB);\n            ImageNew.setRGB(0, 0, qrImageWidth, fontsImageHeight, ImageArrayFonts, 0, qrImageWidth);// 设置上半部分的RGB\n            ImageNew.setRGB(0, fontsImageHeight, qrImageWidth, qrImageHeight, ImageArrayQr, 0, qrImageWidth);// 设置下半部分的RGB\n\n            File outFile = new File(para.getFileOutputPath());\n            ImageIO.write(ImageNew, \"jpg\", outFile);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * 一行字符串拆分成多行\n     */\n    private static String[] splitStrLines(String str, int len) {\n        int blocks = str.length() / len + 1;\n        String[] strs = new String[blocks];\n        for (int i = 0; i < blocks; i++) {\n            if ((i + 1) * len > str.length()) {\n                strs[i] = str.substring(i * len);\n            } else {\n                strs[i] = str.substring(i * len, (i + 1) * len);\n            }\n        }\n        return strs;\n    }\n\n    public static void main(String[] args) throws IOException {\n        for (int i = 1; i <= 1; i++) {\n            QrImage para = new QrImage.Builder()\n                    .setFileOutputPath(\"D:\\\\二维码\\\\test\\\\\" + i + \".jpg\")\n                    .setQrContent(\"http://www.baidu.com?a=\" + \"123\")\n                    .setQrHeight(300)\n                    .setQrWidth(300)\n                    .setQrIconFilePath(\"D:\\\\二维码\\\\中间图标\\\\1.png\")\n                    .setTopWrodHeight(100)\n                    .setWordContent(\"test\" + 1)\n                    .setWordSize(18).build();\n            ImgQrTool.createQrWithFontsAbove(para);\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/qr/MatrixToImageConfig.java",
    "content": "/*\n * Copyright 2012 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage cn.enilu.material.admin.core.qr;\n\nimport java.awt.image.BufferedImage;\n\n/**\n * Encapsulates custom configuration used in methods of {@link MatrixToImageWriter}.\n */\npublic final class MatrixToImageConfig {\n\n  public static final int BLACK = 0xFF000000;\n  public static final int WHITE = 0xFFFFFFFF;\n  \n  private final int onColor;\n  private final int offColor;\n\n  /**\n   * Creates a default config with on color {@link #BLACK} and off color {@link #WHITE}, generating normal\n   * black-on-white barcodes.\n   */\n  public MatrixToImageConfig() {\n    this(BLACK, WHITE);\n  }\n\n  /**\n   * @param onColor pixel on color, specified as an ARGB value as an int\n   * @param offColor pixel off color, specified as an ARGB value as an int\n   */\n  public MatrixToImageConfig(int onColor, int offColor) {\n    this.onColor = onColor;\n    this.offColor = offColor;\n  }\n\n  public int getPixelOnColor() {\n    return onColor;\n  }\n\n  public int getPixelOffColor() {\n    return offColor;\n  }\n\n  int getBufferedImageColorModel() {\n    // Use faster BINARY if colors match default\n    return onColor == BLACK && offColor == WHITE ? BufferedImage.TYPE_BYTE_BINARY : BufferedImage.TYPE_INT_RGB;\n  }\n\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/qr/MatrixToImageWriter.java",
    "content": "/*\n * Copyright 2009 ZXing authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.admin.core.qr;\n\nimport com.google.zxing.common.BitMatrix;\n\nimport javax.imageio.ImageIO;\nimport java.awt.image.BufferedImage;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.file.Path;\n\n/**\n * Writes a {@link BitMatrix} to {@link BufferedImage},\n * file or stream. Provided here instead of core since it depends on\n * Java SE libraries.\n *\n * @author Sean Owen\n */\npublic final class MatrixToImageWriter {\n\n  private static final MatrixToImageConfig DEFAULT_CONFIG = new MatrixToImageConfig();\n\n  private MatrixToImageWriter() {}\n\n  /**\n   * Renders a {@link BitMatrix} as an image, where \"false\" bits are rendered\n   * as white, and \"true\" bits are rendered as black.\n   */\n  public static BufferedImage toBufferedImage(BitMatrix matrix) {\n    return toBufferedImage(matrix, DEFAULT_CONFIG);\n  }\n\n  /**\n   * As {@link #toBufferedImage(BitMatrix)}, but allows customization of the output.\n   */\n  public static BufferedImage toBufferedImage(BitMatrix matrix, MatrixToImageConfig config) {\n    int width = matrix.getWidth();\n    int height = matrix.getHeight();\n    BufferedImage image = new BufferedImage(width, height, config.getBufferedImageColorModel());\n    int onColor = config.getPixelOnColor();\n    int offColor = config.getPixelOffColor();\n    for (int x = 0; x < width; x++) {\n      for (int y = 0; y < height; y++) {\n        image.setRGB(x, y, matrix.get(x, y) ? onColor : offColor);\n      }\n    }\n    return image;\n  }\n\n  /**\n   * @deprecated use {@link #writeToPath(BitMatrix, String, Path)}\n   */\n  @Deprecated\n  public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {\n    writeToPath(matrix, format, file.toPath());\n  }\n\n  /**\n   * Writes a {@link BitMatrix} to a file.\n   *\n   * @see #toBufferedImage(BitMatrix)\n   */\n  public static void writeToPath(BitMatrix matrix, String format, Path file) throws IOException {\n    writeToPath(matrix, format, file, DEFAULT_CONFIG);\n  }\n\n  /**\n   * @deprecated use {@link #writeToPath(BitMatrix, String, Path, MatrixToImageConfig)}\n   */\n  @Deprecated\n  public static void writeToFile(BitMatrix matrix, String format, File file, MatrixToImageConfig config) \n      throws IOException {\n    writeToPath(matrix, format, file.toPath(), config);\n  }\n\n  /**\n   * As {@link #writeToFile(BitMatrix, String, File)}, but allows customization of the output.\n   */\n  public static void writeToPath(BitMatrix matrix, String format, Path file, MatrixToImageConfig config)\n      throws IOException {\n    BufferedImage image = toBufferedImage(matrix, config);\n    if (!ImageIO.write(image, format, file.toFile())) {\n      throw new IOException(\"Could not write an image of format \" + format + \" to \" + file);\n    }\n  }\n\n  /**\n   * Writes a {@link BitMatrix} to a stream.\n   *\n   * @see #toBufferedImage(BitMatrix)\n   */\n  public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException {\n    writeToStream(matrix, format, stream, DEFAULT_CONFIG);\n  }\n\n  /**\n   * As {@link #writeToStream(BitMatrix, String, OutputStream)}, but allows customization of the output.\n   */\n  public static void writeToStream(BitMatrix matrix, String format, OutputStream stream, MatrixToImageConfig config) \n      throws IOException {  \n    BufferedImage image = toBufferedImage(matrix, config);\n    if (!ImageIO.write(image, format, stream)) {\n      throw new IOException(\"Could not write an image of format \" + format);\n    }\n  }\n\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/qr/QrImage.java",
    "content": "package cn.enilu.material.admin.core.qr;\n\n/**\n * 二维码图片对象\n *\n * @author fengshuonan\n * @date 2016年12月8日 上午11:37:09\n */\npublic class QrImage {\n\n    /**\n     * 二维码的内容\n     */\n    private String qrContent;\n\n    /**\n     * 二维码的宽度\n     */\n    private int qrWidth;\n\n    /**\n     * 二维码的高度\n     */\n    private int qrHeight;\n\n    /**\n     * 二维码中间图标的文件路径\n     */\n    private String qrIconFilePath;\n\n    /**\n     * 二维码中间小图标的边长\n     */\n    private int qrIconWidth;\n\n    /**\n     * 顶部文字的高度\n     */\n    private int topWrodHeight;\n\n    /**\n     * 文字的大小\n     */\n    private int wordSize;\n\n    /**\n     * 文字的内容\n     */\n    private String wordContent;\n\n    /**\n     * 文件的输出路径\n     */\n    private String fileOutputPath;\n\n    public static class Builder {\n        private String qrContent;\n        private int qrWidth;\n        private int qrHeight;\n        private String qrIconFilePath;\n        private int topWrodHeight;\n        private int wordSize;\n        private String wordContent;\n        private String fileOutputPath;\n        private int qrIconWidth;\n\n        public Builder() {\n        }\n\n        public Builder setQrContent(String qrContent) {\n            this.qrContent = qrContent;\n            return this;\n        }\n\n        public Builder setQrWidth(int qrWidth) {\n            this.qrWidth = qrWidth;\n            return this;\n        }\n\n        public Builder setQrHeight(int qrHeight) {\n            this.qrHeight = qrHeight;\n            return this;\n        }\n\n        public Builder setQrIconFilePath(String qrIconFilePath) {\n            this.qrIconFilePath = qrIconFilePath;\n            return this;\n        }\n\n        public Builder setTopWrodHeight(int topWrodHeight) {\n            this.topWrodHeight = topWrodHeight;\n            return this;\n        }\n\n        public Builder setWordSize(int wordSize) {\n            this.wordSize = wordSize;\n            return this;\n        }\n\n        public Builder setWordContent(String wordContent) {\n            this.wordContent = wordContent;\n            return this;\n        }\n\n        public Builder setFileOutputPath(String fileOutputPath) {\n            this.fileOutputPath = fileOutputPath;\n            return this;\n        }\n\n        public Builder setQrIconWidth(int qrIconWidth) {\n            this.qrIconWidth = qrIconWidth;\n            return this;\n        }\n\n        public QrImage build() {\n            return new QrImage(this.qrContent, this.qrWidth, this.qrHeight, this.qrIconFilePath, this.qrIconWidth,\n                    this.topWrodHeight, this.wordSize, this.wordContent, this.fileOutputPath);\n        }\n    }\n\n    public QrImage(String qrContent, int qrWidth, int qrHeight, String qrIconFilePath, int qrIconWidth,\n                   int topWrodHeight, int wordSize, String wordContent, String fileOutputPath) {\n        super();\n        this.qrContent = qrContent;\n        this.qrWidth = qrWidth;\n        this.qrHeight = qrHeight;\n        this.qrIconFilePath = qrIconFilePath;\n        this.qrIconWidth = qrIconWidth;\n        this.topWrodHeight = topWrodHeight;\n        this.wordSize = wordSize;\n        this.wordContent = wordContent;\n        this.fileOutputPath = fileOutputPath;\n    }\n\n    public String getQrContent() {\n        return qrContent;\n    }\n\n    public int getQrWidth() {\n        return qrWidth;\n    }\n\n    public int getQrHeight() {\n        return qrHeight;\n    }\n\n    public String getQrIconFilePath() {\n        return qrIconFilePath;\n    }\n\n    public int getTopWrodHeight() {\n        return topWrodHeight;\n    }\n\n    public int getWordSize() {\n        return wordSize;\n    }\n\n    public String getWordContent() {\n        return wordContent;\n    }\n\n    public String getFileOutputPath() {\n        return fileOutputPath;\n    }\n\n    public int getQrIconWidth() {\n        return qrIconWidth;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/BasicType.java",
    "content": "package cn.enilu.material.admin.core.support;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 基本变量类型的枚举\n * @author xiaoleilu\n */\npublic enum BasicType {\n\tBYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING;\n\t\n\t/** 原始类型为Key，包装类型为Value，例如： int.class -> Integer.class. */\n\tpublic static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<Class<?>, Class<?>>(8);\n\t/** 包装类型为Key，原始类型为Value，例如： Integer.class -> int.class. */\n\tpublic static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>(8);\n\t\n\tstatic {\n\t\twrapperPrimitiveMap.put(Boolean.class, boolean.class);\n\t\twrapperPrimitiveMap.put(Byte.class, byte.class);\n\t\twrapperPrimitiveMap.put(Character.class, char.class);\n\t\twrapperPrimitiveMap.put(Double.class, double.class);\n\t\twrapperPrimitiveMap.put(Float.class, float.class);\n\t\twrapperPrimitiveMap.put(Integer.class, int.class);\n\t\twrapperPrimitiveMap.put(Long.class, long.class);\n\t\twrapperPrimitiveMap.put(Short.class, short.class);\n\n\t\tfor (Map.Entry<Class<?>, Class<?>> entry : wrapperPrimitiveMap.entrySet()) {\n\t\t\tprimitiveWrapperMap.put(entry.getValue(), entry.getKey());\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/BeanKit.java",
    "content": "package cn.enilu.material.admin.core.support;\n\nimport cn.enilu.material.admin.core.support.exception.ToolBoxException;\nimport cn.enilu.material.utils.Convert;\nimport cn.enilu.material.utils.StrKit;\n\nimport java.beans.*;\nimport java.lang.reflect.Method;\nimport java.util.*;\nimport java.util.Map.Entry;\n\n/**\n * Bean工具类\n *\n * @author Looly\n */\npublic class BeanKit {\n\n    /**\n     * 判断是否为Bean对象\n     *\n     * @param clazz 待测试类\n     * @return 是否为Bean对象\n     */\n    public static boolean isBean(Class<?> clazz) {\n        if (ClassKit.isNormalClass(clazz)) {\n            Method[] methods = clazz.getMethods();\n            for (Method method : methods) {\n                if (method.getParameterTypes().length == 1 && method.getName().startsWith(\"set\")) {\n                    //检测包含标准的setXXX方法即视为标准的JavaBean\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    public static PropertyEditor findEditor(Class<?> type) {\n        return PropertyEditorManager.findEditor(type);\n    }\n\n    /**\n     * 获得Bean字段描述数组\n     *\n     * @param clazz Bean类\n     * @return 字段描述数组\n     * @throws IntrospectionException\n     */\n    public static PropertyDescriptor[] getPropertyDescriptors(Class<?> clazz) throws IntrospectionException {\n        return Introspector.getBeanInfo(clazz).getPropertyDescriptors();\n    }\n\n    /**\n     * 获得字段名和字段描述Map\n     *\n     * @param clazz Bean类\n     * @return 字段名和字段描述Map\n     * @throws IntrospectionException\n     */\n    public static Map<String, PropertyDescriptor> getFieldNamePropertyDescriptorMap(Class<?> clazz) throws IntrospectionException {\n        final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz);\n        Map<String, PropertyDescriptor> map = new HashMap<>();\n        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {\n            map.put(propertyDescriptor.getName(), propertyDescriptor);\n        }\n        return map;\n    }\n\n    /**\n     * 获得Bean类属性描述\n     *\n     * @param clazz     Bean类\n     * @param fieldName 字段名\n     * @return PropertyDescriptor\n     * @throws IntrospectionException\n     */\n    public static PropertyDescriptor getPropertyDescriptor(Class<?> clazz, final String fieldName) throws IntrospectionException {\n        PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz);\n        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {\n            if (ObjectKit.equals(fieldName, propertyDescriptor.getName())) {\n                return propertyDescriptor;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Map转换为Bean对象\n     *\n     * @param map       Map\n     * @param beanClass Bean Class\n     * @return Bean\n     */\n    public static <T> T mapToBean(Map<?, ?> map, Class<T> beanClass) {\n        return fillBeanWithMap(map, ClassKit.newInstance(beanClass));\n    }\n\n    /**\n     * Map转换为Bean对象<br>\n     * 忽略大小写\n     *\n     * @param map       Map\n     * @param beanClass Bean Class\n     * @return Bean\n     */\n    public static <T> T mapToBeanIgnoreCase(Map<?, ?> map, Class<T> beanClass) {\n        return fillBeanWithMapIgnoreCase(map, ClassKit.newInstance(beanClass));\n    }\n\n    /**\n     * 使用Map填充Bean对象\n     *\n     * @param map  Map\n     * @param bean Bean\n     * @return Bean\n     */\n    public static <T> T fillBeanWithMap(final Map<?, ?> map, T bean) {\n        return fillBean(bean, new ValueProvider() {\n            @Override\n            public Object value(String name) {\n                return map.get(name);\n            }\n        });\n    }\n\n    /**\n     * 使用Map填充Bean对象，可配置将下划线转换为驼峰\n     *\n     * @param map           Map\n     * @param bean          Bean\n     * @param isToCamelCase 是否将下划线模式转换为驼峰模式\n     * @return Bean\n     */\n    public static <T> T fillBeanWithMap(Map<?, ?> map, T bean, boolean isToCamelCase) {\n        if (isToCamelCase) {\n            final Map<Object, Object> map2 = new HashMap<Object, Object>();\n            for (Entry<?, ?> entry : map.entrySet()) {\n                final Object key = entry.getKey();\n                if (null != key && key instanceof String) {\n                    final String keyStr = (String) key;\n                    map2.put(StrKit.toCamelCase(keyStr), entry.getValue());\n                } else {\n                    map2.put(key, entry.getValue());\n                }\n            }\n            return fillBeanWithMap(map2, bean);\n        }\n\n        return fillBeanWithMap(map, bean);\n    }\n\n    /**\n     * 使用Map填充Bean对象，忽略大小写\n     *\n     * @param map  Map\n     * @param bean Bean\n     * @return Bean\n     */\n    public static <T> T fillBeanWithMapIgnoreCase(Map<?, ?> map, T bean) {\n        final Map<Object, Object> map2 = new HashMap<Object, Object>();\n        for (Entry<?, ?> entry : map.entrySet()) {\n            final Object key = entry.getKey();\n            if (key instanceof String) {\n                final String keyStr = (String) key;\n                map2.put(keyStr.toLowerCase(), entry.getValue());\n            } else {\n                map2.put(key, entry.getValue());\n            }\n        }\n\n        return fillBean(bean, new ValueProvider() {\n            @Override\n            public Object value(String name) {\n                return map2.get(name.toLowerCase());\n            }\n        });\n    }\n\n    /**\n     * ServletRequest 参数转Bean\n     *\n     * @param request   ServletRequest\n     * @param beanClass Bean Class\n     * @return Bean\n     */\n    public static <T> T requestParamToBean(javax.servlet.ServletRequest request, Class<T> beanClass) {\n        return fillBeanWithRequestParam(request, ClassKit.newInstance(beanClass));\n    }\n\n    /**\n     * ServletRequest 参数转Bean\n     *\n     * @param request ServletRequest\n     * @param bean    Bean\n     * @return Bean\n     */\n    public static <T> T fillBeanWithRequestParam(final javax.servlet.ServletRequest request, T bean) {\n        final String beanName = StrKit.lowerFirst(bean.getClass().getSimpleName());\n        return fillBean(bean, new ValueProvider() {\n            @Override\n            public Object value(String name) {\n                String value = request.getParameter(name);\n                if (StrKit.isEmpty(value)) {\n                    // 使用类名前缀尝试查找值\n                    value = request.getParameter(beanName + StrKit.DOT + name);\n                    if (StrKit.isEmpty(value)) {\n                        // 此处取得的值为空时跳过，包括null和\"\"\n                        value = null;\n                    }\n                }\n                return value;\n            }\n        });\n    }\n\n    /**\n     * ServletRequest 参数转Bean\n     *\n     * @param <T>\n     * @param beanClass     Bean Class\n     * @param valueProvider 值提供者\n     * @return Bean\n     */\n    public static <T> T toBean(Class<T> beanClass, ValueProvider valueProvider) {\n        return fillBean(ClassKit.newInstance(beanClass), valueProvider);\n    }\n\n    /**\n     * 填充Bean\n     *\n     * @param <T>\n     * @param bean          Bean\n     * @param valueProvider 值提供者\n     * @return Bean\n     */\n    public static <T> T fillBean(T bean, ValueProvider valueProvider) {\n        if (null == valueProvider) {\n            return bean;\n        }\n\n        Class<?> beanClass = bean.getClass();\n        try {\n            PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(beanClass);\n            String propertyName;\n            Object value;\n            for (PropertyDescriptor property : propertyDescriptors) {\n                propertyName = property.getName();\n                value = valueProvider.value(propertyName);\n                if (null == value) {\n                    continue;\n                }\n                try {\n                    property.getWriteMethod().invoke(bean, Convert.parse(property.getPropertyType(), value));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n        } catch (Exception e) {\n            throw new ToolBoxException(e);\n        }\n        return bean;\n    }\n\n    /**\n     * 对象转Map\n     *\n     * @param bean bean对象\n     * @return Map\n     */\n    public static <T> Map<String, Object> beanToMap(T bean) {\n        return beanToMap(bean, false);\n    }\n\n    /**\n     * 对象转Map\n     *\n     * @param bean bean对象\n     * @return Map\n     */\n    public static <T> List<Map<String, Object>> listToMapList(List<T> bean) {\n        ArrayList<Map<String, Object>> maps = new ArrayList<>();\n        for (T t : bean) {\n            maps.add(beanToMap(bean, false));\n        }\n        return maps;\n    }\n\n    /**\n     * 对象转Map\n     *\n     * @param bean              bean对象\n     * @param isToUnderlineCase 是否转换为下划线模式\n     * @return Map\n     */\n    public static <T> Map<String, Object> beanToMap(T bean, boolean isToUnderlineCase) {\n\n        if (bean == null) {\n            return null;\n        }\n        Map<String, Object> map = new HashMap<String, Object>();\n        try {\n            final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(bean.getClass());\n            for (PropertyDescriptor property : propertyDescriptors) {\n                String key = property.getName();\n                // 过滤class属性\n                if (false == key.equals(\"class\")) {\n                    // 得到property对应的getter方法\n                    Method getter = property.getReadMethod();\n                    Object value = getter.invoke(bean);\n                    if (null != value) {\n                        map.put(isToUnderlineCase ? StrKit.toUnderlineCase(key) : key, value);\n                    }\n                }\n            }\n        } catch (Exception e) {\n            throw new ToolBoxException(e);\n        }\n        return map;\n    }\n\n    /**\n     * 复制Bean对象属性\n     *\n     * @param source 源Bean对象\n     * @param target 目标Bean对象\n     */\n    public static void copyProperties(Object source, Object target) {\n        copyProperties(source, target, CopyOptions.create());\n    }\n\n    /**\n     * 复制Bean对象属性<br>\n     * 限制类用于限制拷贝的属性，例如一个类我只想复制其父类的一些属性，就可以将editable设置为父类\n     *\n     * @param source           源Bean对象\n     * @param target           目标Bean对象\n     * @param ignoreProperties 不拷贝的的属性列表\n     */\n    public static void copyProperties(Object source, Object target, String... ignoreProperties) {\n        copyProperties(source, target, CopyOptions.create().setIgnoreProperties(ignoreProperties));\n    }\n\n    /**\n     * 复制Bean对象属性<br>\n     * 限制类用于限制拷贝的属性，例如一个类我只想复制其父类的一些属性，就可以将editable设置为父类\n     *\n     * @param source      源Bean对象\n     * @param target      目标Bean对象\n     * @param copyOptions 拷贝选项，见 {@link CopyOptions}\n     */\n    public static void copyProperties(Object source, Object target, CopyOptions copyOptions) {\n        if (null == copyOptions) {\n            copyOptions = new CopyOptions();\n        }\n\n        Class<?> actualEditable = target.getClass();\n        if (copyOptions.editable != null) {\n            //检查限制类是否为target的父类或接口\n            if (!copyOptions.editable.isInstance(target)) {\n                throw new IllegalArgumentException(StrKit.format(\"Target class [{}] not assignable to Editable class [{}]\", target.getClass().getName(), copyOptions.editable.getName()));\n            }\n            actualEditable = copyOptions.editable;\n        }\n        PropertyDescriptor[] targetPds = null;\n        Map<String, PropertyDescriptor> sourcePdMap;\n        try {\n            sourcePdMap = getFieldNamePropertyDescriptorMap(source.getClass());\n            targetPds = getPropertyDescriptors(actualEditable);\n        } catch (IntrospectionException e) {\n            throw new ToolBoxException(e);\n        }\n\n        HashSet<String> ignoreSet = copyOptions.ignoreProperties != null ? CollectionKit.newHashSet(copyOptions.ignoreProperties) : null;\n        for (PropertyDescriptor targetPd : targetPds) {\n            Method writeMethod = targetPd.getWriteMethod();\n            if (writeMethod != null && (ignoreSet == null || false == ignoreSet.contains(targetPd.getName()))) {\n                PropertyDescriptor sourcePd = sourcePdMap.get(targetPd.getName());\n                if (sourcePd != null) {\n                    Method readMethod = sourcePd.getReadMethod();\n                    // 源对象字段的getter方法返回值必须可转换为目标对象setter方法的第一个参数\n                    if (readMethod != null && ClassKit.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {\n                        try {\n                            Object value = ClassKit.setAccessible(readMethod).invoke(source);\n                            if (null != value || false == copyOptions.isIgnoreNullValue) {\n                                ClassKit.setAccessible(writeMethod).invoke(target, value);\n                            }\n                        } catch (Throwable ex) {\n                            throw new ToolBoxException(ex, \"Copy property [{}] to [{}] error: {}\", sourcePd.getName(), targetPd.getName(), ex.getMessage());\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 值提供者，用于提供Bean注入时参数对应值得抽象接口<br>\n     * 继承或匿名实例化此接口<br>\n     * 在Bean注入过程中，Bean获得字段名，通过外部方式根据这个字段名查找相应的字段值，然后注入Bean<br>\n     *\n     * @author Looly\n     */\n    public static interface ValueProvider {\n        /**\n         * 获取值\n         *\n         * @param name Bean对象中参数名\n         * @return 对应参数名的值\n         */\n        public Object value(String name);\n    }\n\n    /**\n     * 属性拷贝选项<br>\n     * 包括：<br>\n     * 1、限制的类或接口，必须为目标对象的实现接口或父类，用于限制拷贝的属性，例如一个类我只想复制其父类的一些属性，就可以将editable设置为父类<br>\n     * 2、是否忽略空值，当源对象的值为null时，true: 忽略而不注入此值，false: 注入null<br>\n     * 3、忽略的属性列表，设置一个属性列表，不拷贝这些属性值<br>\n     *\n     * @author Looly\n     */\n    public static class CopyOptions {\n        /**\n         * 限制的类或接口，必须为目标对象的实现接口或父类，用于限制拷贝的属性，例如一个类我只想复制其父类的一些属性，就可以将editable设置为父类\n         */\n        private Class<?> editable;\n        /**\n         * 是否忽略空值，当源对象的值为null时，true: 忽略而不注入此值，false: 注入null\n         */\n        private boolean isIgnoreNullValue;\n        /**\n         * 忽略的属性列表，设置一个属性列表，不拷贝这些属性值\n         */\n        private String[] ignoreProperties;\n\n        /**\n         * 创建拷贝选项\n         *\n         * @return 拷贝选项\n         */\n        public static CopyOptions create() {\n            return new CopyOptions();\n        }\n\n        /**\n         * 创建拷贝选项\n         *\n         * @param editable          限制的类或接口，必须为目标对象的实现接口或父类，用于限制拷贝的属性\n         * @param isIgnoreNullValue 是否忽略空值，当源对象的值为null时，true: 忽略而不注入此值，false: 注入null\n         * @param ignoreProperties  忽略的属性列表，设置一个属性列表，不拷贝这些属性值\n         * @return 拷贝选项\n         */\n        public static CopyOptions create(Class<?> editable, boolean isIgnoreNullValue, String... ignoreProperties) {\n            return new CopyOptions(editable, isIgnoreNullValue, ignoreProperties);\n        }\n\n        /**\n         * 构造拷贝选项\n         */\n        public CopyOptions() {\n        }\n\n        /**\n         * 构造拷贝选项\n         *\n         * @param editable          限制的类或接口，必须为目标对象的实现接口或父类，用于限制拷贝的属性\n         * @param isIgnoreNullValue 是否忽略空值，当源对象的值为null时，true: 忽略而不注入此值，false: 注入null\n         * @param ignoreProperties  忽略的属性列表，设置一个属性列表，不拷贝这些属性值\n         */\n        public CopyOptions(Class<?> editable, boolean isIgnoreNullValue, String... ignoreProperties) {\n            this.editable = editable;\n            this.isIgnoreNullValue = isIgnoreNullValue;\n            this.ignoreProperties = ignoreProperties;\n        }\n\n        /**\n         * 设置限制的类或接口，必须为目标对象的实现接口或父类，用于限制拷贝的属性\n         *\n         * @param editable 限制的类或接口\n         * @return CopyOptions\n         */\n        public CopyOptions setEditable(Class<?> editable) {\n            this.editable = editable;\n            return this;\n        }\n\n        /**\n         * 设置是否忽略空值，当源对象的值为null时，true: 忽略而不注入此值，false: 注入null\n         *\n         * @param isIgnoreNullVall 是否忽略空值，当源对象的值为null时，true: 忽略而不注入此值，false: 注入null\n         * @return CopyOptions\n         */\n        public CopyOptions setIgnoreNullValue(boolean isIgnoreNullVall) {\n            this.isIgnoreNullValue = isIgnoreNullVall;\n            return this;\n        }\n\n        /**\n         * 设置忽略的属性列表，设置一个属性列表，不拷贝这些属性值\n         *\n         * @param ignoreProperties 忽略的属性列表，设置一个属性列表，不拷贝这些属性值\n         * @return CopyOptions\n         */\n        public CopyOptions setIgnoreProperties(String... ignoreProperties) {\n            this.ignoreProperties = ignoreProperties;\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/ClassKit.java",
    "content": "package cn.enilu.material.admin.core.support;\n\n\nimport cn.enilu.material.admin.core.support.exception.ToolBoxException;\nimport cn.enilu.material.utils.StrKit;\n\nimport java.lang.reflect.Method;\nimport java.lang.reflect.Modifier;\n\n/**\n * 类工具类\n * 1、扫描指定包下的所有类<br>\n * 参考 http://www.oschina.net/code/snippet_234657_22722\n * @author seaside_hi, xiaoleilu, chill\n *\n */\npublic class ClassKit {\n\t\n\tprivate ClassKit() {\n\t\t// 静态类不可实例化\n\t}\n\t\n\t/**\n\t * 是否为标准的类<br>\n\t * 这个类必须：<br>\n\t * 1、非接口 2、非抽象类 3、非Enum枚举 4、非数组 5、非注解 6、非原始类型（int, long等）\n\t * \n\t * @param clazz 类\n\t * @return 是否为标准类\n\t */\n\tpublic static boolean isNormalClass(Class<?> clazz) {\n\t\treturn null != clazz && false == clazz.isInterface() && false == isAbstract(clazz) && false == clazz.isEnum() && false == clazz.isArray() && false == clazz.isAnnotation() && false == clazz\n\t\t\t\t.isSynthetic() && false == clazz.isPrimitive();\n\t}\n\t\n\t/**\n\t * 是否为抽象类\n\t * \n\t * @param clazz 类\n\t * @return 是否为抽象类\n\t */\n\tpublic static boolean isAbstract(Class<?> clazz) {\n\t\treturn Modifier.isAbstract(clazz.getModifiers());\n\t}\n\t\n\t/**\n\t * 实例化对象\n\t * \n\t * @param clazz 类名\n\t * @return 对象\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T newInstance(String clazz) {\n\t\tif (null == clazz)\n\t\t\treturn null;\n\t\ttry {\n\t\t\treturn (T) Class.forName(clazz).newInstance();\n\t\t} catch (Exception e) {\n\t\t\tthrow new ToolBoxException(StrKit.format(\"Instance class [{}] error!\", clazz), e);\n\t\t}\n\t}\n\n\t/**\n\t * 实例化对象\n\t * \n\t * @param clazz 类\n\t * @return 对象\n\t */\n\tpublic static <T> T newInstance(Class<T> clazz) {\n\t\tif (null == clazz)\n\t\t\treturn null;\n\t\ttry {\n\t\t\treturn (T) clazz.newInstance();\n\t\t} catch (Exception e) {\n\t\t\tthrow new ToolBoxException(StrKit.format(\"Instance class [{}] error!\", clazz), e);\n\t\t}\n\t}\n\n\t/**\n\t * 实例化对象\n\t * \n\t * @param clazz 类\n\t * @return 对象\n\t */\n\tpublic static <T> T newInstance(Class<T> clazz, Object... params) {\n\t\tif (null == clazz)\n\t\t\treturn null;\n\t\tif (CollectionKit.isEmpty(params)) {\n\t\t\treturn newInstance(clazz);\n\t\t}\n\t\ttry {\n\t\t\treturn clazz.getDeclaredConstructor(getClasses(params)).newInstance(params);\n\t\t} catch (Exception e) {\n\t\t\tthrow new ToolBoxException(StrKit.format(\"Instance class [{}] error!\", clazz), e);\n\t\t}\n\t}\n\t\n\t/**\n\t * 获得对象数组的类数组\n\t * @param objects 对象数组\n\t * @return 类数组\n\t */\n\tpublic static Class<?>[] getClasses(Object... objects){\n\t\tClass<?>[] classes = new Class<?>[objects.length];\n\t\tfor (int i = 0; i < objects.length; i++) {\n\t\t\tclasses[i] = objects[i].getClass();\n\t\t}\n\t\treturn classes;\n\t}\n\t\n\t/**\n\t * 检查目标类是否可以从原类转化<br>\n\t * 转化包括：<br>\n\t * 1、原类是对象，目标类型是原类型实现的接口<br>\n\t * 2、目标类型是原类型的父类<br>\n\t * 3、两者是原始类型或者包装类型（相互转换）\n\t * \n\t * @param targetType 目标类型\n\t * @param sourceType 原类型\n\t * @return 是否可转化\n\t */\n\tpublic static boolean isAssignable(Class<?> targetType, Class<?> sourceType) {\n\t\tif (null == targetType || null == sourceType) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// 对象类型\n\t\tif (targetType.isAssignableFrom(sourceType)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// 基本类型\n\t\tif (targetType.isPrimitive()) {\n\t\t\t// 原始类型\n\t\t\tClass<?> resolvedPrimitive = BasicType.wrapperPrimitiveMap.get(sourceType);\n\t\t\tif (resolvedPrimitive != null && targetType.equals(resolvedPrimitive)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else {\n\t\t\t// 包装类型\n\t\t\tClass<?> resolvedWrapper = BasicType.primitiveWrapperMap.get(sourceType);\n\t\t\tif (resolvedWrapper != null && targetType.isAssignableFrom(resolvedWrapper)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 设置方法为可访问\n\t * \n\t * @param method 方法\n\t * @return 方法\n\t */\n\tpublic static Method setAccessible(Method method) {\n\t\tif (null != method && ClassKit.isNotPublic(method)) {\n\t\t\tmethod.setAccessible(true);\n\t\t}\n\t\treturn method;\n\t}\n\t\n\t/**\n\t * 指定类是否为非public\n\t * \n\t * @param clazz 类\n\t * @return 是否为非public\n\t */\n\tpublic static boolean isNotPublic(Class<?> clazz) {\n\t\treturn false == isPublic(clazz);\n\t}\n\n\t/**\n\t * 指定方法是否为非public\n\t * \n\t * @param method 方法\n\t * @return 是否为非public\n\t */\n\tpublic static boolean isNotPublic(Method method) {\n\t\treturn false == isPublic(method);\n\t}\n\t\n\t/**\n\t * 指定类是否为Public\n\t * \n\t * @param clazz 类\n\t * @return 是否为public\n\t */\n\tpublic static boolean isPublic(Class<?> clazz) {\n\t\tif (null == clazz) {\n\t\t\tthrow new NullPointerException(\"Class to provided is null.\");\n\t\t}\n\t\treturn Modifier.isPublic(clazz.getModifiers());\n\t}\n\t\n\t/**\n\t * 指定方法是否为Public\n\t * \n\t * @param method 方法\n\t * @return 是否为public\n\t */\n\tpublic static boolean isPublic(Method method) {\n\t\tif (null == method) {\n\t\t\tthrow new NullPointerException(\"Method to provided is null.\");\n\t\t}\n\t\treturn isPublic(method.getDeclaringClass());\n\t}\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/CollectionKit.java",
    "content": "package cn.enilu.material.admin.core.support;\n\n\nimport cn.enilu.material.admin.core.support.exception.ToolBoxException;\nimport cn.enilu.material.utils.StrKit;\n\nimport java.lang.reflect.Array;\nimport java.util.*;\nimport java.util.Map.Entry;\n\n/**\n * 集合相关工具类，包括数组\n * \n * @author xiaoleilu\n * \n */\npublic class CollectionKit {\n\t\n\tprivate CollectionKit() {\n\t\t// 静态类不可实例化\n\t}\n\t\n\t/**\n\t * 以 conjunction 为分隔符将集合转换为字符串\n\t * \n\t * @param <T> 被处理的集合\n\t * @param collection 集合\n\t * @param conjunction 分隔符\n\t * @return 连接后的字符串\n\t */\n\tpublic static <T> String join(Iterable<T> collection, String conjunction) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tboolean isFirst = true;\n\t\tfor (T item : collection) {\n\t\t\tif (isFirst) {\n\t\t\t\tisFirst = false;\n\t\t\t} else {\n\t\t\t\tsb.append(conjunction);\n\t\t\t}\n\t\t\tsb.append(item);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n\t/**\n\t * 以 conjunction 为分隔符将数组转换为字符串\n\t * \n\t * @param <T> 被处理的集合\n\t * @param array 数组\n\t * @param conjunction 分隔符\n\t * @return 连接后的字符串\n\t */\n\tpublic static <T> String join(T[] array, String conjunction) {\n\t\tStringBuilder sb = new StringBuilder();\n\t\tboolean isFirst = true;\n\t\tfor (T item : array) {\n\t\t\tif (isFirst) {\n\t\t\t\tisFirst = false;\n\t\t\t} else {\n\t\t\t\tsb.append(conjunction);\n\t\t\t}\n\t\t\tsb.append(item);\n\t\t}\n\t\treturn sb.toString();\n\t}\n\t\n\t/**\n\t * 将多个集合排序并显示不同的段落（分页）\n\t * @param pageNo 页码\n\t * @param numPerPage 每页的条目数\n\t * @param comparator 比较器\n\t * @param colls 集合数组\n\t * @return 分页后的段落内容\n\t */\n\t@SafeVarargs\n\tpublic static <T> List<T> sortPageAll(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) {\n\t\tfinal List<T> result = new ArrayList<T>();\n\t\tfor (Collection<T> coll : colls) {\n\t\t\tresult.addAll(coll);\n\t\t}\n\t\t\n\t\tCollections.sort(result, comparator);\n\t\t\n\t\t//第一页且数目少于第一页显示的数目\n\t\tif(pageNo <=1 && result.size() <= numPerPage) {\n\t\t\treturn result;\n\t\t}\n\t\t\n\t\tfinal int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage);\n\t\treturn result.subList(startEnd[0], startEnd[1]);\n\t}\n\n\t/**\n\t * 将多个集合排序并显示不同的段落（分页）\n\t * @param pageNo 页码\n\t * @param numPerPage 每页的条目数\n\t * @param comparator 比较器\n\t * @param colls 集合数组\n\t * @return 分业后的段落内容\n\t */\n//\t@SafeVarargs\n//\tpublic static <T> List<T> sortPageAll2(int pageNo, int numPerPage, Comparator<T> comparator, Collection<T>... colls) {\n//\t\tBoundedPriorityQueue<T> queue = new BoundedPriorityQueue<T>(pageNo * numPerPage);\n//\t\tfor (Collection<T> coll : colls) {\n//\t\t\tqueue.addAll(coll);\n//\t\t}\n//\n//\t\t//第一页且数目少于第一页显示的数目\n//\t\tif(pageNo <=1 && queue.size() <= numPerPage) {\n//\t\t\treturn queue.toList();\n//\t\t}\n//\n//\t\tfinal int[] startEnd = PageKit.transToStartEnd(pageNo, numPerPage);\n//\t\treturn queue.toList().subList(startEnd[0], startEnd[1]);\n//\t}\n\n\t/**\n\t * 将Set排序（根据Entry的值）\n\t *\n\t * @param set 被排序的Set\n\t * @return 排序后的Set\n\t */\n\tpublic static List<Entry<Long, Long>> sortEntrySetToList(Set<Entry<Long, Long>> set) {\n\t\tList<Entry<Long, Long>> list = new LinkedList<Entry<Long, Long>>(set);\n\t\tCollections.sort(list, new Comparator<Entry<Long, Long>>(){\n\n\t\t\t@Override\n\t\t\tpublic int compare(Entry<Long, Long> o1, Entry<Long, Long> o2) {\n\t\t\t\tif (o1.getValue() > o2.getValue()){\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tif (o1.getValue() < o2.getValue()){\n\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t});\n\t\treturn list;\n\t}\n\n\t/**\n\t * 切取部分数据\n\t *\n\t * @param <T> 集合元素类型\n\t * @param surplusAlaDatas 原数据\n\t * @param partSize 每部分数据的长度\n\t * @return 切取出的数据或null\n\t */\n\tpublic static <T> List<T> popPart(Stack<T> surplusAlaDatas, int partSize) {\n\t\tif (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal List<T> currentAlaDatas = new ArrayList<T>();\n\t\tint size = surplusAlaDatas.size();\n\t\t// 切割\n\t\tif (size > partSize) {\n\t\t\tfor (int i = 0; i < partSize; i++) {\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t} else {\n\t\t\tfor (int i = 0; i < size; i++) {\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t}\n\t\treturn currentAlaDatas;\n\t}\n\n\t/**\n\t * 切取部分数据\n\t *\n\t * @param <T> 集合元素类型\n\t * @param surplusAlaDatas 原数据\n\t * @param partSize 每部分数据的长度\n\t * @return 切取出的数据或null\n\t */\n\tpublic static <T> List<T> popPart(Deque<T> surplusAlaDatas, int partSize) {\n\t\tif (surplusAlaDatas == null || surplusAlaDatas.size() <= 0){\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal List<T> currentAlaDatas = new ArrayList<T>();\n\t\tint size = surplusAlaDatas.size();\n\t\t// 切割\n\t\tif (size > partSize) {\n\t\t\tfor (int i = 0; i < partSize; i++) {\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t} else {\n\t\t\tfor (int i = 0; i < size; i++) {\n\t\t\t\tcurrentAlaDatas.add(surplusAlaDatas.pop());\n\t\t\t}\n\t\t}\n\t\treturn currentAlaDatas;\n\t}\n\n\t/**\n\t * 新建一个HashMap\n\t *\n\t * @return HashMap对象\n\t */\n\tpublic static <T, K> HashMap<T, K> newHashMap() {\n\t\treturn new HashMap<T, K>();\n\t}\n\n\t/**\n\t * 新建一个HashMap\n\t * @param size 初始大小，由于默认负载因子0.75，传入的size会实际初始大小为size / 0.75\n\t * @return HashMap对象\n\t */\n\tpublic static <T, K> HashMap<T, K> newHashMap(int size) {\n\t\treturn new HashMap<T, K>((int)(size / 0.75));\n\t}\n\n\t/**\n\t * 新建一个HashSet\n\t *\n\t * @return HashSet对象\n\t */\n\tpublic static <T> HashSet<T> newHashSet() {\n\t\treturn new HashSet<T>();\n\t}\n\n\t/**\n\t * 新建一个HashSet\n\t *\n\t * @return HashSet对象\n\t */\n\t@SafeVarargs\n\tpublic static <T> HashSet<T> newHashSet(T... ts) {\n\t\tHashSet<T> set = new HashSet<T>();\n\t\tfor (T t : ts) {\n\t\t\tset.add(t);\n\t\t}\n\t\treturn set;\n\t}\n\n\t/**\n\t * 新建一个ArrayList\n\t *\n\t * @return ArrayList对象\n\t */\n\tpublic static <T> ArrayList<T> newArrayList() {\n\t\treturn new ArrayList<T>();\n\t}\n\n\t/**\n\t * 新建一个ArrayList\n\t *\n\t * @return ArrayList对象\n\t */\n\t@SafeVarargs\n\tpublic static <T> ArrayList<T> newArrayList(T... values) {\n\t\treturn new ArrayList<T>(Arrays.asList(values));\n\t}\n\n\t/**\n\t * 将新元素添加到已有数组中<br/>\n\t * 添加新元素会生成一个新的数组，不影响原数组\n\t *\n\t * @param buffer 已有数组\n\t * @param newElement 新元素\n\t * @return 新数组\n\t */\n\tpublic static <T> T[] append(T[] buffer, T newElement) {\n\t\tT[] t = resize(buffer, buffer.length + 1, newElement.getClass());\n\t\tt[buffer.length] = newElement;\n\t\treturn t;\n\t}\n\n\t/**\n\t * 生成一个新的重新设置大小的数组\n\t *\n\t * @param buffer 原数组\n\t * @param newSize 新的数组大小\n\t * @param componentType 数组元素类型\n\t * @return 调整后的新数组\n\t */\n\tpublic static <T> T[] resize(T[] buffer, int newSize, Class<?> componentType) {\n\t\tT[] newArray = newArray(componentType, newSize);\n\t\tSystem.arraycopy(buffer, 0, newArray, 0, buffer.length >= newSize ? newSize : buffer.length);\n\t\treturn newArray;\n\t}\n\n\t/**\n\t * 新建一个空数组\n\t * @param componentType 元素类型\n\t * @param newSize 大小\n\t * @return 空数组\n\t */\n\t@SuppressWarnings(\"unchecked\")\n\tpublic static <T> T[] newArray(Class<?> componentType, int newSize) {\n\t\treturn (T[]) Array.newInstance(componentType, newSize);\n\t}\n\n\t/**\n\t * 生成一个新的重新设置大小的数组<br/>\n\t * 新数组的类型为原数组的类型\n\t *\n\t * @param buffer 原数组\n\t * @param newSize 新的数组大小\n\t * @return 调整后的新数组\n\t */\n\tpublic static <T> T[] resize(T[] buffer, int newSize) {\n\t\treturn resize(buffer, newSize, buffer.getClass().getComponentType());\n\t}\n\n\t/**\n\t * 将多个数组合并在一起<br>\n\t * 忽略null的数组\n\t *\n\t * @param arrays 数组集合\n\t * @return 合并后的数组\n\t */\n\t@SafeVarargs\n\tpublic static <T> T[] addAll(T[]... arrays) {\n\t\tif (arrays.length == 1) {\n\t\t\treturn arrays[0];\n\t\t}\n\n\t\tint length = 0;\n\t\tfor (T[] array : arrays) {\n\t\t\tif(array == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlength += array.length;\n\t\t}\n\t\tT[] result = newArray(arrays.getClass().getComponentType().getComponentType(), length);\n\n\t\tlength = 0;\n\t\tfor (T[] array : arrays) {\n\t\t\tif(array == null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tSystem.arraycopy(array, 0, result, length, array.length);\n\t\t\tlength += array.length;\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * 克隆数组\n\t * @param array 被克隆的数组\n\t * @return 新数组\n\t */\n\tpublic static <T> T[] clone(T[] array) {\n\t\tif (array == null) {\n\t\t\treturn null;\n\t\t}\n\t\treturn array.clone();\n\t}\n\n\t/**\n\t * 生成一个数字列表<br>\n\t * 自动判定正序反序\n\t * @param excludedEnd 结束的数字（不包含）\n\t * @return 数字列表\n\t */\n\tpublic static int[] range(int excludedEnd) {\n\t\treturn range(0, excludedEnd, 1);\n\t}\n\n\t/**\n\t * 生成一个数字列表<br>\n\t * 自动判定正序反序\n\t * @param includedStart 开始的数字（包含）\n\t * @param excludedEnd 结束的数字（不包含）\n\t * @return 数字列表\n\t */\n\tpublic static int[] range(int includedStart, int excludedEnd) {\n\t\treturn range(includedStart, excludedEnd, 1);\n\t}\n\n\t/**\n\t * 生成一个数字列表<br>\n\t * 自动判定正序反序\n\t * @param includedStart 开始的数字（包含）\n\t * @param excludedEnd 结束的数字（不包含）\n\t * @param step 步进\n\t * @return 数字列表\n\t */\n\tpublic static int[] range(int includedStart, int excludedEnd, int step) {\n\t\tif(includedStart > excludedEnd) {\n\t\t\tint tmp = includedStart;\n\t\t\tincludedStart = excludedEnd;\n\t\t\texcludedEnd = tmp;\n\t\t}\n\n\t\tif(step <=0) {\n\t\t\tstep = 1;\n\t\t}\n\n\t\tint deviation = excludedEnd - includedStart;\n\t\tint length = deviation / step;\n\t\tif(deviation % step != 0) {\n\t\t\tlength += 1;\n\t\t}\n\t\tint[] range = new int[length];\n\t\tfor(int i = 0; i < length; i++) {\n\t\t\trange[i] = includedStart;\n\t\t\tincludedStart += step;\n\t\t}\n\t\treturn range;\n\t}\n\n\t/**\n\t * 截取数组的部分\n\t * @param list 被截取的数组\n\t * @param start 开始位置（包含）\n\t * @param end 结束位置（不包含）\n\t * @return 截取后的数组，当开始位置超过最大时，返回null\n\t */\n\tpublic static <T> List<T> sub(List<T> list, int start, int end) {\n\t\tif(list == null || list.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif(start < 0) {\n\t\t\tstart = 0;\n\t\t}\n\t\tif(end < 0) {\n\t\t\tend = 0;\n\t\t}\n\n\t\tif(start > end) {\n\t\t\tint tmp = start;\n\t\t\tstart = end;\n\t\t\tend = tmp;\n\t\t}\n\n\t\tfinal int size = list.size();\n\t\tif(end > size) {\n\t\t\tif(start >= size) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tend = size;\n\t\t}\n\n\t\treturn list.subList(start, end);\n\t}\n\n\t/**\n\t * 截取集合的部分\n\t * @param list 被截取的数组\n\t * @param start 开始位置（包含）\n\t * @param end 结束位置（不包含）\n\t * @return 截取后的数组，当开始位置超过最大时，返回null\n\t */\n\tpublic static <T> List<T> sub(Collection<T> list, int start, int end) {\n\t\tif(list == null || list.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn sub(new ArrayList<T>(list), start, end);\n\t}\n\n\t/**\n\t * 数组是否为空\n\t * @param array 数组\n\t * @return 是否为空\n\t */\n\tpublic static <T> boolean isEmpty(T[] array) {\n\t\treturn array == null || array.length == 0;\n\t}\n\n\t/**\n\t * 数组是否为非空\n\t * @param array 数组\n\t * @return 是否为非空\n\t */\n\tpublic static <T> boolean isNotEmpty(T[] array) {\n\t\treturn false == isEmpty(array);\n\t}\n\n\t/**\n\t * 集合是否为空\n\t * @param collection 集合\n\t * @return 是否为空\n\t */\n\tpublic static boolean isEmpty(Collection<?> collection) {\n\t\treturn collection == null || collection.isEmpty();\n\t}\n\n\t/**\n\t * 集合是否为非空\n\t * @param collection 集合\n\t * @return 是否为非空\n\t */\n\tpublic static boolean isNotEmpty(Collection<?> collection) {\n\t\treturn false == isEmpty(collection);\n\t}\n\n\t/**\n\t * Map是否为空\n\t * @param map 集合\n\t * @return 是否为空\n\t */\n\tpublic static boolean isEmpty(Map<?, ?> map) {\n\t\treturn map == null || map.isEmpty();\n\t}\n\n\t/**\n\t * Map是否为非空\n\t * @param map 集合\n\t * @return 是否为非空\n\t */\n\tpublic static <T> boolean isNotEmpty(Map<?, ?> map) {\n\t\treturn false == isEmpty(map);\n\t}\n\n\t/**\n\t * 映射键值（参考Python的zip()函数）<br>\n\t * 例如：<br>\n\t * \t\tkeys =    [a,b,c,d]<br>\n\t *\t\tvalues = [1,2,3,4]<br>\n\t * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>\n\t * 如果两个数组长度不同，则只对应最短部分\n\t * @param keys 键列表\n\t * @param values 值列表\n\t * @return Map\n\t */\n\tpublic static <T, K> Map<T, K> zip(T[] keys, K[] values) {\n\t\tif(isEmpty(keys) || isEmpty(values)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tfinal int size = Math.min(keys.length, values.length);\n\t\tfinal Map<T, K> map = new HashMap<T, K>((int)(size / 0.75));\n\t\tfor(int i = 0; i < size; i++) {\n\t\t\tmap.put(keys[i], values[i]);\n\t\t}\n\n\t\treturn map;\n\t}\n\n\t/**\n\t * 映射键值（参考Python的zip()函数）<br>\n\t * 例如：<br>\n\t * \t\tkeys =    a,b,c,d<br>\n\t *\t\tvalues = 1,2,3,4<br>\n\t *\t\tdelimiter = ,\n\t * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>\n\t * 如果两个数组长度不同，则只对应最短部分\n\t * @param keys 键列表\n\t * @param values 值列表\n\t * @return Map\n\t */\n\tpublic static Map<String, String> zip(String keys, String values, String delimiter) {\n\t\treturn zip(StrKit.split(keys, delimiter), StrKit.split(values, delimiter));\n\t}\n\t\n\t/**\n\t * 映射键值（参考Python的zip()函数）<br>\n\t * 例如：<br>\n\t * \t\tkeys =    [a,b,c,d]<br>\n\t *\t\tvalues = [1,2,3,4]<br>\n\t * 则得到的Map是 {a=1, b=2, c=3, d=4}<br>\n\t * 如果两个数组长度不同，则只对应最短部分\n\t * @param keys 键列表\n\t * @param values 值列表\n\t * @return Map\n\t */\n\tpublic static <T, K> Map<T, K> zip(Collection<T> keys, Collection<K> values) {\n\t\tif(isEmpty(keys) || isEmpty(values)) {\n\t\t\treturn null;\n\t\t}\n\t\t\n\t\tfinal List<T> keyList = new ArrayList<T>(keys);\n\t\tfinal List<K> valueList = new ArrayList<K>(values);\n\t\t\n\t\tfinal int size = Math.min(keys.size(), values.size());\n\t\tfinal Map<T, K> map = new HashMap<T, K>((int)(size / 0.75));\n\t\tfor(int i = 0; i < size; i++) {\n\t\t\tmap.put(keyList.get(i), valueList.get(i));\n\t\t}\n\t\t\n\t\treturn map;\n\t}\n\t\n\t/**\n\t * 数组中是否包含元素\n\t * @param array 数组\n\t * @param value 被检查的元素\n\t * @return 是否包含\n\t */\n\tpublic static <T> boolean contains(T[] array, T value) {\n\t\tfinal Class<?> componetType = array.getClass().getComponentType();\n\t\tboolean isPrimitive = false;\n\t\tif(null != componetType) {\n\t\t\tisPrimitive = componetType.isPrimitive();\n\t\t}\n\t\tfor (T t : array) {\n\t\t\tif(t == value) {\n\t\t\t\treturn true;\n\t\t\t}else if(false == isPrimitive && null != value && value.equals(t)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\t\n\t/**\n\t * 将Entry集合转换为HashMap\n\t * @param entryCollection entry集合\n\t * @return Map\n\t */\n\tpublic static <T, K> HashMap<T, K> toMap(Collection<Entry<T, K>> entryCollection) {\n\t\tHashMap<T,K> map = new HashMap<T, K>();\n\t\tfor (Entry<T, K> entry : entryCollection) {\n\t\t\tmap.put(entry.getKey(), entry.getValue());\n\t\t}\n\t\treturn map;\n\t}\n\t\n\t/**\n\t * 将集合转换为排序后的TreeSet\n\t * @param collection 集合\n\t * @param comparator 比较器\n\t * @return treeSet\n\t */\n\tpublic static <T> TreeSet<T> toTreeSet(Collection<T> collection, Comparator<T> comparator){\n\t\tfinal TreeSet<T> treeSet = new TreeSet<T>(comparator);\n\t\tfor (T t : collection) {\n\t\t\ttreeSet.add(t);\n\t\t}\n\t\treturn treeSet;\n\t}\n\t\n\t/**\n\t * 排序集合\n\t * @param collection 集合\n\t * @param comparator 比较器\n\t * @return treeSet\n\t */\n\tpublic static <T> List<T> sort(Collection<T> collection, Comparator<T> comparator){\n\t\tList<T> list = new ArrayList<T>(collection);\n\t\tCollections.sort(list, comparator);\n\t\treturn list;\n\t}\n\t\n\t//------------------------------------------------------------------- 基本类型的数组转换为包装类型数组\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Integer[] wrap(int... values){\n\t\tfinal int length = values.length;\n\t\tInteger[] array = new Integer[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\t\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Long[] wrap(long... values){\n\t\tfinal int length = values.length;\n\t\tLong[] array = new Long[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\t\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Character[] wrap(char... values){\n\t\tfinal int length = values.length;\n\t\tCharacter[] array = new Character[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\t\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Byte[] wrap(byte... values){\n\t\tfinal int length = values.length;\n\t\tByte[] array = new Byte[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\t\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Short[] wrap(short... values){\n\t\tfinal int length = values.length;\n\t\tShort[] array = new Short[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\t\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Float[] wrap(float... values){\n\t\tfinal int length = values.length;\n\t\tFloat[] array = new Float[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\t\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Double[] wrap(double... values){\n\t\tfinal int length = values.length;\n\t\tDouble[] array = new Double[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\t\n\t/**\n\t * 将基本类型数组包装为包装类型\n\t * @param values 基本类型数组\n\t * @return 包装类型数组\n\t */\n\tpublic static Boolean[] wrap(boolean... values){\n\t\tfinal int length = values.length;\n\t\tBoolean[] array = new Boolean[length];\n\t\tfor(int i = 0; i < length; i++){\n\t\t\tarray[i] = values[i];\n\t\t}\n\t\treturn array;\n\t}\n\t\n\t/**\n\t * 判定给定对象是否为数组类型\n\t * @param obj 对象\n\t * @return 是否为数组类型\n\t */\n\tpublic static boolean isArray(Object obj){\n\t\treturn obj.getClass().isArray();\n\t}\n\t\n\t/**\n\t * 数组或集合转String\n\t * \n\t * @param obj 集合或数组对象\n\t * @return 数组字符串，与集合转字符串格式相同\n\t */\n\tpublic static String toString(Object obj) {\n\t\tif (null == obj) {\n\t\t\treturn null;\n\t\t}\n\t\tif (isArray(obj)) {\n\t\t\ttry {\n\t\t\t\treturn Arrays.deepToString((Object[]) obj);\n\t\t\t} catch (Exception e) {\n\t\t\t\tfinal String className = obj.getClass().getComponentType().getName();\n\t\t\t\tswitch (className) {\n\t\t\t\t\tcase \"long\":\n\t\t\t\t\t\treturn Arrays.toString((long[]) obj);\n\t\t\t\t\tcase \"int\":\n\t\t\t\t\t\treturn Arrays.toString((int[]) obj);\n\t\t\t\t\tcase \"short\":\n\t\t\t\t\t\treturn Arrays.toString((short[]) obj);\n\t\t\t\t\tcase \"char\":\n\t\t\t\t\t\treturn Arrays.toString((char[]) obj);\n\t\t\t\t\tcase \"byte\":\n\t\t\t\t\t\treturn Arrays.toString((byte[]) obj);\n\t\t\t\t\tcase \"boolean\":\n\t\t\t\t\t\treturn Arrays.toString((boolean[]) obj);\n\t\t\t\t\tcase \"float\":\n\t\t\t\t\t\treturn Arrays.toString((float[]) obj);\n\t\t\t\t\tcase \"double\":\n\t\t\t\t\t\treturn Arrays.toString((double[]) obj);\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthrow new ToolBoxException(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn obj.toString();\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/DateTime.java",
    "content": "package cn.enilu.material.admin.core.support;\n\nimport java.util.Date;\n\n/**\n * 封装java.util.Date\n * @author xiaoleilu\n *\n */\npublic class DateTime extends Date{\n\tprivate static final long serialVersionUID = -5395712593979185936L;\n\t\n\t/**\n\t * 转换JDK date为 DateTime\n\t * @param date JDK Date\n\t * @return DateTime\n\t */\n\tpublic static DateTime parse(Date date) {\n\t\treturn new DateTime(date);\n\t}\n\t\n\t/**\n\t * 当前时间\n\t */\n\tpublic DateTime() {\n\t\tsuper();\n\t}\n\t\n\t/**\n\t * 给定日期的构造\n\t * @param date 日期\n\t */\n\tpublic DateTime(Date date) {\n\t\tthis(date.getTime());\n\t}\n\t\n\t/**\n\t * 给定日期毫秒数的构造\n\t * @param timeMillis 日期毫秒数\n\t */\n\tpublic DateTime(long timeMillis) {\n\t\tsuper(timeMillis);\n\t}\n\t\n\t@Override\n\tpublic String toString() {\n\t\treturn DateTimeKit.formatDateTime(this);\n\t}\n\t\n\tpublic String toString(String format) {\n\t\treturn DateTimeKit.format(this, format);\n\t}\n\t\n\t/**\n\t * @return 输出精确到毫秒的标准日期形式\n\t */\n\tpublic String toMsStr() {\n\t\treturn DateTimeKit.format(this, DateTimeKit.NORM_DATETIME_MS_PATTERN);\n\t}\n\t\n\t/**   \n\t * @return java.util.Date\n\t*/\n\tpublic Date toDate() {\n\t\treturn new Date(this.getTime());\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/DateTimeKit.java",
    "content": "package cn.enilu.material.admin.core.support;\n\nimport cn.enilu.material.admin.core.support.exception.ToolBoxException;\nimport cn.enilu.material.utils.StrKit;\n\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.LinkedHashSet;\nimport java.util.Locale;\n\n/**\n * 时间工具类\n * @author xiaoleilu\n */\npublic class DateTimeKit {\n\t/** 毫秒 */\n\tpublic final static long MS = 1;\n\t/** 每秒钟的毫秒数 */\n\tpublic final static long SECOND_MS = MS * 1000;\n\t/** 每分钟的毫秒数 */\n\tpublic final static long MINUTE_MS = SECOND_MS * 60;\n\t/** 每小时的毫秒数 */\n\tpublic final static long HOUR_MS = MINUTE_MS * 60;\n\t/** 每天的毫秒数 */\n\tpublic final static long DAY_MS = HOUR_MS * 24;\n\n\t/** 标准日期格式 */\n\tpublic final static String NORM_DATE_PATTERN = \"yyyy-MM-dd\";\n\t/** 标准时间格式 */\n\tpublic final static String NORM_TIME_PATTERN = \"HH:mm:ss\";\n\t/** 标准日期时间格式，精确到分 */\n\tpublic final static String NORM_DATETIME_MINUTE_PATTERN = \"yyyy-MM-dd HH:mm\";\n\t/** 标准日期时间格式，精确到秒 */\n\tpublic final static String NORM_DATETIME_PATTERN = \"yyyy-MM-dd HH:mm:ss\";\n\t/** 标准日期时间格式，精确到毫秒 */\n\tpublic final static String NORM_DATETIME_MS_PATTERN = \"yyyy-MM-dd HH:mm:ss.SSS\";\n\t/** HTTP头中日期时间格式 */\n\tpublic final static String HTTP_DATETIME_PATTERN = \"EEE, dd MMM yyyy HH:mm:ss z\";\n\n\t/** 标准日期（不含时间）格式化器 */\n\t// private final static SimpleDateFormat NORM_DATE_FORMAT = new SimpleDateFormat(NORM_DATE_PATTERN);\n\tprivate static ThreadLocal<SimpleDateFormat> NORM_DATE_FORMAT = new ThreadLocal<SimpleDateFormat>(){\n\t\tsynchronized protected SimpleDateFormat initialValue() {\n\t\t\treturn new SimpleDateFormat(NORM_DATE_PATTERN);\n\t\t};\n\t};\n\t/** 标准时间格式化器 */\n\t// private final static SimpleDateFormat NORM_TIME_FORMAT = new SimpleDateFormat(NORM_TIME_PATTERN);\n\tprivate static ThreadLocal<SimpleDateFormat> NORM_TIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){\n\t\tsynchronized protected SimpleDateFormat initialValue() {\n\t\t\treturn new SimpleDateFormat(NORM_TIME_PATTERN);\n\t\t};\n\t};\n\t/** 标准日期时间格式化器 */\n\t// private final static SimpleDateFormat NORM_DATETIME_FORMAT = new SimpleDateFormat(NORM_DATETIME_PATTERN);\n\tprivate static ThreadLocal<SimpleDateFormat> NORM_DATETIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){\n\t\tsynchronized protected SimpleDateFormat initialValue() {\n\t\t\treturn new SimpleDateFormat(NORM_DATETIME_PATTERN);\n\t\t};\n\t};\n\t/** HTTP日期时间格式化器 */\n\t// private final static SimpleDateFormat HTTP_DATETIME_FORMAT = new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US);\n\tprivate static ThreadLocal<SimpleDateFormat> HTTP_DATETIME_FORMAT = new ThreadLocal<SimpleDateFormat>(){\n\t\tsynchronized protected SimpleDateFormat initialValue() {\n\t\t\treturn new SimpleDateFormat(HTTP_DATETIME_PATTERN, Locale.US);\n\t\t};\n\t};\n\n\t/**\n\t * 当前时间，格式 yyyy-MM-dd HH:mm:ss\n\t * \n\t * @return 当前时间的标准形式字符串\n\t */\n\tpublic static String now() {\n\t\treturn formatDateTime(new DateTime());\n\t}\n\n\t/**\n\t * 当前时间long\n\t *\n\t * @param isNano 是否为高精度时间\n\t * @return 时间\n\t */\n\tpublic static long current(boolean isNano) {\n\t\treturn isNano ? System.nanoTime() : System.currentTimeMillis();\n\t}\n\n\t/**\n\t * 当前日期，格式 yyyy-MM-dd\n\t *\n\t * @return 当前日期的标准形式字符串\n\t */\n\tpublic static String today() {\n\t\treturn formatDate(new DateTime());\n\t}\n\n\t/**\n\t * @return 当前月份\n\t */\n\tpublic static int thisMonth() {\n\t\treturn month(date());\n\t}\n\n\t/**\n\t * @return 今年\n\t */\n\tpublic static int thisYear() {\n\t\treturn year(date());\n\t}\n\n\t/**\n\t * @return 当前时间\n\t */\n\tpublic static DateTime date() {\n\t\treturn new DateTime();\n\t}\n\n\t/**\n\t * Long类型时间转为Date\n\t *\n\t * @param date Long类型Date（Unix时间戳）\n\t * @return 时间对象\n\t */\n\tpublic static DateTime date(long date) {\n\t\treturn new DateTime(date);\n\t}\n\n\t/**\n\t * 转换为Calendar对象\n\t *\n\t * @param date 日期对象\n\t * @return Calendar对象\n\t */\n\tpublic static Calendar toCalendar(Date date) {\n\t\tfinal Calendar cal = Calendar.getInstance();\n\t\tcal.setTime(date);\n\t\treturn cal;\n\t}\n\n\t/**\n\t * 获得月份，从1月开始计数\n\t *\n\t * @param date 日期\n\t * @return 月份\n\t */\n\tpublic static int month(Date date) {\n\t\treturn toCalendar(date).get(Calendar.MONTH) + 1;\n\t}\n\n\t/**\n\t * 获得年\n\t *\n\t * @param date 日期\n\t * @return 年\n\t */\n\tpublic static int year(Date date) {\n\t\treturn toCalendar(date).get(Calendar.YEAR);\n\t}\n\n\t/**\n\t * 获得季节\n\t *\n\t * @param date 日期\n\t * @return 第几个季节\n\t */\n\tpublic static int season(Date date) {\n\t\treturn toCalendar(date).get(Calendar.MONTH) / 3 + 1;\n\t}\n\n\t/**\n\t * 获得指定日期年份和季节<br>\n\t * 格式：[20131]表示2013年第一季度\n\t *\n\t * @param date 日期\n\t * @return Season ，类似于 20132\n\t */\n\tpublic static String yearAndSeason(Date date) {\n\t\treturn yearAndSeason(toCalendar(date));\n\t}\n\n\t/**\n\t * 获得指定日期区间内的年份和季节<br>\n\t *\n\t * @param startDate 其实日期（包含）\n\t * @param endDate 结束日期（包含）\n\t * @return Season列表 ，元素类似于 20132\n\t */\n\tpublic static LinkedHashSet<String> yearAndSeasons(Date startDate, Date endDate) {\n\t\tfinal LinkedHashSet<String> seasons = new LinkedHashSet<String>();\n\t\tif (startDate == null || endDate == null) {\n\t\t\treturn seasons;\n\t\t}\n\n\t\tfinal Calendar cal = Calendar.getInstance();\n\t\tcal.setTime(startDate);\n\t\twhile (true) {\n\t\t\t// 如果开始时间超出结束时间，让结束时间为开始时间，处理完后结束循环\n\t\t\tif (startDate.after(endDate)) {\n\t\t\t\tstartDate = endDate;\n\t\t\t}\n\n\t\t\tseasons.add(yearAndSeason(cal));\n\n\t\t\tif (startDate.equals(endDate)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcal.add(Calendar.MONTH, 3);\n\t\t\tstartDate = cal.getTime();\n\t\t}\n\n\t\treturn seasons;\n\t}\n\n\t// ------------------------------------ Format start ----------------------------------------------\n\t/**\n\t * 根据特定格式格式化日期\n\t *\n\t * @param date 被格式化的日期\n\t * @param format 格式\n\t * @return 格式化后的字符串\n\t */\n\tpublic static String format(Date date, String format) {\n\t\treturn new SimpleDateFormat(format).format(date);\n\t}\n\n\t/**\n\t * 格式 yyyy-MM-dd HH:mm:ss\n\t *\n\t * @param date 被格式化的日期\n\t * @return 格式化后的日期\n\t */\n\tpublic static String formatDateTime(Date date) {\n\t\tif(null == date){\n\t\t\treturn null;\n\t\t}\n\t\treturn NORM_DATETIME_FORMAT.get().format(date);\n\t}\n\n\t/**\n\t * 格式 yyyy-MM-dd\n\t *\n\t * @param date 被格式化的日期\n\t * @return 格式化后的字符串\n\t */\n\tpublic static String formatDate(Date date) {\n\t\tif(null == date){\n\t\t\treturn null;\n\t\t}\n\t\treturn NORM_DATE_FORMAT.get().format(date);\n\t}\n\n\t/**\n\t * 格式化为Http的标准日期格式\n\t *\n\t * @param date 被格式化的日期\n\t * @return HTTP标准形式日期字符串\n\t */\n\tpublic static String formatHttpDate(Date date) {\n\t\tif(null == date){\n\t\t\treturn null;\n\t\t}\n\t\treturn HTTP_DATETIME_FORMAT.get().format(date);\n\t}\n\t// ------------------------------------ Format end ----------------------------------------------\n\n\t// ------------------------------------ Parse start ----------------------------------------------\n\n\t/**\n\t * 构建DateTime对象\n\t *\n\t * @param dateStr Date字符串\n\t * @param simpleDateFormat 格式化器\n\t * @return DateTime对象\n\t */\n\tpublic static DateTime parse(String dateStr, SimpleDateFormat simpleDateFormat) {\n\t\ttry {\n\t\t\treturn new DateTime(simpleDateFormat.parse(dateStr));\n\t\t} catch (Exception e) {\n\t\t\tthrow new ToolBoxException(StrKit.format(\"Parse [{}] with format [{}] error!\", dateStr, simpleDateFormat.toPattern()), e);\n\t\t}\n\t}\n\n\t/**\n\t * 将特定格式的日期转换为Date对象\n\t *\n\t * @param dateString 特定格式的日期\n\t * @param format 格式，例如yyyy-MM-dd\n\t * @return 日期对象\n\t */\n\tpublic static DateTime parse(String dateString, String format) {\n\t\treturn parse(dateString, new SimpleDateFormat(format));\n\t}\n\n\t/**\n\t * 格式yyyy-MM-dd HH:mm:ss\n\t *\n\t * @param dateString 标准形式的时间字符串\n\t * @return 日期对象\n\t */\n\tpublic static DateTime parseDateTime(String dateString) {\n\t\treturn parse(dateString, NORM_DATETIME_FORMAT.get());\n\t}\n\n\t/**\n\t * 格式yyyy-MM-dd\n\t *\n\t * @param dateString 标准形式的日期字符串\n\t * @return 日期对象\n\t */\n\tpublic static DateTime parseDate(String dateString) {\n\t\treturn parse(dateString, NORM_DATE_FORMAT.get());\n\t}\n\n\t/**\n\t * 格式HH:mm:ss\n\t *\n\t * @param timeString 标准形式的日期字符串\n\t * @return 日期对象\n\t */\n\tpublic static DateTime parseTime(String timeString) {\n\t\treturn parse(timeString, NORM_TIME_FORMAT.get());\n\t}\n\n\t/**\n\t * 格式：<br>\n\t * 1、yyyy-MM-dd HH:mm:ss<br>\n\t * 2、yyyy-MM-dd<br>\n\t * 3、HH:mm:ss<br>\n\t * 4、yyyy-MM-dd HH:mm 5、yyyy-MM-dd HH:mm:ss.SSS\n\t *\n\t * @param dateStr 日期字符串\n\t * @return 日期\n\t */\n\tpublic static DateTime parse(String dateStr) {\n\t\tif (null == dateStr) {\n\t\t\treturn null;\n\t\t}\n\t\tdateStr = dateStr.trim();\n\t\tint length = dateStr.length();\n\t\ttry {\n\t\t\tif (length == NORM_DATETIME_PATTERN.length()) {\n\t\t\t\treturn parseDateTime(dateStr);\n\t\t\t} else if (length == NORM_DATE_PATTERN.length()) {\n\t\t\t\treturn parseDate(dateStr);\n\t\t\t} else if (length == NORM_TIME_PATTERN.length()) {\n\t\t\t\treturn parseTime(dateStr);\n\t\t\t} else if (length == NORM_DATETIME_MINUTE_PATTERN.length()) {\n\t\t\t\treturn parse(dateStr, NORM_DATETIME_MINUTE_PATTERN);\n\t\t\t} else if (length >= NORM_DATETIME_MS_PATTERN.length() - 2) {\n\t\t\t\treturn parse(dateStr, NORM_DATETIME_MS_PATTERN);\n\t\t\t}\n\t\t} catch (Exception e) {\n\t\t\tthrow new ToolBoxException(StrKit.format(\"Parse [{}] with format normal error!\", dateStr));\n\t\t}\n\n\t\t// 没有更多匹配的时间格式\n\t\tthrow new ToolBoxException(StrKit.format(\" [{}] format is not fit for date pattern!\", dateStr));\n\t}\n\t// ------------------------------------ Parse end ----------------------------------------------\n\n\t// ------------------------------------ Offset start ----------------------------------------------\n\t/**\n\t * 获取某天的开始时间\n\t *\n\t * @param date 日期\n\t * @return 某天的开始时间\n\t */\n\tpublic static DateTime getBeginTimeOfDay(Date date) {\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tcalendar.setTime(date);\n\t\tcalendar.set(Calendar.HOUR_OF_DAY, 0);\n\t\tcalendar.set(Calendar.MINUTE, 0);\n\t\tcalendar.set(Calendar.SECOND, 0);\n\t\tcalendar.set(Calendar.MILLISECOND, 0);\n\t\treturn new DateTime(calendar.getTime());\n\t}\n\n\t/**\n\t * 获取某天的结束时间\n\t *\n\t * @param date 日期\n\t * @return 某天的结束时间\n\t */\n\tpublic static DateTime getEndTimeOfDay(Date date) {\n\t\tCalendar calendar = Calendar.getInstance();\n\t\tcalendar.setTime(date);\n\t\tcalendar.set(Calendar.HOUR_OF_DAY, 23);\n\t\tcalendar.set(Calendar.MINUTE, 59);\n\t\tcalendar.set(Calendar.SECOND, 59);\n\t\tcalendar.set(Calendar.MILLISECOND, 999);\n\t\treturn new DateTime(calendar.getTime());\n\t}\n\n\t/**\n\t * 昨天\n\t *\n\t * @return 昨天\n\t */\n\tpublic static DateTime yesterday() {\n\t\treturn offsiteDay(new DateTime(), -1);\n\t}\n\n\t/**\n\t * 上周\n\t *\n\t * @return 上周\n\t */\n\tpublic static DateTime lastWeek() {\n\t\treturn offsiteWeek(new DateTime(), -1);\n\t}\n\n\t/**\n\t * 上个月\n\t *\n\t * @return 上个月\n\t */\n\tpublic static DateTime lastMouth() {\n\t\treturn offsiteMonth(new DateTime(), -1);\n\t}\n\n\t/**\n\t * 偏移天\n\t *\n\t * @param date 日期\n\t * @param offsite 偏移天数，正数向未来偏移，负数向历史偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static DateTime offsiteDay(Date date, int offsite) {\n\t\treturn offsiteDate(date, Calendar.DAY_OF_YEAR, offsite);\n\t}\n\n\t/**\n\t * 偏移周\n\t *\n\t * @param date 日期\n\t * @param offsite 偏移周数，正数向未来偏移，负数向历史偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static DateTime offsiteWeek(Date date, int offsite) {\n\t\treturn offsiteDate(date, Calendar.WEEK_OF_YEAR, offsite);\n\t}\n\n\t/**\n\t * 偏移月\n\t *\n\t * @param date 日期\n\t * @param offsite 偏移月数，正数向未来偏移，负数向历史偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static DateTime offsiteMonth(Date date, int offsite) {\n\t\treturn offsiteDate(date, Calendar.MONTH, offsite);\n\t}\n\n\t/**\n\t * 获取指定日期偏移指定时间后的时间\n\t *\n\t * @param date 基准日期\n\t * @param calendarField 偏移的粒度大小（小时、天、月等）使用Calendar中的常数\n\t * @param offsite 偏移量，正数为向后偏移，负数为向前偏移\n\t * @return 偏移后的日期\n\t */\n\tpublic static DateTime offsiteDate(Date date, int calendarField, int offsite) {\n\t\tCalendar cal = Calendar.getInstance();\n\t\tcal.setTime(date);\n\t\tcal.add(calendarField, offsite);\n\t\treturn new DateTime(cal.getTime());\n\t}\n\t// ------------------------------------ Offset end ----------------------------------------------\n\n\t/**\n\t * 判断两个日期相差的时长<br/>\n\t * 返回 minuend - subtrahend 的差\n\t * \n\t * @param subtrahend 减数日期\n\t * @param minuend 被减数日期\n\t * @param diffField 相差的选项：相差的天、小时\n\t * @return 日期差\n\t */\n\tpublic static long diff(Date subtrahend, Date minuend, long diffField) {\n\t\tlong diff = minuend.getTime() - subtrahend.getTime();\n\t\treturn diff / diffField;\n\t}\n\n\t/**\n\t * 计时，常用于记录某段代码的执行时间，单位：纳秒\n\t * \n\t * @param preTime 之前记录的时间\n\t * @return 时间差，纳秒\n\t */\n\tpublic static long spendNt(long preTime) {\n\t\treturn System.nanoTime() - preTime;\n\t}\n\n\t/**\n\t * 计时，常用于记录某段代码的执行时间，单位：毫秒\n\t * \n\t * @param preTime 之前记录的时间\n\t * @return 时间差，毫秒\n\t */\n\tpublic static long spendMs(long preTime) {\n\t\treturn System.currentTimeMillis() - preTime;\n\t}\n\n\t/**\n\t * 格式化成yyMMddHHmm后转换为int型\n\t * \n\t * @param date 日期\n\t * @return int\n\t */\n\tpublic static int toIntSecond(Date date) {\n\t\treturn Integer.parseInt(format(date, \"yyMMddHHmm\"));\n\t}\n\n\t/**\n\t * 计算指定指定时间区间内的周数\n\t * \n\t * @param start 开始时间\n\t * @param end 结束时间\n\t * @return 周数\n\t */\n\tpublic static int weekCount(Date start, Date end) {\n\t\tfinal Calendar startCalendar = Calendar.getInstance();\n\t\tstartCalendar.setTime(start);\n\t\tfinal Calendar endCalendar = Calendar.getInstance();\n\t\tendCalendar.setTime(end);\n\n\t\tfinal int startWeekofYear = startCalendar.get(Calendar.WEEK_OF_YEAR);\n\t\tfinal int endWeekofYear = endCalendar.get(Calendar.WEEK_OF_YEAR);\n\n\t\tint count = endWeekofYear - startWeekofYear + 1;\n\n\t\tif (Calendar.SUNDAY != startCalendar.get(Calendar.DAY_OF_WEEK)) {\n\t\t\tcount--;\n\t\t}\n\n\t\treturn count;\n\t}\n\n\t/**\n\t * 计时器<br>\n\t * 计算某个过程话费的时间，精确到毫秒\n\t * \n\t * @return Timer\n\t */\n\tpublic static Timer timer() {\n\t\treturn new Timer();\n\n\t}\n\t\n\t/**\n\t * 生日转为年龄，计算法定年龄\n\t * @param birthDay 生日，标准日期字符串\n\t * @return 年龄\n\t * @throws Exception\n\t */\n\tpublic static int ageOfNow(String birthDay) {\n\t\treturn ageOfNow(parse(birthDay));\n\t}\n\n\t/**\n\t * 生日转为年龄，计算法定年龄\n\t * @param birthDay 生日\n\t * @return 年龄\n\t * @throws Exception\n\t */\n\tpublic static int ageOfNow(Date birthDay) {\n\t\treturn age(birthDay,date());\n\t}\n\t\n\t/**\n\t * 计算相对于dateToCompare的年龄，长用于计算指定生日在某年的年龄\n\t * @param birthDay 生日\n\t * @param dateToCompare 需要对比的日期\n\t * @return 年龄\n\t * @throws Exception\n\t */\n\tpublic static int age(Date birthDay, Date dateToCompare) {\n\t\tCalendar cal = Calendar.getInstance();\n\t\tcal.setTime(dateToCompare);\n\n\t\tif (cal.before(birthDay)) {\n\t\t\tthrow new IllegalArgumentException(StrKit.format(\"Birthday is after date {}!\", formatDate(dateToCompare)));\n\t\t}\n\n\t\tint year = cal.get(Calendar.YEAR);\n\t\tint month = cal.get(Calendar.MONTH);\n\t\tint dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);\n\n\t\tcal.setTime(birthDay);\n\t\tint age = year - cal.get(Calendar.YEAR);\n\t\t\n\t\tint monthBirth = cal.get(Calendar.MONTH);\n\t\tif (month == monthBirth) {\n\t\t\tint dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);\n\t\t\tif (dayOfMonth < dayOfMonthBirth) {\n\t\t\t\t//如果生日在当月，但是未达到生日当天的日期，年龄减一\n\t\t\t\tage--;\n\t\t\t}\n\t\t} else if (month < monthBirth){\n\t\t\t//如果当前月份未达到生日的月份，年龄计算减一\n\t\t\tage--;\n\t\t}\n\n\t\treturn age;\n\t}\n\n\t/**\n\t * 计时器<br>\n\t * 计算某个过程话费的时间，精确到毫秒\n\t * \n\t * @author Looly\n\t *\n\t */\n\tpublic static class Timer {\n\t\tprivate long time;\n\t\tprivate boolean isNano;\n\n\t\tpublic Timer() {\n\t\t\tthis(false);\n\t\t}\n\n\t\tpublic Timer(boolean isNano) {\n\t\t\tthis.isNano = isNano;\n\t\t\tstart();\n\t\t}\n\n\t\t/**\n\t\t * @return 开始计时并返回当前时间\n\t\t */\n\t\tpublic long start() {\n\t\t\ttime = current(isNano);\n\t\t\treturn time;\n\t\t}\n\n\t\t/**\n\t\t * @return 重新计时并返回从开始到当前的持续时间\n\t\t */\n\t\tpublic long durationRestart() {\n\t\t\tlong now = current(isNano);\n\t\t\tlong d = now - time;\n\t\t\ttime = now;\n\t\t\treturn d;\n\t\t}\n\n\t\t/**\n\t\t * @return 从开始到当前的持续时间\n\t\t */\n\t\tpublic long duration() {\n\t\t\treturn current(isNano) - time;\n\t\t}\n\t}\n\n\t// ------------------------------------------------------------------------ Private method start\n\t/**\n\t * 获得指定日期年份和季节<br>\n\t * 格式：[20131]表示2013年第一季度\n\t * \n\t * @param cal 日期\n\t */\n\tprivate static String yearAndSeason(Calendar cal) {\n\t\treturn new StringBuilder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString();\n\t}\n\t// ------------------------------------------------------------------------ Private method end\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/HexKit.java",
    "content": "package cn.enilu.material.admin.core.support;\n\nimport cn.enilu.material.utils.StrKit;\n\nimport java.nio.charset.Charset;\n\n/**\n * 十六进制（简写为hex或下标16）在数学中是一种逢16进1的进位制，一般用数字0到9和字母A到F表示（其中:A~F即10~15）。<br>\n * 例如十进制数57，在二进制写作111001，在16进制写作39。<br>\n * 像java,c这样的语言为了区分十六进制和十进制数值,会在十六进制数的前面加上 0x,比如0x20是十进制的32,而不是十进制的20<br>\n * \n * 参考：https://my.oschina.net/xinxingegeya/blog/287476\n * \n * @author Looly\n *\n */\npublic class HexKit {\n\n\t/**\n\t * 用于建立十六进制字符的输出的小写字符数组\n\t */\n\tprivate static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n\t/**\n\t * 用于建立十六进制字符的输出的大写字符数组\n\t */\n\tprivate static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n\n\t//---------------------------------------------------------------------------------------------------- encode\n\t/**\n\t * 将字节数组转换为十六进制字符数组\n\t *\n\t * @param data byte[]\n\t * @return 十六进制char[]\n\t */\n\tpublic static char[] encodeHex(byte[] data) {\n\t\treturn encodeHex(data, true);\n\t}\n\t\n\t/**\n\t * 将字节数组转换为十六进制字符数组\n\t *\n\t * @param str 字符串\n\t * @param charset 编码\n\t * @return 十六进制char[]\n\t */\n\tpublic static char[] encodeHex(String str, Charset charset) {\n\t\treturn encodeHex(StrKit.getBytes(str, charset), true);\n\t}\n\n\t/**\n\t * 将字节数组转换为十六进制字符数组\n\t *\n\t * @param data byte[]\n\t * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式\n\t * @return 十六进制char[]\n\t */\n\tpublic static char[] encodeHex(byte[] data, boolean toLowerCase) {\n\t\treturn encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);\n\t}\n\n\t/**\n\t * 将字节数组转换为十六进制字符串\n\t *\n\t * @param data byte[]\n\t * @return 十六进制String\n\t */\n\tpublic static String encodeHexStr(byte[] data) {\n\t\treturn encodeHexStr(data, true);\n\t}\n\n\t/**\n\t * 将字节数组转换为十六进制字符串\n\t *\n\t * @param data byte[]\n\t * @param toLowerCase <code>true</code> 传换成小写格式 ， <code>false</code> 传换成大写格式\n\t * @return 十六进制String\n\t */\n\tpublic static String encodeHexStr(byte[] data, boolean toLowerCase) {\n\t\treturn encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);\n\t}\n\t\n\t//---------------------------------------------------------------------------------------------------- decode\n\t/**\n\t * 将十六进制字符数组转换为字符串\n\t *\n\t * @param hexStr 十六进制String\n\t * @param charset 编码\n\t * @return 字符串\n\t */\n\tpublic static String decodeHexStr(String hexStr, Charset charset) {\n\t\tif(StrKit.isEmpty(hexStr)){\n\t\t\treturn hexStr;\n\t\t}\n\t\treturn decodeHexStr(hexStr.toCharArray(), charset);\n\t}\n\t\n\t/**\n\t * 将十六进制字符数组转换为字符串\n\t *\n\t * @param hexData 十六进制char[]\n\t * @param charset 编码\n\t * @return 字符串\n\t */\n\tpublic static String decodeHexStr(char[] hexData, Charset charset) {\n\t\treturn StrKit.str(decodeHex(hexData), charset);\n\t}\n\n\t/**\n\t * 将十六进制字符数组转换为字节数组\n\t *\n\t * @param hexData 十六进制char[]\n\t * @return byte[]\n\t * @throws RuntimeException 如果源十六进制字符数组是一个奇怪的长度，将抛出运行时异常\n\t */\n\tpublic static byte[] decodeHex(char[] hexData) {\n\n\t\tint len = hexData.length;\n\n\t\tif ((len & 0x01) != 0) {\n\t\t\tthrow new RuntimeException(\"Odd number of characters.\");\n\t\t}\n\n\t\tbyte[] out = new byte[len >> 1];\n\n\t\t// two characters form the hex value.\n\t\tfor (int i = 0, j = 0; j < len; i++) {\n\t\t\tint f = toDigit(hexData[j], j) << 4;\n\t\t\tj++;\n\t\t\tf = f | toDigit(hexData[j], j);\n\t\t\tj++;\n\t\t\tout[i] = (byte) (f & 0xFF);\n\t\t}\n\n\t\treturn out;\n\t}\n\t\n\t//---------------------------------------------------------------------------------------- Private method start\n\t/**\n\t * 将字节数组转换为十六进制字符串\n\t *\n\t * @param data byte[]\n\t * @param toDigits 用于控制输出的char[]\n\t * @return 十六进制String\n\t */\n\tprivate static String encodeHexStr(byte[] data, char[] toDigits) {\n\t\treturn new String(encodeHex(data, toDigits));\n\t}\n\t\n\t/**\n\t * 将字节数组转换为十六进制字符数组\n\t *\n\t * @param data byte[]\n\t * @param toDigits 用于控制输出的char[]\n\t * @return 十六进制char[]\n\t */\n\tprivate static char[] encodeHex(byte[] data, char[] toDigits) {\n\t\tint l = data.length;\n\t\tchar[] out = new char[l << 1];\n\t\t// two characters form the hex value.\n\t\tfor (int i = 0, j = 0; i < l; i++) {\n\t\t\tout[j++] = toDigits[(0xF0 & data[i]) >>> 4];\n\t\t\tout[j++] = toDigits[0x0F & data[i]];\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * 将十六进制字符转换成一个整数\n\t *\n\t * @param ch 十六进制char\n\t * @param index 十六进制字符在字符数组中的位置\n\t * @return 一个整数\n\t * @throws RuntimeException 当ch不是一个合法的十六进制字符时，抛出运行时异常\n\t */\n\tprivate static int toDigit(char ch, int index) {\n\t\tint digit = Character.digit(ch, 16);\n\t\tif (digit == -1) {\n\t\t\tthrow new RuntimeException(\"Illegal hexadecimal character \" + ch + \" at index \" + index);\n\t\t}\n\t\treturn digit;\n\t}\n\t//---------------------------------------------------------------------------------------- Private method end\n\t\n\t\n\t\n\t/**\n\t * 2进制转16进制\n\t * @param bString 2进制字符串\n\t * @return\n\t */\n\tpublic static String binary2Hex(String bString) {\n\t\tif (bString == null || bString.equals(\"\") || bString.length() % 8 != 0)\n\t\t\treturn null;\n\t\tStringBuffer tmp = new StringBuffer();\n\t\tint iTmp = 0;\n\t\tfor (int i = 0; i < bString.length(); i += 4) {\n\t\t\tiTmp = 0;\n\t\t\tfor (int j = 0; j < 4; j++) {\n\t\t\t\tiTmp += Integer.parseInt(bString.substring(i + j, i + j + 1)) << (4 - j - 1);\n\t\t\t}\n\t\t\ttmp.append(Integer.toHexString(iTmp));\n\t\t}\n\t\treturn tmp.toString();\n\t}\n\n\t/**\n\t * 16进制转2进制\n\t * @param hexString\n\t * @return\n\t */\n\tpublic static String hex2Binary(String hexString) {\n\t\tif (hexString == null || hexString.length() % 2 != 0)\n\t\t\treturn null;\n\t\tString bString = \"\", tmp;\n\t\tfor (int i = 0; i < hexString.length(); i++) {\n\t\t\ttmp = \"0000\" + Integer.toBinaryString(Integer.parseInt(hexString.substring(i, i + 1), 16));\n\t\t\tbString += tmp.substring(tmp.length() - 4);\n\t\t}\n\t\treturn bString;\n\t}\n\n\t/**\n\t * 将二进制转换成16进制\n\t * @param buf\n\t * @return\n\t */\n\tpublic static String binary2Hex(byte buf[]) {\n\t\tStringBuffer sb = new StringBuffer();\n\t\tfor (int i = 0; i < buf.length; i++) {\n\t\t\tString hex = Integer.toHexString(buf[i] & 0xFF);\n\t\t\tif (hex.length() == 1) {\n\t\t\t\thex = '0' + hex;\n\t\t\t}\n\t\t\tsb.append(hex.toUpperCase());\n\t\t}\n\t\treturn sb.toString();\n\t}\n\n\t/**\n\t * 将16进制转换为二进制\n\t * @param hexStr\n\t * @return\n\t */\n\tpublic static byte[] hex2Byte(String hexStr) {\n\t\tif (hexStr.length() < 1)\n\t\t\treturn null;\n\t\tbyte[] result = new byte[hexStr.length() / 2];\n\t\tfor (int i = 0; i < hexStr.length() / 2; i++) {\n\t\t\tint high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);\n\t\t\tint low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);\n\t\t\tresult[i] = (byte) (high * 16 + low);\n\t\t}\n\t\treturn result;\n\t}\n\t\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/ObjectKit.java",
    "content": "package cn.enilu.material.admin.core.support;\n\n/**\n * 一些通用的函数\n * \n * @author Looly\n *\n */\npublic class ObjectKit {\n\t/**\n\t * 比较两个对象是否相等。<br>\n\t * 相同的条件有两个，满足其一即可：<br>\n\t * 1. obj1 == null && obj2 == null; 2. obj1.equals(obj2)\n\t * \n\t * @param obj1 对象1\n\t * @param obj2 对象2\n\t * @return 是否相等\n\t */\n\tpublic static boolean equals(Object obj1, Object obj2) {\n\t\treturn (obj1 != null) ? (obj1.equals(obj2)) : (obj2 == null);\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/PageKit.java",
    "content": "package cn.enilu.material.admin.core.support;\n\n/**\n * 分页工具类\n * \n * @author xiaoleilu\n * \n */\npublic class PageKit {\n\n\t/**\n\t * 将页数和每页条目数转换为开始位置和结束位置<br>\n\t * 此方法用于不包括结束位置的分页方法<br>\n\t * 例如：<br>\n\t * 页码：1，每页10 -> [0, 10]<br>\n\t * 页码：2，每页10 -> [10, 20]<br>\n\t * 。。。<br>\n\t * \n\t * @param pageNo\n\t *            页码（从1计数）\n\t * @param countPerPage\n\t *            每页条目数\n\t * @return 第一个数为开始位置，第二个数为结束位置\n\t */\n\tpublic static int[] transToStartEnd(int pageNo, int countPerPage) {\n\t\tif (pageNo < 1) {\n\t\t\tpageNo = 1;\n\t\t}\n\n\t\tif (countPerPage < 1) {\n\t\t\tcountPerPage = 0;\n//\t\t\tLogKit.warn(\"Count per page  [\" + countPerPage + \"] is not valid!\");\n\t\t}\n\n\t\tint start = (pageNo - 1) * countPerPage;\n\t\tint end = start + countPerPage;\n\n\t\treturn new int[] { start, end };\n\t}\n\n\t/**\n\t * 根据总数计算总页数\n\t * \n\t * @param totalCount\n\t *            总数\n\t * @param numPerPage\n\t *            每页数\n\t * @return 总页数\n\t */\n\tpublic static int totalPage(int totalCount, int numPerPage) {\n\t\tif (numPerPage == 0) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn totalCount % numPerPage == 0 ? (totalCount / numPerPage)\n\t\t\t\t: (totalCount / numPerPage + 1);\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/support/exception/ToolBoxException.java",
    "content": "/**\n * Copyright (c) 2015-2017, Chill Zhuang 庄骞 (smallchill@163.com).\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npackage cn.enilu.material.admin.core.support.exception;\n\n\nimport cn.enilu.material.utils.StrKit;\n\n/**\n * 工具类初始化异常\n */\npublic class ToolBoxException extends RuntimeException{\n\tprivate static final long serialVersionUID = 8247610319171014183L;\n\n\tpublic ToolBoxException(Throwable e) {\n\t\tsuper(e.getMessage(), e);\n\t}\n\t\n\tpublic ToolBoxException(String message) {\n\t\tsuper(message);\n\t}\n\t\n\tpublic ToolBoxException(String messageTemplate, Object... params) {\n\t\tsuper(StrKit.format(messageTemplate, params));\n\t}\n\t\n\tpublic ToolBoxException(String message, Throwable throwable) {\n\t\tsuper(message, throwable);\n\t}\n\t\n\tpublic ToolBoxException(Throwable throwable, String messageTemplate, Object... params) {\n\t\tsuper(StrKit.format(messageTemplate, params), throwable);\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/ApiMenuFilter.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport cn.enilu.material.admin.config.properties.AppProperties;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.vo.SpringContextHolder;\nimport cn.enilu.material.bean.vo.node.MenuNode;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * api接口文档显示过滤\n *\n * @author fengshuonan\n * @date 2017-08-17 16:55\n */\npublic class ApiMenuFilter extends MenuNode {\n\n\n    public static List<MenuNode> build(List<MenuNode> nodes) {\n\n        //如果关闭了接口文档,则不显示接口文档菜单\n        AppProperties appProperties = SpringContextHolder.getBean(AppProperties.class);\n        if (!appProperties.getSwaggerOpen()) {\n            List<MenuNode> menuNodesCopy = new ArrayList<>();\n            for (MenuNode menuNode : nodes) {\n                if (Const.API_MENU_NAME.equals(menuNode.getName())) {\n                    continue;\n                } else {\n                    menuNodesCopy.add(menuNode);\n                }\n            }\n            nodes = menuNodesCopy;\n        }\n\n        return nodes;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/FileUtil.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.exception.ExceptionEnum;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\n\npublic class FileUtil {\n\n    private static Logger log = LoggerFactory.getLogger(FileUtil.class);\n\n    /**\n     * NIO way\n     */\n    public static byte[] toByteArray(String filename) {\n\n        File f = new File(filename);\n        if (!f.exists()) {\n            log.error(\"文件未找到！\" + filename);\n            throw new ApplicationException(ExceptionEnum.FILE_NOT_FOUND);\n        }\n        FileChannel channel = null;\n        FileInputStream fs = null;\n        try {\n            fs = new FileInputStream(f);\n            channel = fs.getChannel();\n            ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());\n            while ((channel.read(byteBuffer)) > 0) {\n                // do nothing\n                // System.out.println(\"reading\");\n            }\n            return byteBuffer.array();\n        } catch (IOException e) {\n            throw new ApplicationException(ExceptionEnum.FILE_READING_ERROR);\n        } finally {\n            try {\n                channel.close();\n            } catch (IOException e) {\n                throw new ApplicationException(ExceptionEnum.FILE_READING_ERROR);\n            }\n            try {\n                fs.close();\n            } catch (IOException e) {\n                throw new ApplicationException(ExceptionEnum.FILE_READING_ERROR);\n            }\n        }\n    }\n\n    /**\n     * 删除目录\n     *\n     * @author fengshuonan\n     * @Date 2017/10/30 下午4:15\n     */\n    public static boolean deleteDir(File dir) {\n        if (dir.isDirectory()) {\n            String[] children = dir.list();\n            for (int i = 0; i < children.length; i++) {\n                boolean success = deleteDir(new File(dir, children[i]));\n                if (!success) {\n                    return false;\n                }\n            }\n        }\n        return dir.delete();\n    }\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/HttpSessionHolder.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport javax.servlet.http.HttpSession;\n\n/**\n * 非Controller中获取当前session的工具类\n *\n * @author fengshuonan\n * @date 2016年11月28日 上午10:24:31\n */\npublic class HttpSessionHolder {\n\n    private static ThreadLocal<HttpSession> tl = new ThreadLocal<HttpSession>();\n\n    public static void put(HttpSession s) {\n        tl.set(s);\n    }\n\n    public static HttpSession get() {\n        return tl.get();\n    }\n\n    public static void remove() {\n        tl.remove();\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/KaptchaUtil.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport cn.enilu.material.admin.config.properties.AppProperties;\nimport cn.enilu.material.bean.vo.SpringContextHolder;\n\n/**\n * 验证码工具类\n */\npublic class KaptchaUtil {\n\n    /**\n     * 获取验证码开关\n     *\n     * @author enilu.cn\n     * @Date 2017/5/23 22:34\n     */\n    public static Boolean getKaptchaOnOff() {\n        return SpringContextHolder.getBean(AppProperties.class).getKaptchaOpen();\n    }\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/NumUtil.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.text.DecimalFormat;\nimport java.text.NumberFormat;\n\n/**\n * 数字格式化的类\n *\n * @author fengshuonan\n * @date 2016年11月30日 下午5:58:40\n */\npublic class NumUtil {\n\n    /**\n     * @Description 保留指定位数的小数(少的位数不补零)\n     * @author fengshuonan\n     */\n    public static String keepRandomPoint(Double value, int n) {\n        if (value == null) {\n            value = 0.00;\n            return new BigDecimal(value).setScale(n, RoundingMode.HALF_UP).toString();\n        } else {\n            return new BigDecimal(value).setScale(n, RoundingMode.HALF_UP).toString();\n        }\n    }\n\n    /**\n     * @Description 浮点保留两位小数(少的位数不补零)\n     * @author fengshuonan\n     */\n    public static String keep2Point(double value) {\n        return keepRandomPoint(value, 2);\n    }\n\n    /**\n     * @Description 浮点保留1位小数(少的位数不补零)\n     * @author fengshuonan\n     */\n    public static String keep1Point(double value) {\n        return keepRandomPoint(value, 1);\n    }\n\n    /**\n     * @Description 浮点保留任意位小数(少位补零)\n     * @author fengshuonan\n     */\n    public static String keepRandomPointZero(double value, int n) {\n        DecimalFormat df = new DecimalFormat(\"#0.00\");\n        return df.format(Double.valueOf(keepRandomPoint(value, n)));\n    }\n\n    /**\n     * @Description 浮点保留两位小数(少位补零)\n     * @author fengshuonan\n     */\n    public static String keep2PointZero(double value) {\n        return keepRandomPointZero(value, 2);\n    }\n\n    /**\n     * @Description 获取任意小数点位的百分比表示\n     * @author fengshuonan\n     */\n    public static String percentRandomPoint(double value, int n) {\n        NumberFormat percent = NumberFormat.getPercentInstance();\n        percent.setGroupingUsed(false);\n        percent.setMaximumFractionDigits(n);\n        return percent.format(value);\n    }\n\n    /**\n     * @Description 百分比保留两位小数\n     * @author fengshuonan\n     */\n    public static String percent2Point(double value) {\n        return percentRandomPoint(value, 2);\n    }\n\n    /**\n     * @Description 获取格式化经纬度后的小数(保留3位)\n     * @author fengshuonan\n     */\n    public static String latLngPoint(double value) {\n        return keepRandomPoint(value, 3);\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/PingYinUtil.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport java.util.Random;\n\n/***\n * \n * 得到中文首字母\n * \n * @author lxm_09\n * \n */\n\npublic class PingYinUtil {\n\n\tpublic static void main(String[] args) {\n\t\tString str = \"这是一个测试\";\n\t\tSystem.out.println(\"中文首字母：\" + getPYIndexStr(str, true));\n\t}\n\n\t/**\n\t * 返回首字母\n\t */\n\tpublic static String getPYIndexStr(String strChinese, boolean bUpCase) {\n\t\ttry {\n\t\t\tStringBuffer buffer = new StringBuffer();\n\t\t\tbyte b[] = strChinese.getBytes(\"GBK\");// 把中文转化成byte数组\n\t\t\tfor (int i = 0; i < b.length; i++) {\n\t\t\t\tif ((b[i] & 255) > 128) {\n\t\t\t\t\tint char1 = b[i++] & 255;\n\t\t\t\t\tchar1 <<= 8;// 左移运算符用“<<”表示，是将运算符左边的对象，向左移动运算符右边指定的位数，并且在低位补零。其实，向左移n位，就相当于乘上2的n次方\n\t\t\t\t\tint chart = char1 + (b[i] & 255);\n\t\t\t\t\tbuffer.append(getPYIndexChar((char) chart, bUpCase));\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tchar c = (char) b[i];\n\t\t\t\tif (!Character.isJavaIdentifierPart(c))// 确定指定字符是否可以是 Java\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// 标识符中首字符以外的部分。\n\t\t\t\t\tc = 'A';\n\t\t\t\tbuffer.append(c);\n\t\t\t}\n\t\t\treturn buffer.toString();\n\t\t} catch (Exception e) {\n\t\t\tSystem.out.println((new StringBuilder()).append(\"\\u53D6\\u4E2D\\u6587\\u62FC\\u97F3\\u6709\\u9519\")\n\t\t\t\t\t.append(e.getMessage()).toString());\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * 得到首字母\n\t */\n\tprivate static char getPYIndexChar(char strChinese, boolean bUpCase) {\n\n\t\tint charGBK = strChinese;\n\n\t\tchar result;\n\n\t\tif (charGBK >= 45217 && charGBK <= 45252)\n\n\t\t\tresult = 'A';\n\n\t\telse\n\n\t\tif (charGBK >= 45253 && charGBK <= 45760)\n\n\t\t\tresult = 'B';\n\n\t\telse\n\n\t\tif (charGBK >= 45761 && charGBK <= 46317)\n\n\t\t\tresult = 'C';\n\n\t\telse\n\n\t\tif (charGBK >= 46318 && charGBK <= 46825)\n\n\t\t\tresult = 'D';\n\n\t\telse\n\n\t\tif (charGBK >= 46826 && charGBK <= 47009)\n\n\t\t\tresult = 'E';\n\n\t\telse\n\n\t\tif (charGBK >= 47010 && charGBK <= 47296)\n\n\t\t\tresult = 'F';\n\n\t\telse\n\n\t\tif (charGBK >= 47297 && charGBK <= 47613)\n\n\t\t\tresult = 'G';\n\n\t\telse\n\n\t\tif (charGBK >= 47614 && charGBK <= 48118)\n\n\t\t\tresult = 'H';\n\n\t\telse\n\n\t\tif (charGBK >= 48119 && charGBK <= 49061)\n\n\t\t\tresult = 'J';\n\n\t\telse\n\n\t\tif (charGBK >= 49062 && charGBK <= 49323)\n\n\t\t\tresult = 'K';\n\n\t\telse\n\n\t\tif (charGBK >= 49324 && charGBK <= 49895)\n\n\t\t\tresult = 'L';\n\n\t\telse\n\n\t\tif (charGBK >= 49896 && charGBK <= 50370)\n\n\t\t\tresult = 'M';\n\n\t\telse\n\n\t\tif (charGBK >= 50371 && charGBK <= 50613)\n\n\t\t\tresult = 'N';\n\n\t\telse\n\n\t\tif (charGBK >= 50614 && charGBK <= 50621)\n\n\t\t\tresult = 'O';\n\n\t\telse\n\n\t\tif (charGBK >= 50622 && charGBK <= 50905)\n\n\t\t\tresult = 'P';\n\n\t\telse\n\n\t\tif (charGBK >= 50906 && charGBK <= 51386)\n\n\t\t\tresult = 'Q';\n\n\t\telse\n\n\t\tif (charGBK >= 51387 && charGBK <= 51445)\n\n\t\t\tresult = 'R';\n\n\t\telse\n\n\t\tif (charGBK >= 51446 && charGBK <= 52217)\n\n\t\t\tresult = 'S';\n\n\t\telse\n\n\t\tif (charGBK >= 52218 && charGBK <= 52697)\n\n\t\t\tresult = 'T';\n\n\t\telse\n\n\t\tif (charGBK >= 52698 && charGBK <= 52979)\n\n\t\t\tresult = 'W';\n\n\t\telse\n\n\t\tif (charGBK >= 52980 && charGBK <= 53688)\n\n\t\t\tresult = 'X';\n\n\t\telse\n\n\t\tif (charGBK >= 53689 && charGBK <= 54480)\n\n\t\t\tresult = 'Y';\n\n\t\telse\n\n\t\tif (charGBK >= 54481 && charGBK <= 55289)\n\n\t\t\tresult = 'Z';\n\n\t\telse\n\n\t\t\tresult = (char) (65 + (new Random()).nextInt(25));\n\n\t\tif (!bUpCase)\n\n\t\t\tresult = Character.toLowerCase(result);\n\n\t\treturn result;\n\n\t}\n\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/RenderUtil.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport com.alibaba.fastjson.JSON;\nimport cn.enilu.material.bean.exception.ExceptionEnum;\n\nimport javax.servlet.http.HttpServletResponse;\nimport java.io.IOException;\nimport java.io.PrintWriter;\n\n/**\n * 渲染工具类\n *\n * @author enilu.cn\n * @date 2017-08-25 14:13\n */\npublic class RenderUtil {\n\n    /**\n     * 渲染json对象\n     */\n    public static void renderJson(HttpServletResponse response, Object jsonObject) {\n        try {\n            response.setContentType(\"application/json\");\n            response.setCharacterEncoding(\"UTF-8\");\n            PrintWriter writer = response.getWriter();\n            writer.write(JSON.toJSONString(jsonObject));\n        } catch (IOException e) {\n            throw new ApplicationException(ExceptionEnum.WRITE_ERROR);\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/ResKit.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.core.io.support.ResourcePatternResolver;\n\nimport java.io.IOException;\n\n/**\n * 资源文件相关的操作类\n *\n * @author fengshuonan\n * @date 2016年11月17日 下午10:09:23\n */\npublic class ResKit {\n\n    /**\n     * @Description 批量获取ClassPath下的资源文件\n     * @author fengshuonan\n     */\n    public static Resource[] getClassPathResources(String pattern) {\n        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();\n        try {\n            return resolver.getResources(pattern);\n        } catch (IOException e) {\n            throw new RuntimeException(\"加载resource文件时,找不到文件,所找文件为：\" + pattern);\n        }\n    }\n\n    /**\n     * @Description 批量获取ClassPath下的资源文件\n     * @author fengshuonan\n     */\n    public static String getClassPathFile(String file) {\n\t\t//return ResKit.class.getClassLoader().getResource(file).getPath();\n        return Thread.currentThread().getContextClassLoader().getResource(file).getPath();\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/util/SqlUtil.java",
    "content": "package cn.enilu.material.admin.core.util;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * sql语句工具类\n *\n * @author fengshuonan\n * @date 2016年12月6日 下午1:01:54\n */\npublic class SqlUtil {\n\n    /**\n     * @Description 根据集合的大小，输出相应个数\"?\"\n     * @author fengshuonan\n     */\n    public static String parse(List<?> list) {\n        String str = \"\";\n        if (list != null && list.size() > 0) {\n            str = str + \"?\";\n            for (int i = 1; i < list.size(); i++) {\n                str = str + \",?\";\n            }\n        }\n        return str;\n    }\n\n    public static void main(String[] args) {\n        ArrayList<Object> arrayList = new ArrayList<>();\n        arrayList.add(2);\n        arrayList.add(2);\n        System.out.println(parse(arrayList));\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/xss/XssFilter.java",
    "content": "package cn.enilu.material.admin.core.xss;\n\n\nimport javax.servlet.*;\nimport javax.servlet.http.HttpServletRequest;\nimport java.io.IOException;\nimport java.util.List;\n\n\npublic class XssFilter implements Filter {\n\n    FilterConfig filterConfig = null;\n\n    private List<String> urlExclusion = null;\n\n    public void init(FilterConfig filterConfig) throws ServletException {\n        this.filterConfig = filterConfig;\n    }\n\n    public void destroy() {\n        this.filterConfig = null;\n    }\n\n    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {\n        HttpServletRequest httpServletRequest = (HttpServletRequest) request;\n        String servletPath = httpServletRequest.getServletPath();\n\n        if (urlExclusion != null && urlExclusion.contains(servletPath)) {\n            chain.doFilter(request, response);\n        } else {\n            chain.doFilter(new XssHttpServletRequestWrapper((HttpServletRequest) request), response);\n        }\n    }\n\n    public List<String> getUrlExclusion() {\n        return urlExclusion;\n    }\n\n    public void setUrlExclusion(List<String> urlExclusion) {\n        this.urlExclusion = urlExclusion;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/core/xss/XssHttpServletRequestWrapper.java",
    "content": "package cn.enilu.material.admin.core.xss;\n\n\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletRequestWrapper;\n\n\npublic class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {\n\n    public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {\n\n        super(servletRequest);\n\n    }\n\n    public String[] getParameterValues(String parameter) {\n\n        String[] values = super.getParameterValues(parameter);\n\n        if (values == null) {\n\n            return null;\n\n        }\n\n        int count = values.length;\n\n        String[] encodedValues = new String[count];\n\n        for (int i = 0; i < count; i++) {\n\n            encodedValues[i] = cleanXSS(values[i]);\n\n        }\n\n        return encodedValues;\n\n    }\n\n    public String getParameter(String parameter) {\n\n        String value = super.getParameter(parameter);\n\n        if (value == null) {\n\n            return null;\n\n        }\n\n        return cleanXSS(value);\n\n    }\n\n    public String getHeader(String name) {\n\n        String value = super.getHeader(name);\n\n        if (value == null)\n\n            return null;\n\n        return cleanXSS(value);\n\n    }\n\n    private String cleanXSS(String value) {\n\n        //You'll need to remove the spaces from the html entities below\n\n        value = value.replaceAll(\"<\", \"& lt;\").replaceAll(\">\", \"& gt;\");\n\n        value = value.replaceAll(\"\\\\(\", \"& #40;\").replaceAll(\"\\\\)\", \"& #41;\");\n\n        value = value.replaceAll(\"'\", \"& #39;\");\n\n        value = value.replaceAll(\"eval\\\\((.*)\\\\)\", \"\");\n\n        value = value.replaceAll(\"[\\\\\\\"\\\\\\'][\\\\s]*javascript:(.*)[\\\\\\\"\\\\\\']\", \"\\\"\\\"\");\n\n        value = value.replaceAll(\"script\", \"\");\n\n        return value;\n\n    }\n\n\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/lab/controller/LabController.java",
    "content": "package cn.enilu.material.admin.modular.lab.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\n\n/**\n * @author ：enilu\n * @date ：Created in 2019/9/3 16:53\n */\n@RequestMapping(\"/lab\")\n@Controller\npublic class LabController extends BaseController {\n    @RequestMapping(value=\"/actuator\",method = RequestMethod.GET)\n    public String index(){\n        return \"/lab/actuator.html\";\n    }\n    @RequestMapping(value=\"/gis\",method = RequestMethod.GET)\n    public String gis(){\n        return \"/lab/gis.html\";\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/lab/package-info.java",
    "content": "/**\n * @author ：enilu\n * @date ：Created in 2019/9/3 16:54\n */\npackage cn.enilu.material.admin.modular.lab;"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/message/MessageController.java",
    "content": "package cn.enilu.material.admin.modular.message;\n\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.constant.factory.PageFactory;\nimport cn.enilu.material.bean.entity.message.Message;\nimport cn.enilu.material.bean.vo.front.Rets;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.service.message.MessageService;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\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.ResponseBody;\n\n@Controller\n@RequestMapping(\"/message/history\")\npublic class MessageController extends BaseController {\n\n    private static String PREFIX = \"/message/history/\";\n    @Autowired\n    private MessageService messageService;\n\n    /**\n     * 跳转到参数首页\n     */\n    @RequestMapping(value = \"\",method = RequestMethod.GET)\n    public String index() {\n        return PREFIX + \"message.html\";\n    }\n\n    /**\n     * 跳转到消息详情\n     */\n    @RequestMapping(value = \"/view/{id}\",method = RequestMethod.GET)\n    public String view(@PathVariable Long id, Model model) {\n        Message message = messageService.get(id);\n        model.addAttribute(\"item\",message);\n        return PREFIX + \"message_view.html\";\n    }\n\n    @RequestMapping(value = \"/list\", method = RequestMethod.POST)\n    @ResponseBody\n    public Object list() {\n        Page<Message> page = new PageFactory<Message>().defaultPage();\n        page = messageService.queryPage(page);\n        page.setRecords(page.getRecords());\n        return super.packForBT(page);\n    }\n\n\n    @RequestMapping(value=\"/clear\",method = RequestMethod.POST)\n    @BussinessLog(value = \"清空所有历史消息\")\n    @ResponseBody\n    public Object clear() {\n        messageService.clear();\n        return Rets.success();\n    }\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/message/MessagesenderController.java",
    "content": "package cn.enilu.material.admin.modular.message;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.constant.factory.PageFactory;\nimport cn.enilu.material.bean.dictmap.CommonDict;\nimport cn.enilu.material.bean.entity.message.MessageSender;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.service.message.MessagesenderService;\nimport cn.enilu.material.utils.ToolUtil;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.validation.Valid;\n\n@Controller\n@RequestMapping(\"/message/sender\")\npublic class MessagesenderController extends BaseController {\n\n    private static String PREFIX = \"/message/sender/\";\n    @Autowired\n    private MessagesenderService messagesenderService;\n\n    /**\n     * 跳转到首页\n     */\n    @RequestMapping(value = \"\", method = RequestMethod.GET)\n    public String index() {\n        return PREFIX + \"sender.html\";\n    }\n\n    /**\n     * 跳转到添加参数\n     */\n    @RequestMapping(\"/add\")\n    public String add() {\n        return PREFIX + \"sender_add.html\";\n    }\n\n    /**\n     * 跳转到修改参数\n     */\n    @RequestMapping(\"/update/{id}\")\n    public String update(@PathVariable Long id, Model model) {\n        MessageSender sender = messagesenderService.get(id);\n        model.addAttribute(\"item\", sender);\n        return PREFIX + \"sender_edit.html\";\n    }\n\n    @RequestMapping(value = \"/list\", method = RequestMethod.POST)\n    @ResponseBody\n    public Object list() {\n        Page<MessageSender> page = new PageFactory<MessageSender>().defaultPage();\n        page = messagesenderService.queryPage(page);\n        page.setRecords(page.getRecords());\n        return packForBT(page);\n    }\n\n\n    @RequestMapping(method = RequestMethod.POST)\n    @BussinessLog(value = \"保存消息发送器\", key = \"name\", dict = CommonDict.class)\n    @ResponseBody\n    public Object save(@ModelAttribute @Valid MessageSender tMessageSender) {\n        messagesenderService.save(tMessageSender);\n        return SUCCESS_TIP;\n    }\n\n    @RequestMapping(method = RequestMethod.DELETE)\n    @BussinessLog(value = \"删除消息发送器\", key = \"id\", dict = CommonDict.class)\n    @ResponseBody\n    public Object remove(Long id) throws ApplicationException {\n        if (ToolUtil.isEmpty(id)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        messagesenderService.delete(id);\n        return SUCCESS_TIP;\n\n\n    }\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/message/MessagetemplateController.java",
    "content": "package cn.enilu.material.admin.modular.message;\n\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.constant.factory.PageFactory;\nimport cn.enilu.material.bean.dictmap.CommonDict;\nimport cn.enilu.material.bean.entity.message.MessageSender;\nimport cn.enilu.material.bean.entity.message.MessageTemplate;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.service.message.MessagesenderService;\nimport cn.enilu.material.service.message.MessagetemplateService;\nimport cn.enilu.material.utils.ToolUtil;\nimport org.nutz.json.Json;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.validation.Valid;\nimport java.util.List;\n\n@Controller\n@RequestMapping(\"/message/template\")\npublic class MessagetemplateController extends BaseController {\n\n    private static String PREFIX = \"/message/template/\";\n    @Autowired\n    private MessagetemplateService messagetemplateService;\n    @Autowired\n    private MessagesenderService messagesenderService;\n    /**\n     * 跳转到首页\n     */\n    @RequestMapping(value = \"\",method = RequestMethod.GET)\n    public String index() {\n        return PREFIX + \"template.html\";\n    }\n\n    /**\n     * 跳转到添加模板\n     */\n    @RequestMapping(\"/add\")\n    public String add(Model model) {\n        List<MessageSender> messageSenderList = messagesenderService.queryAll();\n        model.addAttribute(\"messageSenderList\",messageSenderList);\n        return PREFIX + \"template_add.html\";\n    }\n\n    /**\n     * 跳转到修改模板\n     */\n    @RequestMapping(\"/update/{id}\")\n    public String update(@PathVariable Long id, Model model) {\n        MessageTemplate template = messagetemplateService.get(id);\n        model.addAttribute(\"item\",template);\n        List<MessageSender> messageSenderList = messagesenderService.queryAll();\n        model.addAttribute(\"messageSenderList\",messageSenderList);\n        return PREFIX + \"template_edit.html\";\n    }\n    @RequestMapping(value = \"/list\", method = RequestMethod.POST)\n    @ResponseBody\n    public Object list() {\n        Page<MessageTemplate> page = new PageFactory<MessageTemplate>().defaultPage();\n        page = messagetemplateService.queryPage(page);\n        page.setRecords(page.getRecords());\n        System.out.println(Json.toJson(page));\n        return packForBT(page);\n    }\n\n    @RequestMapping(method = RequestMethod.POST)\n    @BussinessLog(value = \"编辑消息模板\", key = \"name\", dict = CommonDict.class)\n    @ResponseBody\n    public Object save(@ModelAttribute @Valid MessageTemplate messageTemplate) {\n        if(messageTemplate.getId()==null) {\n            messagetemplateService.insert(messageTemplate);\n        }else{\n            messagetemplateService.update(messageTemplate);\n        }\n        return SUCCESS_TIP;\n    }\n\n    @RequestMapping(method = RequestMethod.DELETE)\n    @BussinessLog(value = \"删除消息模板\", key = \"id\", dict = CommonDict.class)\n    @ResponseBody\n    public Object remove(Long id) {\n        if (ToolUtil.isEmpty(id)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        messagetemplateService.delete(id);\n        return SUCCESS_TIP;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/BlackboardController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.dao.system.SysNoticeRepository;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport java.util.List;\n\n/**\n * 总览信息\n *\n * @author fengshuonan\n * @Date 2017年3月4日23:05:54\n */\n@Controller\n@RequestMapping(\"/blackboard\")\npublic class BlackboardController extends BaseController {\n\n    @Autowired\n    SysNoticeRepository sysNoticeRepository;\n\n    /**\n     * 跳转到黑板\n     */\n    @RequestMapping(\"\")\n    public String blackboard(Model model) {\n        List notices = (List) sysNoticeRepository.findAll();\n        model.addAttribute(\"noticeList\",notices);\n        return \"/blackboard.html\";\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/CfgController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.constant.factory.PageFactory;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.dictmap.CfgDict;\nimport cn.enilu.material.bean.entity.system.Cfg;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.service.system.CfgService;\nimport cn.enilu.material.utils.StringUtils;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.*;\n\nimport javax.validation.Valid;\n\n/**\n * CfgController\n *\n * @author enilu\n * @version 2018/8/9 0009\n */\n\n@Controller\n@RequestMapping(\"/cfg\")\npublic class CfgController extends BaseController {\n    @Autowired\n    private CfgService cfgService;\n    private static String PREFIX = \"/system/cfg/\";\n    /**\n     * 跳转到参数首页\n     */\n    @RequestMapping(value = \"\",method = RequestMethod.GET)\n    public String index() {\n        return PREFIX + \"cfg.html\";\n    }\n    /**\n     * 分页查询系统参数\n     */\n    @RequestMapping(value = \"/list\",method = RequestMethod.POST)\n    @ResponseBody\n    public Object list(@RequestParam(required = false) String cfgName, @RequestParam(required = false) String cfgValue) {\n        Page<Cfg> page = new PageFactory<Cfg>().defaultPage();\n        if(StringUtils.isNotEmpty(cfgName)){\n            page.addFilter(SearchFilter.build(\"cfgName\", SearchFilter.Operator.LIKE, cfgName));\n        }\n        if(StringUtils.isNotEmpty(cfgValue)){\n            page.addFilter(SearchFilter.build(\"cfgValue\", SearchFilter.Operator.LIKE, cfgValue));\n        }\n        page = cfgService.queryPage(page);\n        return packForBT(page);\n    }\n    /**\n     * 跳转到添加参数页面\n     */\n    @RequestMapping(value = \"/cfg_add\",method = RequestMethod.GET)\n    public String add() {\n        return PREFIX + \"cfg_add.html\";\n    }\n\n    /**\n     * 新增参数\n     */\n    @RequestMapping(value = \"/add\",method = RequestMethod.POST)\n    @ResponseBody\n    @BussinessLog(value = \"添加参数\", key = \"cfgName\",dict = CfgDict.class)\n    public Object add(@Valid Cfg cfg) {\n        cfgService.saveOrUpdate(cfg);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 跳转到修改参数\n     */\n    @RequestMapping(value = \"/cfg_update/{cfgId}\",method = RequestMethod.GET)\n    public String update(@PathVariable Long cfgId, Model model) {\n        Cfg cfg = cfgService.get(cfgId);\n        model.addAttribute(\"item\",cfg);\n        return PREFIX + \"cfg_edit.html\";\n    }\n\n    /**\n     * 修改参数\n     */\n    @RequestMapping(value = \"/update\",method = RequestMethod.POST)\n    @ResponseBody\n    @BussinessLog(value = \"编辑参数\", key = \"cfgName\",dict = CfgDict.class)\n    @Permission(Const.ADMIN_NAME)\n    public Object update(@Valid  Cfg cfg) {\n        cfgService.saveOrUpdate(cfg);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 删除参数\n     */\n    @RequestMapping(value = \"/delete\",method = RequestMethod.DELETE)\n    @ResponseBody\n    @BussinessLog(value = \"删除参数\", key = \"cfgId\",dict = CfgDict.class)\n    @Permission(Const.ADMIN_NAME)\n    public Object delete(@RequestParam Long cfgId) {\n        cfgService.delete(cfgId);\n        return SUCCESS_TIP;\n    }\n\n\n}"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/DeptController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.dictmap.DeptDict;\nimport cn.enilu.material.bean.entity.system.Dept;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.vo.node.ZTreeNode;\nimport cn.enilu.material.service.system.DeptService;\nimport cn.enilu.material.service.system.LogObjectHolder;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.utils.ToolUtil;\nimport cn.enilu.material.warpper.DeptWarpper;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\n/**\n * 部门控制器\n *\n * @author fengshuonan\n * @Date 2017年2月17日20:27:22\n */\n@Controller\n@RequestMapping(\"/dept\")\npublic class DeptController extends BaseController {\n\n    private String PREFIX = \"/system/dept/\";\n\n    @Autowired\n    DeptService deptService;\n\n\n    /**\n     * 跳转到部门管理首页\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"dept.html\";\n    }\n\n    /**\n     * 跳转到添加部门\n     */\n    @RequestMapping(\"/dept_add\")\n    public String deptAdd() {\n        return PREFIX + \"dept_add.html\";\n    }\n\n    /**\n     * 跳转到修改部门\n     */\n    @Permission\n    @RequestMapping(\"/dept_update/{deptId}\")\n    public String deptUpdate(@PathVariable Long deptId, Model model) {\n        Dept dept = deptService.get(deptId);\n        model.addAttribute(dept);\n        model.addAttribute(\"pName\", ConstantFactory.me().getDeptName(dept.getPid()));\n        LogObjectHolder.me().set(dept);\n        return PREFIX + \"dept_edit.html\";\n    }\n\n    /**\n     * 获取部门的tree列表\n     */\n    @RequestMapping(value = \"/tree\")\n    @ResponseBody\n    public List<ZTreeNode> tree() {\n        List<ZTreeNode> tree = this.deptService.tree();\n        tree.add(ZTreeNode.createParent());\n        return tree;\n    }\n\n    /**\n     * 新增部门\n     */\n    @BussinessLog(value = \"添加部门\", key = \"simplename\", dict = DeptDict.class)\n    @RequestMapping(value = \"/add\")\n    @Permission\n    @ResponseBody\n    public Object add(Dept dept) {\n        if (ToolUtil.isOneEmpty(dept, dept.getSimplename())) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        //完善pids,根据pid拿到pid的pids\n        deptService.deptSetPids(dept);\n        return deptService.insert(dept);\n    }\n\n    /**\n     * 获取所有部门列表\n     */\n    @RequestMapping(value = \"/list\")\n    @Permission\n    @ResponseBody\n    public Object list(String condition) {\n        List<Dept> list = this.deptService.query(condition);\n        return super.warpObject(new DeptWarpper(BeanUtil.objectsToMaps(list)));\n    }\n\n    /**\n     * 部门详情\n     */\n    @RequestMapping(value = \"/detail/{deptId}\")\n    @Permission\n    @ResponseBody\n    public Object detail(@PathVariable(\"deptId\") Long deptId) {\n        return deptService.get(deptId);\n    }\n\n    /**\n     * 修改部门\n     */\n    @BussinessLog(value = \"修改部门\", key = \"simplename\", dict = DeptDict.class)\n    @RequestMapping(value = \"/update\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object update(Dept dept) {\n        if (ToolUtil.isEmpty(dept) || dept.getId() == null) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        deptService.deptSetPids(dept);\n        deptService.update(dept);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 删除部门\n     */\n    @BussinessLog(value = \"删除部门\", key = \"deptId\", dict = DeptDict.class)\n    @RequestMapping(value = \"/delete\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object delete(@RequestParam Long deptId) {\n        //缓存被删除的部门名称\n        LogObjectHolder.me().set(ConstantFactory.me().getDeptName(deptId));\n        deptService.deleteDept(deptId);\n        return SUCCESS_TIP;\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/DictController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.dictmap.DictMap;\nimport cn.enilu.material.bean.entity.system.Dict;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.service.system.DictService;\nimport cn.enilu.material.service.system.LogObjectHolder;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.utils.ToolUtil;\nimport cn.enilu.material.warpper.DictWarpper;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\n\n/**\n * 字典控制器\n *\n * @author fengshuonan\n * @Date 2017年4月26日 12:55:31\n */\n@Controller\n@RequestMapping(\"/dict\")\npublic class DictController extends BaseController {\n\n    private String PREFIX = \"/system/dict/\";\n\n    @Autowired\n    DictService dictService;\n\n    /**\n     * 跳转到字典管理首页\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"dict.html\";\n    }\n\n    /**\n     * 跳转到添加字典\n     */\n    @RequestMapping(\"/dict_add\")\n    public String deptAdd() {\n        return PREFIX + \"dict_add.html\";\n    }\n\n    /**\n     * 跳转到修改字典\n     */\n    @Permission(Const.ADMIN_NAME)\n    @RequestMapping(\"/dict_edit/{dictId}\")\n    public String deptUpdate(@PathVariable Long dictId, Model model) {\n        Dict dict = dictService.get(dictId);\n        model.addAttribute(\"dict\", dict);\n        List<Dict> subDicts = dictService.queryByPid(dictId);\n        model.addAttribute(\"subDicts\", subDicts);\n        LogObjectHolder.me().set(dict);\n        return PREFIX + \"dict_edit.html\";\n    }\n\n    /**\n     * 新增字典\n     *\n     * @param dictValues 格式例如   \"1:启用;2:禁用;3:冻结\"\n     */\n    @BussinessLog(value = \"添加字典记录\", key = \"dictName,dictValues\", dict = DictMap.class)\n    @RequestMapping(value = \"/add\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object add(String dictName, String dictValues) {\n        if (ToolUtil.isOneEmpty(dictName, dictValues)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        this.dictService.addDict(dictName, dictValues);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 获取所有字典列表\n     */\n    @RequestMapping(value = \"/list\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object list(String condition) {\n        List<Dict> list = dictService.queryByPid(0L);\n        return super.warpObject(new DictWarpper(BeanUtil.objectsToMaps(list)));\n    }\n\n    /**\n     * 字典详情\n     */\n    @RequestMapping(value = \"/detail/{dictId}\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object detail(@PathVariable(\"dictId\") Long dictId) {\n        return dictService.get(dictId);\n    }\n\n    /**\n     * 修改字典\n     */\n    @BussinessLog(value = \"修改字典\", key = \"dictName,dictValues\", dict = DictMap.class)\n    @RequestMapping(value = \"/update\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object update(Long dictId, String dictName, String dictValues) {\n        if (ToolUtil.isOneEmpty(dictId, dictName, dictValues)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        dictService.editDict(dictId, dictName, dictValues);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 删除字典记录\n     */\n    @BussinessLog(value = \"删除字典记录\", key = \"dictId\", dict = DictMap.class)\n    @RequestMapping(value = \"/delete\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object delete(@RequestParam Long dictId) {\n\n        //缓存被删除的名称\n        LogObjectHolder.me().set(ConstantFactory.me().getDictName(dictId));\n\n        this.dictService.delteDict(dictId);\n        return SUCCESS_TIP;\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/KaptchaController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.config.properties.AppProperties;\nimport cn.enilu.material.admin.core.util.FileUtil;\nimport com.google.code.kaptcha.Constants;\nimport com.google.code.kaptcha.Producer;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\n\nimport javax.annotation.Resource;\nimport javax.imageio.ImageIO;\nimport javax.servlet.ServletOutputStream;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\nimport java.awt.image.BufferedImage;\nimport java.io.IOException;\n\n/**\n * 验证码生成\n *\n * @author fengshuonan\n * @date 2017-05-05 23:10\n */\n@Controller\n@RequestMapping(\"/kaptcha\")\npublic class KaptchaController {\n\n    @Resource\n    private AppProperties appProperties;\n\n    @Autowired\n    Producer producer;\n\n    /**\n     * 生成验证码\n     */\n    @RequestMapping(\"\")\n    public void index(HttpServletRequest request, HttpServletResponse response) {\n        HttpSession session = request.getSession();\n\n        response.setDateHeader(\"Expires\", 0);\n\n        // Set standard HTTP/1.1 no-cache headers.\n        response.setHeader(\"Cache-Control\", \"no-store, no-cache, must-revalidate\");\n\n        // Set IE extended HTTP/1.1 no-cache headers (use addHeader).\n        response.addHeader(\"Cache-Control\", \"post-check=0, pre-check=0\");\n\n        // Set standard HTTP/1.0 no-cache header.\n        response.setHeader(\"Pragma\", \"no-cache\");\n\n        // return a jpeg\n        response.setContentType(\"image/jpeg\");\n\n        // create the text for the image\n        String capText = producer.createText();\n\n        // store the text in the session\n        session.setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);\n\n        // create the image with the text\n        BufferedImage bi = producer.createImage(capText);\n        ServletOutputStream out = null;\n        try {\n            out = response.getOutputStream();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        // write the data out\n        try {\n            ImageIO.write(bi, \"jpg\", out);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            try {\n                out.flush();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        } finally {\n            try {\n                out.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    /**\n     * 返回图片\n     *\n     * @author enilu.cn\n     * @Date 2017/5/24 23:00\n     */\n    @RequestMapping(\"/{pictureId}\")\n    public void renderPicture(@PathVariable(\"pictureId\") String pictureId, HttpServletResponse response) {\n        String path = appProperties.getFileUploadPath() + pictureId;\n        try {\n            byte[] bytes = FileUtil.toByteArray(path);\n            response.getOutputStream().write(bytes);\n        }catch (Exception e){\n            //如果找不到图片就返回一个默认图片\n            try {\n                response.sendRedirect(\"/static/img/avatar.png\");\n            } catch (IOException e1) {\n                e1.printStackTrace();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/LogController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.admin.core.support.BeanKit;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.constant.factory.PageFactory;\nimport cn.enilu.material.bean.constant.state.BizLogType;\nimport cn.enilu.material.bean.entity.system.OperationLog;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.service.system.OperationLogService;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.utils.DateUtil;\nimport cn.enilu.material.warpper.LogWarpper;\nimport org.springframework.beans.factory.annotation.Autowired;\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.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 日志管理的控制器\n *\n * @author fengshuonan\n * @Date 2017年4月5日 19:45:36\n */\n@Controller\n@RequestMapping(\"/log\")\npublic class LogController extends BaseController {\n\n    private static String PREFIX = \"/system/log/\";\n\n    @Autowired\n    private OperationLogService operationLogService;\n\n\n    /**\n     * 跳转到日志管理的首页\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"log.html\";\n    }\n\n    /**\n     * 查询操作日志列表\n     */\n    @RequestMapping(\"/list\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object list(@RequestParam(required = false) String beginTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String logName, @RequestParam(required = false) Integer logType) {\n        Page<OperationLog> page = new PageFactory<OperationLog>().defaultPage();\n        page.addFilter(\"createTime\", SearchFilter.Operator.GTE, DateUtil.parseDate(beginTime));\n        page.addFilter(\"createTime\", SearchFilter.Operator.LTE, DateUtil.parseDate(endTime));\n        page.addFilter( \"logname\", SearchFilter.Operator.LIKE, logName);\n        if(logType!=0) {\n            page.addFilter(SearchFilter.build(\"logtype\", SearchFilter.Operator.EQ, BizLogType.valueOf(logType)));\n        }\n        page = operationLogService.queryPage(page);\n        page.setRecords((List<OperationLog>) new LogWarpper(BeanUtil.objectsToMaps(page.getRecords())).warp());\n        return super.packForBT(page);\n    }\n\n    /**\n     * 查询操作日志详情\n     */\n    @RequestMapping(\"/detail/{id}\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object detail(@PathVariable Long id) {\n        OperationLog operationLog = operationLogService.get(id);\n        Map<String, Object> stringObjectMap = BeanKit.beanToMap(operationLog);\n        return super.warpObject(new LogWarpper(stringObjectMap));\n    }\n\n    /**\n     * 清空日志\n     */\n    @BussinessLog(value = \"清空业务日志\")\n    @RequestMapping(\"/delLog\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object delLog() {\n        operationLogService.clear();\n        return SUCCESS_TIP;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/LoginController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.admin.core.util.KaptchaUtil;\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.bean.exception.InvalidKaptchaException;\nimport cn.enilu.material.platform.log.LogManager;\nimport cn.enilu.material.platform.log.LogTaskFactory;\nimport cn.enilu.material.service.system.MenuService;\nimport cn.enilu.material.service.system.UserService;\nimport cn.enilu.material.shiro.ShiroKit;\nimport cn.enilu.material.utils.HttpKit;\nimport cn.enilu.material.utils.ToolUtil;\nimport com.google.code.kaptcha.Constants;\nimport org.apache.shiro.authc.UsernamePasswordToken;\nimport org.apache.shiro.subject.Subject;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestMethod;\n\nimport java.util.List;\n\n/**\n * 登录控制器\n *\n * @author fengshuonan\n * @Date 2017年1月10日 下午8:25:24\n */\n@Controller\npublic class LoginController extends BaseController {\n    Logger logger = LoggerFactory.getLogger(LoginController.class);\n    @Autowired\n    MenuService menuService;\n    @Autowired\n    UserService userService;\n\n\n    /**\n     * 跳转到主页\n     */\n    @RequestMapping(value = \"/\", method = RequestMethod.GET)\n    public String index(Model model) {\n        List<Long> roleList = ShiroKit.getUser().getRoleList();\n        if (roleList == null || roleList.size() == 0) {\n            ShiroKit.getSubject().logout();\n            model.addAttribute(\"tips\", \"该用户没有角色，无法登陆\");\n            return \"/login.html\";\n        }\n        return \"/index.html\";\n    }\n\n    /**\n     * 跳转到登录页面\n     */\n    @RequestMapping(value = \"/login\", method = RequestMethod.GET)\n    public String login() {\n        if (ShiroKit.isAuthenticated() || ShiroKit.getUser() != null) {\n            return REDIRECT + \"/\";\n        } else {\n            return \"/login.html\";\n        }\n    }\n\n    /**\n     * 点击登录执行的动作\n     */\n    @RequestMapping(value = \"/login\", method = RequestMethod.POST)\n    public String loginVali() {\n        String username = super.getPara(\"username\").trim();\n        String password = super.getPara(\"password\").trim();\n        String remember = super.getPara(\"remember\");\n\n        //验证验证码是否正确\n        if (KaptchaUtil.getKaptchaOnOff()) {\n            String kaptcha = super.getPara(\"kaptcha\").trim();\n            String code = (String) super.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);\n            if (ToolUtil.isEmpty(kaptcha) || !kaptcha.equalsIgnoreCase(code)) {\n                throw new InvalidKaptchaException();\n            }\n        }\n\n        Subject currentUser = ShiroKit.getSubject();\n        UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray());\n\n        if (\"on\".equals(remember)) {\n            token.setRememberMe(true);\n        } else {\n            token.setRememberMe(false);\n        }\n\n        currentUser.login(token);\n\n        ShiroUser shiroUser = ShiroKit.getUser();\n        super.getSession().setAttribute(\"shiroUser\", shiroUser);\n        super.getSession().setAttribute(\"username\", shiroUser.getAccount());\n\n        LogManager.me().executeLog(LogTaskFactory.loginLog(shiroUser.getId(), HttpKit.getIp()));\n\n        ShiroKit.getSession().setAttribute(\"sessionFlag\", true);\n\n        return REDIRECT + \"/\";\n    }\n\n    /**\n     * 退出登录\n     */\n    @RequestMapping(value = \"/logout\", method = RequestMethod.GET)\n    public String logOut() {\n        LogManager.me().executeLog(LogTaskFactory.exitLog(ShiroKit.getUser().getId(), HttpKit.getIp()));\n        ShiroKit.getSubject().logout();\n        return REDIRECT + \"/login\";\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/LoginLogController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.constant.factory.PageFactory;\nimport cn.enilu.material.bean.entity.system.LoginLog;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.service.system.LoginLogService;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.utils.DateUtil;\nimport cn.enilu.material.warpper.LogWarpper;\nimport org.springframework.beans.factory.annotation.Autowired;\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 java.util.List;\n\n/**\n * 日志管理的控制器\n *\n * @author fengshuonan\n * @Date 2017年4月5日 19:45:36\n */\n@Controller\n@RequestMapping(\"/loginLog\")\npublic class LoginLogController extends BaseController {\n\n    private static String PREFIX = \"/system/log/\";\n\n    @Autowired\n    private LoginLogService loginlogService;\n\n    /**\n     * 跳转到日志管理的首页\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"login_log.html\";\n    }\n\n    /**\n     * 查询登录日志列表\n     */\n    @RequestMapping(\"/list\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object list(@RequestParam(required = false) String beginTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String logName) {\n        Page<LoginLog> page = new PageFactory<LoginLog>().defaultPage();\n        page.addFilter(\"createTime\", SearchFilter.Operator.GTE, DateUtil.parseDate(beginTime));\n        page.addFilter(\"createTime\", SearchFilter.Operator.LTE, DateUtil.parseDate(endTime));\n        page.addFilter( \"logname\", SearchFilter.Operator.LIKE, logName);\n\n        page = loginlogService.queryPage(page);\n        page.setRecords((List<LoginLog>) new LogWarpper(BeanUtil.objectsToMaps(page.getRecords())).warp());\n        return super.packForBT(page);\n\n    }\n\n    /**\n     * 清空日志\n     */\n    @BussinessLog(\"清空登录日志\")\n    @RequestMapping(\"/delLoginLog\")\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Object delLog() {\n        loginlogService.clear();\n        return SUCCESS_TIP;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/MenuController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.admin.core.base.tips.Tip;\nimport cn.enilu.material.admin.core.support.BeanKit;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.constant.state.MenuStatus;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.dictmap.MenuDict;\nimport cn.enilu.material.bean.entity.system.Menu;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.exception.ExceptionEnum;\nimport cn.enilu.material.bean.vo.node.ZTreeNode;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.service.system.LogObjectHolder;\nimport cn.enilu.material.service.system.MenuService;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.utils.Lists;\nimport cn.enilu.material.utils.ToolUtil;\nimport cn.enilu.material.warpper.MenuWarpper;\nimport com.google.common.base.Strings;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport javax.validation.Valid;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * 菜单控制器\n *\n * @author fengshuonan\n * @Date 2017年2月12日21:59:14\n */\n@Controller\n@RequestMapping(\"/menu\")\npublic class MenuController extends BaseController {\n\n    private static String PREFIX = \"/system/menu/\";\n\n\n    @Autowired\n    MenuService menuService;\n\n    /**\n     * 跳转到菜单列表列表页面\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"menu.html\";\n    }\n\n    /**\n     * 跳转到菜单列表列表页面\n     */\n    @RequestMapping(value = \"/menu_add\")\n    public String menuAdd() {\n        return PREFIX + \"menu_add.html\";\n    }\n\n    /**\n     * 跳转到菜单详情列表页面\n     */\n    @Permission(Const.ADMIN_NAME)\n    @RequestMapping(value = \"/menu_edit/{menuId}\")\n    public String menuEdit(@PathVariable Long menuId, Model model) {\n        if (ToolUtil.isEmpty(menuId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        Menu menu = menuService.get(menuId);\n\n        //获取父级菜单的id\n        Menu pMenu = menuService.findByCode(menu.getPcode());\n\n        //如果父级是顶级菜单\n        if (pMenu == null) {\n            menu.setPcode(\"0\");\n        }\n        Map<String, Object> menuMap = BeanKit.beanToMap(menu);\n        menuMap.put(\"pcodeName\", ConstantFactory.me().getMenuNameByCode(menu.getPcode()));\n        model.addAttribute(\"menu\", menuMap);\n        LogObjectHolder.me().set(menu);\n        return PREFIX + \"menu_edit.html\";\n    }\n\n    /**\n     * 修该菜单\n     */\n    @Permission(Const.ADMIN_NAME)\n    @RequestMapping(value = \"/edit\")\n    @BussinessLog(value = \"修改菜单\", key = \"name\", dict = MenuDict.class)\n    @ResponseBody\n    public Tip edit(@Valid Menu menu, BindingResult result) {\n        //设置父级菜单编号\n        menuService.menuSetPcode(menu);\n        menu.setStatus(MenuStatus.ENABLE.getCode());\n        this.menuService.update(menu);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 获取菜单列表\n     */\n    @Permission\n    @RequestMapping(value = \"/list\")\n    @ResponseBody\n    public Object list(@RequestParam(required = false) String menuName, @RequestParam(required = false) String level) {\n        List<Menu> menus = null;\n        if (Strings.isNullOrEmpty(menuName) && Strings.isNullOrEmpty(level)) {\n            menus =   menuService.queryAll();\n        }\n        if (!Strings.isNullOrEmpty(menuName) && !Strings.isNullOrEmpty(level)) {\n            menus = menuService.queryAll(Lists.newArrayList(\n                    SearchFilter.build(\"name\", SearchFilter.Operator.LIKE,menuName),\n                    SearchFilter.build(\"levels\",level)\n            ));\n        }\n        if (!Strings.isNullOrEmpty(menuName) && Strings.isNullOrEmpty(level)) {\n            menus = menuService.findByNameLike( menuName );\n        }\n        if (Strings.isNullOrEmpty(menuName) && !Strings.isNullOrEmpty(level)) {\n            menus = menuService.findByLevels(Integer.valueOf(level));\n        }\n\n        return super.warpObject(new MenuWarpper(BeanUtil.objectsToMaps(menus)));\n    }\n\n    /**\n     * 新增菜单\n     */\n    @Permission(Const.ADMIN_NAME)\n    @RequestMapping(value = \"/add\")\n    @BussinessLog(value = \"菜单新增\", key = \"name\", dict = MenuDict.class)\n    @ResponseBody\n    public Tip add(@Valid Menu menu, BindingResult result) {\n        if (result.hasErrors()) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n\n        //判断是否存在该编号\n        String existedMenuName = ConstantFactory.me().getMenuNameByCode(menu.getCode());\n        if (ToolUtil.isNotEmpty(existedMenuName)) {\n            throw new ApplicationException(BizExceptionEnum.EXISTED_THE_MENU);\n        }\n\n        //设置父级菜单编号\n        menuService.menuSetPcode(menu);\n        menu.setStatus(MenuStatus.ENABLE.getCode());\n        this.menuService.insert(menu);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 删除菜单\n     */\n    @Permission(Const.ADMIN_NAME)\n    @RequestMapping(value = \"/remove\")\n    @BussinessLog(value = \"删除菜单\", key = \"menuId\", dict = MenuDict.class)\n    @ResponseBody\n    public Tip remove(@RequestParam Long menuId) {\n        if (ToolUtil.isEmpty(menuId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n\n        //缓存菜单的名称\n        LogObjectHolder.me().set(ConstantFactory.me().getMenuName(menuId));\n\n        this.menuService.delMenuContainSubMenus(menuId);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 查看菜单\n     */\n    @RequestMapping(value = \"/view/{menuId}\")\n    @ResponseBody\n    public Tip view(@PathVariable Long menuId) {\n        if (ToolUtil.isEmpty(menuId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        menuService.get(menuId);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 获取菜单列表(首页用)\n     */\n    @RequestMapping(value = \"/menuTreeList\")\n    @ResponseBody\n    public List<ZTreeNode> menuTreeList() {\n        List<ZTreeNode> roleTreeList = this.menuService.menuTreeList();\n        return roleTreeList;\n    }\n\n    /**\n     * 获取菜单列表(选择父级菜单用)\n     */\n    @RequestMapping(value = \"/selectMenuTreeList\")\n    @ResponseBody\n    public List<ZTreeNode> selectMenuTreeList() {\n        List<ZTreeNode> roleTreeList = this.menuService.menuTreeList();\n        roleTreeList.add(ZTreeNode.createParent());\n        return roleTreeList;\n\n    }\n\n    /**\n     * 获取角色列表\n     */\n    @RequestMapping(value = \"/menuTreeListByRoleId/{roleId}\")\n    @ResponseBody\n    public List<ZTreeNode> menuTreeListByRoleId(@PathVariable Integer roleId) {\n        List<Long> menuIds = this.menuService.getMenuIdsByRoleId(roleId);\n        if (ToolUtil.isEmpty(menuIds)) {\n            List<ZTreeNode> roleTreeList = this.menuService.menuTreeList();\n            return roleTreeList;\n        } else {\n            List<ZTreeNode> roleTreeListByUserId = this.menuService.menuTreeListByMenuIds(menuIds);\n            return roleTreeListByUserId;\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/NoticeController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.dictmap.NoticeMap;\nimport cn.enilu.material.bean.entity.system.Notice;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.service.system.LogObjectHolder;\nimport cn.enilu.material.service.system.NoticeService;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.utils.ToolUtil;\nimport cn.enilu.material.warpper.NoticeWrapper;\nimport com.google.common.base.Strings;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport javax.annotation.Resource;\nimport java.util.List;\n\n/**\n * 通知控制器\n *\n * @author fengshuonan\n * @Date 2017-05-09 23:02:21\n */\n@Controller\n@RequestMapping(\"/notice\")\npublic class NoticeController extends BaseController {\n\n    private String PREFIX = \"/system/notice/\";\n\n    @Resource\n    private NoticeService noticeService;\n\n\n\n    /**\n     * 跳转到通知列表首页\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"notice.html\";\n    }\n\n    /**\n     * 跳转到添加通知\n     */\n    @RequestMapping(\"/notice_add\")\n    public String noticeAdd() {\n        return PREFIX + \"notice_add.html\";\n    }\n\n    /**\n     * 跳转到修改通知\n     */\n    @RequestMapping(\"/notice_update/{noticeId}\")\n    public String noticeUpdate(@PathVariable Long noticeId, Model model) {\n        Notice notice = ConstantFactory.me().getNotice(noticeId);\n        model.addAttribute(\"notice\",notice);\n        LogObjectHolder.me().set(notice);\n        return PREFIX + \"notice_edit.html\";\n    }\n\n    /**\n     * 跳转到首页通知\n     */\n    @RequestMapping(\"/hello\")\n    public String hello() {\n        List<Notice> notices = (List<Notice>) noticeService.queryAll();\n        super.setAttr(\"noticeList\",notices);\n        return \"/blackboard.html\";\n    }\n\n    /**\n     * 获取通知列表\n     */\n    @RequestMapping(value = \"/list\")\n    @ResponseBody\n    public Object list(String condition) {\n        List<Notice> list = null;\n        if(Strings.isNullOrEmpty(condition)) {\n         list = (List<Notice>) this.noticeService.queryAll();\n        }else{\n            list = noticeService.findByTitleLike(\"%\"+condition+\"%\");\n        }\n        return super.warpObject(new NoticeWrapper(BeanUtil.objectsToMaps(list)));\n    }\n\n    /**\n     * 新增通知\n     */\n    @RequestMapping(value = \"/add\")\n    @ResponseBody\n    @BussinessLog(value = \"新增通知\",key = \"title\",dict = NoticeMap.class)\n    public Object add(Notice notice) {\n        if (ToolUtil.isOneEmpty(notice, notice.getTitle(), notice.getContent())) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n\n        noticeService.insert(notice);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 删除通知\n     */\n    @RequestMapping(value = \"/delete\")\n    @ResponseBody\n    @BussinessLog(value = \"删除通知\",key = \"noticeId\",dict = NoticeMap.class)\n    public Object delete(@RequestParam Long noticeId) {\n\n        //缓存通知名称\n        LogObjectHolder.me().set(ConstantFactory.me().getNoticeTitle(noticeId));\n\n        this.noticeService.delete(noticeId);\n\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 修改通知\n     */\n    @RequestMapping(value = \"/update\")\n    @ResponseBody\n    @BussinessLog(value = \"修改通知\",key = \"title\",dict = NoticeMap.class)\n    public Object update(Notice notice) {\n        if (ToolUtil.isOneEmpty(notice, notice.getId(), notice.getTitle(), notice.getContent())) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        Notice old = ConstantFactory.me().getNotice(notice.getId());\n        old.setTitle(notice.getTitle());\n        old.setContent(notice.getContent());\n        noticeService.update(old);\n        return SUCCESS_TIP;\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/RoleController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.tips.ErrorTip;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.dictmap.RoleDict;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.admin.core.base.tips.Tip;\nimport cn.enilu.material.admin.core.cache.CacheKit;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.bean.vo.query.SearchFilter;\nimport cn.enilu.material.service.system.UserService;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.warpper.RoleWarpper;\nimport cn.enilu.material.bean.vo.node.ZTreeNode;\nimport cn.enilu.material.bean.constant.cache.Cache;\nimport cn.enilu.material.bean.entity.system.Role;\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.service.system.LogObjectHolder;\nimport cn.enilu.material.service.system.RoleService;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.utils.Convert;\nimport cn.enilu.material.utils.ToolUtil;\nimport com.google.common.base.Strings;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport javax.validation.Valid;\nimport java.util.List;\n\n/**\n * 角色控制器\n *\n * @author fengshuonan\n * @Date 2017年2月12日21:59:14\n */\n@Controller\n@RequestMapping(\"/role\")\npublic class RoleController extends BaseController {\n\n    private static String PREFIX = \"/system/role\";\n\n    @Autowired\n    private RoleService roleService;\n    @Autowired\n    private UserService userService;\n\n\n    /**\n     * 跳转到角色列表页面\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"/role.html\";\n    }\n\n    /**\n     * 跳转到添加角色\n     */\n    @RequestMapping(value = \"/role_add\")\n    public String roleAdd() {\n        return PREFIX + \"/role_add.html\";\n    }\n\n    /**\n     * 跳转到修改角色\n     */\n    @Permission\n    @RequestMapping(value = \"/role_edit/{roleId}\")\n    public String roleEdit(@PathVariable Long roleId, Model model) {\n        if (ToolUtil.isEmpty(roleId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        Role role = roleService.get(roleId);\n        model.addAttribute(role);\n        model.addAttribute(\"pName\", ConstantFactory.me().getSingleRoleName(role.getPid()));\n        model.addAttribute(\"deptName\", ConstantFactory.me().getDeptName(role.getDeptid()));\n        LogObjectHolder.me().set(role);\n        return PREFIX + \"/role_edit.html\";\n    }\n\n    /**\n     * 跳转到角色分配\n     */\n    @Permission\n    @RequestMapping(value = \"/role_assign/{roleId}\")\n    public String roleAssign(@PathVariable(\"roleId\") Long roleId, Model model) {\n        if (ToolUtil.isEmpty(roleId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        model.addAttribute(\"roleId\", roleId);\n        model.addAttribute(\"roleName\", ConstantFactory.me().getSingleRoleName(roleId));\n        return PREFIX + \"/role_assign.html\";\n    }\n\n    /**\n     * 获取角色列表\n     */\n    @Permission\n    @RequestMapping(value = \"/list\")\n    @ResponseBody\n    public Object list(@RequestParam(required = false) String roleName) {\n        List roles = null;\n        if(Strings.isNullOrEmpty(roleName)) {\n            roles = (List) roleService.queryAll();\n        }else{\n            roles = roleService.findByName(roleName);\n        }\n        return super.warpObject(new RoleWarpper(BeanUtil.objectsToMaps(roles)));\n    }\n\n    /**\n     * 角色新增\n     */\n    @RequestMapping(value = \"/add\")\n    @BussinessLog(value = \"添加角色\", key = \"name\", dict = RoleDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip add(@Valid Role role, BindingResult result) {\n        if (result.hasErrors()) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        role.setId(null);\n        roleService.insert(role);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 角色修改\n     */\n    @RequestMapping(value = \"/edit\")\n    @BussinessLog(value = \"修改角色\", key = \"name\", dict = RoleDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip edit(@Valid Role role, BindingResult result) {\n        if (result.hasErrors()) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        this.roleService.update(role);\n\n        //删除缓存\n        CacheKit.removeAll(Cache.CONSTANT);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 删除角色\n     */\n    @RequestMapping(value = \"/remove\")\n    @BussinessLog(value = \"删除角色\", key = \"roleId\", dict = RoleDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip remove(@RequestParam Long roleId) {\n        if (ToolUtil.isEmpty(roleId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n\n        //不能删除超级管理员角色\n        if(roleId.intValue() ==Const.ADMIN_ROLE_ID){\n            throw new ApplicationException(BizExceptionEnum.CANT_DELETE_ADMIN);\n        }\n        List<User> userList = userService.queryAll(SearchFilter.build(\"roleid\", SearchFilter.Operator.EQ,String.valueOf(roleId)));\n        if(!userList.isEmpty()){\n            return new ErrorTip(400,\"有用户使用该角色，禁止删除\");\n        }\n        //缓存被删除的角色名称\n        LogObjectHolder.me().set(ConstantFactory.me().getSingleRoleName(roleId));\n\n        this.roleService.delRoleById(roleId);\n\n        //删除缓存\n        CacheKit.removeAll(Cache.CONSTANT);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 查看角色\n     */\n    @RequestMapping(value = \"/view/{roleId}\")\n    @ResponseBody\n    public Tip view(@PathVariable Long roleId) {\n        if (ToolUtil.isEmpty(roleId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n       roleService.get(roleId);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 配置权限\n     */\n    @RequestMapping(\"/setAuthority\")\n    @BussinessLog(value = \"配置权限\", key = \"roleId,ids\", dict = RoleDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip setAuthority(@RequestParam(\"roleId\") Long roleId, @RequestParam(\"ids\") String ids) {\n        if (ToolUtil.isOneEmpty(roleId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        roleService.setAuthority(roleId, ids);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 获取角色列表\n     */\n    @RequestMapping(value = \"/roleTreeList\")\n    @ResponseBody\n    public List<ZTreeNode> roleTreeList() {\n        List<ZTreeNode> roleTreeList =  roleService.roleTreeList();\n        roleTreeList.add(ZTreeNode.createParent());\n        return roleTreeList;\n    }\n\n    /**\n     * 获取角色列表\n     */\n    @RequestMapping(value = \"/roleTreeListByUserId/{userId}\")\n    @ResponseBody\n    public List<ZTreeNode> roleTreeListByUserId(@PathVariable Long userId) {\n        User theUser = userService.get(userId);\n        String roleid = theUser.getRoleid();\n        if (ToolUtil.isEmpty(roleid)) {\n            List<ZTreeNode> roleTreeList = roleService.roleTreeList();\n            return roleTreeList;\n        } else {\n            Long[] roleIds = Convert.toLongArray(\",\", roleid);\n            List<ZTreeNode> roleTreeListByUserId = this.roleService.roleTreeListByRoleId(roleIds);\n            return roleTreeListByUserId;\n        }\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/TaskController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.constant.factory.PageFactory;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.dictmap.TaskDict;\nimport cn.enilu.material.bean.entity.system.Task;\nimport cn.enilu.material.bean.entity.system.TaskLog;\nimport cn.enilu.material.bean.vo.query.Page;\nimport cn.enilu.material.service.task.TaskService;\nimport cn.enilu.material.utils.StringUtils;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.web.bind.annotation.PathVariable;\nimport org.springframework.web.bind.annotation.RequestMapping;\nimport org.springframework.web.bind.annotation.RequestParam;\nimport org.springframework.web.bind.annotation.ResponseBody;\n\nimport javax.validation.Valid;\n\n/**\n * Created  on 2018/4/9 0009.\n * 系统参数\n * @author enilu\n */\n@Controller\n@RequestMapping(\"/task\")\npublic class TaskController extends BaseController {\n    private Logger logger = LoggerFactory.getLogger(TaskController.class);\n\n    @Autowired\n    private TaskService taskService;\n    private String PREFIX = \"/system/task/\";\n    /**\n     * 跳转到定时任务管理首页\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"task.html\";\n    }\n\n    /**\n     * 跳转到添加定时任务管理\n     */\n    @RequestMapping(\"/task_add\")\n    public String add() {\n        return PREFIX + \"task_add.html\";\n    }\n\n    /**\n     * 跳转到修改定时任务管理\n     */\n    @RequestMapping(\"/task_update/{taskId}\")\n    public String update(@PathVariable Long taskId, Model model) {\n        Task task = taskService.get(taskId);\n        model.addAttribute(\"item\",task);\n        return PREFIX + \"task_edit.html\";\n    }\n\n    /**\n     * 获取定时任务管理列表\n     */\n    @RequestMapping(value = \"/list\")\n    @ResponseBody\n    public Object list(String condition) {\n        if(StringUtils.isNullOrEmpty(condition)) {\n            return taskService.queryAll();\n        }else{\n            return taskService.findByNameLike(\"%\"+condition+\"%\");\n        }\n    }\n\n    /**\n     * 新增定时任务管理\n     */\n    @RequestMapping(value = \"/add\")\n    @ResponseBody\n    @BussinessLog(value = \"添加定时任务\", key = \"name\",dict = TaskDict.class)\n    @Permission(Const.ADMIN_NAME)\n    public Object add(@Valid Task task) {\n        taskService.save(task);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 删除定时任务管理\n     */\n    @RequestMapping(value = \"/delete\")\n    @ResponseBody\n    @BussinessLog(value = \"删除定时任务\", key = \"taskId\",dict = TaskDict.class)\n    @Permission(Const.ADMIN_NAME)\n    public Object delete(@RequestParam Long taskId) {\n        taskService.delete(taskId);\n        return SUCCESS_TIP;\n    }\n\n    @RequestMapping(\"/disable\")\n    @ResponseBody\n    @BussinessLog(value = \"禁用定时任务\", key = \"taskId\",dict = TaskDict.class)\n    @Permission(Const.ADMIN_NAME)\n    public Object disable(@RequestParam Long taskId  ) {\n        taskService.disable(taskId);\n        return SUCCESS_TIP;\n    }\n    @RequestMapping(\"/enable\")\n    @ResponseBody\n    @BussinessLog(value = \"启用定时任务\", key = \"taskId\",dict = TaskDict.class)\n    @Permission(Const.ADMIN_NAME)\n    public Object enable(@RequestParam Long taskId  ) {\n        taskService.enable(taskId);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 修改定时任务管理\n     */\n    @RequestMapping(value = \"/update\")\n    @ResponseBody\n    @BussinessLog(value = \"编辑定时任务\", key = \"name\",dict = TaskDict.class)\n    public Object update(@Valid Task task) {\n        Task old = taskService.get(task.getId());\n        old.setName(task.getName());\n        old.setCron(task.getCron());\n        old.setNote(task.getNote());\n        old.setJobClass(task.getJobClass());\n        old.setData(task.getData());\n        taskService.update(old);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 定时任务管理详情\n     */\n    @RequestMapping(value = \"/detail/{taskId}\")\n    @ResponseBody\n    public Object detail(@PathVariable(\"taskId\") Long taskId) {\n        return taskService.get(taskId);\n    }\n\n    @RequestMapping(value = \"/viewLog/{taskId}\")\n    public String viewLog(@PathVariable(\"taskId\") Long taskId,Model model) {\n        model.addAttribute(\"taskId\",taskId);\n        return PREFIX+\"task_log.html\";\n    }\n\n    @RequestMapping(value=\"/logList/{taskId}\")\n    @ResponseBody\n    public Object listList(@PathVariable(\"taskId\") Long taskId) {\n        Page<TaskLog> page = new PageFactory<TaskLog>().defaultPage();\n        page = taskService.getTaskLogs(page,taskId);\n        return super.packForBT(page);\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/controller/UserMgrController.java",
    "content": "package cn.enilu.material.admin.modular.system.controller;\n\nimport cn.enilu.material.admin.config.properties.AppProperties;\nimport cn.enilu.material.admin.core.base.controller.BaseController;\nimport cn.enilu.material.admin.core.base.tips.Tip;\nimport cn.enilu.material.bean.constant.Const;\nimport cn.enilu.material.bean.constant.state.ManagerStatus;\nimport cn.enilu.material.bean.core.BussinessLog;\nimport cn.enilu.material.bean.core.Permission;\nimport cn.enilu.material.bean.core.ShiroUser;\nimport cn.enilu.material.bean.dictmap.UserDict;\nimport cn.enilu.material.bean.dto.UserDto;\nimport cn.enilu.material.bean.entity.system.User;\nimport cn.enilu.material.bean.enumeration.BizExceptionEnum;\nimport cn.enilu.material.bean.exception.ApplicationException;\nimport cn.enilu.material.factory.UserFactory;\nimport cn.enilu.material.service.system.LogObjectHolder;\nimport cn.enilu.material.service.system.UserService;\nimport cn.enilu.material.service.system.impl.ConstantFactory;\nimport cn.enilu.material.shiro.ShiroKit;\nimport cn.enilu.material.utils.BeanUtil;\nimport cn.enilu.material.utils.MD5;\nimport cn.enilu.material.utils.ToolUtil;\nimport cn.enilu.material.warpper.UserWarpper;\nimport com.google.common.base.Strings;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.stereotype.Controller;\nimport org.springframework.ui.Model;\nimport org.springframework.validation.BindingResult;\nimport org.springframework.web.bind.annotation.*;\nimport org.springframework.web.multipart.MultipartFile;\n\nimport javax.annotation.Resource;\nimport javax.naming.NoPermissionException;\nimport javax.validation.Valid;\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\n/**\n * 系统管理员控制器\n *\n * @author fengshuonan\n * @Date 2017年1月11日 下午1:08:17\n */\n@Controller\n@RequestMapping(\"/mgr\")\npublic class UserMgrController extends BaseController {\n\n    private static String PREFIX = \"/system/user/\";\n\n    @Resource\n    private AppProperties appProperties;\n\n    @Autowired\n    private UserService userService;\n\n    /**\n     * 跳转到查看管理员列表的页面\n     */\n    @RequestMapping(\"\")\n    public String index() {\n        return PREFIX + \"user.html\";\n    }\n\n    /**\n     * 跳转到查看管理员列表的页面\n     */\n    @RequestMapping(\"/user_add\")\n    public String addView() {\n        return PREFIX + \"user_add.html\";\n    }\n\n    /**\n     * 跳转到角色分配页面\n     */\n    @Permission\n    @RequestMapping(\"/role_assign/{userId}\")\n    public String roleAssign(@PathVariable Long userId, Model model) {\n        if (ToolUtil.isEmpty(userId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n\n        User user = userService.get(userId);\n        model.addAttribute(\"userId\", userId);\n        model.addAttribute(\"userAccount\", user.getAccount());\n        return PREFIX + \"user_roleassign.html\";\n    }\n\n    /**\n     * 跳转到编辑管理员页面\n     */\n    @Permission\n    @RequestMapping(\"/user_edit/{userId}\")\n    public String userEdit(@PathVariable Long userId, Model model) {\n        if (ToolUtil.isEmpty(userId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        assertAuth(userId);\n        User user = userService.get(userId);\n        model.addAttribute(user);\n        model.addAttribute(\"roleName\", ConstantFactory.me().getRoleName(user.getRoleid()));\n        model.addAttribute(\"deptName\", ConstantFactory.me().getDeptName(user.getDeptid()));\n\n        LogObjectHolder.me().set(user);\n        return PREFIX + \"user_edit.html\";\n    }\n\n    /**\n     * 跳转到查看用户详情页面\n     */\n    @RequestMapping(\"/user_info\")\n    public String userInfo(Model model) {\n        Long userId = ShiroKit.getUser().getId();\n        if (ToolUtil.isEmpty(userId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        User user = userService.get(userId);\n        model.addAttribute(user);\n        model.addAttribute(\"roleName\", ConstantFactory.me().getRoleName(user.getRoleid()));\n        model.addAttribute(\"deptName\", ConstantFactory.me().getDeptName(user.getDeptid()));\n        LogObjectHolder.me().set(user);\n        return PREFIX + \"user_view.html\";\n    }\n\n    /**\n     * 跳转到修改密码界面\n     */\n    @RequestMapping(\"/user_chpwd\")\n    public String chPwd() {\n        return PREFIX + \"user_chpwd.html\";\n    }\n\n    /**\n     * 修改当前用户的密码\n     */\n    @RequestMapping(\"/changePwd\")\n    @ResponseBody\n    public Object changePwd(@RequestParam String oldPwd, @RequestParam String newPwd, @RequestParam String rePwd) {\n        if (!newPwd.equals(rePwd)) {\n            throw new ApplicationException(BizExceptionEnum.TWO_PWD_NOT_MATCH);\n        }\n        Long userId = ShiroKit.getUser().getId();\n        User user = userService.get(userId);\n        String oldMd5 = MD5.md5(oldPwd, user.getSalt());\n        if (user.getPassword().equals(oldMd5)) {\n            String newMd5 = MD5.md5(newPwd, user.getSalt());\n            user.setPassword(newMd5);\n            userService.update(user);\n            return SUCCESS_TIP;\n        } else {\n            throw new ApplicationException(BizExceptionEnum.OLD_PWD_NOT_RIGHT);\n        }\n    }\n\n    /**\n     * 查询管理员列表\n     */\n    @RequestMapping(\"/list\")\n    @Permission\n    @ResponseBody\n    public Object list(@RequestParam(required = false) String name, @RequestParam(required = false) String beginTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) Integer deptid) {\n        Map<String, Object> params = new HashMap<>();\n        params.put(\"name\", name);\n        params.put(\"beginTime\", beginTime);\n        params.put(\"endTime\", endTime);\n        if (deptid != null && deptid != 0) {\n            params.put(\"deptid\", deptid);\n        }\n        if (!Strings.isNullOrEmpty(name)) {\n            params.put(\"name\",\"%\"+ name+\"%\");\n        }\n        List<User> users = userService.findAll(params);\n\n        return new UserWarpper(BeanUtil.objectsToMaps(users)).warp();\n\n    }\n\n    /**\n     * 添加管理员\n     */\n    @RequestMapping(\"/add\")\n    @BussinessLog(value = \"添加管理员\", key = \"account\", dict = UserDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip add(@Valid UserDto user, BindingResult result) {\n        if (result.hasErrors()) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n\n        // 判断账号是否重复\n        User theUser = userService.findByAccount(user.getAccount());\n        if (theUser != null) {\n            throw new ApplicationException(BizExceptionEnum.USER_ALREADY_REG);\n        }\n\n        // 完善账号信息\n        user.setSalt(ToolUtil.getRandomString(5));\n        user.setPassword(MD5.md5(user.getPassword(), user.getSalt()));\n        user.setStatus(ManagerStatus.OK.getCode());\n\n        this.userService.insert(UserFactory.createUser(user, new User()));\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 修改管理员\n     *\n     * @throws NoPermissionException\n     */\n    @RequestMapping(\"/edit\")\n    @BussinessLog(value = \"修改管理员\", key = \"account\", dict = UserDict.class)\n    @ResponseBody\n    @Permission(Const.ADMIN_NAME)\n    public Tip edit(@Valid UserDto user, BindingResult result) throws NoPermissionException {\n        if (result.hasErrors()) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        User oldUser = userService.get(user.getId());\n        if (ShiroKit.hasRole(Const.ADMIN_NAME)) {\n            userService.update(UserFactory.updateUser(user, oldUser));\n            return SUCCESS_TIP;\n        } else {\n            assertAuth(user.getId());\n            ShiroUser shiroUser = ShiroKit.getUser();\n            if (shiroUser.getId().equals(user.getId())) {\n                userService.update(UserFactory.updateUser(user, oldUser));\n                return SUCCESS_TIP;\n            } else {\n                throw new ApplicationException(BizExceptionEnum.NO_PERMITION);\n            }\n        }\n    }\n\n    /**\n     * 删除管理员（逻辑删除）\n     */\n    @RequestMapping(\"/delete\")\n    @BussinessLog(value = \"删除管理员\", key = \"userId\", dict = UserDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip delete(@RequestParam Long userId) {\n        if (ToolUtil.isEmpty(userId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        //不能删除超级管理员\n        if (userId.intValue() == Const.ADMIN_ID) {\n            throw new ApplicationException(BizExceptionEnum.CANT_DELETE_ADMIN);\n        }\n        assertAuth(userId);\n        User user = userService.get(userId);\n        user.setStatus(ManagerStatus.DELETED.getCode());\n        userService.update(user);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 查看管理员详情\n     */\n    @RequestMapping(\"/view/{userId}\")\n    @ResponseBody\n    public User view(@PathVariable Long userId) {\n        if (ToolUtil.isEmpty(userId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        assertAuth(userId);\n        return userService.get(userId);\n    }\n\n    /**\n     * 重置管理员的密码\n     */\n    @RequestMapping(\"/reset\")\n    @BussinessLog(value = \"重置管理员密码\", key = \"userId\", dict = UserDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip reset(@RequestParam Long userId) {\n        if (ToolUtil.isEmpty(userId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        if (userId.intValue() == Const.ADMIN_ID) {\n            throw new ApplicationException(BizExceptionEnum.CANT_CHANGE_ADMIN);\n        }\n        assertAuth(userId);\n        User user = userService.get(userId);\n        user.setSalt(ToolUtil.getRandomString(5));\n        user.setPassword(MD5.md5(Const.DEFAULT_PWD, user.getSalt()));\n        userService.update(user);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 冻结用户\n     */\n    @RequestMapping(\"/freeze\")\n    @BussinessLog(value = \"冻结用户\", key = \"userId\", dict = UserDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip freeze(@RequestParam Long userId) {\n        if (ToolUtil.isEmpty(userId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        //不能冻结超级管理员\n        if (userId.intValue() == Const.ADMIN_ID) {\n            throw new ApplicationException(BizExceptionEnum.CANT_FREEZE_ADMIN);\n        }\n        assertAuth(userId);\n        User user = userService.get(userId);\n        user.setStatus(ManagerStatus.FREEZED.getCode());\n        userService.update(user);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 解除冻结用户\n     */\n    @RequestMapping(\"/unfreeze\")\n    @BussinessLog(value = \"解除冻结用户\", key = \"userId\", dict = UserDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip unfreeze(@RequestParam Long userId) {\n        if (ToolUtil.isEmpty(userId)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        assertAuth(userId);\n        User user = userService.get(userId);\n        user.setStatus(ManagerStatus.OK.getCode());\n        userService.update(user);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 分配角色\n     */\n    @RequestMapping(\"/setRole\")\n    @BussinessLog(value = \"分配角色\", key = \"userId\", dict = UserDict.class)\n    @Permission(Const.ADMIN_NAME)\n    @ResponseBody\n    public Tip setRole(@RequestParam(\"userId\") Long userId, @RequestParam(\"roleIds\") String roleIds) {\n        if (ToolUtil.isOneEmpty(userId, roleIds)) {\n            throw new ApplicationException(BizExceptionEnum.REQUEST_NULL);\n        }\n        //不能修改超级管理员\n        if (userId.intValue() == Const.ADMIN_ID) {\n            throw new ApplicationException(BizExceptionEnum.CANT_CHANGE_ADMIN);\n        }\n        assertAuth(userId);\n        User user = userService.get(userId);\n        user.setRoleid(roleIds);\n        userService.update(user);\n        return SUCCESS_TIP;\n    }\n\n    /**\n     * 上传图片(上传到项目的webapp/static/img)\n     */\n    @RequestMapping(method = RequestMethod.POST, path = \"/upload\")\n    @ResponseBody\n    public String upload(@RequestPart(\"file\") MultipartFile picture) {\n        String pictureName = UUID.randomUUID().toString() + \".jpg\";\n        try {\n            String fileSavePath = appProperties.getFileUploadPath();\n            picture.transferTo(new File(fileSavePath + pictureName));\n        } catch (Exception e) {\n            throw new ApplicationException(BizExceptionEnum.UPLOAD_ERROR);\n        }\n        return pictureName;\n    }\n\n    /**\n     * 判断当前登录的用户是否有操作这个用户的权限\n     */\n    private void assertAuth(Long userId) {\n        if (ShiroKit.isAdmin()) {\n            return;\n        }\n        List<Long> deptDataScope = ShiroKit.getDeptDataScope();\n        User user = userService.get(userId);\n        Long deptid = user.getDeptid();\n        if (deptDataScope.contains(deptid)) {\n            return;\n        } else {\n            throw new ApplicationException(BizExceptionEnum.NO_PERMITION);\n        }\n\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/transfer/ManagerUser.java",
    "content": "package cn.enilu.material.admin.modular.system.transfer;\n\nimport java.util.Date;\n\n/**\n * 管理员的信息封装\n *\n * @author fengshuonan\n * @Date 2017年1月11日 下午7:46:53\n */\npublic class ManagerUser {\n\n    private String userId;\n\n    /* 用户账号 */\n    private String userNo;\n\n    /* 用户姓名 */\n    private String userName;\n\n    private String userPhone;\n\n    //1:超级管理员  2：管理员\n    private String userRole;\n\n    /* 1：登录状态 2：退出状态 3：停用状态 */\n    private Integer userStatus;\n\n    private Date createTime;\n\n    private Date loginTime;\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getUserNo() {\n        return userNo;\n    }\n\n    public void setUserNo(String userNo) {\n        this.userNo = userNo;\n    }\n\n    public String getUserName() {\n        return userName;\n    }\n\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    public String getUserPhone() {\n        return userPhone;\n    }\n\n    public void setUserPhone(String userPhone) {\n        this.userPhone = userPhone;\n    }\n\n    public String getUserRole() {\n        return userRole;\n    }\n\n    public void setUserRole(String userRole) {\n        this.userRole = userRole;\n    }\n\n    public Integer getUserStatus() {\n        return userStatus;\n    }\n\n    public void setUserStatus(Integer userStatus) {\n        this.userStatus = userStatus;\n    }\n\n    public Date getCreateTime() {\n        return createTime;\n    }\n\n    public void setCreateTime(Date createTime) {\n        this.createTime = createTime;\n    }\n\n    public Date getLoginTime() {\n        return loginTime;\n    }\n\n    public void setLoginTime(Date loginTime) {\n        this.loginTime = loginTime;\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/transfer/ReqAddManager.java",
    "content": "package cn.enilu.material.admin.modular.system.transfer;\n\nimport org.hibernate.validator.constraints.Length;\n\nimport javax.validation.constraints.NotNull;\n\n/**\n * 添加管理员的请求bean\n *\n * @author fengshuonan\n * @Date 2017年1月12日 下午6:46:24\n */\npublic class ReqAddManager {\n\n    // 用户姓名\n    @NotNull\n    private String userName;\n\n    // 用户账号\n    @NotNull\n    private String userNo;\n\n    // 手机号\n    @NotNull\n    @Length(min = 11, max = 11)\n    private String userPhone;\n\n    // 1:超级管理员 2：管理员\n    @NotNull\n    private String userRole;\n\n    // 密码\n    @NotNull\n    private String userPassword;\n\n    public String getUserName() {\n        return userName;\n    }\n\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    public String getUserNo() {\n        return userNo;\n    }\n\n    public void setUserNo(String userNo) {\n        this.userNo = userNo;\n    }\n\n    public String getUserPhone() {\n        return userPhone;\n    }\n\n    public void setUserPhone(String userPhone) {\n        this.userPhone = userPhone;\n    }\n\n    public String getUserRole() {\n        return userRole;\n    }\n\n    public void setUserRole(String userRole) {\n        this.userRole = userRole;\n    }\n\n    public String getUserPassword() {\n        return userPassword;\n    }\n\n    public void setUserPassword(String userPassword) {\n        this.userPassword = userPassword;\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/modular/system/transfer/ReqEditManager.java",
    "content": "package cn.enilu.material.admin.modular.system.transfer;\n\nimport org.hibernate.validator.constraints.Length;\n\nimport javax.validation.constraints.NotNull;\n\n/**\n * 编辑管理员的请求\n *\n * @author fengshuonan\n * @Date 2017年1月15日 下午10:29:16\n */\npublic class ReqEditManager {\n\n    @NotNull\n    private String userId;\n\n    /* 用户姓名 */\n    @NotNull\n    private String userName;\n\n    private String userPassword;\n\n    @NotNull\n    @Length(min = 11, max = 11)\n    private String userPhone;\n\n    public String getUserId() {\n        return userId;\n    }\n\n    public void setUserId(String userId) {\n        this.userId = userId;\n    }\n\n    public String getUserName() {\n        return userName;\n    }\n\n    public void setUserName(String userName) {\n        this.userName = userName;\n    }\n\n    public String getUserPassword() {\n        return userPassword;\n    }\n\n    public void setUserPassword(String userPassword) {\n        this.userPassword = userPassword;\n    }\n\n    public String getUserPhone() {\n        return userPhone;\n    }\n\n    public void setUserPhone(String userPhone) {\n        this.userPhone = userPhone;\n    }\n\n}\n"
  },
  {
    "path": "material-manage/src/main/java/cn/enilu/material/admin/runner/StartJob.java",
    "content": "package cn.enilu.material.admin.runner;\n\nimport cn.enilu.material.bean.vo.QuartzJob;\nimport cn.enilu.material.service.task.JobService;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.ApplicationArguments;\nimport org.springframework.boot.ApplicationRunner;\nimport org.springframework.stereotype.Component;\n\nimport java.util.List;\n/**\n * 启动定时任务\n *\n * @author enilu\n * @Date 2019-08-13\n */\n@Component\npublic class StartJob implements ApplicationRunner {\n\n    @Autowired\n    private JobService jobService;\n\n    private Logger log = LoggerFactory.getLogger(getClass());\n\n    @Override\n    public void run(ApplicationArguments applicationArguments) throws Exception {\n        log.info(\"start Job >>>>>>>>>>>>>>>>>>>>>>>\");\n        List<QuartzJob> list = jobService.getTaskList();\n        for (QuartzJob quartzJob : list) {\n            jobService.addJob(quartzJob);\n        }\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/resources/META-INF/spring-devtools.properties",
    "content": "restart.include.beetl=/beetl-2.7.15.jar"
  },
  {
    "path": "material-manage/src/main/resources/application-dev.properties",
    "content": "## 开发环境配置\nspring.datasource.url=jdbc:mysql://enilu-db:3306/material?useUnicode=true&characterEncoding=UTF8&useSSL=false\nspring.datasource.username=material\nspring.datasource.password=material@123ABC\n\n\n##实际开发和生产环境中注释掉下面配置\nspring.jpa.hibernate.ddl-auto=create\n#默认使用InnoDB引擎\nspring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect\nspring.datasource.sql-script-encoding=utf-8\nspring.jpa.show-sql=true\n"
  },
  {
    "path": "material-manage/src/main/resources/application-lab.properties",
    "content": "## 开发环境配置,该配置相对dev增加了个所有实验特性的功能，如果使用改配置，请确保pom.xml添加了material-lab的依赖\nspring.datasource.url=jdbc:mysql://enilu-db:3306/material?useUnicode=true&characterEncoding=UTF8&useSSL=false\nspring.datasource.username=material\nspring.datasource.password=material@123ABC\n\n\n##实际开发和生产环境中注释掉下面配置\nspring.jpa.hibernate.ddl-auto=create\n#默认使用InnoDB引擎\nspring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect\nspring.datasource.sql-script-encoding=utf-8\nspring.jpa.show-sql=true\n\n\n#####################################################################\n##########################以下为实验特性的功能###########################\n#####################################################################\n\n#启用actuator监控功能\n##监控地址端口\nmanagement.server.port=8000\n##springboot2.0之后，在Http环境下将默认的endpoint只设置为info和health，要想开启其他的监控功能，需要手动配置\nmanagement.endpoints.web.exposure.include=*\n##请求连接前缀 默认是/actuator\nmanagement.endpoints.web.base-path=/actuator\nmanagement.health.mail.enabled=false\n"
  },
  {
    "path": "material-manage/src/main/resources/application-prod.properties",
    "content": "## 生产环境配置\ndebug=false\n#Mysql属性配置文件,Spring-boot系统配置\nspring.datasource.url=jdbc:mysql://enilu-db:3306/material?useUnicode=true&characterEncoding=UTF8&useSSL=false\nspring.datasource.username=material\nspring.datasource.password=material@123ABC\n\n##实际开发和生产环境中注释掉下面配置\nspring.jpa.hibernate.ddl-auto=create\n#默认使用InnoDB引擎\nspring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect\nspring.datasource.sql-script-encoding=utf-8\nspring.jpa.show-sql=true\n"
  },
  {
    "path": "material-manage/src/main/resources/application.properties",
    "content": "#项目环境包括：dev(开发),lab(在dev基础上包含各种实验功能),prod(生产环境)\nspring.profiles.active=lab\n\nserver.port=8085\nserver.tomcat.max-threads=800\n\n\nspring.main.allow-bean-definition-overriding=true\nspring.jpa.hibernate.use-new-id-generator-mappings=false\n##是否开启swagger (true/false)\napps.swagger-open=true\n#是否开启spring session,如果是多机环境需要开启(true/false)\napps.spring-session-open=false\n#session失效时间(只在单机环境下生效，多机环境在SpringSessionConfig类中配置) 单位：秒\napps.session-invalidate-time=1800\n#多久检测一次失效的session(只在单机环境下生效) 单位：秒\napps.session-validation-interval=900\n\n\n###################  beetl配置  ###################\n#开始结束标签(yaml不允许@开头)\nbeetl.delimiter-statement-start=@\nbeetl.delimiter-statement-end=null\n#自定义标签文件Root目录和后缀\nbeetl.resource-tagroot=common/tags\nbeetl.resource-tagsuffix=tag\n#是否检测文件变化,开发用true合适，但线上要改为false\nbeetl.resource-auto-check=true\n\n\n###################  spring配置  ###################\nspring.mvc.static-path-pattern=/static/**\nspring.mvc.view.prefix=/WEB-INF/view\nspring.http.converters.preferred-json-mapper=fastjson\n#最大请求大小\nspring.http.multipart.max-request-size=100MB\n#最大文件大小\nspring.http.multipart.max-file-size=100MB\n#是否开启开发者工具（true/false）\nspring.devtools.restart.enabled=false\nspring.devtools.restart.additional-paths=src/main/java\nspring.devtools.restart.exclude=static/**,WEB-INF/view/**\n#false为启用jdk默认动态代理,true为cglib动态代理\nspring.aop.proxy-target-class=true\nspring.datasource.driverClassName=com.mysql.jdbc.Driver\n\n\n###################  邮件服务配置  ###################\nspring.mail.host=smtp.qq.com\nspring.mail.username=eniluzt@qq.com\nspring.mail.password=peqmfythvisgbhcb\nspring.mail.port=465\nspring.mail.protocol=smtp\nspring.mail.properties.mail.smtp.auth=true\nspring.mail.properties.mail.smtp.ssl.enable=true\n"
  },
  {
    "path": "material-manage/src/main/resources/banner.txt",
    "content": "  __  __      _      _____   _____   ____    ___      _      _            _      ____    __  __   ___   _   _ \n |  \\/  |    / \\    |_   _| | ____| |  _ \\  |_ _|    / \\    | |          / \\    |  _ \\  |  \\/  | |_ _| | \\ | |\n | |\\/| |   / _ \\     | |   |  _|   | |_) |  | |    / _ \\   | |         / _ \\   | | | | | |\\/| |  | |  |  \\| |\n | |  | |  / ___ \\    | |   | |___  |  _ <   | |   / ___ \\  | |___     / ___ \\  | |_| | | |  | |  | |  | |\\  |\n |_|  |_| /_/   \\_\\   |_|   |_____| |_| \\_\\ |___| /_/   \\_\\ |_____|   /_/   \\_\\ |____/  |_|  |_| |___| |_| \\_|\n\n                                                                                                              by enilu.cn"
  },
  {
    "path": "material-manage/src/main/resources/ehcache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ehcache xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNamespaceSchemaLocation=\"ehcache.xsd\"\n         updateCheck=\"false\" monitoring=\"autodetect\"\n         dynamicConfig=\"true\" >\n\n    <diskStore path=\"java.io.tmpdir/ehcache\"/>\n\n    <defaultCache\n            maxElementsInMemory=\"50000\"\n            eternal=\"false\"\n            timeToIdleSeconds=\"3600\"\n            timeToLiveSeconds=\"3600\"\n            overflowToDisk=\"true\"\n            diskPersistent=\"false\"\n            diskExpiryThreadIntervalSeconds=\"120\"\n    />\n\n    <!-- 全局变量：永不过期-->\n    <cache name=\"CONSTANT\"\n           maxElementsInMemory=\"50000\"\n           eternal=\"true\"\n           clearOnFlush=\"false\"\n           overflowToDisk=\"true\"\n           diskSpoolBufferSizeMB=\"1024\"\n           maxElementsOnDisk=\"100000\"\n           diskPersistent=\"false\"\n           diskExpiryThreadIntervalSeconds=\"120\"\n           memoryStoreEvictionPolicy=\"LFU\"\n           transactionalMode=\"off\">\n    </cache>\n    <!--SESSION缓存-->\n    <cache name=\"SESSION\"\n           maxElementsInMemory=\"50000\"\n           timeToIdleSeconds=\"3600\"\n           timeToLiveSeconds=\"3600\"\n           eternal=\"true\"\n           clearOnFlush=\"false\"\n           overflowToDisk=\"true\"\n           diskSpoolBufferSizeMB=\"1024\"\n           maxElementsOnDisk=\"100000\"\n           diskPersistent=\"false\"\n           diskExpiryThreadIntervalSeconds=\"120\"\n           memoryStoreEvictionPolicy=\"LFU\"\n           transactionalMode=\"off\">\n    </cache>\n\n    <!--app数据缓存-->\n    <cache name=\"APPLICATION\"\n           maxElementsInMemory=\"50000\"\n           timeToIdleSeconds=\"3600\"\n           timeToLiveSeconds=\"3600\"\n           eternal=\"true\"\n           clearOnFlush=\"false\"\n           overflowToDisk=\"true\"\n           diskSpoolBufferSizeMB=\"1024\"\n           maxElementsOnDisk=\"100000\"\n           diskPersistent=\"false\"\n           diskExpiryThreadIntervalSeconds=\"120\"\n           memoryStoreEvictionPolicy=\"LFU\"\n           transactionalMode=\"off\">\n    </cache>\n\n</ehcache>\n\n        <!--\n            maxElementsInMemory=\"10000\" \t//Cache中最多允许保存的数据对象的数量\n            external=\"false\" \t\t\t\t//缓存中对象是否为永久的，如果是，超时设置将被忽略，对象从不过期\n            timeToLiveSeconds=\"3600\"  \t\t//缓存的存活时间，从开始创建的时间算起\n            timeToIdleSeconds=\"3600\"  \t\t//多长时间不访问该缓存，那么ehcache 就会清除该缓存\n\n            这两个参数很容易误解，看文档根本没用，我仔细分析了ehcache的代码。结论如下：\n            1、timeToLiveSeconds的定义是：以创建时间为基准开始计算的超时时长；\n            2、timeToIdleSeconds的定义是：在创建时间和最近访问时间中取出离现在最近的时间作为基准计算的超时时长；\n            3、如果仅设置了timeToLiveSeconds，则该对象的超时时间=创建时间+timeToLiveSeconds，假设为A；\n            4、如果没设置timeToLiveSeconds，则该对象的超时时间=min(创建时间，最近访问时间)+timeToIdleSeconds，假设为B；\n            5、如果两者都设置了，则取出A、B最少的值，即min(A,B)，表示只要有一个超时成立即算超时。\n\n            overflowToDisk=\"true\"    \t\t//内存不足时，是否启用磁盘缓存\n            diskSpoolBufferSizeMB\t//设置DiskStore（磁盘缓存）的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区\n            maxElementsOnDisk\t\t//硬盘最大缓存个数\n            diskPersistent\t\t\t//是否缓存虚拟机重启期数据The default value is false\n            diskExpiryThreadIntervalSeconds\t//磁盘失效线程运行时间间隔，默认是120秒。\n            memoryStoreEvictionPolicy=\"LRU\" //当达到maxElementsInMemory限制时，Ehcache将会根据指定的策略去清理内存。默认策略是LRU（最近最少使用）。你可以设置为FIFO（先进先出）或是LFU（较少使用）。\n            clearOnFlush\t//内存数量最大时是否清除\n            maxEntriesLocalHeap=\"0\"  //堆内存中最大缓存对象数,0没有限制\n            maxEntriesLocalDisk=\"1000\" //硬盘最大缓存个数。\n        -->\n"
  },
  {
    "path": "material-manage/src/main/resources/import.sql",
    "content": "INSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('16', '0', '0', '状态', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('17', '1', '16', '启用', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('18', '2', '16', '禁用', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('29', '0', '0', '性别', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('30', '1', '29', '男', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('31', '2', '29', '女', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('35', '0', '0', '账号状态', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('36', '1', '35', '启用', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('37', '2', '35', '冻结', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('38', '3', '35', '已删除', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('53', '0', '0', '证件类型', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('54', '1', '53', '身份证', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('55', '2', '53', '护照', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('68', '0', '0', '是否', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('69', '1', '68', '是', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('70', '0', '68', '否', '2019-01-13 14:18:21', '1', '2019-01-13 14:18:21', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('71', '0', '0', '消息类型', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('72', '0', '71', '短信', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\nINSERT INTO `t_sys_dict`(id,value,pid,name,create_time,create_by,modify_time,modify_by) VALUES ('73', '1', '71', '邮件', '2019-07-23 21:30:09', '1', '2019-07-23 21:30:09', '1');\n\n-- ----------------------------\n-- Records of t_sys_cfg\n-- ----------------------------\nINSERT INTO `t_sys_cfg` VALUES ('1', null, null, '1', '2019-04-15 21:36:07', '应用名称update by 2019-03-27 11:47:04', 'system.app.name', 'material-admin');\nINSERT INTO `t_sys_cfg` VALUES ('2', null, null, '1', '2019-04-15 21:36:17', '系统默认上传文件路径', 'system.file.upload.path', '/data/material-admin/runtime/upload');\nINSERT INTO `t_sys_cfg` VALUES ('3', null, null, '1', '2019-04-15 21:36:17', '腾讯sms接口appid', 'api.tencent.sms.appid', '1400219425');\nINSERT INTO `t_sys_cfg` VALUES ('4', null, null, '1', '2019-04-15 21:36:17', '腾讯sms接口appkey', 'api.tencent.sms.appkey', '5f71ed5325f3b292946530a1773e997a');\nINSERT INTO `t_sys_cfg` VALUES ('5', null, null, '1', '2019-04-15 21:36:17', '腾讯sms接口签名参数', 'api.tencent.sms.sign', '需要去申请咯');\nINSERT INTO `t_sys_cfg` VALUES ('6', null, null, '1', '2019-08-18 21:36:17', '系统资源版本号', 'system.resource.version', '1.0');\n\n-- ----------------------------\n-- Records of t_sys_dept\n-- ----------------------------\nINSERT INTO `t_sys_dept` VALUES ('1', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '山迪亚集团', '1', '0', '[0],', '总公司', '', null);\nINSERT INTO `t_sys_dept` VALUES ('2', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '开发部', '2', '1', '[0],[1],', '开发部', null, null);\nINSERT INTO `t_sys_dept` VALUES ('3', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '运营部', '3', '1', '[0],[1],', '运营部', null, null);\nINSERT INTO `t_sys_dept` VALUES ('4', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '战略部', '4', '1', '[0],[1],', '战略部', null, null);\nINSERT INTO `t_sys_dept` VALUES ('5', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '人事部', '5', '1', '[0],[1],', '人事部', null, null);\nINSERT INTO `t_sys_dept` VALUES ('6', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '行政部', '6', '1', '[0],[1],', '行政部', null, null);\nINSERT INTO `t_sys_dept` VALUES ('7', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '山迪亚上海有限责任公司', '7', '1', '[0],[1],', '上海分公司', '', null);\nINSERT INTO `t_sys_dept` VALUES ('8', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '运维部', '8', '7', '[0],[1],[7],', '运维部', null, null);\nINSERT INTO `t_sys_dept` VALUES ('9', '1', '2019-08-15 16:31:13', '1', '2019-08-15 16:31:13', '销售部', '9', '7', '[0],[1],[7],', '销售部', null, null);\n\n\n-- ----------------------------\n-- Records of t_sys_login_log\n-- ----------------------------\nINSERT INTO `t_sys_login_log` (`id`, `logname`, `userid`, `create_time`, `succeed`, `message`, `ip`) VALUES ('71', '登录日志', '1', '2019-05-10 13:17:43', '成功', null, '127.0.0.1');\nINSERT INTO `t_sys_login_log` (`id`, `logname`, `userid`, `create_time`, `succeed`, `message`, `ip`) VALUES ('72', '登录日志', '1', '2019-05-12 13:36:56', '成功', null, '127.0.0.1');\n\n-- ----------------------------\n-- Records of t_sys_menu\n-- ----------------------------\nINSERT INTO `t_sys_menu` VALUES ('1', null, null, null, null, 'system', 'fa-cog', '1', '1', '1', '系统管理', '1', '0', '[0],', '1', null, '/system');\nINSERT INTO `t_sys_menu` VALUES ('4', null, null, '1', '2019-04-16 18:59:15', 'mgr', '', '1', null, '2', '用户管理', '1', 'system', '[0],[system],', '1', null, '/mgr');\nINSERT INTO `t_sys_menu` VALUES ('5', null, null, null, null, 'mgr_add', '', '0', null, '3', '添加用户', '1', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/add');\nINSERT INTO `t_sys_menu` VALUES ('6', null, null, null, null, 'mgr_edit', '', '0', null, '3', '修改用户', '2', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/edit');\nINSERT INTO `t_sys_menu` VALUES ('7', null, null, null, null, 'mgr_delete', '', '0', '0', '3', '删除用户', '3', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/delete');\nINSERT INTO `t_sys_menu` VALUES ('8', null, null, null, null, 'mgr_reset', '', '0', '0', '3', '重置密码', '4', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/reset');\nINSERT INTO `t_sys_menu` VALUES ('9', null, null, null, null, 'mgr_freeze', '', '0', '0', '3', '冻结用户', '5', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/freeze');\nINSERT INTO `t_sys_menu` VALUES ('10', null, null, null, null, 'mgr_unfreeze', '', '0', '0', '3', '解除冻结用户', '6', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/unfreeze');\nINSERT INTO `t_sys_menu` VALUES ('11', null, null, null, null, 'mgr_setRole', '', '0', '0', '3', '分配角色', '7', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/setRole');\nINSERT INTO `t_sys_menu` VALUES ('12', null, null, null, null, 'role', '', '1', '0', '2', '角色管理', '2', 'system', '[0],[system],', '1', null, '/role');\nINSERT INTO `t_sys_menu` VALUES ('13', null, null, null, null, 'role_add', '', '0', '0', '3', '添加角色', '1', 'role', '[0],[system],[role],', '1', null, '/role/add');\nINSERT INTO `t_sys_menu` VALUES ('14', null, null, null, null, 'role_edit', '', '0', '0', '3', '修改角色', '2', 'role', '[0],[system],[role],', '1', null, '/role/edit');\nINSERT INTO `t_sys_menu` VALUES ('15', null, null, null, null, 'role_remove', '', '0', '0', '3', '删除角色', '3', 'role', '[0],[system],[role],', '1', null, '/role/remove');\nINSERT INTO `t_sys_menu` VALUES ('16', null, null, null, null, 'role_setAuthority', '', '0', '0', '3', '配置权限', '4', 'role', '[0],[system],[role],', '1', null, '/role/setAuthority');\nINSERT INTO `t_sys_menu` VALUES ('17', null, null, null, null, 'menu', '', '1', '0', '2', '菜单管理', '4', 'system', '[0],[system],', '1', null, '/menu');\nINSERT INTO `t_sys_menu` VALUES ('18', null, null, null, null, 'menu_add', '', '0', '0', '3', '添加菜单', '1', 'menu', '[0],[system],[menu],', '1', null, '/menu/add');\nINSERT INTO `t_sys_menu` VALUES ('19', null, null, null, null, 'menu_edit', '', '0', '0', '3', '修改菜单', '2', 'menu', '[0],[system],[menu],', '1', null, '/menu/edit');\nINSERT INTO `t_sys_menu` VALUES ('20', null, null, null, null, 'menu_remove', '', '0', '0', '3', '删除菜单', '3', 'menu', '[0],[system],[menu],', '1', null, '/menu/remove');\nINSERT INTO `t_sys_menu` VALUES ('58', null, null, '47', '2019-06-02 10:25:31', 'log', null, '1', null, '2', '业务日志', '6', 'operationMgr', '[0],[operationMgr],', '1', null, '/log');\nINSERT INTO `t_sys_menu` VALUES ('21', null, null, null, null, 'dept', '', '1', null, '2', '部门管理', '3', 'system', '[0],[system],', '1', null, '/dept');\nINSERT INTO `t_sys_menu` VALUES ('22', null, null, null, null, 'dict', '', '1', null, '2', '字典管理', '4', 'system', '[0],[system],', '1', null, '/dict');\nINSERT INTO `t_sys_menu` VALUES ('59', null, null, '47', '2019-06-02 10:25:36', 'loginLog', null, '1', null, '2', '登录日志', '6', 'operationMgr', '[0],[operationMgr],', '1', null, '/loginLog');\nINSERT INTO `t_sys_menu` VALUES ('60', null, null, null, null, 'log_clean', '', '0', null, '3', '清空日志', '3', 'log', '[0],[system],[log],', '1', null, '/log/delLog');\nINSERT INTO `t_sys_menu` VALUES ('36', null, null, null, null, 'dept_add', '', '0', null, '3', '添加部门', '1', 'dept', '[0],[system],[dept],', '1', null, '/dept/add');\nINSERT INTO `t_sys_menu` VALUES ('23', null, null, null, null, 'dept_update', '', '0', null, '3', '修改部门', '1', 'dept', '[0],[system],[dept],', '1', null, '/dept/update');\nINSERT INTO `t_sys_menu` VALUES ('24', null, null, null, null, 'dept_delete', '', '0', null, '3', '删除部门', '1', 'dept', '[0],[system],[dept],', '1', null, '/dept/delete');\nINSERT INTO `t_sys_menu` VALUES ('25', null, null, null, null, 'dict_add', '', '0', null, '3', '添加字典', '1', 'dict', '[0],[system],[dict],', '1', null, '/dict/add');\nINSERT INTO `t_sys_menu` VALUES ('26', null, null, null, null, 'dict_update', '', '0', null, '3', '修改字典', '1', 'dict', '[0],[system],[dict],', '1', null, '/dict/update');\nINSERT INTO `t_sys_menu` VALUES ('27', null, null, null, null, 'dict_delete', '', '0', null, '3', '删除字典', '1', 'dict', '[0],[system],[dict],', '1', null, '/dict/delete');\nINSERT INTO `t_sys_menu` VALUES ('28', null, null, null, null, 'to_menu_edit', '', '0', null, '3', '菜单编辑跳转', '4', 'menu', '[0],[system],[menu],', '1', null, '/menu/menu_edit');\nINSERT INTO `t_sys_menu` VALUES ('29', null, null, null, null, 'menu_list', '', '0', null, '3', '菜单列表', '5', 'menu', '[0],[system],[menu],', '1', null, '/menu/list');\nINSERT INTO `t_sys_menu` VALUES ('30', null, null, null, null, 'to_dept_update', '', '0', null, '3', '修改部门跳转', '4', 'dept', '[0],[system],[dept],', '1', null, '/dept/dept_update');\nINSERT INTO `t_sys_menu` VALUES ('31', null, null, null, null, 'dept_list', '', '0', null, '3', '部门列表', '5', 'dept', '[0],[system],[dept],', '1', null, '/dept/list');\nINSERT INTO `t_sys_menu` VALUES ('32', null, null, null, null, 'dept_detail', '', '0', null, '3', '部门详情', '6', 'dept', '[0],[system],[dept],', '1', null, '/dept/detail');\nINSERT INTO `t_sys_menu` VALUES ('33', null, null, null, null, 'to_dict_edit', '', '0', null, '3', '修改菜单跳转', '4', 'dict', '[0],[system],[dict],', '1', null, '/dict/dict_edit');\nINSERT INTO `t_sys_menu` VALUES ('34', null, null, null, null, 'dict_list', '', '0', null, '3', '字典列表', '5', 'dict', '[0],[system],[dict],', '1', null, '/dict/list');\nINSERT INTO `t_sys_menu` VALUES ('35', null, null, null, null, 'dict_detail', '', '0', null, '3', '字典详情', '6', 'dict', '[0],[system],[dict],', '1', null, '/dict/detail');\nINSERT INTO `t_sys_menu` VALUES ('61', null, null, null, null, 'log_detail', '', '0', null, '3', '日志详情', '3', 'log', '[0],[system],[log],', '1', null, '/log/detail');\nINSERT INTO `t_sys_menu` VALUES ('62', null, null, null, null, 'del_login_log', '', '0', null, '3', '清空登录日志', '1', 'loginLog', '[0],[system],[loginLog],', '1', null, '/loginLog/delLoginLog');\nINSERT INTO `t_sys_menu` VALUES ('63', null, null, null, null, 'login_log_list', '', '0', null, '3', '登录日志列表', '2', 'loginLog', '[0],[system],[loginLog],', '1', null, '/loginLog/list');\nINSERT INTO `t_sys_menu` VALUES ('37', null, null, null, null, 'to_role_edit', '', '0', null, '3', '修改角色跳转', '5', 'role', '[0],[system],[role],', '1', null, '/role/role_edit');\nINSERT INTO `t_sys_menu` VALUES ('38', null, null, null, null, 'to_role_assign', '', '0', null, '3', '角色分配跳转', '6', 'role', '[0],[system],[role],', '1', null, '/role/role_assign');\nINSERT INTO `t_sys_menu` VALUES ('39', null, null, null, null, 'role_list', '', '0', null, '3', '角色列表', '7', 'role', '[0],[system],[role],', '1', null, '/role/list');\nINSERT INTO `t_sys_menu` VALUES ('40', null, null, null, null, 'to_assign_role', '', '0', null, '3', '分配角色跳转', '8', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/role_assign');\nINSERT INTO `t_sys_menu` VALUES ('41', null, null, null, null, 'to_user_edit', '', '0', null, '3', '编辑用户跳转', '9', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/user_edit');\nINSERT INTO `t_sys_menu` VALUES ('42', null, null, null, null, 'mgr_list', '', '0', null, '3', '用户列表', '10', 'mgr', '[0],[system],[mgr],', '1', null, '/mgr/list');\nINSERT INTO `t_sys_menu` VALUES ('43', null, null, null, null, 'cfg', '', '1', null, '2', '参数管理', '10', 'system', '[0],[system],', '1', null, '/cfg');\nINSERT INTO `t_sys_menu` VALUES ('44', null, null, null, null, 'cfg_add', '', '0', null, '3', '添加系统参数', '1', 'cfg', '[0],[system],[cfg],', '1', null, '/cfg/add');\nINSERT INTO `t_sys_menu` VALUES ('45', null, null, null, null, 'cfg_update', '', '0', null, '3', '修改系统参数', '2', 'cfg', '[0],[system],[cfg],', '1', null, '/cfg/update');\nINSERT INTO `t_sys_menu` VALUES ('46', null, null, null, null, 'cfg_delete', '', '0', null, '3', '删除系统参数', '3', 'cfg', '[0],[system],[cfg],', '1', null, '/cfg/delete');\nINSERT INTO `t_sys_menu` VALUES ('47', null, null, null, null, 'task', '', '1', null, '2', '任务管理', '11', 'system', '[0],[system],', '1', null, '/task');\nINSERT INTO `t_sys_menu` VALUES ('48', null, null, null, null, 'task_add', '', '0', null, '3', '添加任务', '1', 'task', '[0],[system],[task],', '1', null, '/task/add');\nINSERT INTO `t_sys_menu` VALUES ('49', null, null, null, null, 'task_update', '', '0', null, '3', '修改任务', '2', 'task', '[0],[system],[task],', '1', null, '/task/update');\nINSERT INTO `t_sys_menu` VALUES ('50', null, null, null, null, 'task_delete', '', '0', null, '3', '删除任务', '3', 'task', '[0],[system],[task],', '1', null, '/task/delete');\nINSERT INTO `t_sys_menu` VALUES ('3', null, null, '47', '2019-06-02 10:09:09', 'operationMgr', 'fa-wrench', '1', null, '1', '运维管理', '3', '0', '[0],', '1', null, '/optionMgr');\nINSERT INTO `t_sys_menu` VALUES ('64', '47', '2019-06-02 10:10:20', '47', '2019-06-02 10:10:20', 'druid', '', '1', null, '2', '数据库监控', '1', 'operationMgr', '[0],[operationMgr],', '1', null, '/druid');\nINSERT INTO `t_sys_menu` VALUES ('65', '47', '2019-06-02 10:10:20', '47', '2019-06-02 10:10:20', 'swagger', null, '1', null, '2', '接口文档', '2', 'operationMgr', '[0],[operationMgr],', '1', null, '/swagger-ui.html');\nINSERT INTO `t_sys_menu` VALUES ('66', '1', '2019-06-10 21:26:52', '1', '2019-06-10 21:26:52', 'messageMgr', 'fa-envelope-o', '1', null, '1', '消息管理', '2', '0', '[0],', '1', null, '/message');\nINSERT INTO `t_sys_menu` VALUES ('67', '1', '2019-06-10 21:27:34', '1', '2019-06-10 21:27:34', 'historyMessage', null, '1', null, '2', '历史消息', '1', 'messageMgr', '[0],[messageMgr],', '1', null, '/message/history');\nINSERT INTO `t_sys_menu` VALUES ('68', '1', '2019-06-10 21:27:56', '1', '2019-06-10 21:27:56', 'messageTemplate', null, '1', null, '2', '消息模板', '2', 'messageMgr', '[0],[messageMgr],', '1', null, '/message/template');\nINSERT INTO `t_sys_menu` VALUES ('69', '1', '2019-06-10 21:28:21', '1', '2019-06-10 21:28:21', 'messageSender', null, '1', null, '2', '消息发送器', '3', 'messageMgr', '[0],[messageMgr],', '1', null, '/message/sender');\n\n-- ----------------------------\n-- Records of t_sys_notice\n-- ----------------------------\nINSERT INTO `t_sys_notice` (`id`, `title`, `type`, `content`, `create_time`, `create_by`, `modify_time`, `modify_by`) VALUES ('1', '世界', '10', '欢迎使用material-admin后台管理系统，点击查看<a href=\\\"http://enilu.gitee.io/material-admin\\\" target=\\\"_blank\\\">官方文档</a>', '2017-01-11 08:53:20', '1', '2019-01-08 23:30:58', '1');\n\n-- ----------------------------\n-- Records of t_sys_operation_log\n-- ----------------------------\nINSERT INTO `t_sys_operation_log` (`id`, `logtype`, `logname`, `userid`, `classname`, `method`, `create_time`, `succeed`, `message`) VALUES ('76', '业务日志', '编辑文章', '1', 'cn.enilu.material.api.controller.cms.ArticleMgrController', 'upload', '2019-05-10 13:22:49', '成功', '名称=null;;;');\nINSERT INTO `t_sys_operation_log` (`id`, `logtype`, `logname`, `userid`, `classname`, `method`, `create_time`, `succeed`, `message`) VALUES ('77', '业务日志', '编辑文章', '1', 'cn.enilu.material.api.controller.cms.ArticleMgrController', 'upload', '2019-05-10 13:31:09', '成功', '名称=null;;;');\n\n-- ----------------------------\n-- Records of t_sys_relation\n-- ----------------------------\nINSERT INTO `t_sys_relation` VALUES ('1', '1', '1');\nINSERT INTO `t_sys_relation` VALUES ('2', '4', '1');\nINSERT INTO `t_sys_relation` VALUES ('3', '5', '1');\nINSERT INTO `t_sys_relation` VALUES ('4', '6', '1');\nINSERT INTO `t_sys_relation` VALUES ('5', '7', '1');\nINSERT INTO `t_sys_relation` VALUES ('6', '8', '1');\nINSERT INTO `t_sys_relation` VALUES ('7', '9', '1');\nINSERT INTO `t_sys_relation` VALUES ('8', '10', '1');\nINSERT INTO `t_sys_relation` VALUES ('9', '11', '1');\nINSERT INTO `t_sys_relation` VALUES ('10', '40', '1');\nINSERT INTO `t_sys_relation` VALUES ('11', '41', '1');\nINSERT INTO `t_sys_relation` VALUES ('12', '42', '1');\nINSERT INTO `t_sys_relation` VALUES ('13', '12', '1');\nINSERT INTO `t_sys_relation` VALUES ('14', '13', '1');\nINSERT INTO `t_sys_relation` VALUES ('15', '14', '1');\nINSERT INTO `t_sys_relation` VALUES ('16', '15', '1');\nINSERT INTO `t_sys_relation` VALUES ('17', '16', '1');\nINSERT INTO `t_sys_relation` VALUES ('18', '37', '1');\nINSERT INTO `t_sys_relation` VALUES ('19', '38', '1');\nINSERT INTO `t_sys_relation` VALUES ('20', '39', '1');\nINSERT INTO `t_sys_relation` VALUES ('21', '17', '1');\nINSERT INTO `t_sys_relation` VALUES ('22', '18', '1');\nINSERT INTO `t_sys_relation` VALUES ('23', '19', '1');\nINSERT INTO `t_sys_relation` VALUES ('24', '20', '1');\nINSERT INTO `t_sys_relation` VALUES ('25', '28', '1');\nINSERT INTO `t_sys_relation` VALUES ('26', '29', '1');\nINSERT INTO `t_sys_relation` VALUES ('27', '21', '1');\nINSERT INTO `t_sys_relation` VALUES ('28', '23', '1');\nINSERT INTO `t_sys_relation` VALUES ('29', '24', '1');\nINSERT INTO `t_sys_relation` VALUES ('30', '30', '1');\nINSERT INTO `t_sys_relation` VALUES ('31', '31', '1');\nINSERT INTO `t_sys_relation` VALUES ('32', '32', '1');\nINSERT INTO `t_sys_relation` VALUES ('33', '36', '1');\nINSERT INTO `t_sys_relation` VALUES ('34', '22', '1');\nINSERT INTO `t_sys_relation` VALUES ('35', '25', '1');\nINSERT INTO `t_sys_relation` VALUES ('36', '26', '1');\nINSERT INTO `t_sys_relation` VALUES ('37', '27', '1');\nINSERT INTO `t_sys_relation` VALUES ('38', '33', '1');\nINSERT INTO `t_sys_relation` VALUES ('39', '34', '1');\nINSERT INTO `t_sys_relation` VALUES ('40', '35', '1');\nINSERT INTO `t_sys_relation` VALUES ('41', '43', '1');\nINSERT INTO `t_sys_relation` VALUES ('42', '44', '1');\nINSERT INTO `t_sys_relation` VALUES ('43', '45', '1');\nINSERT INTO `t_sys_relation` VALUES ('44', '46', '1');\nINSERT INTO `t_sys_relation` VALUES ('45', '47', '1');\nINSERT INTO `t_sys_relation` VALUES ('46', '48', '1');\nINSERT INTO `t_sys_relation` VALUES ('47', '49', '1');\nINSERT INTO `t_sys_relation` VALUES ('48', '50', '1');\nINSERT INTO `t_sys_relation` VALUES ('49', '2', '1');\nINSERT INTO `t_sys_relation` VALUES ('50', '3', '1');\nINSERT INTO `t_sys_relation` VALUES ('51', '58', '1');\nINSERT INTO `t_sys_relation` VALUES ('52', '60', '1');\nINSERT INTO `t_sys_relation` VALUES ('53', '61', '1');\nINSERT INTO `t_sys_relation` VALUES ('54', '59', '1');\nINSERT INTO `t_sys_relation` VALUES ('55', '62', '1');\nINSERT INTO `t_sys_relation` VALUES ('56', '63', '1');\nINSERT INTO `t_sys_relation` VALUES ('57', '64', '1');\nINSERT INTO `t_sys_relation` VALUES ('58', '65', '1');\nINSERT INTO `t_sys_relation` VALUES ('59', '66', '1');\nINSERT INTO `t_sys_relation` VALUES ('60', '67', '1');\nINSERT INTO `t_sys_relation` VALUES ('61', '68', '1');\nINSERT INTO `t_sys_relation` VALUES ('62', '69', '1');\nINSERT INTO `t_sys_relation` VALUES ('63', '1', '2');\nINSERT INTO `t_sys_relation` VALUES ('64', '4', '2');\nINSERT INTO `t_sys_relation` VALUES ('65', '5', '2');\nINSERT INTO `t_sys_relation` VALUES ('66', '40', '2');\nINSERT INTO `t_sys_relation` VALUES ('67', '41', '2');\nINSERT INTO `t_sys_relation` VALUES ('68', '42', '2');\nINSERT INTO `t_sys_relation` VALUES ('69', '12', '2');\nINSERT INTO `t_sys_relation` VALUES ('70', '13', '2');\nINSERT INTO `t_sys_relation` VALUES ('71', '16', '2');\nINSERT INTO `t_sys_relation` VALUES ('72', '37', '2');\nINSERT INTO `t_sys_relation` VALUES ('73', '38', '2');\nINSERT INTO `t_sys_relation` VALUES ('74', '39', '2');\nINSERT INTO `t_sys_relation` VALUES ('75', '17', '2');\nINSERT INTO `t_sys_relation` VALUES ('76', '28', '2');\nINSERT INTO `t_sys_relation` VALUES ('77', '29', '2');\nINSERT INTO `t_sys_relation` VALUES ('78', '21', '2');\nINSERT INTO `t_sys_relation` VALUES ('79', '23', '2');\nINSERT INTO `t_sys_relation` VALUES ('80', '24', '2');\nINSERT INTO `t_sys_relation` VALUES ('81', '30', '2');\nINSERT INTO `t_sys_relation` VALUES ('82', '31', '2');\nINSERT INTO `t_sys_relation` VALUES ('83', '32', '2');\nINSERT INTO `t_sys_relation` VALUES ('84', '36', '2');\nINSERT INTO `t_sys_relation` VALUES ('85', '22', '2');\nINSERT INTO `t_sys_relation` VALUES ('86', '25', '2');\nINSERT INTO `t_sys_relation` VALUES ('87', '26', '2');\nINSERT INTO `t_sys_relation` VALUES ('88', '27', '2');\nINSERT INTO `t_sys_relation` VALUES ('89', '33', '2');\nINSERT INTO `t_sys_relation` VALUES ('90', '34', '2');\nINSERT INTO `t_sys_relation` VALUES ('91', '35', '2');\nINSERT INTO `t_sys_relation` VALUES ('92', '43', '2');\nINSERT INTO `t_sys_relation` VALUES ('93', '44', '2');\nINSERT INTO `t_sys_relation` VALUES ('94', '45', '2');\nINSERT INTO `t_sys_relation` VALUES ('95', '46', '2');\nINSERT INTO `t_sys_relation` VALUES ('96', '47', '2');\nINSERT INTO `t_sys_relation` VALUES ('97', '48', '2');\nINSERT INTO `t_sys_relation` VALUES ('98', '49', '2');\nINSERT INTO `t_sys_relation` VALUES ('99', '50', '2');\nINSERT INTO `t_sys_relation` VALUES ('100', '3', '2');\nINSERT INTO `t_sys_relation` VALUES ('101', '58', '2');\nINSERT INTO `t_sys_relation` VALUES ('102', '60', '2');\nINSERT INTO `t_sys_relation` VALUES ('103', '61', '2');\nINSERT INTO `t_sys_relation` VALUES ('104', '59', '2');\nINSERT INTO `t_sys_relation` VALUES ('105', '62', '2');\nINSERT INTO `t_sys_relation` VALUES ('106', '63', '2');\nINSERT INTO `t_sys_relation` VALUES ('107', '64', '2');\nINSERT INTO `t_sys_relation` VALUES ('108', '65', '2');\nINSERT INTO `t_sys_relation` VALUES ('109', '66', '2');\nINSERT INTO `t_sys_relation` VALUES ('110', '67', '2');\nINSERT INTO `t_sys_relation` VALUES ('111', '68', '2');\nINSERT INTO `t_sys_relation` VALUES ('112', '69', '2');\n\n\n-- ----------------------------\n-- Records of t_sys_role\n-- ----------------------------\nINSERT INTO `t_sys_role` VALUES ('1', null, null, null, null, '24', '超级管理员', '1', '0', 'administrator', '1');\nINSERT INTO `t_sys_role` VALUES ('2', null, null, null, null, '25', '网站管理员', '1', '1', 'developer', null);\n\n-- ----------------------------\n-- Records of t_sys_task\n-- ----------------------------\nINSERT INTO `t_sys_task` (`id`, `name`, `job_group`, `job_class`, `note`, `cron`, `data`, `exec_at`, `exec_result`, `disabled`, `create_time`, `create_by`, `concurrent`, `modify_time`, `modify_by`) VALUES ('1', '测试任务', 'default', 'cn.enilu.material.service.task.job.HelloJob', '测试任务,每30分钟行一次', '0 0/30 * * * ?', '{\\n\\\"appname\\\": \\\"material-admin\\\",\\n\\\"version\\\":1\\n}\\n            \\n            \\n            \\n            \\n            \\n            \\n            \\n            \\n            \\n            \\n            \\n            ', '2019-03-27 11:47:00', '执行成功', '0', '2018-12-28 09:54:00', '1', '0', '2019-03-27 11:47:11', '-1');\n\n-- ----------------------------\n-- Records of t_sys_task_log\n-- ----------------------------\n\n-- ----------------------------\n-- Records of t_sys_user\n-- ----------------------------\n\nINSERT INTO `t_sys_user` VALUES ('-1', null, null, null, null, 'system', null, null, null, null, '应用系统', null, null, null, null, null, null, null);\nINSERT INTO `t_sys_user` VALUES ('1', null, '2016-01-29 08:49:53', '1', '2019-03-20 23:45:24', 'admin', 'avatar.png', '2017-05-05 00:00:00', '3', 'eniluzt@qq.com', '管理员', '6ab1f386d715cfb6be85de941d438b02', '15011111111', '1', '8pgby', '2', '1', '25');\nINSERT INTO `t_sys_user` VALUES ('2', null, '2018-09-13 17:21:02', '1', '2019-01-09 23:05:51', 'developer', 'avatar.png', '2017-12-31 00:00:00', '4', 'eniluzt@qq.com', '网站管理员', '4552805b07a4bf92ce1cea0373aab868', '15222222222', '2', 'vscp9', '1', '1', null);\n\n-- ----------------------------\n-- Records of t_test_boy\n-- ----------------------------\nINSERT INTO `t_test_boy` (`id`, `create_by`, `create_time`, `modify_by`, `modify_time`, `age`, `birthday`, `has_girl_friend`, `name`) VALUES ('1', null, null, null, null, '18', '2000-01-01', '1', '张三');\n\n\n-- ----------------------------\n-- Records of t_message_sender\n-- ----------------------------\nINSERT INTO `t_message_sender` VALUES ('1', null, null, null, null, 'tencentSmsSender', ' 腾讯短信服务', null);\nINSERT INTO `t_message_sender` VALUES ('2', null, null, null, null, 'defaultEmailSender', '默认邮件发送器', null);\n\n-- ----------------------------\n-- Records of t_message_template\n-- ----------------------------\nINSERT INTO `t_message_template` VALUES ('1', null, null, null, null, 'REGISTER_CODE', '注册页面，点击获取验证码', '【腾讯云】校验码{1}，请于5分钟内完成验证，如非本人操作请忽略本短信。', '1', '注册验证码', 0);\nINSERT INTO `t_message_template` VALUES ('2', null, null, null, null, 'EMAIL_TEST', '测试发送', '你好:{1},欢迎使用{2}', '2', '测试邮件', 1);\nINSERT INTO `t_message_template` VALUES ('3', null, null, null, null, 'EMAIL_HTML_TEMPLATE_TEST', '测试发送模板邮件', '你好<strong>${userName}</strong>欢迎使用<font color=\\\"red\\\">${appName}</font>,这是html模板邮件', '2', '测试发送模板邮件', 1);\n\n-- ----------------------------\n-- Records of t_message\n-- ----------------------------\nINSERT INTO `t_message` VALUES ('1', null, '2019-06-10 21:20:16', null, null, '【腾讯云】校验码1032，请于5分钟内完成验证，如非本人操作请忽略本短信。', '15021592814', '2', 'REGISTER_CODE', '0');\n"
  },
  {
    "path": "material-manage/src/main/resources/logback.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<configuration scan=\"true\" scanPeriod=\"10 seconds\" debug=\"false\">\n\t<!-- 应用名称 -->\n\t<contextName>admin</contextName>\n\n\t<!-- 向控制台输出日志 -->\n\t<appender name=\"stdout\" class=\"ch.qos.logback.core.ConsoleAppender\">\n\t\t<encoder>\n<!-- \t\t\t<pattern>%d{yyyy-M-d HH:mm:ss} [%thread] %p [%logger{80}]:%L %msg%n</pattern> -->\n\t\t\t<pattern>%d{yyyy-M-d HH:mm:ss} [%thread] %p [%logger{0}]:%L %msg%n</pattern>\n\t\t\t<charset>UTF-8</charset>\n\t\t</encoder>\n\t</appender>\n\n\t<!-- 向文件输出日志 -->\n\t<appender name=\"file\" class=\"ch.qos.logback.core.rolling.RollingFileAppender\">\n\t\t<rollingPolicy class=\"ch.qos.logback.core.rolling.TimeBasedRollingPolicy\">\n\t\t\t<fileNamePattern>/data/app/material-admin/runtime/log/admin_%d{yyyy-MM-dd}.log</fileNamePattern>\n\t\t\t<maxHistory>1000</maxHistory>\n\t\t</rollingPolicy>\n\t\t<encoder>\n\t\t\t<pattern>%d{yyyy-M-d HH:mm:ss} [%thread] %p [%logger{0}]:%L %msg%n</pattern>\n\t\t\t<charset>UTF-8</charset>\n\t\t</encoder>\n\t</appender>\n\n\t<!-- druid连接池的日志级别 -->\n\t<logger name=\"com.alibaba.druid\" level=\"INFO\" />\n\n\t<!-- snow_credit的日志级别 -->\n\t<logger name=\"cn.enilu.material\" level=\"DEBUG\" />\n\n\t<!-- root级别的logger -->\n\t<root level=\"INFO\">\n\t\t<appender-ref ref=\"file\" />\n\t\t<appender-ref ref=\"stdout\" />\n\t</root>\n</configuration>"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/404.html",
    "content": "<!DOCTYPE html>\n<!--[if IE 9 ]><html class=\"ie9\"><![endif]-->\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <title>Material Admin</title>\n\n    <!-- Vendor CSS -->\n    <link href=\"${ctxPath}/static/vendors/bower_components/animate.css/animate.min.css\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/material-design-iconic-font/dist/css/material-design-iconic-font.min.css\" rel=\"stylesheet\">\n\n    <!-- CSS -->\n    <link href=\"${ctxPath}/static/css/app.min.1.css\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/app.min.2.css\" rel=\"stylesheet\">\n</head>\n\n<body class=\"four-zero-content\">\n<div class=\"four-zero\">\n    <h2>SEX!</h2>\n    <small>Nah.. it's 404</small>\n\n    <footer>\n        <a href=\"javascript:history.back();\"><i class=\"zmdi zmdi-arrow-back\"></i></a>\n        <a href=\"${ctxPath}/\"><i class=\"zmdi zmdi-home\"></i></a>\n    </footer>\n</div>\n\n<!-- Older IE warning message -->\n<!--[if lt IE 9]>\n<div class=\"ie-warning\">\n    <h1 class=\"c-white\">Warning!!</h1>\n    <p>You are using an outdated version of Internet Explorer, please upgrade <br/>to any of the following web browsers to access this website.</p>\n    <div class=\"iew-container\">\n        <ul class=\"iew-download\">\n            <li>\n                <a href=\"http://www.google.com/chrome/\">\n                    <img src=\"img/browsers/chrome.png\" alt=\"\">\n                    <div>Chrome</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"https://www.mozilla.org/en-US/firefox/new/\">\n                    <img src=\"img/browsers/firefox.png\" alt=\"\">\n                    <div>Firefox</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"http://www.opera.com\">\n                    <img src=\"img/browsers/opera.png\" alt=\"\">\n                    <div>Opera</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"https://www.apple.com/safari/\">\n                    <img src=\"img/browsers/safari.png\" alt=\"\">\n                    <div>Safari</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"http://windows.microsoft.com/en-us/internet-explorer/download-ie\">\n                    <img src=\"img/browsers/ie.png\" alt=\"\">\n                    <div>IE (New)</div>\n                </a>\n            </li>\n        </ul>\n    </div>\n    <p>Sorry for the inconvenience!</p>\n</div>\n<![endif]-->\n</body>\n</html>"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/_chat.html",
    "content": "<aside id=\"chat\" class=\"sidebar c-overflow\">\n\n    <div class=\"chat-search\">\n        <div class=\"fg-line\">\n            <input type=\"text\" class=\"form-control\" placeholder=\"Search People\">\n        </div>\n    </div>\n\n    <div class=\"listview\">\n        <a class=\"lv-item\" href=\"\">\n            <div class=\"media\">\n                <div class=\"pull-left p-relative\">\n                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/2.jpg\" alt=\"\">\n                    <i class=\"chat-status-busy\"></i>\n                </div>\n                <div class=\"media-body\">\n                    <div class=\"lv-title\">Jonathan Morris</div>\n                    <small class=\"lv-small\">Available</small>\n                </div>\n            </div>\n        </a>\n\n        <a class=\"lv-item\" href=\"\">\n            <div class=\"media\">\n                <div class=\"pull-left\">\n                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/1.jpg\" alt=\"\">\n                </div>\n                <div class=\"media-body\">\n                    <div class=\"lv-title\">David Belle</div>\n                    <small class=\"lv-small\">Last seen 3 hours ago</small>\n                </div>\n            </div>\n        </a>\n\n        <a class=\"lv-item\" href=\"\">\n            <div class=\"media\">\n                <div class=\"pull-left p-relative\">\n                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/3.jpg\" alt=\"\">\n                    <i class=\"chat-status-online\"></i>\n                </div>\n                <div class=\"media-body\">\n                    <div class=\"lv-title\">Fredric Mitchell Jr.</div>\n                    <small class=\"lv-small\">Availble</small>\n                </div>\n            </div>\n        </a>\n\n        <a class=\"lv-item\" href=\"\">\n            <div class=\"media\">\n                <div class=\"pull-left p-relative\">\n                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/4.jpg\" alt=\"\">\n                    <i class=\"chat-status-online\"></i>\n                </div>\n                <div class=\"media-body\">\n                    <div class=\"lv-title\">Glenn Jecobs</div>\n                    <small class=\"lv-small\">Availble</small>\n                </div>\n            </div>\n        </a>\n\n        <a class=\"lv-item\" href=\"\">\n            <div class=\"media\">\n                <div class=\"pull-left\">\n                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/5.jpg\" alt=\"\">\n                </div>\n                <div class=\"media-body\">\n                    <div class=\"lv-title\">Bill Phillips</div>\n                    <small class=\"lv-small\">Last seen 3 days ago</small>\n                </div>\n            </div>\n        </a>\n\n        <a class=\"lv-item\" href=\"\">\n            <div class=\"media\">\n                <div class=\"pull-left\">\n                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/6.jpg\" alt=\"\">\n                </div>\n                <div class=\"media-body\">\n                    <div class=\"lv-title\">Wendy Mitchell</div>\n                    <small class=\"lv-small\">Last seen 2 minutes ago</small>\n                </div>\n            </div>\n        </a>\n        <a class=\"lv-item\" href=\"\">\n            <div class=\"media\">\n                <div class=\"pull-left p-relative\">\n                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/7.jpg\" alt=\"\">\n                    <i class=\"chat-status-busy\"></i>\n                </div>\n                <div class=\"media-body\">\n                    <div class=\"lv-title\">Teena Bell Ann</div>\n                    <small class=\"lv-small\">Busy</small>\n                </div>\n            </div>\n        </a>\n    </div>\n</aside>"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/_footer.html",
    "content": "<footer id=\"footer\" vvvv>\n    Copyright &copy; 2019 Material Admin\n\n    <ul class=\"f-menu\">\n        <li><a href=\"/\">首页</a></li>\n        <li><a href=\"${ctxPath}/druid/index.html\" target=\"_blank\">系统监控</a></li>\n        <li><a href=\"http://enilu.github.io/material-admin\" target=\"_blank\">在线文档</a></li>\n        <li><a href=\"http://www.enilu.cn\" target=\"_blank\">联系我们</a></li>\n    </ul>\n</footer>\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/_header.html",
    "content": "<header id=\"header\" class=\"clearfix\" data-current-skin=\"blue\">\n    <ul class=\"header-inner\">\n        <li id=\"menu-trigger\" data-trigger=\"#sidebar\">\n            <div class=\"line-wrap\">\n                <div class=\"line top\"></div>\n                <div class=\"line center\"></div>\n                <div class=\"line bottom\"></div>\n            </div>\n        </li>\n\n        <li class=\"logo hidden-xs\">\n            <a href=\"${ctxPath}/\">Material Admin</a>\n        </li>\n\n        <li class=\"pull-right\">\n            <ul class=\"top-menu\">\n                <li id=\"toggle-width\">\n                    <div class=\"toggle-switch\">\n                        <input id=\"tw-switch\" type=\"checkbox\" hidden=\"hidden\">\n                        <label for=\"tw-switch\" class=\"ts-helper\"></label>\n                    </div>\n                </li>\n\n                <li id=\"top-search\">\n                    <a href=\"\"><i class=\"tm-icon zmdi zmdi-search\"></i></a>\n                </li>\n\n                <li class=\"dropdown\">\n                    <a data-toggle=\"dropdown\" href=\"\">\n                        <i class=\"tm-icon zmdi zmdi-notifications\"></i>\n                        <i class=\"tmn-counts\">9</i>\n                    </a>\n                    <div class=\"dropdown-menu dropdown-menu-lg pull-right\">\n                        <div class=\"listview\" id=\"notifications\">\n                            <div class=\"lv-header\">\n                                通知中心\n                                <ul class=\"actions\">\n                                    <li class=\"dropdown\">\n                                        <a href=\"\" data-clear=\"notification\">\n                                            <i class=\"zmdi zmdi-check-all\"></i>\n                                        </a>\n                                    </li>\n                                </ul>\n                            </div>\n                            <div class=\"lv-body\">\n                                <a class=\"lv-item\" href=\"\">\n                                    <div class=\"media\">\n                                        <div class=\"pull-left\">\n                                            <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/1.jpg\" alt=\"\">\n                                        </div>\n                                        <div class=\"media-body\">\n                                            <div class=\"lv-title\">David Belle</div>\n                                            <small class=\"lv-small\">Cum sociis natoque penatibus et magnis dis parturient montes</small>\n                                        </div>\n                                    </div>\n                                </a>\n                                <a class=\"lv-item\" href=\"\">\n                                    <div class=\"media\">\n                                        <div class=\"pull-left\">\n                                            <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/2.jpg\" alt=\"\">\n                                        </div>\n                                        <div class=\"media-body\">\n                                            <div class=\"lv-title\">Jonathan Morris</div>\n                                            <small class=\"lv-small\">Nunc quis diam diamurabitur at dolor elementum, dictum turpis vel</small>\n                                        </div>\n                                    </div>\n                                </a>\n                                <a class=\"lv-item\" href=\"\">\n                                    <div class=\"media\">\n                                        <div class=\"pull-left\">\n                                            <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/3.jpg\" alt=\"\">\n                                        </div>\n                                        <div class=\"media-body\">\n                                            <div class=\"lv-title\">Fredric Mitchell Jr.</div>\n                                            <small class=\"lv-small\">Phasellus a ante et est ornare accumsan at vel magnauis blandit turpis at augue ultricies</small>\n                                        </div>\n                                    </div>\n                                </a>\n                                <a class=\"lv-item\" href=\"\">\n                                    <div class=\"media\">\n                                        <div class=\"pull-left\">\n                                            <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/4.jpg\" alt=\"\">\n                                        </div>\n                                        <div class=\"media-body\">\n                                            <div class=\"lv-title\">Glenn Jecobs</div>\n                                            <small class=\"lv-small\">Ut vitae lacus sem ellentesque maximus, nunc sit amet varius dignissim, dui est consectetur neque</small>\n                                        </div>\n                                    </div>\n                                </a>\n                                <a class=\"lv-item\" href=\"\">\n                                    <div class=\"media\">\n                                        <div class=\"pull-left\">\n                                            <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/4.jpg\" alt=\"\">\n                                        </div>\n                                        <div class=\"media-body\">\n                                            <div class=\"lv-title\">Bill Phillips</div>\n                                            <small class=\"lv-small\">Proin laoreet commodo eros id faucibus. Donec ligula quam, imperdiet vel ante placerat</small>\n                                        </div>\n                                    </div>\n                                </a>\n                            </div>\n\n                            <a class=\"lv-footer\" href=\"\">View Previous</a>\n                        </div>\n\n                    </div>\n                </li>\n                <li class=\"dropdown hidden-xs\">\n                    <a data-toggle=\"dropdown\" href=\"\">\n                        <i class=\"tm-icon zmdi zmdi-view-list-alt\"></i>\n                        <i class=\"tmn-counts\">2</i>\n                    </a>\n                    <div class=\"dropdown-menu pull-right dropdown-menu-lg\">\n                        <div class=\"listview\">\n                            <div class=\"lv-header\">\n                                Tasks\n                            </div>\n                            <div class=\"lv-body\">\n                                <div class=\"lv-item\">\n                                    <div class=\"lv-title m-b-5\">HTML5 Validation Report</div>\n\n                                    <div class=\"progress\">\n                                        <div class=\"progress-bar\" role=\"progressbar\" aria-valuenow=\"95\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 95%\">\n                                            <span class=\"sr-only\">95% Complete (success)</span>\n                                        </div>\n                                    </div>\n                                </div>\n                                <div class=\"lv-item\">\n                                    <div class=\"lv-title m-b-5\">Google Chrome Extension</div>\n\n                                    <div class=\"progress\">\n                                        <div class=\"progress-bar progress-bar-success\" role=\"progressbar\" aria-valuenow=\"80\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 80%\">\n                                            <span class=\"sr-only\">80% Complete (success)</span>\n                                        </div>\n                                    </div>\n                                </div>\n                                <div class=\"lv-item\">\n                                    <div class=\"lv-title m-b-5\">Social Intranet Projects</div>\n\n                                    <div class=\"progress\">\n                                        <div class=\"progress-bar progress-bar-info\" role=\"progressbar\" aria-valuenow=\"20\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 20%\">\n                                            <span class=\"sr-only\">20% Complete</span>\n                                        </div>\n                                    </div>\n                                </div>\n                                <div class=\"lv-item\">\n                                    <div class=\"lv-title m-b-5\">Bootstrap Admin Template</div>\n\n                                    <div class=\"progress\">\n                                        <div class=\"progress-bar progress-bar-warning\" role=\"progressbar\" aria-valuenow=\"60\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 60%\">\n                                            <span class=\"sr-only\">60% Complete (warning)</span>\n                                        </div>\n                                    </div>\n                                </div>\n                                <div class=\"lv-item\">\n                                    <div class=\"lv-title m-b-5\">Youtube Client App</div>\n\n                                    <div class=\"progress\">\n                                        <div class=\"progress-bar progress-bar-danger\" role=\"progressbar\" aria-valuenow=\"80\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 80%\">\n                                            <span class=\"sr-only\">80% Complete (danger)</span>\n                                        </div>\n                                    </div>\n                                </div>\n                            </div>\n\n                            <a class=\"lv-footer\" href=\"\">View All</a>\n                        </div>\n                    </div>\n                </li>\n                <li class=\"dropdown\">\n                    <a data-toggle=\"dropdown\" href=\"\"><i class=\"tm-icon zmdi zmdi-more-vert\"></i></a>\n                    <ul class=\"dropdown-menu dm-icon pull-right\">\n                        <li class=\"skin-switch hidden-xs\">\n                            <span class=\"ss-skin bgm-lightblue\" data-skin=\"lightblue\"></span>\n                            <span class=\"ss-skin bgm-bluegray\" data-skin=\"bluegray\"></span>\n                            <span class=\"ss-skin bgm-cyan\" data-skin=\"cyan\"></span>\n                            <span class=\"ss-skin bgm-teal\" data-skin=\"teal\"></span>\n                            <span class=\"ss-skin bgm-orange\" data-skin=\"orange\"></span>\n                            <span class=\"ss-skin bgm-blue\" data-skin=\"blue\"></span>\n                        </li>\n                        <li class=\"divider hidden-xs\"></li>\n                        <li class=\"hidden-xs\">\n                            <a data-action=\"fullscreen\" href=\"\"><i class=\"zmdi zmdi-fullscreen\"></i> Toggle Fullscreen</a>\n                        </li>\n                        <li>\n                            <a data-action=\"clear-localstorage\" href=\"\"><i class=\"zmdi zmdi-delete\"></i> Clear Local Storage</a>\n                        </li>\n                        <li>\n                            <a href=\"\"><i class=\"zmdi zmdi-face\"></i> Privacy Settings</a>\n                        </li>\n                        <li>\n                            <a href=\"\"><i class=\"zmdi zmdi-settings\"></i> Other Settings</a>\n                        </li>\n                    </ul>\n                </li>\n                <li class=\"hidden-xs\" id=\"chat-trigger\" data-trigger=\"#chat\">\n                    <a href=\"\"><i class=\"tm-icon zmdi zmdi-comment-alt-text\"></i></a>\n                </li>\n            </ul>\n        </li>\n    </ul>\n\n\n    <!-- Top Search Content -->\n    <div id=\"top-search-wrap\">\n        <div class=\"tsw-inner\">\n            <i id=\"top-search-close\" class=\"zmdi zmdi-arrow-left\"></i>\n            <input type=\"text\">\n        </div>\n    </div>\n</header>\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/_sidebar.html",
    "content": "<aside id=\"sidebar\" class=\"sidebar c-overflow\">\n    <div class=\"profile-menu\">\n        <a href=\"\">\n            <div class=\"profile-pic\">\n                @if (shiro.getUser().profile.avatar==\"avatar.png\" ){\n                <img src=\"${ctxPath}/static/img/avatar.png\">\n\n                @}else{\n                <img src=\"${ctxPath}/kaptcha/${shiro.getUser().profile.avatar}\">\n                @}\n            </div>\n\n            <div class=\"profile-info\">\n                ${shiro.getUser().name}\n                <i class=\"zmdi zmdi-caret-down\"></i>\n            </div>\n        </a>\n\n        <ul class=\"main-menu\">\n            <li>\n                <a href=\"${ctxPath}/mgr/user_info\"><i class=\"zmdi zmdi-input-antenna\"></i> 个人资料</a>\n            </li>\n            <li>\n                <a href=\"${ctxPath}/mgr/user_chpwd\"><i class=\"zmdi zmdi-settings\"></i> 修改密码</a>\n            </li>\n            <li>\n                <a href=\"${ctxPath}/logout\"><i class=\"zmdi zmdi-time-restore\"></i> 退出登陆</a>\n            </li>\n        </ul>\n    </div>\n\n    <ul class=\"main-menu\">\n        @for(title in shiro.getUser().titles){\n            @if(tool.isEmpty(title.children)){\n                @if(request.requestURI == title.url){\n                <li><a class=\"active\" href=\"${ctxPath}${title.url}\"><i class=\"fa ${title.icon}\"></i> ${title.name}</a></li>\n                @}else{\n                <li><a href=\"${ctxPath}${title.url}\"><i class=\"fa ${title.icon}\"></i> ${title.name}</a></li>\n                @}\n            @}else{\n                <li\n                    @if(shiro.isParent(request.requestURI,title.name)){\n                        class=\"sub-menu active toggled\"\n                    @}else{\n                        class=\"sub-menu\"\n                    @}\n                >\n                    <a href=\"\"><i class=\"fa ${title.icon}\"></i> ${title.name}</a>\n                    <ul>\n                      @for(subTitle in title.children){\n                        @if(request.requestURI == subTitle.url){\n                        <li><a class=\"active\" href=\"${ctxPath}${subTitle.url}\">${subTitle.name}</a></li>\n                        @}else{\n                        <li><a href=\"${ctxPath}${subTitle.url}\">${subTitle.name}</a></li>\n                        @}\n                      @}\n                    </ul>\n                </li>\n\n            @}\n        @}\n\n        <li> <a href=\"${ctxPath}/lab/actuator\"><i class=\"fa fa-laptop\"></i>实验室</a></li>\n\n        <li>\n            <a target=\"_blank\" href=\"http://enilu.gitee.io/material-admin\"><i class=\"zmdi zmdi-arrow-out\"></i> 在线文档</a>\n        </li>\n    </ul>\n</aside>"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/include.html",
    "content": "<!DOCTYPE html>\n<!--[if IE 9 ]><html class=\"ie9\"><![endif]-->\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>后台管理 - 主页</title>\n    <link rel=\"shortcut icon\" href=\"${ctxPath}/static/favicon.ico\">\n    <!-- Vendor CSS -->\n    <link href=\"${ctxPath}/static/vendors/bower_components/animate.css/animate.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/material-design-iconic-font/dist/css/material-design-iconic-font.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/bootstrap-select/1.7.2/css/bootstrap-select.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/font-awesome.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/nouislider/distribute/jquery.nouislider.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/eonasdan-bootstrap-datetimepicker/4.7.14/css/bootstrap-datetimepicker.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/farbtastic/farbtastic.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/chosen/chosen.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/summernote/dist/summernote.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n\n    <!-- CSS -->\n    <link href=\"${ctxPath}/static/css/app.min.1.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/app.min.2.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n\n    <style>\n        .ztree-icon-default{\n            background-image: url(\"/img/tree/default/icon.png\");\n        }\n    </style>\n\n    <!--整合-->\n    <link href=\"${ctxPath}/static/css/plugins/bootstrap-table/bootstrap-table.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/plugins/ztree/zTreeStyle.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/plugins/jquery-treegrid/css/jquery.treegrid.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\"/>\n    <link href=\"${ctxPath}/static/css/plugins/webuploader/webuploader.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <!--自定义css-->\n    <link href=\"${ctxPath}/static/css/_fstyle.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/material.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n\n    <!-- Javascript Libraries -->\n    <script src=\"${ctxPath}/static/vendors/bower_components/jquery/2.1.4/jquery.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/bootstrap/3.3.6/js/bootstrap.min.js?ver=${constant.resourceVersion()}\"></script>\n\n    <script src=\"${ctxPath}/static/vendors/bower_components/flot/jquery.flot.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/flot/jquery.flot.resize.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/flot.curvedlines/curvedLines.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/sparklines/jquery.sparkline.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/jquery.easy-pie-chart/2.1.6/jquery.easypiechart.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/bootstrap-select/1.7.2/js/bootstrap-select.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/moment/2.10.6/moment-with-locales.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/eonasdan-bootstrap-datetimepicker/4.7.14/js/bootstrap-datetimepicker.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/moment/2.10.6/moment.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/Waves/0.7.4/waves.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bootstrap-growl/bootstrap-growl.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.concat.min.js?ver=${constant.resourceVersion()}\"></script>\n\n    <!-- Placeholder for IE9 -->\n    <!--[if IE 9 ]>\n    <script src=\"${ctxPath}/static/vendors/bower_components/jquery-placeholder/jquery.placeholder.min.js?ver=${constant.resourceVersion()}\"></script>\n    <![endif]-->\n\n    <script src=\"${ctxPath}/static/js/flot-charts/curved-line-chart.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/flot-charts/line-chart.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/charts.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/functions.js?ver=${constant.resourceVersion()}\"></script>\n\n    <!-- 整合 -->\n    <script src=\"${ctxPath}/static/js/plugins/ztree/jquery.ztree.all.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/bootstrap-table/bootstrap-table.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/validate/bootstrapValidator.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/validate/zh_CN.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/jquery-treegrid/js/jquery.treegrid.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/jquery-treegrid/js/jquery.treegrid.bootstrap3.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/jquery-treegrid/extension/jquery.treegrid.extension.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/layer/layer.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/layer/laydate/laydate.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/webuploader/webuploader.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/ajax-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/bootstrap-table-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/tree-table-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/web-upload-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/ztree-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/Feng.js?ver=${constant.resourceVersion()}\"></script>\n\n\n\n\n\n    <script type=\"text/javascript\">\n        Feng.addCtx(\"${ctxPath}\");\n        Feng.sessionTimeoutRegistry();\n    </script>\n\n</head>\n\n<body>\n\n <div class=\"container\" style=\"padding-top:15px;\">\n    ${layoutContent}\n </div>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/layout.html",
    "content": "<!DOCTYPE html>\n<!--[if IE 9 ]><html class=\"ie9\"><![endif]-->\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>后台管理 - 主页</title>\n    <link rel=\"shortcut icon\" href=\"${ctxPath}/static/favicon.ico\">\n    <!-- Vendor CSS -->\n    <link href=\"${ctxPath}/static/vendors/bower_components/animate.css/animate.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/material-design-iconic-font/dist/css/material-design-iconic-font.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/bootstrap-select/1.7.2/css/bootstrap-select.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/font-awesome.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/nouislider/distribute/jquery.nouislider.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/eonasdan-bootstrap-datetimepicker/4.7.14/css/bootstrap-datetimepicker.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/farbtastic/farbtastic.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/chosen/chosen.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/summernote/dist/summernote.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n\n    <!-- CSS -->\n    <link href=\"${ctxPath}/static/css/app.min.1.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/app.min.2.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n\n    <style>\n        .ztree-icon-default{\n            background-image: url(\"/img/tree/default/icon.png\");\n        }\n    </style>\n\n    <!--整合-->\n    <link href=\"${ctxPath}/static/css/plugins/bootstrap-table/bootstrap-table.min.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/plugins/ztree/zTreeStyle.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/plugins/jquery-treegrid/css/jquery.treegrid.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\"/>\n    <link href=\"${ctxPath}/static/css/plugins/webuploader/webuploader.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <!--自定义css-->\n    <link href=\"${ctxPath}/static/css/_fstyle.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/material.css?ver=${constant.resourceVersion()}\" rel=\"stylesheet\">\n\n    <!-- Javascript Libraries -->\n    <script src=\"${ctxPath}/static/vendors/bower_components/jquery/2.1.4/jquery.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/bootstrap/3.3.6/js/bootstrap.min.js?ver=${constant.resourceVersion()}\"></script>\n\n    <script src=\"${ctxPath}/static/vendors/bower_components/flot/jquery.flot.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/flot/jquery.flot.resize.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/flot.curvedlines/curvedLines.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/sparklines/jquery.sparkline.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/jquery.easy-pie-chart/2.1.6/jquery.easypiechart.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/bootstrap-select/1.7.2/js/bootstrap-select.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/moment/2.10.6/moment-with-locales.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/eonasdan-bootstrap-datetimepicker/4.7.14/js/bootstrap-datetimepicker.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/moment/2.10.6/moment.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/Waves/0.7.4/waves.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bootstrap-growl/bootstrap-growl.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/vendors/bower_components/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.concat.min.js?ver=${constant.resourceVersion()}\"></script>\n\n    <!-- Placeholder for IE9 -->\n    <!--[if IE 9 ]>\n    <script src=\"${ctxPath}/static/vendors/bower_components/jquery-placeholder/jquery.placeholder.min.js?ver=${constant.resourceVersion()}\"></script>\n    <![endif]-->\n\n    <script src=\"${ctxPath}/static/js/flot-charts/curved-line-chart.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/flot-charts/line-chart.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/charts.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/functions.js?ver=${constant.resourceVersion()}\"></script>\n\n    <!-- 整合 -->\n    <script src=\"${ctxPath}/static/js/plugins/ztree/jquery.ztree.all.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/bootstrap-table/bootstrap-table.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/validate/bootstrapValidator.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/validate/zh_CN.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/bootstrap-table/bootstrap-table-mobile.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/jquery-treegrid/js/jquery.treegrid.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/jquery-treegrid/js/jquery.treegrid.bootstrap3.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/jquery-treegrid/extension/jquery.treegrid.extension.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/layer/layer.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/layer/laydate/laydate.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/plugins/webuploader/webuploader.min.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/ajax-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/bootstrap-table-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/tree-table-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/web-upload-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/ztree-object.js?ver=${constant.resourceVersion()}\"></script>\n    <script src=\"${ctxPath}/static/js/common/Feng.js?ver=${constant.resourceVersion()}\"></script>\n\n\n    <script type=\"text/javascript\">\n        Feng.addCtx(\"${ctxPath}\");\n\n        Feng.sessionTimeoutRegistry();\n    </script>\n\n</head>\n\n<body class=\"toggled sw-toggled\">\n\n    <!--顶部开始-->\n    @include(\"/common/_header.html\"){}\n    <!--顶部结束-->\n    <section id=\"main\" data-layout=\"layout-1\">\n    <!--sidebar部分开始-->\n    @include(\"/common/_sidebar.html\"){}\n    <!--sidebar部分结束-->\n    <!--chat部分开始-->\n    @include(\"/common/_chat.html\"){}\n    <!--chat部分结束-->\n    <!--正文部分开始-->\n     <section id=\"content\">\n         <div class=\"container\" style=\"padding-left:0px;padding-right:0px;\">\n            ${layoutContent}\n         </div>\n     </section>\n    </section>\n    <!--正文部分结束-->\n    <!--底部开始-->\n    @include(\"/common/_footer.html\"){}\n    <!--底部结束-->\n\n\n<!-- Older IE warning message -->\n<!--[if lt IE 9]>\n<div class=\"ie-warning\">\n    <h1 class=\"c-white\">Warning!!</h1>\n    <p>You are using an outdated version of Internet Explorer, please upgrade <br/>to any of the following web browsers to access this website.</p>\n    <div class=\"iew-container\">\n        <ul class=\"iew-download\">\n            <li>\n                <a href=\"http://www.google.com/chrome/\">\n                    <img src=\"img/browsers/chrome.png\" alt=\"\">\n                    <div>Chrome</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"https://www.mozilla.org/en-US/firefox/new/\">\n                    <img src=\"img/browsers/firefox.png\" alt=\"\">\n                    <div>Firefox</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"http://www.opera.com\">\n                    <img src=\"img/browsers/opera.png\" alt=\"\">\n                    <div>Opera</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"https://www.apple.com/safari/\">\n                    <img src=\"img/browsers/safari.png\" alt=\"\">\n                    <div>Safari</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"http://windows.microsoft.com/en-us/internet-explorer/download-ie\">\n                    <img src=\"img/browsers/ie.png\" alt=\"\">\n                    <div>IE (New)</div>\n                </a>\n            </li>\n        </ul>\n    </div>\n    <p>Sorry for the inconvenience!</p>\n</div>\n<![endif]-->\n\n</body>\n\n</html>\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/NameCon.tag",
    "content": "@/*\n    名称查询条件标签的参数说明:\n\n    name : 查询条件的名称\n    id : 查询内容的input框id\n    type: 输入框类型：text,number\n@*/\n<div class=\"input-group\">\n    <div class=\"fg-line\">\n    <input\n            @if(isNotEmpty(type)){\n            type=\"${type}\"\n            @}else{\n            type=\"text\"\n            @}\n\n            class=\"form-control\" id=\"${id}\" placeholder=\"${placeholder!}\" />\n    </div>\n</div>"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/SelectCon.tag",
    "content": "@/*\n    选择查询条件标签的参数说明:\n\n    name : 查询条件的名称\n    id : 查询内容的input框id\n@*/\n<div class=\"form-group\">\n    <div class=\"fg-line\">\n    <div class=\"select\">\n        <select class=\"selectpicker\" id=\"${id}\">\n            ${tagBody!}\n        </select>\n    </div>\n    </div>\n</div>"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/TimeCon.tag",
    "content": "@/*\n    时间查询条件标签的参数说明:\n\n    name : 查询条件的名称\n    id : 查询内容的input框id\n    type : date 或者 datetime\n@*/\n<div class=\"input-group\">\n    <div class=\"fg-line\">\n    <input id=\"${id}\"  type=\"text\"\n           @if(isNotEmpty(type)){\n                @if(type == \"date\"){\n                    class=\"form-control date-picker\"\n                @}else{\n                    class=\"form-control date-time-picker\"\n                @}\n            @}else{\n                class=\"form-control date-picker\"\n            @}\n\n           @if(isNotEmpty(value)){\n           value=\"${tool.dateType(value)}\"\n           @}\n\n           @if(isNotEmpty(readonly)){\n           readonly=\"${readonly}\"\n           @}\n\n           @if(isNotEmpty(placeholder)){\n            placeholder=\"${placeholder}\"\n           @}\n\n           @if(isNotEmpty(style)){\n           style=\"${style}\"\n           @}\n           @if(isNotEmpty(disabled)){\n           disabled=\"${disabled}\"\n           @}\n    >\n    </div>\n</div>"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/avatar.tag",
    "content": "@/*\n    头像参数的说明:\n    name : 名称\n    id : 头像的id\n@*/\n<div class=\"form-group\">\n    <label class=\"col-sm-3 control-label head-scu-label\">${name}</label>\n    <div class=\"col-sm-5\">\n        <div id=\"${id}PreId\">\n            <div><img width=\"100px\" height=\"100px\"\n                @if(isEmpty(avatarImg)){\n                      src=\"${ctxPath}/static/img/user.png\">\n                @}else{\n                      src=\"${ctxPath}/kaptcha/${avatarImg}\">\n                @}\n            </div>\n        </div>\n    </div>\n    <div class=\"col-sm-4\">\n        <div class=\"head-scu-btn upload-btn\" id=\"${id}BtnId\">\n            <i class=\"fa fa-upload\"></i>&nbsp;上传\n        </div>\n    </div>\n    <input type=\"hidden\" id=\"${id}\" value=\"${avatarImg!}\"/>\n</div>\n@if(isNotEmpty(underline) && underline == 'true'){\n    <div class=\"hr-line-dashed\"></div>\n@}\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/button.tag",
    "content": "@/*\n    按钮标签中各个参数的说明:\n\n    btnType : 按钮的类型决定了颜色(default-灰色,primary-绿色,success-蓝色,info-淡蓝色,warning-黄色,danger-红色,white-白色)\n    space : 按钮左侧是否有间隔(true/false)\n    clickFun : 点击按钮所执行的方法\n    icon : 按钮上的图标的样式\n    name : 按钮名称\n@*/\n\n@var spaceCss = \"\";\n@var btnType = \"\";\n@if(isEmpty(space)){\n@   spaceCss = \"\";\n@}else{\n@   spaceCss = \"button-margin\";\n@}\n@if(isEmpty(btnCss)){\n@   btnType = \"primary\";\n@}else{\n@   btnType = btnCss;\n@}\n<button type=\"button\" class=\"btn btn-${btnType} ${spaceCss}\" onclick=\"${clickFun!}\" id=\"${id!}\">\n@if(isNotEmpty(icon)){\n    <i class=\"fa ${icon}\"></i>\n@}\n&nbsp;${name}\n</button>\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/datePicker.tag",
    "content": "@/*\n表单中日期选择框框标签中各个参数的说明:\n\nid : 元素id\nname : 元素名称\nreadonly : readonly属性\nplaceHolder : placeHolder\ndisabled: 是否禁用\nvalue : 默认值\nstyle : 附加的css属性\nid : 查询内容的input框id\ntype : date 或者 datetime\n@*/\n<div class=\"form-group\">\n    <label class=\"col-sm-3 control-label\">${name}</label>\n    <div class=\"col-sm-9\">\n        <div class=\"fg-line\">\n            <input\n                  @if(isNotEmpty(type)){\n                    @if(type == \"date\"){\n                        class=\"form-control date-picker\"\n                    @}else{\n                        class=\"form-control date-time-picker\"\n                    @}\n                  @}else{\n                    class=\"form-control date-picker\"\n                  @}\n\n                   id=\"${id}\" name=\"${id}\" type=\"text\"\n                   @if(isNotEmpty(value)){\n                   value=\"${tool.dateType(value)}\"\n                   @}\n\n                   @if(isNotEmpty(readonly)){\n                   readonly=\"${readonly}\"\n                   @}\n\n                   @if(isNotEmpty(placeHolder)){\n                   placeHolder=\"${placeHolder}\"\n                   @}\n\n                   @if(isNotEmpty(style)){\n                   style=\"${style}\"\n                   @}\n                   @if(isNotEmpty(disabled)){\n                   disabled=\"${disabled}\"\n                   @}\n            >\n\n        </div>\n    </div>\n</div>\n@if(isNotEmpty(underline) && underline == 'true'){\n<div class=\"hr-line-dashed\"></div>\n@}\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/input.tag",
    "content": "@/*\n    表单中input框标签中各个参数的说明:\n\n    hidden : input hidden框的id\n    id : input框id\n    name : input框名称\n    readonly : readonly属性\n    clickFun : 点击事件的方法名\n    style : 附加的css属性\n@*/\n<div class=\"form-group\">\n    <label class=\"col-sm-3 control-label\">${name}</label>\n    <div class=\"col-sm-9\">\n        <div class=\"fg-line\">\n        <input class=\"form-control\" id=\"${id}\" name=\"${id}\"\n               @if(isNotEmpty(value)){\n                    value=\"${tool.dateType(value)}\"\n               @}\n               @if(isNotEmpty(type)){\n                    type=\"${type}\"\n               @}else{\n                    type=\"text\"\n               @}\n               @if(isNotEmpty(readonly)){\n                    readonly=\"${readonly}\"\n               @}\n               @if(isNotEmpty(clickFun)){\n                    onclick=\"${clickFun}\"\n               @}\n               @if(isNotEmpty(style)){\n                    style=\"${style}\"\n               @}\n               @if(isNotEmpty(disabled)){\n                    disabled=\"${disabled}\"\n               @}\n\n        >\n        @if(isNotEmpty(hidden)){\n            <input class=\"form-control\" type=\"hidden\" id=\"${hidden}\" value=\"${hiddenValue!}\">\n        @}\n\n        @if(isNotEmpty(selectFlag)){\n            <div id=\"${selectId}\" style=\"display: none; position: absolute; z-index: 200;\">\n                <ul id=\"${selectTreeId}\" class=\"ztree tree-box\" style=\"${selectStyle!}\"></ul>\n            </div>\n        @}\n        </div>\n    </div>\n</div>\n@if(isNotEmpty(underline) && underline == 'true'){\n    <div class=\"hr-line-dashed\"></div>\n@}\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/select.tag",
    "content": "@/*\n    select标签中各个参数的说明:\n    name : select的名称\n    id : select的id\n    underline : 是否带分割线\n    multiple : 是否多选\n@*/\n<div class=\"form-group\">\n    <label class=\"col-sm-3 control-label\">${name}</label>\n    <div class=\"col-sm-9\">\n        @if(isNotEmpty(multiple)){\n            <select class=\"selectpicker\" id=\"${id}\" name=\"${id}\" multiple=\"${multiple}\">\n                ${tagBody!}\n            </select>\n\n        @}else{\n            <select class=\"selectpicker\" id=\"${id}\" name=\"${id}\">\n                ${tagBody!}\n            </select>\n        @}\n\n        @if(isNotEmpty(hidden)){\n            <input class=\"form-control\" type=\"hidden\" id=\"${hidden}\" value=\"${hiddenValue!}\">\n        @}\n        </div>\n</div>\n@if(isNotEmpty(underline) && underline == 'true'){\n    <div class=\"hr-line-dashed\"></div>\n@}\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/table.tag",
    "content": "@/*\n    表格标签的参数说明:\n\n    id : table表格的id\n@*/\n<table id=\"${id}\" data-mobile-responsive=\"true\" data-click-to-select=\"true\">\n    <thead>\n        <tr>\n            <th data-field=\"selectItem\" data-checkbox=\"true\"></th>\n        </tr>\n    </thead>\n</table>"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/common/tags/textarea.tag",
    "content": "@/*\n    textarea标签中各个参数的说明:\n    name : 名称\n    id : id\n    underline : 是否带分割线\n    rows : 行数\n    cols : 列数\n    readonly : 是否只读\n@*/\n<div class=\"form-group\">\n    <label class=\"col-sm-3 control-label\">${name}</label>\n    <div class=\"col-sm-9\">\n        <div class=\"fg-line\">\n            <textarea class=\"form-control\" id=\"${id}\" name=\"${id}\" rows=\"${rows}\" cols=\"${cols}\"\n                      @if(isNotEmpty(readonly)){\n                        readonly=\"readonly\"\n                      @}\n>\n@if(isNotEmpty(value)){\n${value}\n@}\n</textarea>\n        </div>\n    </div>\n</div>\n@if(isNotEmpty(underline) && underline == 'true'){\n    <div class=\"hr-line-dashed\"></div>\n@}\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/index.html",
    "content": "@layout(\"/common/layout.html\"){\n\n    <div class=\"block-header\">\n        <h2>Dashboard</h2>\n\n        <ul class=\"actions\">\n            <li>\n                <a href=\"\">\n                    <i class=\"zmdi zmdi-trending-up\"></i>\n                </a>\n            </li>\n            <li>\n                <a href=\"\">\n                    <i class=\"zmdi zmdi-check-all\"></i>\n                </a>\n            </li>\n            <li class=\"dropdown\">\n                <a href=\"\" data-toggle=\"dropdown\">\n                    <i class=\"zmdi zmdi-more-vert\"></i>\n                </a>\n\n                <ul class=\"dropdown-menu dropdown-menu-right\">\n                    <li>\n                        <a href=\"\">Refresh</a>\n                    </li>\n                    <li>\n                        <a href=\"\">Manage Widgets</a>\n                    </li>\n                    <li>\n                        <a href=\"\">Widgets Settings</a>\n                    </li>\n                </ul>\n            </li>\n        </ul>\n\n    </div>\n\n    <div class=\"card\">\n        <div class=\"card-header\">\n            <h2>Sales Statistics <small>Vestibulum purus quam scelerisque, mollis nonummy metus</small></h2>\n\n            <ul class=\"actions\">\n                <li>\n                    <a href=\"\">\n                        <i class=\"zmdi zmdi-refresh-alt\"></i>\n                    </a>\n                </li>\n                <li>\n                    <a href=\"\">\n                        <i class=\"zmdi zmdi-download\"></i>\n                    </a>\n                </li>\n                <li class=\"dropdown\">\n                    <a href=\"\" data-toggle=\"dropdown\">\n                        <i class=\"zmdi zmdi-more-vert\"></i>\n                    </a>\n\n                    <ul class=\"dropdown-menu dropdown-menu-right\">\n                        <li>\n                            <a href=\"\">Change Date Range</a>\n                        </li>\n                        <li>\n                            <a href=\"\">Change Graph Type</a>\n                        </li>\n                        <li>\n                            <a href=\"\">Other Settings</a>\n                        </li>\n                    </ul>\n                </li>\n            </ul>\n        </div>\n\n        <div class=\"card-body\">\n            <div class=\"chart-edge\">\n                <div id=\"curved-line-chart\" class=\"flot-chart \"></div>\n            </div>\n        </div>\n    </div>\n\n    <div class=\"mini-charts\">\n        <div class=\"row\">\n            <div class=\"col-sm-6 col-md-3\">\n                <div class=\"mini-charts-item bgm-cyan\">\n                    <div class=\"clearfix\">\n                        <div class=\"chart stats-bar\"></div>\n                        <div class=\"count\">\n                            <small>Website Traffics</small>\n                            <h2>987,459</h2>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-sm-6 col-md-3\">\n                <div class=\"mini-charts-item bgm-lightgreen\">\n                    <div class=\"clearfix\">\n                        <div class=\"chart stats-bar-2\"></div>\n                        <div class=\"count\">\n                            <small>Website Impressions</small>\n                            <h2>356,785K</h2>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-sm-6 col-md-3\">\n                <div class=\"mini-charts-item bgm-orange\">\n                    <div class=\"clearfix\">\n                        <div class=\"chart stats-line\"></div>\n                        <div class=\"count\">\n                            <small>Total Sales</small>\n                            <h2>$ 458,778</h2>\n                        </div>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-sm-6 col-md-3\">\n                <div class=\"mini-charts-item bgm-bluegray\">\n                    <div class=\"clearfix\">\n                        <div class=\"chart stats-line-2\"></div>\n                        <div class=\"count\">\n                            <small>Support Tickets</small>\n                            <h2>23,856</h2>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n\n\n    <div class=\"dash-widgets\">\n        <div class=\"row\">\n            <div class=\"col-md-3 col-sm-6\">\n                <div id=\"site-visits\" class=\"dash-widget-item bgm-teal\">\n                    <div class=\"dash-widget-header\">\n                        <div class=\"p-20\">\n                            <div class=\"dash-widget-visits\"></div>\n                        </div>\n\n                        <div class=\"dash-widget-title\">For the past 30 days</div>\n\n                        <ul class=\"actions actions-alt\">\n                            <li class=\"dropdown\">\n                                <a href=\"\" data-toggle=\"dropdown\">\n                                    <i class=\"zmdi zmdi-more-vert\"></i>\n                                </a>\n\n                                <ul class=\"dropdown-menu dropdown-menu-right\">\n                                    <li>\n                                        <a href=\"\">Refresh</a>\n                                    </li>\n                                    <li>\n                                        <a href=\"\">Manage Widgets</a>\n                                    </li>\n                                    <li>\n                                        <a href=\"\">Widgets Settings</a>\n                                    </li>\n                                </ul>\n                            </li>\n                        </ul>\n                    </div>\n\n                    <div class=\"p-20\">\n\n                        <small>Page Views</small>\n                        <h3 class=\"m-0 f-400\">47,896,536</h3>\n\n                        <br/>\n\n                        <small>Site Visitors</small>\n                        <h3 class=\"m-0 f-400\">24,456,799</h3>\n\n                        <br/>\n\n                        <small>Total Clicks</small>\n                        <h3 class=\"m-0 f-400\">13,965</h3>\n                    </div>\n                </div>\n            </div>\n\n            <div class=\"col-md-3 col-sm-6\">\n                <div id=\"pie-charts\" class=\"dash-widget-item\">\n                    <div class=\"bgm-pink\">\n                        <div class=\"dash-widget-header\">\n                            <div class=\"dash-widget-title\">Email Statistics</div>\n                        </div>\n\n                        <div class=\"clearfix\"></div>\n\n                        <div class=\"text-center p-20 m-t-25\">\n                            <div class=\"easy-pie main-pie\" data-percent=\"75\">\n                                <div class=\"percent\">45</div>\n                                <div class=\"pie-title\">Total Emails Sent</div>\n                            </div>\n                        </div>\n                    </div>\n\n                    <div class=\"p-t-20 p-b-20 text-center\">\n                        <div class=\"easy-pie sub-pie-1\" data-percent=\"56\">\n                            <div class=\"percent\">56</div>\n                            <div class=\"pie-title\">Bounce Rate</div>\n                        </div>\n                        <div class=\"easy-pie sub-pie-2\" data-percent=\"84\">\n                            <div class=\"percent\">84</div>\n                            <div class=\"pie-title\">Total Opened</div>\n                        </div>\n                    </div>\n\n                </div>\n            </div>\n\n            <div class=\"col-md-3 col-sm-6\">\n                <div class=\"dash-widget-item bgm-lime\">\n                    <div id=\"weather-widget\"></div>\n                </div>\n            </div>\n\n            <div class=\"col-md-3 col-sm-6\">\n                <div id=\"best-selling\" class=\"dash-widget-item\">\n                    <div class=\"dash-widget-header\">\n                        <div class=\"dash-widget-title\">Best Sellings</div>\n                        <img src=\"${ctxPath}/static/img/widgets/alpha.jpg\" alt=\"\">\n                        <div class=\"main-item\">\n                            <small>Samsung Galaxy Alpha</small>\n                            <h2>$799.99</h2>\n                        </div>\n                    </div>\n\n                    <div class=\"listview p-t-5\">\n                        <a class=\"lv-item\" href=\"\">\n                            <div class=\"media\">\n                                <div class=\"pull-left\">\n                                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/widgets/note4.jpg\" alt=\"\">\n                                </div>\n                                <div class=\"media-body\">\n                                    <div class=\"lv-title\">Samsung Galaxy Note 4</div>\n                                    <small class=\"lv-small\">$850.00 - $1199.99</small>\n                                </div>\n                            </div>\n                        </a>\n                        <a class=\"lv-item\" href=\"\">\n                            <div class=\"media\">\n                                <div class=\"pull-left\">\n                                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/widgets/mate7.jpg\" alt=\"\">\n                                </div>\n                                <div class=\"media-body\">\n                                    <div class=\"lv-title\">Huawei Ascend Mate</div>\n                                    <small class=\"lv-small\">$649.59 - $749.99</small>\n                                </div>\n                            </div>\n                        </a>\n                        <a class=\"lv-item\" href=\"\">\n                            <div class=\"media\">\n                                <div class=\"pull-left\">\n                                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/widgets/535.jpg\" alt=\"\">\n                                </div>\n                                <div class=\"media-body\">\n                                    <div class=\"lv-title\">Nokia Lumia 535</div>\n                                    <small class=\"lv-small\">$189.99 - $250.00</small>\n                                </div>\n                            </div>\n                        </a>\n\n                        <a class=\"lv-footer\" href=\"\">\n                            View All\n                        </a>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <div class=\"row\">\n        <div class=\"col-sm-6\">\n\n            <!-- Todo Lists -->\n            <div class=\"card\">\n            <div id=\"todo-lists\">\n                <div class=\"tl-header\">\n                    <h2>Todo List</h2>\n                    <small>Add, edit and manage your Todo Lists</small>\n\n                    <ul class=\"actions actions-alt\">\n                        <li class=\"dropdown\">\n                            <a href=\"\" data-toggle=\"dropdown\">\n                                <i class=\"zmdi zmdi-more-vert\"></i>\n                            </a>\n\n                            <ul class=\"dropdown-menu dropdown-menu-right\">\n                                <li>\n                                    <a href=\"\">刷新</a>\n                                </li>\n                                <li>\n                                    <a href=\"havascript:;\">设置</a>\n                                </li>\n                            </ul>\n                        </li>\n                    </ul>\n                </div>\n                <div class=\"card-body m-t-0\">\n                <div class=\"clearfix\"></div>\n\n                <div class=\"tl-body\">\n                    <div id=\"add-tl-item\">\n                        <i class=\"add-new-item zmdi zmdi-plus\"></i>\n\n                        <div class=\"add-tl-body\">\n                            <textarea placeholder=\"What you want to do...\"></textarea>\n\n                            <div class=\"add-tl-actions\">\n                                <a href=\"\" data-tl-action=\"dismiss\"><i class=\"zmdi zmdi-close\"></i></a>\n                                <a href=\"\" data-tl-action=\"save\"><i class=\"zmdi zmdi-check\"></i></a>\n                            </div>\n                        </div>\n                    </div>\n\n                    <div class=\"checkbox media\">\n                        <div class=\"pull-right\">\n                            <ul class=\"actions actions-alt\">\n                                <li class=\"dropdown\">\n                                    <a href=\"\" data-toggle=\"dropdown\">\n                                        <i class=\"zmdi zmdi-more-vert\"></i>\n                                    </a>\n\n                                    <ul class=\"dropdown-menu dropdown-menu-right\">\n                                        <li><a href=\"\">Delete</a></li>\n                                        <li><a href=\"\">Archive</a></li>\n                                    </ul>\n                                </li>\n                            </ul>\n                        </div>\n                        <div class=\"media-body\">\n                            <label>\n                                <input type=\"checkbox\">\n                                <i class=\"input-helper\"></i>\n                                <span>Duis vitae nibh molestie pharetra augue vitae</span>\n                            </label>\n                        </div>\n                    </div>\n\n                    <div class=\"checkbox media\">\n                        <div class=\"pull-right\">\n                            <ul class=\"actions actions-alt\">\n                                <li class=\"dropdown\">\n                                    <a href=\"\" data-toggle=\"dropdown\">\n                                        <i class=\"zmdi zmdi-more-vert\"></i>\n                                    </a>\n\n                                    <ul class=\"dropdown-menu dropdown-menu-right\">\n                                        <li><a href=\"\">Delete</a></li>\n                                        <li><a href=\"\">Archive</a></li>\n                                    </ul>\n                                </li>\n                            </ul>\n                        </div>\n                        <div class=\"media-body\">\n                            <label>\n                                <input type=\"checkbox\">\n                                <i class=\"input-helper\"></i>\n                                <span>In vel imperdiet leoorbi mollis leo sit amet quam fringilla varius mauris orci turpis</span>\n                            </label>\n                        </div>\n                    </div>\n\n                    <div class=\"checkbox media\">\n                        <div class=\"pull-right\">\n                            <ul class=\"actions actions-alt\">\n                                <li class=\"dropdown\">\n                                    <a href=\"\" data-toggle=\"dropdown\">\n                                        <i class=\"zmdi zmdi-more-vert\"></i>\n                                    </a>\n\n                                    <ul class=\"dropdown-menu dropdown-menu-right\">\n                                        <li><a href=\"\">Delete</a></li>\n                                        <li><a href=\"\">Archive</a></li>\n                                    </ul>\n                                </li>\n                            </ul>\n                        </div>\n                        <div class=\"media-body\">\n                            <label>\n                                <input type=\"checkbox\">\n                                <i class=\"input-helper\"></i>\n                                <span>Suspendisse quis sollicitudin erosvel dictum nunc</span>\n                            </label>\n                        </div>\n                    </div>\n\n                    <div class=\"checkbox media\">\n                        <div class=\"pull-right\">\n                            <ul class=\"actions actions-alt\">\n                                <li class=\"dropdown\">\n                                    <a href=\"\" data-toggle=\"dropdown\">\n                                        <i class=\"zmdi zmdi-more-vert\"></i>\n                                    </a>\n\n                                    <ul class=\"dropdown-menu dropdown-menu-right\">\n                                        <li><a href=\"\">Delete</a></li>\n                                        <li><a href=\"\">Archive</a></li>\n                                    </ul>\n                                </li>\n                            </ul>\n                        </div>\n                        <div class=\"media-body\">\n                            <label>\n                                <input type=\"checkbox\">\n                                <i class=\"input-helper\"></i>\n                                <span>Curabitur egestas finibus sapien quis faucibusras bibendum ut justo at sagittis. In hac habitasse platea dictumst</span>\n                            </label>\n                        </div>\n                    </div>\n\n                    <div class=\"checkbox media\">\n                        <div class=\"pull-right\">\n                            <ul class=\"actions actions-alt\">\n                                <li class=\"dropdown\">\n                                    <a href=\"\" data-toggle=\"dropdown\">\n                                        <i class=\"zmdi zmdi-more-vert\"></i>\n                                    </a>\n\n                                    <ul class=\"dropdown-menu dropdown-menu-right\">\n                                        <li><a href=\"\">Delete</a></li>\n                                        <li><a href=\"\">Archive</a></li>\n                                    </ul>\n                                </li>\n                            </ul>\n                        </div>\n                        <div class=\"media-body\">\n                            <label>\n                                <input type=\"checkbox\">\n                                <i class=\"input-helper\"></i>\n                                <span>Suspendisse potenti. Cras dolor augue, tincidunt sit amet lorem id, blandit rutrum libero</span>\n                            </label>\n                        </div>\n                    </div>\n\n                    <div class=\"checkbox media\">\n                        <div class=\"pull-right\">\n                            <ul class=\"actions actions-alt\">\n                                <li class=\"dropdown\">\n                                    <a href=\"\" data-toggle=\"dropdown\">\n                                        <i class=\"zmdi zmdi-more-vert\"></i>\n                                    </a>\n\n                                    <ul class=\"dropdown-menu dropdown-menu-right\">\n                                        <li><a href=\"\">Delete</a></li>\n                                        <li><a href=\"\">Archive</a></li>\n                                    </ul>\n                                </li>\n                            </ul>\n                        </div>\n                        <div class=\"media-body\">\n                            <label>\n                                <input type=\"checkbox\">\n                                <i class=\"input-helper\"></i>\n                                <span>Proin luctus dictum nisl id auctor. Nullam lobortis condimentum arcu sit amet gravida</span>\n                            </label>\n                        </div>\n                    </div>\n                </div>\n                </div>\n                </div>\n            </div>\n\n\n        </div>\n\n        <div class=\"col-sm-6\">\n            <!-- Recent Items -->\n            <div class=\"card\">\n                <div class=\"card-header\">\n                    <h2>Recent Items <small>Phasellus condimentum ipsum id auctor imperdie</small></h2>\n                    <ul class=\"actions\">\n                        <li class=\"dropdown\">\n                            <a href=\"\" data-toggle=\"dropdown\">\n                                <i class=\"zmdi zmdi-more-vert\"></i>\n                            </a>\n\n                            <ul class=\"dropdown-menu dropdown-menu-right\">\n                                <li>\n                                    <a href=\"\">Refresh</a>\n                                </li>\n                                <li>\n                                    <a href=\"\">Settings</a>\n                                </li>\n                                <li>\n                                    <a href=\"\">Other Settings</a>\n                                </li>\n                            </ul>\n                        </li>\n                    </ul>\n                </div>\n\n                <div class=\"card-body m-t-0\">\n                    <table class=\"table table-inner table-vmiddle\">\n                        <thead>\n                        <tr>\n                            <th>ID</th>\n                            <th>Name</th>\n                            <th style=\"width: 60px\">Price</th>\n                        </tr>\n                        </thead>\n                        <tbody>\n                        <tr>\n                            <td class=\"f-500 c-cyan\">2569</td>\n                            <td>Samsung Galaxy Mega</td>\n                            <td class=\"f-500 c-cyan\">$521</td>\n                        </tr>\n                        <tr>\n                            <td class=\"f-500 c-cyan\">9658</td>\n                            <td>Huawei Ascend P6</td>\n                            <td class=\"f-500 c-cyan\">$440</td>\n                        </tr>\n                        <tr>\n                            <td class=\"f-500 c-cyan\">1101</td>\n                            <td>HTC One M8</td>\n                            <td class=\"f-500 c-cyan\">$680</td>\n                        </tr>\n                        <tr>\n                            <td class=\"f-500 c-cyan\">6598</td>\n                            <td>Samsung Galaxy Alpha</td>\n                            <td class=\"f-500 c-cyan\">$870</td>\n                        </tr>\n                        <tr>\n                            <td class=\"f-500 c-cyan\">4562</td>\n                            <td>LG G3</td>\n                            <td class=\"f-500 c-cyan\">$690</td>\n                        </tr>\n                        </tbody>\n                    </table>\n                </div>\n                <div id=\"recent-items-chart\" class=\"flot-chart\"></div>\n            </div>\n            <!-- Recent Posts -->\n            <div class=\"card\">\n                <div class=\"card-header ch-alt m-b-20\">\n                    <h2>Recent Posts <small>Phasellus condimentum ipsum id auctor imperdie</small></h2>\n                    <ul class=\"actions\">\n                        <li>\n                            <a href=\"\">\n                                <i class=\"zmdi zmdi-refresh-alt\"></i>\n                            </a>\n                        </li>\n                        <li>\n                            <a href=\"\">\n                                <i class=\"zmdi zmdi-download\"></i>\n                            </a>\n                        </li>\n                        <li class=\"dropdown\">\n                            <a href=\"\" data-toggle=\"dropdown\">\n                                <i class=\"zmdi zmdi-more-vert\"></i>\n                            </a>\n\n                            <ul class=\"dropdown-menu dropdown-menu-right\">\n                                <li>\n                                    <a href=\"\">Change Date Range</a>\n                                </li>\n                                <li>\n                                    <a href=\"\">Change Graph Type</a>\n                                </li>\n                                <li>\n                                    <a href=\"\">Other Settings</a>\n                                </li>\n                            </ul>\n                        </li>\n                    </ul>\n\n                    <button class=\"btn bgm-cyan btn-float\"><i class=\"zmdi zmdi-plus\"></i></button>\n                </div>\n\n                <div class=\"card-body\">\n                    <div class=\"listview\">\n                        <a class=\"lv-item\" href=\"\">\n                            <div class=\"media\">\n                                <div class=\"pull-left\">\n                                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/1.jpg\" alt=\"\">\n                                </div>\n                                <div class=\"media-body\">\n                                    <div class=\"lv-title\">David Belle</div>\n                                    <small class=\"lv-small\">Cum sociis natoque penatibus et magnis dis parturient montes</small>\n                                </div>\n                            </div>\n                        </a>\n                        <a class=\"lv-item\" href=\"\">\n                            <div class=\"media\">\n                                <div class=\"pull-left\">\n                                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/2.jpg\" alt=\"\">\n                                </div>\n                                <div class=\"media-body\">\n                                    <div class=\"lv-title\">Jonathan Morris</div>\n                                    <small class=\"lv-small\">Nunc quis diam diamurabitur at dolor elementum, dictum turpis vel</small>\n                                </div>\n                            </div>\n                        </a>\n                        <a class=\"lv-item\" href=\"\">\n                            <div class=\"media\">\n                                <div class=\"pull-left\">\n                                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/3.jpg\" alt=\"\">\n                                </div>\n                                <div class=\"media-body\">\n                                    <div class=\"lv-title\">Fredric Mitchell Jr.</div>\n                                    <small class=\"lv-small\">Phasellus a ante et est ornare accumsan at vel magnauis blandit turpis at augue ultricies</small>\n                                </div>\n                            </div>\n                        </a>\n                        <a class=\"lv-item\" href=\"\">\n                            <div class=\"media\">\n                                <div class=\"pull-left\">\n                                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/4.jpg\" alt=\"\">\n                                </div>\n                                <div class=\"media-body\">\n                                    <div class=\"lv-title\">Glenn Jecobs</div>\n                                    <small class=\"lv-small\">Ut vitae lacus sem ellentesque maximus, nunc sit amet varius dignissim, dui est consectetur neque</small>\n                                </div>\n                            </div>\n                        </a>\n                        <a class=\"lv-item\" href=\"\">\n                            <div class=\"media\">\n                                <div class=\"pull-left\">\n                                    <img class=\"lv-img-sm\" src=\"${ctxPath}/static/img/profile-pics/4.jpg\" alt=\"\">\n                                </div>\n                                <div class=\"media-body\">\n                                    <div class=\"lv-title\">Bill Phillips</div>\n                                    <small class=\"lv-small\">Proin laoreet commodo eros id faucibus. Donec ligula quam, imperdiet vel ante placerat</small>\n                                </div>\n                            </div>\n                        </a>\n                        <a class=\"lv-footer\" href=\"\">View All</a>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n\n<script  type=\"text/javascript\">\n    Feng.info('欢迎光临 Flash Material,演示环境禁用了部分功能，完整功能请自行clone代码并运行使用admin账号登录');\n</script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/lab/actuator.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>实验室</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <strong>这里会列出本系统集成的一些实验性质的功能，都放在material-lab模块里，通过启用配置文件application-lab.properties来启用这些功能</strong><br><br><br>\n                <div class=\"pm-body clearfix\">\n                    <ul class=\"tab-nav tn-justified\">\n                        <li class=\"active waves-effect\"><a href=\"${ctxPath}/lab/actuator\">actuator监控</a></li>\n                        <li class=\"waves-effect\"><a href=\"${ctxPath}/lab/gis\">gis地图</a></li>\n                    </ul>\n\n\n                    <div class=\"pmb-block\">\n<pre>\n- 使用actuator可以方便的对spring boot应用做监控\n- 启用该功能后 访问http://localhost:8000/actuator/env\n</pre>\n                        测试访问:<a href=\"http://localhost:8000/actuator/env\">http://localhost:8000/actuator/env</a><br>\n                        更多监控接口查看<a href=\"http://localhost:8000/actuator\">http://localhost:8000/actuator</a><br>\n                        acturator提供的监控能力有限，而且没有界面，如果需要更成熟的工具，可以参考试试：Spring Boot Admin\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/lab/gis.html",
    "content": "@layout(\"/common/layout.html\"){\n\n<style>\n    body {\n        padding: 0;\n        margin: 0;\n    }\n\n      #map {\n        height: 800px;\n    }\n\n    #toolbar {\n    }\n\n\n</style>\n</head>\n\n<div class=\"block-header\">\n    <h2>实验室</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n\n                <strong>这里会列出本系统集成的一些实验性质的功能，都放在material-lab模块里，通过启用配置文件application-lab.properties来启用这些功能</strong><br><br><br>\n                <div class=\"pm-body clearfix\">\n                    <ul class=\"tab-nav tn-justified\">\n                        <li class=\"waves-effect\"><a href=\"${ctxPath}/lab/actuator\">actuator监控</a></li>\n                        <li class=\"active waves-effect\"><a href=\"${ctxPath}/lab/gis\">gis地图</a></li>\n                    </ul>\n\n\n                    <div class=\"pmb-block\">\n                        <div id=\"toolbar\">\n                            <button id=\"btnInit\">地图初始化</button>\n                            <button id=\"btnAddMark\">addMark</button>\n                            <button id=\"btnAddMarks\">addMarks</button>\n                            <button id=\"btnPointTo\">定位上海</button>\n                            <button id=\"btnDrawCircle\">画圆圈</button>\n                            <button id=\"btnDrawArc\">画弧线</button>\n                        </div>\n                        <div id=\"map\"></div>\n                    </div>\n                </div>\n\n\n            </div>\n        </div>\n    </div>\n</div>\n\n<link rel=\"stylesheet\" href=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet/leaflet.css\"/>\n<link rel=\"stylesheet\" href=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet.draw/leaflet.draw.css\"/>\n\n\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet/leaflet.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet.draw/leaflet.draw.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet/leaflet.functionaltilelayer.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet.draw/leaflet.draw-src.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet/leaflet.markercluster.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet/leaflet.polylineDecorator.min.js\"></script>\n\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/arc.js-gh-pages/arc.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/bar.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/arcDecorator.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/mapColumnChart.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet.plugins/arc.js\"></script>\n<script type=\"text/javascript\" src=\"${ctxPath}/static/lab/gis/js/jslib/LMapLib.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/src/L.LineUtil.PolylineDecorator.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/src/L.RotatedMarker.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/src/L.Symbol.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/src/L.PolylineDecorator.js\"></script>\n\n<script src=\"${ctxPath}/static/lab/gis/js/base/base_leaflet.draw.ext.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/base/base_map.js\"></script>\n<script src=\"${ctxPath}/static/lab/gis/js/base/base_tilesUtils.js\"></script>\n\n<script type=\"text/javascript\" src=\"${ctxPath}/static/lab/gis/js/test/data/cirlData.js\"></script>\n<script type=\"text/javascript\" src=\"${ctxPath}/static/lab/gis/index.js\"></script>\n</body>\n</html>\n@}"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/login.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n    <title>flash-material - 登录</title>\n\n    <link rel=\"shortcut icon\" href=\"${ctxPath}/static/favicon.ico\">\n    <!-- Vendor CSS -->\n    <link href=\"${ctxPath}/static/vendors/bower_components/animate.css/animate.min.css?ver=1.0\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/vendors/bower_components/material-design-iconic-font/dist/css/material-design-iconic-font.min.css?ver=1.0\" rel=\"stylesheet\">\n\n    <!-- CSS -->\n    <link href=\"${ctxPath}/static/css/app.min.1.css?ver=1.0\" rel=\"stylesheet\">\n    <link href=\"${ctxPath}/static/css/app.min.2.css?ver=1.0\" rel=\"stylesheet\">\n    <style>\n        .login-header{\n            width:100%;\n            text-align: center;\n            top:19%;\n            font-size:36px;\n            color:#ffffff;\n            position: fixed;\n        }\n    </style>\n    <script>if (window.top !== window.self) {\n        window.top.location = window.location;\n    }</script>\n</head>\n\n<body class=\"login-content\" >\n\n<div class=\"login-header\">\n        <p>Material Admin</p>\n</div>\n<!-- Login -->\n<div class=\"lc-block toggled\" id=\"l-login\">\n\n    <form  role=\"form\" action=\"${ctxPath}/login\" method=\"post\">\n    <div class=\"input-group m-b-20\">\n        <span class=\"input-group-addon\"><i class=\"zmdi zmdi-account\"></i></span>\n        <div class=\"fg-line\">\n            <input name=\"username\" type=\"text\" class=\"form-control\" placeholder=\"用户名\" value=\"developer\">\n        </div>\n    </div>\n\n    <div class=\"input-group m-b-20\">\n        <span class=\"input-group-addon\"><i class=\"zmdi zmdi-male\"></i></span>\n        <div class=\"fg-line\">\n            <input name=\"password\" type=\"password\" class=\"form-control\" placeholder=\"密码\" value=\"123456\">\n        </div>\n    </div>\n\n    <div class=\"clearfix\"></div>\n\n    <div class=\"checkbox\">\n        <label>\n            <input type=\"checkbox\" value=\"on\" name=\"remember\" >\n            <i class=\"input-helper\"></i>\n            记住我\n        </label>\n    </div>\n\n    <button  type=\"submit\"  class=\"btn btn-login btn-primary btn-float\"><i class=\"zmdi zmdi-arrow-forward\"></i></button>\n\n    <ul class=\"login-navigation\">\n        <li data-block=\"#l-register\" class=\"bgm-red\">注册</li>\n        <li data-block=\"#l-forget-password\" class=\"bgm-orange\">忘记密码?</li>\n    </ul>\n    </form>\n</div>\n\n<!-- Register -->\n<div class=\"lc-block\" id=\"l-register\">\n    <div class=\"input-group m-b-20\">\n        <span class=\"input-group-addon\"><i class=\"zmdi zmdi-account\"></i></span>\n        <div class=\"fg-line\">\n            <input type=\"text\" class=\"form-control\" placeholder=\"用户名\">\n        </div>\n    </div>\n\n    <div class=\"input-group m-b-20\">\n        <span class=\"input-group-addon\"><i class=\"zmdi zmdi-email\"></i></span>\n        <div class=\"fg-line\">\n            <input type=\"text\" class=\"form-control\" placeholder=\"邮箱\">\n        </div>\n    </div>\n\n    <div class=\"input-group m-b-20\">\n        <span class=\"input-group-addon\"><i class=\"zmdi zmdi-male\"></i></span>\n        <div class=\"fg-line\">\n            <input type=\"password\" class=\"form-control\" placeholder=\"密码\">\n        </div>\n    </div>\n\n    <div class=\"clearfix\"></div>\n\n    <div class=\"checkbox\">\n        <label>\n            <input type=\"checkbox\" value=\"\">\n            <i class=\"input-helper\"></i>\n            接受协议\n        </label>\n    </div>\n\n    <a href=\"\" class=\"btn btn-login btn-danger btn-float\"><i class=\"zmdi zmdi-arrow-forward\"></i></a>\n\n    <ul class=\"login-navigation\">\n        <li data-block=\"#l-login\" class=\"bgm-green\">登陆</li>\n        <li data-block=\"#l-forget-password\" class=\"bgm-orange\">忘记密码?</li>\n    </ul>\n</div>\n\n<!-- Forgot Password -->\n<div class=\"lc-block\" id=\"l-forget-password\">\n    <p class=\"text-left\">请输入账户的注册邮箱，以找回密码</p>\n\n    <div class=\"input-group m-b-20\">\n        <span class=\"input-group-addon\"><i class=\"zmdi zmdi-email\"></i></span>\n        <div class=\"fg-line\">\n            <input type=\"text\" class=\"form-control\" placeholder=\"邮箱\">\n        </div>\n    </div>\n\n    <a href=\"\" class=\"btn btn-login btn-danger btn-float\"><i class=\"zmdi zmdi-arrow-forward\"></i></a>\n\n    <ul class=\"login-navigation\">\n        <li data-block=\"#l-login\" class=\"bgm-green\">登录</li>\n        <li data-block=\"#l-register\" class=\"bgm-red\">注册</li>\n    </ul>\n</div>\n\n\n<!-- Older IE warning message -->\n<!--[if lt IE 9]>\n<div class=\"ie-warning\">\n    <h1 class=\"c-white\">Warning!!</h1>\n    <p>You are using an outdated version of Internet Explorer, please upgrade <br/>to any of the following web browsers to access this website.</p>\n    <div class=\"iew-container\">\n        <ul class=\"iew-download\">\n            <li>\n                <a href=\"http://www.google.com/chrome/\">\n                    <img src=\"img/browsers/chrome.png\" alt=\"\">\n                    <div>Chrome</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"https://www.mozilla.org/en-US/firefox/new/\">\n                    <img src=\"img/browsers/firefox.png\" alt=\"\">\n                    <div>Firefox</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"http://www.opera.com\">\n                    <img src=\"img/browsers/opera.png\" alt=\"\">\n                    <div>Opera</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"https://www.apple.com/safari/\">\n                    <img src=\"img/browsers/safari.png\" alt=\"\">\n                    <div>Safari</div>\n                </a>\n            </li>\n            <li>\n                <a href=\"http://windows.microsoft.com/en-us/internet-explorer/download-ie\">\n                    <img src=\"img/browsers/ie.png\" alt=\"\">\n                    <div>IE (New)</div>\n                </a>\n            </li>\n        </ul>\n    </div>\n    <p>Sorry for the inconvenience!</p>\n</div>\n<![endif]-->\n\n<!-- Javascript Libraries -->\n<script src=\"${ctxPath}/static/vendors/bower_components/jquery/2.1.4/jquery.min.js?ver=1.0\"></script>\n<script src=\"${ctxPath}/static/vendors/bower_components/bootstrap/3.3.6/js/bootstrap.min.js?ver=1.0\"></script>\n\n<script src=\"${ctxPath}/static/vendors/bower_components/Waves/0.7.4/waves.min.js?ver=1.0\"></script>\n\n<!-- Placeholder for IE9 -->\n<!--[if IE 9 ]>\n<script src=\"${ctxPath}/static/vendors/bower_components/jquery-placeholder/jquery.placeholder.min.js?ver=1.0\"></script>\n<![endif]-->\n\n<script src=\"${ctxPath}/static/js/functions.js?ver=1.0\"></script>\n\n</body>\n\n</html>\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/message/history/message.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>历史消息列表</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n\n                <div class=\"hidden-xs\" id=\"MessageTableToolbar\" role=\"group\">\n                    <div class=\"col-sm-4\">\n                        <#NameCon id=\"condition\" placeholder=\"名称\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"Message.search()\"/>\n\n                    @if(shiro.hasPermission(\"/message/history\")){\n                        <#button name=\"清空\" icon=\"fa-remove\"  btnCss=\"danger\" clickFun=\"Message.clear()\" space=\"true\"/>\n                    @}\n                </div>\n                <#table id=\"MessageTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/message/history/message.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/message/history/message_view.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"${item.id}\">\n            <div class=\"row\">\n                <div class=\"col-sm-12 b-r\">\n                            <#input name=\"消息模板\" value=\"${item.tplCode}\"  readonly=\"readonly\"/>\n                </div>\n                <div class=\"col-sm-12 b-r\">\n                            <#input name=\"接收人\" value=\"${item.receiver}\" underline=\"true\"  readonly=\"readonly\"/>\n                </div>\n                <div class=\"col-sm-12\">\n                            <#textarea  name=\"消息内容\" value=\"${item.content}\"  readonly=\"readonly\" rows=\"3\" cols=\"50\"/>\n                </div>\n            </div>\n\n        </div>\n    </div>\n</div>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/message/sender/sender.html",
    "content": "@layout(\"/common/layout.html\"){\n\n<div class=\"block-header\">\n    <h2>发送器列表</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n\n                <div class=\"hidden-xs\" id=\"MessageSenderTableToolbar\" role=\"group\">\n                    <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"MessageSender.openAdd()\"/>\n                </div>\n                <#table id=\"MessageSenderTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/message/sender/sender.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/message/sender/sender_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"\">\n            <div class=\"row\">\n                <div class=\"col-sm-12 b-r\">\n                            <#input id=\"name\" name=\"名称\"/>\n\n                </div>\n                <div class=\"col-sm-12 b-r\">\n                    <#input id=\"className\" name=\"类名\" underline=\"true\"/>\n                </div>\n                <div class=\"col-sm-12\">\n                            <#input id=\"tplCode\" name=\"外部模板编号\" underline=\"true\"/>\n                </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"MessageSenderInfoDlg.addSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"MessageSenderInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/message/sender/sender_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/message/sender/sender_edit.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"${item.id}\">\n            <div class=\"row\">\n                <div class=\"col-sm-12 b-r\">\n                            <#input id=\"id\" name=\"ID\" value=\"${item.id}\" underline=\"true\"  readonly=\"readonly\"/>\n                </div>\n                <div class=\"col-sm-12 b-r\">\n                            <#input id=\"name\" name=\"名称\" value=\"${item.name}\" />\n                </div>\n                <div class=\"col-sm-12\">\n                            <#input id=\"className\" name=\"类名\" value=\"${item.className}\" underline=\"true\"/>\n                </div>\n                <div class=\"col-sm-12 b-r\">\n                            <#input id=\"tplCode\" name=\"外部模板编号\" value=\"${item.tplCode}\" />\n                </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"MessageSenderInfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"MessageSenderInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/message/sender/sender_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/message/template/template.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>模板列表</h2>\n</div>\n\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n\n                <div class=\"hidden-xs\" id=\"MessageTemplateTableToolbar\" role=\"group\">\n                    <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"MessageTemplate.openAdd()\"/>\n                </div>\n                <#table id=\"MessageTemplateTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/message/template/template.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/message/template/template_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"\">\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <#input id=\"code\" name=\"编号\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                <#input id=\"title\" name=\"标题\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                    <#select id=\"type\" name=\"消息类型\">\n                        @for(dict in constant.getDicts('消息类型')){\n                        <option value=\"${dict.value}\">${dict.name}</option>\n                        @}\n                    </#select>\n                </div>\n                <div class=\"col-sm-6\">\n                    <#select id=\"idMessageSender\" name=\"发送器\">\n                        @for(dict in messageSenderList){\n                        <option value=\"${dict.id}\">${dict.name}</option>\n                        @}\n                    </#select>\n                </div>\n\n                <div class=\"col-sm-6\">\n                    <#textarea id=\"cond\" name=\"发送条件\" rows=\"5\" cols=\"50\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                    <#textarea id=\"content\" name=\"内容\"  rows=\"5\" cols=\"50\"/>\n                </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"MessageTemplateInfoDlg.addSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"MessageTemplateInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/message/template/template_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/message/template/template_edit.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"${item.id}\">\n            <div class=\"row\">\n                <div class=\"col-sm-6\">\n                    <#input id=\"code\" name=\"编号\" value=\"${item.code}\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                    <#input id=\"title\" name=\"标题\" value=\"${item.title}\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                    <#select id=\"type\" name=\"消息类型\">\n                        @for(dict in constant.getDicts('消息类型')){\n                        <option value=\"${dict.value}\"\n                        @if(dict.value == (item.type+\"\")){\n                        selected\n                        @}\n                        >${dict.name}</option>\n                        @}\n                    </#select>\n            </div>\n            <div class=\"col-sm-6\">\n                <#select id=\"idMessageSender\" name=\"发送器\">\n                    @for(sender in messageSenderList){\n                    <option value=\"${sender.id}\"\n                    @if(sender.id == item.idMessageSender ){\n                        selected\n                    @}\n                    >${sender.name}</option>\n                    @}\n                </#select>\n            </div>\n\n        <div class=\"col-sm-6\">\n            <#textarea id=\"cond\" name=\"发送条件\" rows=\"5\" cols=\"50\" value=\"${item.cond}\"/>\n        </div>\n        <div class=\"col-sm-6\">\n            <#textarea id=\"content\" name=\"内容\"  rows=\"5\" cols=\"50\" value=\"${item.content}\"/>\n        </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"MessageTemplateInfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"MessageTemplateInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/message/template/template_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/cfg/cfg.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>参数管理</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"hidden-xs\" id=\"CfgTableToolbar\" role=\"group\">\n                    <div class=\"col-sm-3\">\n                        <#NameCon id=\"cfgName\" placeholder=\"参数名\" />\n                    </div>\n                    <div class=\"col-sm-3\">\n                        <#NameCon id=\"cfgValue\" placeholder=\"参数值\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"Cfg.search()\"/>\n                    <#button name=\"重置\" icon=\"fa-refresh\" clickFun=\"Cfg.reset()\" btnCss=\"info\" space=\"true\"/>\n                    @if(shiro.hasPermission(\"/cfg/add\")){\n                        <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Cfg.openAddCfg()\" space=\"true\"/>\n                    @}\n                </div>\n                <#table id=\"CfgTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/cfg/cfg.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/cfg/cfg_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"\">\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                            <#input id=\"cfgName\" name=\"参数名\"/>\n                            <#input id=\"cfgValue\" name=\"参数值\" underline=\"true\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                            <#input id=\"cfgDesc\" name=\"参数描述\" underline=\"true\"/>\n                </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"CfgInfoDlg.addSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"CfgInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/cfg/cfg_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/cfg/cfg_edit.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n            <input type=\"hidden\" id=\"id\" value=\"${item.id}\">\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                            <#input id=\"id\" name=\"自增主键\" value=\"${item.id}\" disabled=\"disabled\"/>\n                            <#input id=\"cfgName\" name=\"参数名\" value=\"${item.cfgName}\" />\n                </div>\n                <div class=\"col-sm-6\">\n                            <#input id=\"cfgValue\" name=\"参数值\" value=\"${item.cfgValue}\" underline=\"true\"/>\n                            <#input id=\"cfgDesc\" name=\"参数描述\" value=\"${item.cfgDesc}\" />\n                </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"CfgInfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"CfgInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/cfg/cfg_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/dept/dept.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>部门管理</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"hidden-xs\" id=\"DeptTableToolbar\" role=\"group\">\n                    <div class=\"col-sm-4\">\n                        <#NameCon id=\"condition\" placeholder=\"名称\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"Dept.search()\"/>\n\n                    @if(shiro.hasPermission(\"/dept/add\")){\n                        <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Dept.openAddDept()\" space=\"true\"/>\n                    @}\n                </div>\n                <#table id=\"DeptTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n\n<script src=\"${ctxPath}/static/modular/system/dept/dept.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/dept/dept_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\" id=\"deptInfoForm\">\n\n            <input type=\"hidden\" id=\"id\" value=\"\">\n\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                    <#input id=\"simplename\" name=\"部门名称\" underline=\"true\"/>\n\n                    <#input id=\"fullname\" name=\"部门全称\" underline=\"true\"/>\n\n                    <#input id=\"tips\" name=\"备注\" underline=\"true\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                    <#input id=\"num\" name=\"排序\" underline=\"true\"/>\n\n                    <#input id=\"pName\" name=\"上级部门\" readonly=\"readonly\" hidden=\"pid\"\n                            clickFun=\"DeptInfoDlg.showDeptSelectTree(); return false;\"\n                            style=\"background-color: #ffffff !important;\"/>\n                </div>\n            </div>\n\n            <!-- 父级部门的选择框 -->\n            <div id=\"parentDeptMenu\" class=\"menuContent\"\n                 style=\"display: none; position: absolute; z-index: 200;\">\n                <ul id=\"parentDeptMenuTree\" class=\"ztree tree-box\" style=\"width: 245px !important;\"></ul>\n            </div>\n\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"DeptInfoDlg.addSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"DeptInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/dept/dept_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/dept/dept_edit.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\" id=\"deptInfoForm\">\n\n            <input type=\"hidden\" id=\"id\" value=\"${dept.id}\">\n\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                    <#input id=\"simplename\" name=\"部门名称\" underline=\"true\" value=\"${dept.simplename}\"/>\n\n                    <#input id=\"fullname\" name=\"部门全称\" underline=\"true\" value=\"${dept.fullname}\"/>\n\n                    <#input id=\"tips\" name=\"备注\" underline=\"true\" value=\"${dept.tips}\"/>\n                </div>\n                <div class=\"col-sm-6\">\n                    <#input id=\"num\" name=\"排序\" underline=\"true\" value=\"${dept.num}\"/>\n\n                    <#input id=\"pName\" name=\"上级部门\" readonly=\"readonly\" hidden=\"pid\"\n                            hiddenValue=\"${dept.pid}\" value=\"${pName}\"\n                            clickFun=\"DeptInfoDlg.showDeptSelectTree(); return false;\"\n                            style=\"background-color: #ffffff !important;\"/>\n                </div>\n            </div>\n\n            <!-- 父级部门的选择框 -->\n            <div id=\"parentDeptMenu\" class=\"menuContent\"\n                 style=\"display: none; position: absolute; z-index: 200;\">\n                <ul id=\"parentDeptMenuTree\" class=\"ztree tree-box\" style=\"width: 245px !important;\"></ul>\n            </div>\n\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"DeptInfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"DeptInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/dept/dept_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/dict/dict.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>字典管理</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"hidden-xs\" id=\"DictTableToolbar\" role=\"group\">\n                    <div class=\"col-sm-4\">\n                        <#NameCon id=\"condition\" placeholder=\"名称\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"Dict.search()\"/>\n\n                    @if(shiro.hasPermission(\"/dict/add\")){\n                        <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Dict.openAddDict()\" space=\"true\"/>\n                    @}\n\n                </div>\n                <#table id=\"DictTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n\n<script src=\"${ctxPath}/static/modular/system/dict/dict.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/dict/dict_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n\n            <input type=\"hidden\" id=\"id\" value=\"\">\n\n            <div class=\"row\">\n                <div class=\"col-sm-12\" id=\"itemsArea\">\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-2 control-label\">字典名称</label>\n                        <div class=\"col-sm-2\">\n                            <input class=\"form-control\" id=\"dictName\" type=\"text\">\n                        </div>\n                        <div class=\"col-sm-2\">\n                            <#button btnCss=\"info\" name=\"增加\" icon=\"fa-plus\" clickFun=\"DictInfoDlg.addItem()\"/>\n                        </div>\n                    </div>\n                    <div class=\"hr-line-dashed\"></div>\n\n                </div>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"DictInfoDlg.addSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"DictInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <script type=\"text/template\" id=\"itemTemplate\">\n        <div class=\"form-group\" name=\"dictItem\" id=\"dictItem\">\n            <label class=\"col-sm-2 control-label\">值</label>\n            <div class=\"col-sm-2\">\n                <input class=\"form-control\" type=\"text\" name=\"itemNum\">\n            </div>\n            <label class=\"col-sm-2 control-label\" style=\"width: 8%;\">名称</label>\n            <div class=\"col-sm-2\">\n                <input class=\"form-control\" type=\"text\" name=\"itemName\">\n            </div>\n            <div class=\"col-sm-4\">\n                <#button btnCss=\"danger\" name=\"删除\" id=\"cancel\" icon=\"fa-remove\" clickFun=\"DictInfoDlg.deleteItem(event)\"/>\n            </div>\n        </div>\n    </script>\n\n    <script src=\"${ctxPath}/static/modular/system/dict/dict_info.js\"></script>\n@}"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/dict/dict_edit.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n\n            <input type=\"hidden\" id=\"id\" value=\"\">\n\n            <div class=\"row\">\n                <div class=\"col-sm-12\" id=\"itemsArea\">\n                    <input type=\"hidden\" id=\"itemSize\" value=\"${subDicts.~size!0}\" />\n                    <div class=\"form-group\">\n                        <label class=\"col-sm-2 control-label\">字典名称</label>\n                        <div class=\"col-sm-2\">\n                            <input class=\"form-control\" id=\"dictName\" type=\"text\" value=\"${dict.name}\">\n                            <input type=\"hidden\" id=\"dictId\" value=\"${dict.id}\">\n                        </div>\n                        <div class=\"col-sm-2\">\n                            <#button btnCss=\"info\" name=\"增加\" icon=\"fa-plus\" clickFun=\"DictInfoDlg.addItem()\"/>\n                        </div>\n                    </div>\n                    <div class=\"hr-line-dashed\"></div>\n                    @for(item in subDicts){\n                        <div class=\"form-group\" name=\"dictItem\" id=\"dictItem${itemLP.index}\">\n                            <label class=\"col-sm-2 control-label\">值</label>\n                            <div class=\"col-sm-2\">\n                                <input class=\"form-control\" type=\"text\" name=\"itemNum\" value=\"${item.value}\">\n                            </div>\n                            <label class=\"col-sm-2 control-label\" style=\"width: 8%;\">名称</label>\n                            <div class=\"col-sm-2\">\n                                <input class=\"form-control\" type=\"text\" name=\"itemName\" value=\"${item.name}\">\n                            </div>\n                            <div class=\"col-sm-4\">\n                                <#button name=\"删除\" icon=\"fa-remove\" btnCss=\"danger\"  id=\"cancel\"  clickFun=\"DictInfoDlg.deleteItem(event)\"/>\n                            </div>\n                        </div>\n                    @}\n                </input>\n            </div>\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"DictInfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"DictInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n    </div>\n\n    <script type=\"text/template\" id=\"itemTemplate\">\n        <div class=\"form-group\" name=\"dictItem\" id=\"dictItem\">\n            <label class=\"col-sm-2 control-label\">值</label>\n            <div class=\"col-sm-2\">\n                <input class=\"form-control\" type=\"text\" name=\"itemNum\">\n            </div>\n            <label class=\"col-sm-2 control-label\" style=\"width: 8%;\">名称</label>\n            <div class=\"col-sm-2\">\n                <input class=\"form-control\" type=\"text\" name=\"itemName\">\n            </div>\n            <div class=\"col-sm-4\">\n                <#button btnCss=\"danger\" name=\"删除\" id=\"cancel\"   clickFun=\"DictInfoDlg.deleteItem(event)\"/>\n            </div>\n        </div>\n    </script>\n\n    <script src=\"${ctxPath}/static/modular/system/dict/dict_info.js\"></script>\n@}"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/menu/menu.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>菜单管理</h2>\n</div>\n\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"hidden-xs\" id=\"menuTableToolbar\" role=\"group\">\n                    <div class=\"col-sm-4\">\n                        <#NameCon id=\"menuName\" placeholder=\"菜单名称\" />\n                    </div>\n                    <div class=\"col-sm-4\">\n                        <#NameCon id=\"level\" placeholder=\"层级\" type=\"number\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"Menu.search()\"/>\n\n                    @if(shiro.hasPermission(\"/menu/add\")){\n                        <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Menu.openAddMenu()\" space=\"true\"/>\n                    @}\n                </div>\n                <#table id=\"menuTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n\n<script src=\"${ctxPath}/static/modular/system/menu/menu.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/menu/menu_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n\t<div class=\"card-body card-padding\">\n\t\t<div class=\"form-horizontal\" id=\"menuInfoForm\">\n\t\t\n\t\t\t<input type=\"hidden\" id=\"id\" value=\"\">\n\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col-sm-6 b-r\">\n\t\t\t\t\t<#input id=\"name\" name=\"名称\" underline=\"true\" />\n\t\t\t\t\t<#input id=\"code\" name=\"菜单编号\" underline=\"true\" />\n\t\t\t\t\t<#input id=\"pcodeName\" name=\"父级编号\" underline=\"true\"\n\t\t\t\t\t\t\thidden=\"pcode\" readonly=\"readonly\"\n\t\t\t\t\t\t\tclickFun=\"MenuInfoDlg.showMenuSelectTree(); return false;\"\n\t\t\t\t\t\t\tstyle=\"background-color: #ffffff !important;\"\n\t\t\t\t\t\t\tselectFlag=\"true\" selectId=\"pcodeTreeDiv\" selectTreeId=\"pcodeTree\" selectStyle=\"width:244px !important;\"/>\n\t\t\t\t\t<#select id=\"ismenu\" name=\"是否是菜单\">\n\t\t\t\t\t\t@for(dict in constant.getDicts('是否')){\n\t\t\t\t\t\t<option value=\"${dict.value}\">${dict.name}</option>\n\t\t\t\t\t\t@}\n\t\t\t\t\t</#select>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"col-sm-6\">\n\t\t\t\t\t<#input id=\"url\" name=\"请求地址\" underline=\"true\" />\n\t\t\t\t\t<#input id=\"num\" name=\"排序\" underline=\"true\" type=\"number\"/>\n\t\t\t\t\t<#input id=\"icon\" name=\"图标\" underline=\"false\" />\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<div class=\"row btn-group-m-t\">\n\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t<#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"MenuInfoDlg.addSubmit()\"/>\n\t\t\t\t\t<#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"MenuInfoDlg.close()\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t</div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/menu/menu_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/menu/menu_edit.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\" id=\"menuInfoForm\">\n\n            <input type=\"hidden\" id=\"id\" value=\"${menu.id}\">\n            <input type=\"hidden\" id=\"ismenuValue\" value=\"${menu.ismenu}\">\n\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                    <#input id=\"name\" name=\"名称\" value=\"${menu.name}\" underline=\"true\" />\n                    <#input id=\"code\" name=\"菜单编号\" value=\"${menu.code}\" underline=\"true\" />\n                    <#input id=\"pcodeName\" name=\"父级编号\" value=\"${menu.pcodeName}\" underline=\"true\"\n                            hidden=\"pcode\" readonly=\"readonly\" hiddenValue=\"${menu.pcode}\"\n                            clickFun=\"MenuInfoDlg.showMenuSelectTree(); return false;\"\n                            style=\"background-color: #ffffff !important;\"\n                            selectFlag=\"true\" selectId=\"pcodeTreeDiv\" selectTreeId=\"pcodeTree\" selectStyle=\"width:244px !important;\"/>\n                    <#select id=\"ismenu\" name=\"是否是菜单\">\n                        @for(dict in constant.getDicts('是否')){\n                        <option value=\"${dict.value}\">${dict.name}</option>\n                        @}\n                    </#select>\n\n                </div>\n                <div class=\"col-sm-6\">\n                    <#input id=\"url\" name=\"请求地址\" value=\"${menu.url}\" underline=\"true\" />\n                    <#input id=\"num\" name=\"排序\" value=\"${menu.num}\" underline=\"true\" type=\"number\" />\n                    <#input id=\"icon\" name=\"图标\" underline=\"false\" value=\"${menu.icon}\"/>\n                </div>\n            </div>\n\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"MenuInfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"MenuInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/menu/menu_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/role/role.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>角色管理</h2>\n</div>\n\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"hidden-xs\" id=\"roleTableToolbar\" role=\"group\">\n                    <div class=\"col-sm-4\">\n                    <#NameCon id=\"roleName\" placeholder=\"角色名称\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"Role.search()\" />\n                    @if(shiro.hasPermission(\"/role/add\")){\n                        <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Role.openAddRole()\" space=\"true\"/>\n                    @}\n                </div>\n                <#table id=\"roleTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/role/role.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/role/role_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n\t<div class=\"card-body card-padding\">\n\t\t<div class=\"form-horizontal\" id=\"roleInfoForm\">\n\t\t\n\t\t\t<input type=\"hidden\" id=\"id\" value=\"\">\n\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col-sm-6 b-r\">\n\t\t\t\t\t<#input id=\"name\" name=\"角色名称\" underline=\"true\"/>\n\t\t\t\t\t<#input id=\"pName\" name=\"上级名称\" underline=\"true\" hidden=\"pid\" readonly=\"readonly\"\n\t\t\t\t\t\t\tclickFun=\"RolInfoDlg.showPNameSelectTree(); return false;\"\n\t\t\t\t\t\t\tstyle=\"background-color: #ffffff !important;\"/>\n\t\t\t\t\t<#input id=\"deptName\" name=\"部门名称\" hidden=\"deptid\" readonly=\"readonly\"\n\t\t\t\t\t\t\tclickFun=\"RolInfoDlg.showDeptSelectTree(); return false;\"\n\t\t\t\t\t\t\tstyle=\"background-color: #ffffff !important;\"/>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"col-sm-6\">\n\t\t\t\t\t<#input id=\"tips\" name=\"别名\" underline=\"true\"/>\n\t\t\t\t\t<#input id=\"num\" name=\"排序\" type=\"number\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- 这是部门下拉框 -->\n\t\t\t<div id=\"deptContent\" class=\"menuContent\"\n\t\t\t\tstyle=\"display: none; position: absolute; z-index: 200;\">\n\t\t\t\t<ul id=\"deptTree\" class=\"ztree tree-box\" style=\"width: 250px !important;\"></ul>\n\t\t\t</div>\n\t\t\t\n\t\t\t<!-- 这是父级菜单下拉框 -->\n\t\t\t<div id=\"pNameContent\" class=\"menuContent\"\n\t\t\t\tstyle=\"display: none; position: absolute; z-index: 200;\">\n\t\t\t\t<ul id=\"pNameTree\" class=\"ztree tree-box\" style=\"width: 250px !important;\"></ul>\n\t\t\t</div>\n\n\t\t\t<div class=\"row btn-group-m-t\">\n\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t<#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"RolInfoDlg.addSubmit()\"/>\n\t\t\t\t\t<#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"RolInfoDlg.close()\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t</div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/role/role_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/role/role_assign.html",
    "content": "@layout(\"/common/include.html\"){\n\n\n<script type=\"text/javascript\">\n    $(function () {\n        var index = parent.layer.getFrameIndex(window.name); //获取窗口索引\n\n        $(\"#btn_close\").bind(\"click\", function () {\n            parent.layer.close(index);\n        });\n\n        $(\"#btn_save\").bind(\"click\", function () {\n            var ids = Feng.zTreeCheckedNodes(\"zTree\");\n            var ajax = new $ax(Feng.ctxPath + \"/role/setAuthority\", function (data) {\n                Feng.success(\"分配角色成功!\");\n                window.parent.Role.table.refresh();\n                parent.layer.close(index);\n            }, function (data) {\n                Feng.error(\"分配角色失败!\"\n                    + data.responseJSON.message + \"!\");\n            });\n            ajax.set(\"roleId\", \"${roleId}\");\n            ajax.set(\"ids\", ids);\n            ajax.start();\n        });\n\n        initZtree();\n    });\n\n    function initZtree() {\n        var setting = {\n            check: {\n                enable: true,\n                chkboxType: { \"Y\": \"ps\", \"N\": \"ps\" }\n            },\n            data: {\n                simpleData: {\n                    enable: true\n                }\n            },\n            view: {\n                showIcon: false\n            }\n        };\n\n        var ztree = new $ZTree(\"zTree\", \"/menu/menuTreeListByRoleId/\"\n            + \"${roleId}\");\n        ztree.setSettings(setting);\n        ztree.init();\n    }\n</script>\n\n\n<!-- 配置grid -->\n<div class=\"container\" style=\"padding:  0px 10px !important;margin-top: -10px;\">\n    <div class=\"row\">\n        <div class=\"card\">\n            <div class=\"card-header\">\n                <h2>${roleName!}</h2>\n            </div>\n            <div class=\"card-body card-padding\">\n                <ul id=\"zTree\" class=\"ztree\"></ul>\n            </div>\n        </div>\n    </div>\n    <div class=\"row\">\n        <div class=\"col-md-12\">\n            <button class=\"btn btn-sm btn-info\" type=\"button\" id=\"btn_save\">\n                <i class=\"ace-icon fa fa-check bigger-110\"></i>保存\n            </button>\n            &nbsp;\n            <button class=\"btn btn-sm btn-danger\" type=\"button\" id=\"btn_close\">\n                <i class=\"ace-icon fa fa-close bigger-110\"></i>关闭\n            </button>\n        </div>\n    </div>\n</div>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/role/role_edit.html",
    "content": " @layout(\"/common/include.html\"){\n<div class=\"card\">\n\t<div class=\"card-body card-padding\">\n\t\t<div class=\"form-horizontal\" id=\"roleInfoForm\">\n\t\t\n\t\t\t<input type=\"hidden\" id=\"id\" value=\"${role.id}\">\n\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col-sm-6 b-r\">\n\t\t\t\t\t<#input id=\"name\" name=\"角色名称\" underline=\"true\" value=\"${role.name}\"/>\n\t\t\t\t\t<#input id=\"pName\" name=\"上级名称\" underline=\"true\" hidden=\"pid\" hiddenValue=\"${role.pid}\" readonly=\"readonly\" value=\"${pName}\"\n\t\t\t\t\t\t\tclickFun=\"RolInfoDlg.showPNameSelectTree(); return false;\"\n\t\t\t\t\t\t\tstyle=\"background-color: #ffffff !important;\"/>\n\t\t\t\t\t<#input id=\"deptName\" name=\"部门名称\" hidden=\"deptid\" hiddenValue=\"${role.deptid}\" readonly=\"readonly\" value=\"${deptName}\"\n\t\t\t\t\t\t\tclickFun=\"RolInfoDlg.showDeptSelectTree(); return false;\"\n\t\t\t\t\t\t\tstyle=\"background-color: #ffffff !important;\"/>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"col-sm-6\">\n\t\t\t\t\t<#input id=\"tips\" name=\"别名\" underline=\"true\" value=\"${role.tips}\"/>\n\t\t\t\t\t<#input id=\"num\" name=\"排序\" value=\"${role.num}\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- 这是部门下拉框 -->\n\t\t\t<div id=\"deptContent\" class=\"menuContent\"\n\t\t\t\tstyle=\"display: none; position: absolute; z-index: 200;\">\n\t\t\t\t<ul id=\"deptTree\" class=\"ztree tree-box\" style=\"width: 250px !important;\"></ul>\n\t\t\t</div>\n\t\t\t\n\t\t\t<!-- 这是父级菜单下拉框 -->\n\t\t\t<div id=\"pNameContent\" class=\"menuContent\"\n\t\t\t\tstyle=\"display: none; position: absolute; z-index: 200;\">\n\t\t\t\t<ul id=\"pNameTree\" class=\"ztree tree-box\" style=\"width: 250px !important;\"></ul>\n\t\t\t</div>\n\n\t\t\t<div class=\"row btn-group-m-t\">\n\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t<#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"RolInfoDlg.editSubmit()\"/>\n\t\t\t\t\t<#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"RolInfoDlg.close()\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t</div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/role/role_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/task/task.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>任务管理</h2>\n</div>\n\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"hidden-xs\" id=\"TaskTableToolbar\" role=\"group\">\n                    <div class=\"col-sm-4\">\n                        <#NameCon id=\"name\" placeholder=\"名称\" />\n                    </div>\n                    <#button name=\"搜索\" icon=\"fa-search\" clickFun=\"Task.search()\"/>\n                    @if(shiro.hasPermission(\"/task/add\")){\n                        <#button name=\"添加\" icon=\"fa-plus\" clickFun=\"Task.openAddTask()\" space=\"true\"/>\n                    @}\n                </div>\n                <#table id=\"TaskTable\"/>\n            </div>\n        </div>\n    </div>\n</div>\n\n<script src=\"${ctxPath}/static/modular/system/task/task.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/task/task_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n\n            <input type=\"hidden\" id=\"id\" value=\"\">\n\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                            <#input id=\"name\" name=\"任务名\"/>\n                            <#textarea id=\"jobClass\" name=\"执行类\" underline=\"true\" rows=\"3\" cols=\"50\"/>\n                            <#textarea id=\"data\" name=\"执行参数\" underline=\"true\" rows=\"3\"  cols=\"50\"/>\n                </div>\n\n                <div class=\"col-sm-6\">\n                            <#input id=\"cron\" name=\"定时规则\"/>\n                            <#textarea id=\"note\" name=\"任务说明\" underline=\"true\" rows=\"3\"  cols=\"50\"/>\n                </div>\n            </div>\n\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"TaskInfoDlg.addSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"TaskInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/task/task_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/task/task_edit.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"form-horizontal\">\n\n            <input type=\"hidden\" id=\"id\" value=\"${item.id}\">\n\n            <div class=\"row\">\n                <div class=\"col-sm-6 b-r\">\n                    <#input id=\"id\" name=\"自增主键\" value=\"${item.id}\" disabled=\"disabled\"/>\n                    <#input id=\"name\" name=\"任务名\" value=\"${item.name}\" underline=\"true\"  />\n                    <#textarea id=\"jobClass\" name=\"执行类\" value=\"${item.jobClass}\" underline=\"true\"  rows=\"3\"  cols=\"50\"/>\n                    <#textarea id=\"data\" name=\"执行参数\" value=\"${item.data}\" underline=\"true\"  rows=\"3\"  cols=\"50\"/>\n                </div>\n\n                <div class=\"col-sm-6\">\n                            <#input id=\"cron\" name=\"定时规则\" value=\"${item.cron}\" />\n                            <#textarea id=\"note\" name=\"任务说明\" value=\"${item.note}\"  rows=\"3\"  cols=\"50\"/>\n                </div>\n            </div>\n\n            <div class=\"row btn-group-m-t\">\n                <div class=\"col-sm-10\">\n                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"TaskInfoDlg.editSubmit()\"/>\n                    <#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"TaskInfoDlg.close()\"/>\n                </div>\n            </div>\n        </div>\n\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/task/task_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/task/task_log.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"row\">\n    <div class=\"col-sm-12\">\n            <div class=\"card-body card-padding\">\n                <div class=\"row row-lg\">\n                    <div class=\"col-sm-12\">\n                        <#table id=\"TaskLogTable\"/>\n                    </div>\n                </div>\n            </div>\n    </div>\n</div>\n<script type=\"text/javascript\">\n    var taskId = \"${taskId}\";\n</script>\n<script src=\"${ctxPath}/static/modular/system/task/task_log.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/user/user.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n\t<h2>用户管理</h2>\n</div>\n\n<div class=\"card\">\n\t<div class=\"card-body card-padding\">\n\t\t<div class=\"row row-lg\">\n\t\t\t<div class=\"col-sm-12\">\n\t\t\t\t<div class=\"row\">\n\t\t\t\t\t<div class=\"col-lg-2 col-sm-3\" style=\"padding-right:0px;\">\n\t\t\t\t\t\t<div class=\"panel panel-default panel-ztree\">\n\t\t\t\t\t\t\t<div class=\"panel-heading\" style=\"padding:5px;\">组织机构</div>\n\t\t\t\t\t\t\t<div class=\"panel-body dept-tree\">\n\t\t\t\t\t\t\t\t<ul id=\"deptTree\" class=\"ztree\"></ul>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"col-lg-10 col-sm-9\" >\n\t\t\t\t\t\t<div class=\"hidden-xs\" id=\"managerTableToolbar\" role=\"group\">\n\t\t\t\t\t\t\t<div class=\"col-lg-2 col-sm-4\">\n\t\t\t\t\t\t\t\t<#NameCon id=\"name\"  placeholder=\"帐号/姓名/手机号\"/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"col-lg-2 col-sm-4\">\n\t\t\t\t\t\t\t\t<#TimeCon id=\"beginTime\" placeholder=\"创建起始日期\"/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"col-lg-2 col-sm-4\">\n\t\t\t\t\t\t\t\t<#TimeCon id=\"endTime\" placeholder=\"创建结束日期\"/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<#button name=\"搜索\" icon=\"fa-search\" clickFun=\"MgrUser.search()\"/>\n\t\t\t\t\t\t\t\t<#button name=\"重置\" icon=\"fa-refresh\" btnCss=\"info\" clickFun=\"MgrUser.resetSearch()\" space=\"true\"/>\n\t\t\t\t\t\t\t@if(shiro.hasPermission(\"/mgr/add\")){\n\t\t\t\t\t\t\t<#button name=\"添加\" icon=\"fa-plus\" btnCss=\"primary\" clickFun=\"MgrUser.openAddMgr()\" space=\"true\"/>\n\t\t\t\t\t\t\t@}\n\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<#table id=\"managerTable\"/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/user/user.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/user/user_add.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n\t<div class=\"card-body card-padding\">\n\t\t<div class=\"form-horizontal\" id=\"userInfoForm\">\n\t\t\n\t\t\t<input type=\"hidden\" id=\"id\" value=\"\">\n\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col-sm-6 b-r\">\n\t\t\t\t\t<#input id=\"account\" name=\"账户\" underline=\"false\"/>\n\n\t\t\t\t\t<#select id=\"sex\" name=\"性别\" underline=\"false\">\n\t\t\t\t\t\t@for(dict in constant.getDicts('性别')){\n\t\t\t\t\t\t<option value=\"${dict.value}\">${dict.name}</option>\n\t\t\t\t\t\t@}\n\t\t\t\t\t</#select>\n\n\t\t\t\t\t<#input id=\"password\" name=\"密码\" underline=\"false\" type=\"password\"/>\n\n\t\t\t\t\t<#input id=\"roleid\" name=\"角色\" underline=\"false\" disabled=\"disabled\"/>\n\n\t\t\t\t\t<#input id=\"email\" name=\"邮箱\" type=\"email\"/>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"col-sm-6\">\n\t\t\t\t\t<div id=\"driverInfoContent\">\n\t\t\t\t\t\t<#input id=\"name\" name=\"姓名\" underline=\"false\"/>\n\n\t\t\t\t\t\t<#datePicker id=\"birthday\" name=\"出生日期\" underline=\"false\" type=\"date\"/>\n\n\t\t\t\t\t\t<#input id=\"rePassword\" name=\"确认密码\" type=\"password\" underline=\"false\"/>\n\n\t\t\t\t\t\t<#input id=\"citySel\" name=\"部门\" underline=\"true\" readonly=\"readonly\" hidden=\"deptid\"\n\t\t\t\t\t\t\t\tclickFun=\"UserInfoDlg.showDeptSelectTree(); return false;\"\n\t\t\t\t\t\t\t\tstyle=\"background-color: #ffffff !important;\"/>\n\n\t\t\t\t\t\t<#input id=\"phone\" name=\"电话\"/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- 这是部门选择的下拉框 -->\n\t\t\t<div id=\"menuContent\" class=\"menuContent\"\n\t\t\t\tstyle=\"display: none; position: absolute; z-index: 200;\">\n\t\t\t\t<ul id=\"treeDemo\" class=\"ztree tree-box\" style=\"width: 270px !important;\"></ul>\n\t\t\t</div>\n\n\t\t\t<div class=\"row btn-group-m-t\">\n\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t<#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"UserInfoDlg.addSubmit()\"/>\n\t\t\t\t\t<#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"UserInfoDlg.close()\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t</div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/user/user_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/user/user_chpwd.html",
    "content": "@layout(\"/common/layout.html\"){\n<div class=\"block-header\">\n    <h2>个人资料</h2>\n</div>\n<div class=\"card-body card-padding\">\n    <div class=\"card\">\n        <div class=\"card-body card-padding\">\n            <div class=\"card\">\n                <div class=\"card-body card-padding\" style=\"border:none !important; \">\n                    <div class=\"form-horizontal\">\n                        <div class=\"row\">\n                            <div class=\"col-sm-12\">\n                                <#input id=\"oldPwd\" name=\"原密码\" underline=\"true\" type=\"password\"/>\n                                <#input id=\"newPwd\" name=\"新密码\" underline=\"true\" type=\"password\"/>\n                                <#input id=\"rePwd\" name=\"新密码验证\" type=\"password\"/>\n                            </div>\n                        </div>\n                        <div class=\"row btn-group-m-t\">\n                            <div class=\"col-sm-10\">\n                                <#button btnCss=\"primary\" name=\"提 交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"UserInfoDlg.chPwd()\"/>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/user/user_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/user/user_edit.html",
    "content": "@layout(\"/common/include.html\"){\n<div class=\"card\">\n\t<div class=\"card-body card-padding\">\n\t\t<div class=\"form-horizontal\" id=\"userInfoForm\">\n\t\t\t\n\t\t\t<input type=\"hidden\" id=\"id\" value=\"${user.id}\">\n\t\t\t<input type=\"hidden\" id=\"sexValue\" value=\"${user.sex}\">\n\n\t\t\t\n\t\t\t<div class=\"row\">\n\t\t\t\t<div class=\"col-sm-6 b-r\">\n\t\t\t\t\t<#input id=\"account\" name=\"账户\" underline=\"true\" value=\"${user.account}\"/>\n\n\t\t\t\t\t<#select id=\"sex\" name=\"性别\" underline=\"true\">\n\t\t\t\t\t\t@for(dict in constant.getDicts('性别')){\n\t\t\t\t\t\t<option value=\"${dict.value}\">${dict.name}</option>\n\t\t\t\t\t\t@}\n\t\t\t\t\t</#select>\n\n\t\t\t\t\t<#input id=\"roleid\" name=\"角色\" underline=\"true\" value=\"${roleName}\" disabled=\"disabled\"/>\n\n\t\t\t\t\t<#input id=\"email\" name=\"邮箱\" type=\"email\" value=\"${user.email}\"/>\n\n\t\t\t\t</div>\n\t\t\t\t<div class=\"col-sm-6\">\n\t\t\t\t\t<div id=\"driverInfoContent\">\n\t\t\t\t\t\t<#input id=\"name\" name=\"姓名\" underline=\"true\" value=\"${user.name}\"/>\n\n\t\t\t\t\t\t<#input id=\"birthday\" name=\"出生日期\" underline=\"true\" type=\"date\"\n\t\t\t\t\t\t\t\tvalue=\"${user.birthday}\"\n\t\t\t\t\t\t\t\tclickFun=\"laydate({istime: false, format: 'YYYY-MM-DD'})\" />\n\n\t\t\t\t\t\t<#input id=\"citySel\" name=\"部门\" underline=\"true\" readonly=\"readonly\" hidden=\"deptid\" hiddenValue=\"${user.deptid}\" value=\"${deptName}\"\n\t\t\t\t\t\t\t\tclickFun=\"UserInfoDlg.showDeptSelectTree(); return false;\"\n\t\t\t\t\t\t\t\tstyle=\"background-color: #ffffff !important;\"/>\n\n\t\t\t\t\t\t<#input id=\"phone\" name=\"电话\" value=\"${user.phone}\"/>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t<!-- 这是部门选择的下拉框 -->\n\t\t\t<div id=\"menuContent\" class=\"menuContent\"\n\t\t\t\tstyle=\"display: none; position: absolute; z-index: 200;\">\n\t\t\t\t<ul id=\"treeDemo\" class=\"ztree tree-box\" style=\"width: 270px !important;\"></ul>\n\t\t\t</div>\n\n\t\t\t<div class=\"row btn-group-m-t\">\n\t\t\t\t<div class=\"col-sm-10\">\n\t\t\t\t\t<#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\" clickFun=\"UserInfoDlg.editSubmit()\"/>\n\t\t\t\t\t<#button btnCss=\"danger\" name=\"取消\" id=\"cancel\" icon=\"fa-eraser\" clickFun=\"UserInfoDlg.close()\"/>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t</div>\n</div>\n<script src=\"${ctxPath}/static/modular/system/user/user_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/user/user_roleassign.html",
    "content": "@layout(\"/common/include.html\"){\n\n\n<script type=\"text/javascript\">\n    $(function () {\n\n        var index = parent.layer.getFrameIndex(window.name); //获取窗口索引\n\n        $(\"#btn_close\").bind(\"click\", function () {\n            parent.layer.close(index);\n        });\n\n        $(\"#btn_save\").bind(\"click\", function () {\n            var ids = Feng.zTreeCheckedNodes(\"zTree\");\n            var ajax = new $ax(Feng.ctxPath + \"/mgr/setRole\", function (data) {\n                Feng.success(\"分配角色成功!\");\n                window.parent.MgrUser.table.refresh();\n                parent.layer.close(index);\n            }, function (data) {\n                Feng.error(\"分配角色失败!\" + data.responseJSON.message + \"!\");\n            });\n            ajax.set(\"roleIds\", ids);\n            ajax.set(\"userId\", \"${userId}\");\n            ajax.start();\n        });\n\n        initZtree();\n    });\n\n    function initZtree() {\n        var setting = {\n            check: {\n                enable: true,\n                chkboxType: {\n                    \"Y\": \"\",\n                    \"N\": \"\"\n                }\n            },\n            data: {\n                simpleData: {\n                    enable: true\n                }\n            }\n        };\n\n        var ztree = new $ZTree(\"zTree\", \"/role/roleTreeListByUserId/${userId}\");\n        ztree.setSettings(setting);\n        ztree.init();\n    }\n</script>\n\n\n<!-- 配置grid -->\n<div class=\"container\"\n     style=\"padding:  0px 10px !important; margin-top: -10px; text-align: center !important;\">\n    <div class=\"row\">\n        <div class=\"card\">\n\n            <div class=\"card-body card-padding\">\n                <ul id=\"zTree\" class=\"ztree\"></ul>\n            </div>\n        </div>\n    </div>\n    <div class=\"row\">\n        <div class=\"col-md-12\">\n            <button class=\"btn btn-sm btn-info\" type=\"button\" id=\"btn_save\">\n                <i class=\"ace-icon fa fa-check bigger-110\"></i> 保存\n            </button>\n            &nbsp;\n            <button class=\"btn btn-sm btn-danger\" type=\"button\" id=\"btn_close\">\n                <i class=\"ace-icon fa fa-close bigger-110\"></i> 关闭\n            </button>\n        </div>\n    </div>\n</div>\n\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/WEB-INF/view/system/user/user_view.html",
    "content": "@layout(\"/common/layout.html\"){\n\n<div class=\"block-header\">\n    <h2>个人资料</h2>\n</div>\n<div class=\"card\">\n    <div class=\"card-body card-padding\">\n        <div class=\"row row-lg\">\n            <div class=\"col-sm-12\">\n                <div class=\"card\">\n                    <div class=\"card-body card-padding\" style=\"border:none !important; \">\n                        <div class=\"form-horizontal\" id=\"userInfoForm\">\n\n                            <input type=\"hidden\" id=\"id\" value=\"${user.id}\">\n                            <input type=\"hidden\" id=\"sexValue\" value=\"${user.sex}\">\n                            <div class=\"row\">\n                                <div class=\"col-sm-6 b-r\">\n                                    <#avatar id=\"avatar\" name=\"头像\" underline=\"true\" avatarImg=\"${user.avatar}\"/>\n                                    <#input id=\"account\" name=\"账户\" underline=\"true\" value=\"${user.account}\" disabled=\"disabled\" />\n                                    <#select id=\"sex\" name=\"性别\" underline=\"true\" value=\"${user.sex}\">\n                                        <option value=\"1\">男</option>\n                                        <option value=\"2\">女</option>\n                                    </#select>\n\n                                    <#input id=\"roleid\" name=\"角色\" underline=\"true\" value=\"${roleName}\" disabled=\"disabled\"/>\n\n                                    <#input id=\"email\" name=\"邮箱\" type=\"email\" value=\"${user.email}\"/>\n                                </div>\n                                <div class=\"col-sm-6\">\n                                    <div id=\"driverInfoContent\">\n                                        <#input id=\"name\" name=\"姓名\" underline=\"true\" value=\"${user.name}\"/>\n\n\n                                        <#datePicker id=\"birthday\" name=\"出生日期\" value=\"${user.birthday}\"/>\n\n                                        <#input id=\"citySel\" name=\"部门\" underline=\"true\" readonly=\"readonly\"\n                                        value=\"${deptName}\"\n                                        hidden=\"deptid\" hiddenValue=\"${user.deptid}\"\n                                        clickFun=\"UserInfoDlg.showInfoDeptSelectTree(); return false;\"\n                                        style=\"background-color: #ffffff !important;\"\n                                        selectFlag=\"true\" selectId=\"menuContent\" selectTreeId=\"treeDemo\"\n                                        selectStyle=\"width:250px !important;\"/>\n\n                                        <#input id=\"phone\" name=\"电话\" value=\"${user.phone}\"/>\n                                    </div>\n                                </div>\n                            </div>\n\n                            <div class=\"progress progress-striped\" id=\"progressTipArea\" style=\"margin-top: 20px;\">\n                                <div id=\"progressBar\" style=\"width: 0%\" aria-valuemax=\"100\" aria-valuemin=\"0\"\n                                     aria-valuenow=\"0\" role=\"progressbar\" class=\"progress-bar progress-bar-info\">\n                                </div>\n                            </div>\n\n                            <div class=\"row btn-group-m-t\">\n                                <div class=\"col-sm-10\">\n                                    <#button btnCss=\"info\" name=\"提交\" id=\"ensure\" icon=\"fa-check\"\n                                    clickFun=\"UserInfoDlg.editSubmit()\"/>\n                                </div>\n                            </div>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        </div>\n    </div>\n</div>\n\n<script src=\"${ctxPath}/static/modular/system/user/user_info.js\"></script>\n@}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/_fstyle.css",
    "content": ".button-margin {\n\tmargin-left: 15px !important;\n}\n\n.input-none-margin {\n\tmargin: 0px !important;\n}\n\n.btn-margin-left {\n\tmargin-left: 15px !important;\n}\n\n.table-head {\n\tfloat: left;\n\twidth: 100%;\n\theight: auto;\n}\n\n.head-scu-label {\n\tmargin-top: 35px;\n}\n\n.head-scu-btn {\n\tmargin-top: 68px;\n}\n\n.line-margin {\n\tmargin: 8px 0 !important;\n}\n\n.be-driver-checkbox {\n\tmargin-top: 7px;\n}\n\n.btn-group-m-t {\n\tmargin-top: 20px;\n}\n\n.upload-btn {\n\twhite-space: nowrap;\n}\n\n.tree-box {\n\tborder-radius: 0px !important;\n\tbox-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2) !important;\n\tbackground: rgb(250, 250, 250) none repeat scroll 0% 0% !important;\n\tborder: 1px solid rgb(204, 204, 204) !important;\n\toverflow-y: scroll !important;\n\toverflow-x: auto !important;\n\tmargin-top: 0px !important;\n\twidth: 224px !important;\n\tmax-height: 160px !important;\n\t-moz-user-select: none !important;\n}\n.dept-tree {\n\tpadding:10px\n}\n\n.w-e-text-container{\n\theight: 150px !important;\n}\n\n.editorHeight{\n\theight: 170px;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/app.css",
    "content": "/*\n * Load Main Bootstrap LESS files\n */\n/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 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  -ms-text-size-adjust: 100%;\n  -webkit-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  font-size: 2em;\n  margin: 0.67em 0;\n}\nmark {\n  background: #ff0;\n  color: #000;\n}\nsmall {\n  font-size: 80%;\n}\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\nsup {\n  top: -0.5em;\n}\nsub {\n  bottom: -0.25em;\n}\nimg {\n  border: 0;\n}\nsvg:not(:root) {\n  overflow: hidden;\n}\nfigure {\n  margin: 1em 40px;\n}\nhr {\n  box-sizing: content-box;\n  height: 0;\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  color: inherit;\n  font: inherit;\n  margin: 0;\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  border: 0;\n  padding: 0;\n}\ninput {\n  line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\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-appearance: textfield;\n  box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n  border: 0;\n  padding: 0;\n}\ntextarea {\n  overflow: auto;\n}\noptgroup {\n  font-weight: bold;\n}\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\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    background: transparent !important;\n    color: #000 !important;\n    box-shadow: none !important;\n    text-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    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  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  -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  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n  font-family: roboto;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #5e5e5e;\n  background-color: #edecec;\n}\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\na {\n  color: #2196f3;\n  text-decoration: none;\n}\na:hover,\na:focus {\n  color: #0a6ebd;\n  text-decoration: none;\n}\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n  outline: none !important;\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: 2px;\n}\n.img-thumbnail {\n  padding: 3px;\n  line-height: 1.42857143;\n  background-color: #ffffff;\n  border: 1px solid #ededed;\n  border-radius: 2px;\n  -webkit-transition: all 0.2s ease-in-out;\n  -o-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n}\n.img-circle {\n  border-radius: 50%;\n}\nhr {\n  margin-top: 18px;\n  margin-bottom: 18px;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\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: #000000;\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: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 18px;\n  margin-bottom: 9px;\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: 9px;\n  margin-bottom: 9px;\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: 33px;\n}\nh2,\n.h2 {\n  font-size: 27px;\n}\nh3,\n.h3 {\n  font-size: 23px;\n}\nh4,\n.h4 {\n  font-size: 17px;\n}\nh5,\n.h5 {\n  font-size: 13px;\n}\nh6,\n.h6 {\n  font-size: 12px;\n}\np {\n  margin: 0 0 9px;\n}\n.lead {\n  margin-bottom: 18px;\n  font-size: 14px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .lead {\n    font-size: 19.5px;\n  }\n}\nsmall,\n.small {\n  font-size: 92%;\n}\nmark,\n.mark {\n  background-color: #ffa829;\n  padding: .2em;\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: #777777;\n}\n.text-primary {\n  color: #2196f3;\n}\na.text-primary:hover,\na.text-primary:focus {\n  color: #0c7cd5;\n}\n.text-success {\n  color: #67bd6a;\n}\na.text-success:hover,\na.text-success:focus {\n  color: #49a84d;\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: #ffa829;\n}\na.text-warning:hover,\na.text-warning:focus {\n  color: #f59200;\n}\n.text-danger {\n  color: #f6675d;\n}\na.text-danger:hover,\na.text-danger:focus {\n  color: #f33a2c;\n}\n.bg-primary {\n  color: #fff;\n  background-color: #2196f3;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #0c7cd5;\n}\n.bg-success {\n  background-color: #67bd6a;\n}\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #49a84d;\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: #ffa829;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #f59200;\n}\n.bg-danger {\n  background-color: #f6675d;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #f33a2c;\n}\n.page-header {\n  padding-bottom: 8px;\n  margin: 36px 0 18px;\n  border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 9px;\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  list-style: none;\n  margin-left: -5px;\n}\n.list-inline > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\ndl {\n  margin-top: 0;\n  margin-bottom: 18px;\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    clear: left;\n    text-align: right;\n    overflow: hidden;\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 #777777;\n}\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\nblockquote {\n  padding: 9px 18px;\n  margin: 0 0 18px;\n  font-size: 16.25px;\n  border-left: 5px solid #eeeeee;\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: #777777;\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  border-right: 5px solid #eeeeee;\n  border-left: 0;\n  text-align: right;\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: 18px;\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: 2px;\n}\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #ffffff;\n  background-color: #333333;\n  border-radius: 2px;\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  box-shadow: none;\n}\npre {\n  display: block;\n  padding: 8.5px;\n  margin: 0 0 9px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: #333333;\n  background-color: #f5f5f5;\n  border: 1px solid #cccccc;\n  border-radius: 2px;\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  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n@media (min-width: 768px) {\n  .container {\n    width: 100%;\n  }\n}\n@media (min-width: 992px) {\n  .container {\n    width: 100%;\n  }\n}\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n.container-fluid {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.row {\n  margin-left: -15px;\n  margin-right: -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-left: 15px;\n  padding-right: 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: #ffffff;\n}\ncaption {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  color: #777777;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 18px;\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: 10px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #f0f0f0;\n}\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #f0f0f0;\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 #f0f0f0;\n}\n.table .table {\n  background-color: #edecec;\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: 7px;\n}\n.table-bordered {\n  border: 1px solid #f0f0f0;\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 #f0f0f0;\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: #f4f4f4;\n}\n.table-hover > tbody > tr:hover {\n  background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-cell;\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: #fffcbe;\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: #fffba4;\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: #67bd6a;\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: #55b559;\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: #ffa829;\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: #ff9e0f;\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: #f6675d;\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: #f55145;\n}\n.table-responsive {\n  overflow-x: auto;\n  min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 13.5px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #f0f0f0;\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  padding: 0;\n  margin: 0;\n  border: 0;\n  min-width: 0;\n}\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 18px;\n  font-size: 19.5px;\n  line-height: inherit;\n  color: #333333;\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: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n  outline: none !important;\n}\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #000000;\n}\n.form-control {\n  display: block;\n  width: 100%;\n  height: 35px;\n  padding: 6px 12px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #000000;\n  background-color: #ffffff;\n  background-image: none;\n  border: 1px solid #e0e0e0;\n  border-radius: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border-color ease-in-out .15s, 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: #b4b4b4;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(180, 180, 180, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(180, 180, 180, 0.6);\n}\n.form-control::-moz-placeholder {\n  color: #999999;\n  opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n  color: #999999;\n}\n.form-control::-webkit-input-placeholder {\n  color: #999999;\n}\n.form-control::-ms-expand {\n  border: 0;\n  background-color: transparent;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #eeeeee;\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: 35px;\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: 40px;\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: 18px;\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-left: -20px;\n  margin-top: 4px \\9;\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  vertical-align: middle;\n  font-weight: normal;\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  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n  min-height: 31px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-left: 0;\n  padding-right: 0;\n}\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 2px;\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: 2px;\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: 30px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n.input-lg {\n  height: 40px;\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n  border-radius: 0px;\n}\nselect.input-lg {\n  height: 40px;\n  line-height: 40px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n.form-group-lg .form-control {\n  height: 40px;\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n  border-radius: 0px;\n}\n.form-group-lg select.form-control {\n  height: 40px;\n  line-height: 40px;\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: 40px;\n  min-height: 35px;\n  padding: 11px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n}\n.has-feedback {\n  position: relative;\n}\n.has-feedback .form-control {\n  padding-right: 43.75px;\n}\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 35px;\n  height: 35px;\n  line-height: 35px;\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: 40px;\n  height: 40px;\n  line-height: 40px;\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: #67bd6a;\n}\n.has-success .form-control {\n  border-color: #67bd6a;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n  border-color: #49a84d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #aedcb0;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #aedcb0;\n}\n.has-success .input-group-addon {\n  color: #67bd6a;\n  border-color: #67bd6a;\n  background-color: #67bd6a;\n}\n.has-success .form-control-feedback {\n  color: #67bd6a;\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: #ffa829;\n}\n.has-warning .form-control {\n  border-color: #ffa829;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n  border-color: #f59200;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffd28f;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffd28f;\n}\n.has-warning .input-group-addon {\n  color: #ffa829;\n  border-color: #ffa829;\n  background-color: #ffa829;\n}\n.has-warning .form-control-feedback {\n  color: #ffa829;\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: #f6675d;\n}\n.has-error .form-control {\n  border-color: #f6675d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n  border-color: #f33a2c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #fbc2bd;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #fbc2bd;\n}\n.has-error .input-group-addon {\n  color: #f6675d;\n  border-color: #f6675d;\n  background-color: #f6675d;\n}\n.has-error .form-control-feedback {\n  color: #f6675d;\n}\n.has-feedback label ~ .form-control-feedback {\n  top: 23px;\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: #9e9e9e;\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  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 25px;\n}\n.form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    text-align: right;\n    margin-bottom: 0;\n    padding-top: 7px;\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: 17px;\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  margin-bottom: 0;\n  font-weight: 400;\n  text-align: center;\n  vertical-align: middle;\n  touch-action: manipulation;\n  cursor: pointer;\n  background-image: none;\n  border: 1px solid transparent;\n  white-space: nowrap;\n  padding: 6px 12px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  border-radius: 2px;\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\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: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n  outline: none !important;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #333333;\n  text-decoration: none;\n}\n.btn:active,\n.btn.active {\n  outline: 0;\n  background-image: none;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n.btn-default {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #8c8c8c;\n}\n.btn-default:hover {\n  color: #333333;\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: #333333;\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: #333333;\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: #ffffff;\n  border-color: #cccccc;\n}\n.btn-default .badge {\n  color: #ffffff;\n  background-color: #333333;\n}\n.btn-default:hover,\n.btn-default:focus,\n.btn-default.focus,\n.btn-default:active,\n.open > .dropdown-toggle.btn-default {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: transparent;\n}\n.btn-default:hover:hover,\n.btn-default:focus:hover,\n.btn-default.focus:hover,\n.btn-default:active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:hover:focus,\n.btn-default:focus:focus,\n.btn-default.focus:focus,\n.btn-default:active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:hover.focus,\n.btn-default:focus.focus,\n.btn-default.focus.focus,\n.btn-default:active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: transparent;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\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  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.btn-default .badge {\n  color: #ffffff;\n  background-color: #333333;\n}\n.btn-primary {\n  color: #ffffff;\n  background-color: #2196f3;\n  border-color: #0d8aee;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #ffffff;\n  background-color: #0c7cd5;\n  border-color: #064475;\n}\n.btn-primary:hover {\n  color: #ffffff;\n  background-color: #0c7cd5;\n  border-color: #0a68b4;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #ffffff;\n  background-color: #0c7cd5;\n  border-color: #0a68b4;\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: #ffffff;\n  background-color: #0a68b4;\n  border-color: #064475;\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: #2196f3;\n  border-color: #0d8aee;\n}\n.btn-primary .badge {\n  color: #2196f3;\n  background-color: #ffffff;\n}\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary.focus,\n.btn-primary:active,\n.open > .dropdown-toggle.btn-primary {\n  color: #ffffff;\n  background-color: #2196f3;\n  border-color: transparent;\n}\n.btn-primary:hover:hover,\n.btn-primary:focus:hover,\n.btn-primary.focus:hover,\n.btn-primary:active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:hover:focus,\n.btn-primary:focus:focus,\n.btn-primary.focus:focus,\n.btn-primary:active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:hover.focus,\n.btn-primary:focus.focus,\n.btn-primary.focus.focus,\n.btn-primary:active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #ffffff;\n  background-color: #2196f3;\n  border-color: transparent;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\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  background-color: #2196f3;\n  border-color: #0d8aee;\n}\n.btn-primary .badge {\n  color: #2196f3;\n  background-color: #ffffff;\n}\n.btn-success {\n  color: #ffffff;\n  background-color: #4caf50;\n  border-color: #449d48;\n}\n.btn-success:focus,\n.btn-success.focus {\n  color: #ffffff;\n  background-color: #3d8b40;\n  border-color: #1e441f;\n}\n.btn-success:hover {\n  color: #ffffff;\n  background-color: #3d8b40;\n  border-color: #327334;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #ffffff;\n  background-color: #3d8b40;\n  border-color: #327334;\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: #ffffff;\n  background-color: #327334;\n  border-color: #1e441f;\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: #4caf50;\n  border-color: #449d48;\n}\n.btn-success .badge {\n  color: #4caf50;\n  background-color: #ffffff;\n}\n.btn-success:hover,\n.btn-success:focus,\n.btn-success.focus,\n.btn-success:active,\n.open > .dropdown-toggle.btn-success {\n  color: #ffffff;\n  background-color: #4caf50;\n  border-color: transparent;\n}\n.btn-success:hover:hover,\n.btn-success:focus:hover,\n.btn-success.focus:hover,\n.btn-success:active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:hover:focus,\n.btn-success:focus:focus,\n.btn-success.focus:focus,\n.btn-success:active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:hover.focus,\n.btn-success:focus.focus,\n.btn-success.focus.focus,\n.btn-success:active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #ffffff;\n  background-color: #4caf50;\n  border-color: transparent;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\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  background-color: #4caf50;\n  border-color: #449d48;\n}\n.btn-success .badge {\n  color: #4caf50;\n  background-color: #ffffff;\n}\n.btn-info {\n  color: #ffffff;\n  background-color: #00bcd4;\n  border-color: #00a5bb;\n}\n.btn-info:focus,\n.btn-info.focus {\n  color: #ffffff;\n  background-color: #008fa1;\n  border-color: #00343b;\n}\n.btn-info:hover {\n  color: #ffffff;\n  background-color: #008fa1;\n  border-color: #006f7d;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #ffffff;\n  background-color: #008fa1;\n  border-color: #006f7d;\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: #ffffff;\n  background-color: #006f7d;\n  border-color: #00343b;\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: #00bcd4;\n  border-color: #00a5bb;\n}\n.btn-info .badge {\n  color: #00bcd4;\n  background-color: #ffffff;\n}\n.btn-info:hover,\n.btn-info:focus,\n.btn-info.focus,\n.btn-info:active,\n.open > .dropdown-toggle.btn-info {\n  color: #ffffff;\n  background-color: #00bcd4;\n  border-color: transparent;\n}\n.btn-info:hover:hover,\n.btn-info:focus:hover,\n.btn-info.focus:hover,\n.btn-info:active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:hover:focus,\n.btn-info:focus:focus,\n.btn-info.focus:focus,\n.btn-info:active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:hover.focus,\n.btn-info:focus.focus,\n.btn-info.focus.focus,\n.btn-info:active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #ffffff;\n  background-color: #00bcd4;\n  border-color: transparent;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\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  background-color: #00bcd4;\n  border-color: #00a5bb;\n}\n.btn-info .badge {\n  color: #00bcd4;\n  background-color: #ffffff;\n}\n.btn-warning {\n  color: #ffffff;\n  background-color: #ff9800;\n  border-color: #e68900;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #ffffff;\n  background-color: #cc7a00;\n  border-color: #663d00;\n}\n.btn-warning:hover {\n  color: #ffffff;\n  background-color: #cc7a00;\n  border-color: #a86400;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #ffffff;\n  background-color: #cc7a00;\n  border-color: #a86400;\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: #ffffff;\n  background-color: #a86400;\n  border-color: #663d00;\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: #ff9800;\n  border-color: #e68900;\n}\n.btn-warning .badge {\n  color: #ff9800;\n  background-color: #ffffff;\n}\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning.focus,\n.btn-warning:active,\n.open > .dropdown-toggle.btn-warning {\n  color: #ffffff;\n  background-color: #ff9800;\n  border-color: transparent;\n}\n.btn-warning:hover:hover,\n.btn-warning:focus:hover,\n.btn-warning.focus:hover,\n.btn-warning:active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:hover:focus,\n.btn-warning:focus:focus,\n.btn-warning.focus:focus,\n.btn-warning:active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:hover.focus,\n.btn-warning:focus.focus,\n.btn-warning.focus.focus,\n.btn-warning:active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #ffffff;\n  background-color: #ff9800;\n  border-color: transparent;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\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  background-color: #ff9800;\n  border-color: #e68900;\n}\n.btn-warning .badge {\n  color: #ff9800;\n  background-color: #ffffff;\n}\n.btn-danger {\n  color: #ffffff;\n  background-color: #f44336;\n  border-color: #f32c1e;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #ffffff;\n  background-color: #ea1c0d;\n  border-color: #891008;\n}\n.btn-danger:hover {\n  color: #ffffff;\n  background-color: #ea1c0d;\n  border-color: #c8180b;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #ffffff;\n  background-color: #ea1c0d;\n  border-color: #c8180b;\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: #ffffff;\n  background-color: #c8180b;\n  border-color: #891008;\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: #f44336;\n  border-color: #f32c1e;\n}\n.btn-danger .badge {\n  color: #f44336;\n  background-color: #ffffff;\n}\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger.focus,\n.btn-danger:active,\n.open > .dropdown-toggle.btn-danger {\n  color: #ffffff;\n  background-color: #f44336;\n  border-color: transparent;\n}\n.btn-danger:hover:hover,\n.btn-danger:focus:hover,\n.btn-danger.focus:hover,\n.btn-danger:active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:hover:focus,\n.btn-danger:focus:focus,\n.btn-danger.focus:focus,\n.btn-danger:active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:hover.focus,\n.btn-danger:focus.focus,\n.btn-danger.focus.focus,\n.btn-danger:active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #ffffff;\n  background-color: #f44336;\n  border-color: transparent;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\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  background-color: #f44336;\n  border-color: #f32c1e;\n}\n.btn-danger .badge {\n  color: #f44336;\n  background-color: #ffffff;\n}\n.btn-link {\n  color: #2196f3;\n  font-weight: normal;\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: #0a6ebd;\n  text-decoration: none;\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: #777777;\n  text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n  border-radius: 2px;\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: 2px;\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: 2px;\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 0.15s linear;\n  -o-transition: opacity 0.15s linear;\n  transition: opacity 0.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-property: height, visibility;\n  transition-property: height, visibility;\n  -webkit-transition-duration: 0.35s;\n  transition-duration: 0.35s;\n  -webkit-transition-timing-function: ease;\n  transition-timing-function: ease;\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: 9;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  list-style: none;\n  font-size: 13px;\n  text-align: left;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 8px 0;\n  overflow: hidden;\n  background-color: rgba(0, 0, 0, 0.08);\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: #333333;\n  white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  text-decoration: none;\n  color: #333333;\n  background-color: rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #333333;\n  text-decoration: none;\n  outline: 0;\n  background-color: rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #e4e4e4;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  cursor: not-allowed;\n}\n.open > .dropdown-menu {\n  display: block;\n}\n.open > a {\n  outline: 0;\n}\n.dropdown-menu-right {\n  left: auto;\n  right: 0;\n}\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #777777;\n  white-space: nowrap;\n}\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: -1;\n}\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px dashed;\n  border-bottom: 4px solid \\9;\n  content: \"\";\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    left: auto;\n    right: 0;\n  }\n  .navbar-right .dropdown-menu-left {\n    left: 0;\n    right: auto;\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-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-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-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-bottom-left-radius: 0;\n  border-top-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-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 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-right-radius: 2px;\n  border-top-left-radius: 2px;\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-right-radius: 0;\n  border-top-left-radius: 0;\n  border-bottom-right-radius: 2px;\n  border-bottom-left-radius: 2px;\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-right-radius: 0;\n  border-top-left-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  float: none;\n  display: table-cell;\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-left: 0;\n  padding-right: 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: 40px;\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n  border-radius: 0px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 40px;\n  line-height: 40px;\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: 2px;\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: 13px;\n  font-weight: normal;\n  line-height: 1;\n  color: #000000;\n  text-align: center;\n  background-color: transparent;\n  border: 1px solid transparent;\n  border-radius: 0;\n}\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 2px;\n}\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 17px;\n  border-radius: 0px;\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-bottom-right-radius: 0;\n  border-top-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-bottom-left-radius: 0;\n  border-top-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  margin-bottom: 0;\n  padding-left: 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: #eeeeee;\n}\n.nav > li.disabled > a {\n  color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #777777;\n  text-decoration: none;\n  background-color: transparent;\n  cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eeeeee;\n  border-color: #2196f3;\n}\n.nav .nav-divider {\n  height: 1px;\n  margin: 8px 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 #ffffff;\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: 2px 2px 0 0;\n}\n.nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #ffffff;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555555;\n  background-color: transparent;\n  border: 1px solid #ffffff;\n  border-bottom-color: transparent;\n  cursor: default;\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  text-align: center;\n  margin-bottom: 5px;\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: 2px;\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 #dddddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 2px 2px 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: #edecec;\n  }\n}\n.nav-pills > li {\n  float: left;\n}\n.nav-pills > li > a {\n  border-radius: 2px;\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: #ffffff;\n  background-color: #2196f3;\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  text-align: center;\n  margin-bottom: 5px;\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: 2px;\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 #dddddd;\n}\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 2px 2px 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: #edecec;\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-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 18px;\n  border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 2px;\n  }\n}\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: 15px;\n  padding-left: 15px;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n  -webkit-overflow-scrolling: touch;\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    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-left: 0;\n    padding-right: 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  padding: 16px 15px;\n  font-size: 17px;\n  line-height: 18px;\n  height: 50px;\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  margin-right: 15px;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 2px;\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: 8px -15px;\n}\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 18px;\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    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: 18px;\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: 16px;\n    padding-bottom: 16px;\n  }\n}\n.navbar-form {\n  margin-left: -15px;\n  margin-right: -15px;\n  padding: 10px 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, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  margin-top: 7.5px;\n  margin-bottom: 7.5px;\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    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 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-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-right-radius: 2px;\n  border-top-left-radius: 2px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.navbar-btn {\n  margin-top: 7.5px;\n  margin-bottom: 7.5px;\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: 16px;\n  margin-bottom: 16px;\n}\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-left: 15px;\n    margin-right: 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: #777777;\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: #777777;\n}\n.navbar-default .navbar-nav > li > a {\n  color: #777777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333333;\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: #555555;\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: #cccccc;\n  background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n  border-color: #dddddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #dddddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888888;\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  background-color: #e7e7e7;\n  color: #555555;\n}\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777777;\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: #333333;\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: #555555;\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: #cccccc;\n    background-color: transparent;\n  }\n}\n.navbar-default .navbar-link {\n  color: #777777;\n}\n.navbar-default .navbar-link:hover {\n  color: #333333;\n}\n.navbar-default .btn-link {\n  color: #777777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #333333;\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: #cccccc;\n}\n.navbar-inverse {\n  background-color: #222222;\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: #ffffff;\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: #ffffff;\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: #ffffff;\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: #444444;\n  background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n  border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #ffffff;\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  background-color: #080808;\n  color: #ffffff;\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: #ffffff;\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: #ffffff;\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: #444444;\n    background-color: transparent;\n  }\n}\n.navbar-inverse .navbar-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n  color: #ffffff;\n}\n.navbar-inverse .btn-link {\n  color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #ffffff;\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: #444444;\n}\n.breadcrumb {\n  padding: 8px 20px;\n  margin-bottom: 18px;\n  list-style: none;\n  background-color: transparent;\n  border-radius: 2px;\n}\n.breadcrumb > li {\n  display: inline-block;\n}\n.breadcrumb > li + li:before {\n  content: \"/\\00a0\";\n  padding: 0 5px;\n  color: #cccccc;\n}\n.breadcrumb > .active {\n  color: #7c7c7c;\n}\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 18px 0;\n  border-radius: 2px;\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  line-height: 1.42857143;\n  text-decoration: none;\n  color: #7e7e7e;\n  background-color: #e2e2e2;\n  border: 1px solid #ffffff;\n  margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-bottom-left-radius: 2px;\n  border-top-left-radius: 2px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-bottom-right-radius: 2px;\n  border-top-right-radius: 2px;\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: #333333;\n  background-color: #d7d7d7;\n  border-color: #ffffff;\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: #ffffff;\n  background-color: #00bcd4;\n  border-color: #ffffff;\n  cursor: default;\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: #777777;\n  background-color: #e2e2e2;\n  border-color: #ffffff;\n  cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-bottom-left-radius: 2px;\n  border-top-left-radius: 2px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-bottom-right-radius: 2px;\n  border-top-right-radius: 2px;\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-bottom-left-radius: 2px;\n  border-top-left-radius: 2px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-bottom-right-radius: 2px;\n  border-top-right-radius: 2px;\n}\n.pager {\n  padding-left: 0;\n  margin: 18px 0;\n  list-style: none;\n  text-align: center;\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: #e2e2e2;\n  border: 1px solid #ffffff;\n  border-radius: 5px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #d7d7d7;\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: #777777;\n  background-color: #e2e2e2;\n  cursor: not-allowed;\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: #ffffff;\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: #ffffff;\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: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n.label-primary {\n  background-color: #2196f3;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #0c7cd5;\n}\n.label-success {\n  background-color: #4caf50;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #3d8b40;\n}\n.label-info {\n  background-color: #00bcd4;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #008fa1;\n}\n.label-warning {\n  background-color: #ff9800;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #cc7a00;\n}\n.label-danger {\n  background-color: #f44336;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #ea1c0d;\n}\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: 400;\n  color: #ffffff;\n  line-height: 1;\n  vertical-align: middle;\n  white-space: nowrap;\n  text-align: center;\n  background-color: #2196f3;\n  border-radius: 2px;\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: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #ffffff;\n  background-color: #2196f3;\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: #f7f7f7;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 20px;\n  font-weight: 200;\n}\n.jumbotron > hr {\n  border-top-color: #dedede;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n  border-radius: 2px;\n  padding-left: 15px;\n  padding-right: 15px;\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-left: 60px;\n    padding-right: 60px;\n  }\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 59px;\n  }\n}\n.thumbnail {\n  display: block;\n  padding: 3px;\n  margin-bottom: 18px;\n  line-height: 1.42857143;\n  background-color: #ffffff;\n  border: 1px solid #ededed;\n  border-radius: 2px;\n  -webkit-transition: border 0.2s ease-in-out;\n  -o-transition: border 0.2s ease-in-out;\n  transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n  margin-left: auto;\n  margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #2196f3;\n}\n.thumbnail .caption {\n  padding: 9px;\n  color: #5e5e5e;\n}\n.alert {\n  padding: 15px;\n  margin-bottom: 18px;\n  border: 1px solid transparent;\n  border-radius: 2px;\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  background-color: rgba(76, 175, 80, 0.7);\n  border-color: transparent;\n  color: #ffffff;\n}\n.alert-success hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n.alert-success .alert-link {\n  color: #e6e6e6;\n}\n.alert-info {\n  background-color: rgba(33, 150, 243, 0.7);\n  border-color: transparent;\n  color: #ffffff;\n}\n.alert-info hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n.alert-info .alert-link {\n  color: #e6e6e6;\n}\n.alert-warning {\n  background-color: rgba(255, 193, 7, 0.7);\n  border-color: transparent;\n  color: #ffffff;\n}\n.alert-warning hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n.alert-warning .alert-link {\n  color: #e6e6e6;\n}\n.alert-danger {\n  background-color: rgba(244, 67, 54, 0.7);\n  border-color: transparent;\n  color: #ffffff;\n}\n.alert-danger hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n.alert-danger .alert-link {\n  color: #e6e6e6;\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@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n  to {\n    background-position: 0 0;\n  }\n}\n.progress {\n  overflow: hidden;\n  height: 18px;\n  margin-bottom: 18px;\n  background-color: #f5f5f5;\n  border-radius: 2px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: 12px;\n  line-height: 18px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #2196f3;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  -o-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\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: #4caf50;\n}\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n  background-color: #00bcd4;\n}\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n  background-color: #ff9800;\n}\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n  background-color: #f44336;\n}\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.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  zoom: 1;\n  overflow: hidden;\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  margin-bottom: 20px;\n  padding-left: 0;\n}\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #ffffff;\n  border: 1px solid #e9e9e9;\n}\n.list-group-item:first-child {\n  border-top-right-radius: 2px;\n  border-top-left-radius: 2px;\n}\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 2px;\n  border-bottom-left-radius: 2px;\n}\na.list-group-item,\nbutton.list-group-item {\n  color: #555555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n  color: #333333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n  text-decoration: none;\n  color: #555555;\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  background-color: #ffffff;\n  color: #b5b4b4;\n  cursor: not-allowed;\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: #b5b4b4;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #000000;\n  background-color: #f5f5f5;\n  border-color: #e9e9e9;\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: #ffffff;\n}\n.list-group-item-success {\n  color: #67bd6a;\n  background-color: #67bd6a;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n  color: #67bd6a;\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: #67bd6a;\n  background-color: #55b559;\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: #67bd6a;\n  border-color: #67bd6a;\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: #ffa829;\n  background-color: #ffa829;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n  color: #ffa829;\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: #ffa829;\n  background-color: #ff9e0f;\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: #ffa829;\n  border-color: #ffa829;\n}\n.list-group-item-danger {\n  color: #f6675d;\n  background-color: #f6675d;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n  color: #f6675d;\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: #f6675d;\n  background-color: #f55145;\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: #f6675d;\n  border-color: #f6675d;\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: 18px;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 1px rgba(0, 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-right-radius: 1px;\n  border-top-left-radius: 1px;\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: 15px;\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 #dddddd;\n  border-bottom-right-radius: 1px;\n  border-bottom-left-radius: 1px;\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-right-radius: 1px;\n  border-top-left-radius: 1px;\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: 1px;\n  border-bottom-left-radius: 1px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-right-radius: 0;\n  border-top-left-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-left: 15px;\n  padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-right-radius: 1px;\n  border-top-left-radius: 1px;\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: 1px;\n  border-top-right-radius: 1px;\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: 1px;\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: 1px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 1px;\n  border-bottom-left-radius: 1px;\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-left-radius: 1px;\n  border-bottom-right-radius: 1px;\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: 1px;\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: 1px;\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 #f0f0f0;\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  border: 0;\n  margin-bottom: 0;\n}\n.panel-group {\n  margin-bottom: 18px;\n}\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 2px;\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 #dddddd;\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 #dddddd;\n}\n.panel-default {\n  border-color: #dddddd;\n}\n.panel-default > .panel-heading {\n  color: #333333;\n  background-color: #f5f5f5;\n  border-color: #dddddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #dddddd;\n}\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #dddddd;\n}\n.panel-primary {\n  border-color: #2196f3;\n}\n.panel-primary > .panel-heading {\n  color: #ffffff;\n  background-color: #2196f3;\n  border-color: #2196f3;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #2196f3;\n}\n.panel-primary > .panel-heading .badge {\n  color: #2196f3;\n  background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #2196f3;\n}\n.panel-success {\n  border-color: #61b555;\n}\n.panel-success > .panel-heading {\n  color: #67bd6a;\n  background-color: #67bd6a;\n  border-color: #61b555;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #61b555;\n}\n.panel-success > .panel-heading .badge {\n  color: #67bd6a;\n  background-color: #67bd6a;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #61b555;\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: #ff760f;\n}\n.panel-warning > .panel-heading {\n  color: #ffa829;\n  background-color: #ffa829;\n  border-color: #ff760f;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ff760f;\n}\n.panel-warning > .panel-heading .badge {\n  color: #ffa829;\n  background-color: #ffa829;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ff760f;\n}\n.panel-danger {\n  border-color: #f54556;\n}\n.panel-danger > .panel-heading {\n  color: #f6675d;\n  background-color: #f6675d;\n  border-color: #f54556;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #f54556;\n}\n.panel-danger > .panel-heading .badge {\n  color: #f6675d;\n  background-color: #f6675d;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #f54556;\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  left: 0;\n  bottom: 0;\n  height: 100%;\n  width: 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: 2px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n  padding: 24px;\n  border-radius: 2px;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: 2px;\n}\n.close {\n  float: right;\n  font-size: 19.5px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n.modal.fade .modal-dialog {\n  -webkit-transform: translate(0, -25%);\n  -ms-transform: translate(0, -25%);\n  -o-transform: translate(0, -25%);\n  transform: translate(0, -25%);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -moz-transition: -moz-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\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: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  background-clip: padding-box;\n  outline: 0;\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 11;\n  background-color: #000000;\n}\n.modal-backdrop.fade {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid transparent;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: transparent;\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 transparent;\n}\n.modal-footer .btn + .btn {\n  margin-left: 5px;\n  margin-bottom: 0;\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, 0.5);\n    box-shadow: 0 5px 15px rgba(0, 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: roboto;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\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  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 12px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.tooltip.in {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.tooltip.top {\n  margin-top: -3px;\n  padding: 5px 0;\n}\n.tooltip.right {\n  margin-left: 3px;\n  padding: 0 5px;\n}\n.tooltip.bottom {\n  margin-top: 3px;\n  padding: 5px 0;\n}\n.tooltip.left {\n  margin-left: -3px;\n  padding: 0 5px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #737373;\n  border-radius: 2px;\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: #737373;\n}\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  right: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #737373;\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: #737373;\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: #737373;\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: #737373;\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: #737373;\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: #737373;\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: #737373;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 9;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: roboto;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\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  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 13px;\n  background-color: #ffffff;\n  background-clip: padding-box;\n  border: 1px solid #ffffff;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\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  margin: 0;\n  padding: 8px 14px;\n  font-size: 13px;\n  background-color: #ffffff;\n  border-bottom: 1px solid #f2f2f2;\n  border-radius: 1px 1px 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  border-width: 10px;\n  content: \"\";\n}\n.popover.top > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-width: 0;\n  border-top-color: #cccccc;\n  border-top-color: #ffffff;\n  bottom: -11px;\n}\n.popover.top > .arrow:after {\n  content: \" \";\n  bottom: 1px;\n  margin-left: -10px;\n  border-bottom-width: 0;\n  border-top-color: #ffffff;\n}\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-left-width: 0;\n  border-right-color: #cccccc;\n  border-right-color: #ffffff;\n}\n.popover.right > .arrow:after {\n  content: \" \";\n  left: 1px;\n  bottom: -10px;\n  border-left-width: 0;\n  border-right-color: #ffffff;\n}\n.popover.bottom > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #cccccc;\n  border-bottom-color: #ffffff;\n  top: -11px;\n}\n.popover.bottom > .arrow:after {\n  content: \" \";\n  top: 1px;\n  margin-left: -10px;\n  border-top-width: 0;\n  border-bottom-color: #ffffff;\n}\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #cccccc;\n  border-left-color: #ffffff;\n}\n.popover.left > .arrow:after {\n  content: \" \";\n  right: 1px;\n  border-right-width: 0;\n  border-left-color: #ffffff;\n  bottom: -10px;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n.carousel-inner > .item {\n  display: none;\n  position: relative;\n  -webkit-transition: 0.6s ease-in-out left;\n  -o-transition: 0.6s ease-in-out left;\n  transition: 0.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 0.6s ease-in-out;\n    -moz-transition: -moz-transform 0.6s ease-in-out;\n    -o-transition: -o-transform 0.6s ease-in-out;\n    transition: transform 0.6s ease-in-out;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n    -moz-perspective: 1000px;\n    perspective: 1000px;\n  }\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    left: 0;\n  }\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    left: 0;\n  }\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    left: 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  left: 0;\n  bottom: 0;\n  width: 15%;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-size: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n  background-color: rgba(0, 0, 0, 0);\n}\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n  left: auto;\n  right: 0;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  outline: 0;\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\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  margin-top: -10px;\n  z-index: 5;\n  display: inline-block;\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  line-height: 1;\n  font-family: serif;\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  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  border: 1px solid #ffffff;\n  border-radius: 10px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n  margin: 0;\n  width: 12px;\n  height: 12px;\n  background-color: #ffffff;\n}\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 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    left: 20%;\n    right: 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  content: \" \";\n  display: table;\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-left: auto;\n  margin-right: 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/*\n * LESS Plugins\n */\n/*\n * Variable and Mixin\n */\n/*\n * Font Icon Family\n */\n/*\n * Grid System\n */\n/* Typography + Scaffolding + Links */\n/* Border Radius */\n/* Tabs */\n/* Form */\n/* Table */\n/*\n * Input Group\n */\n/*\n * Pagination\n */\n/*\n * Popover\n */\n/*\n * Dropdown\n */\n/*\n * Thumbnail\n */\n/*\n * Alerts\n */\n/*\n * Form Validations\n */\n/*\n * Buttons\n */\n/*\n * Thumbnail\n */\n/*\n * Carousel\n */\n/*\n * Modal\n */\n/*\n * Tooltips\n */\n/*\n * Popover\n */\n/*\n * Breadcrumbs\n */\n/*\n * Jumbotron\n */\n/*\n * List Groups\n */\n/*\n * Badges\n */\n/*\n * Material Colors\n */\n/* Bootstrap Branding */\n/*\n * Colors\n */\n/*\n * Blocks\n */\n/*\n * Misc\n */\n/*\n * Font Face\n */\n/*\n * Background Repeat + Position\n */\n/*\n * CSS Animations based on animate.css\n */\n/*\n * CSS Transform - Scale and Rotate\n */\n/*\n * User Select\n */\n/*\n * Background Image Cover\n */\n/*\n * Tab Focus\n */\n/*\n * Pop-in Hover effects\n */\n/*\n *  Override Bootstrap Button Mixin\n */\n/*\n * Scale 3d\n */\n/* \n * Load Font\n */\n/*\n * Roboto Light\n */\n@font-face {\n  font-family: roboto;\n  src: url('../fonts/roboto/Roboto-Light-webfont.eot');\n  src: url('../fonts/roboto/Roboto-Light-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/roboto/Roboto-Light-webfont.woff') format('woff'), url('../fonts/roboto/Roboto-Light-webfont.ttf') format('truetype'), url('../fonts/roboto/Roboto-Light-webfont.svg#icon') format('svg');\n  font-weight: 300;\n  font-style: normal;\n}\n/*\n * Roboto Regular\n */\n@font-face {\n  font-family: roboto;\n  src: url('../fonts/roboto/Roboto-Regular-webfont.eot');\n  src: url('../fonts/roboto/Roboto-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/roboto/Roboto-Regular-webfont.woff') format('woff'), url('../fonts/roboto/Roboto-Regular-webfont.ttf') format('truetype'), url('../fonts/roboto/Roboto-Regular-webfont.svg#icon') format('svg');\n  font-weight: 400;\n  font-style: normal;\n}\n/*\n * Roboto Medium\n */\n@font-face {\n  font-family: roboto;\n  src: url('../fonts/roboto/Roboto-Medium-webfont.eot');\n  src: url('../fonts/roboto/Roboto-Medium-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/roboto/Roboto-Medium-webfont.woff') format('woff'), url('../fonts/roboto/Roboto-Medium-webfont.ttf') format('truetype'), url('../fonts/roboto/Roboto-Medium-webfont.svg#icon') format('svg');\n  font-weight: 500;\n  font-style: normal;\n}\n/*\n * Roboto Bold\n */\n@font-face {\n  font-family: roboto;\n  src: url('../fonts/roboto/Roboto-Bold-webfont.eot');\n  src: url('../fonts/roboto/Roboto-Bold-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/roboto/Roboto-Bold-webfont.woff') format('woff'), url('../fonts/roboto/Roboto-Bold-webfont.ttf') format('truetype'), url('../fonts/roboto/Roboto-Bold-webfont.svg#icon') format('svg');\n  font-weight: 700;\n  font-style: normal;\n}\n/*\n * Shadow Light\n */\n@font-face {\n  font-family: shadowsintolight;\n  src: url('../fonts/shadowsintolight/shadowsintolight-webfont.eot');\n  src: url('../fonts/shadowsintolight/shadowsintolight-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/shadowsintolight/shadowsintolight-webfont.woff') format('woff'), url('../fonts/shadowsintolight/shadowsintolight-webfont.ttf') format('truetype'), url('../fonts/shadowsintolight/shadowsintolight-webfont.svg#icon') format('svg');\n  font-weight: 400;\n  font-style: normal;\n}\n/*\n * Vendors\n */\n@font-face {\n  font-family: weather-icons;\n  src: url('../fonts/weather-icons/weather-icons.eot');\n  src: url('../fonts/weather-icons/weather-icons.eot?#iefix') format('embedded-opentype'), url('../fonts/weather-icons/weather-icons.woff') format('woff'), url('../fonts/weather-icons/weather-icons.ttf') format('truetype'), url('../fonts/weather-icons/weather-icons.svg#icon') format('svg');\n  font-weight: 400;\n  font-style: normal;\n}\n#weather-widget [class*=\"icon-\"] {\n  font-family: 'weather-icons';\n  font-style: normal;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.icon-0:before {\n  content: \":\";\n}\n.icon-1:before {\n  content: \"p\";\n}\n.icon-2:before {\n  content: \"S\";\n}\n.icon-3:before {\n  content: \"Q\";\n}\n.icon-4:before {\n  content: \"S\";\n}\n.icon-5:before {\n  content: \"W\";\n}\n.icon-6:before {\n  content: \"W\";\n}\n.icon-7:before {\n  content: \"W\";\n}\n.icon-8:before {\n  content: \"W\";\n}\n.icon-9:before {\n  content: \"I\";\n}\n.icon-10:before {\n  content: \"W\";\n}\n.icon-11:before {\n  content: \"I\";\n}\n.icon-12:before {\n  content: \"I\";\n}\n.icon-13:before {\n  content: \"I\";\n}\n.icon-14:before {\n  content: \"I\";\n}\n.icon-15:before {\n  content: \"W\";\n}\n.icon-16:before {\n  content: \"I\";\n}\n.icon-17:before {\n  content: \"W\";\n}\n.icon-18:before {\n  content: \"U\";\n}\n.icon-19:before {\n  content: \"Z\";\n}\n.icon-20:before {\n  content: \"Z\";\n}\n.icon-21:before {\n  content: \"Z\";\n}\n.icon-22:before {\n  content: \"Z\";\n}\n.icon-23:before {\n  content: \"Z\";\n}\n.icon-24:before {\n  content: \"E\";\n}\n.icon-25:before {\n  content: \"E\";\n}\n.icon-26:before {\n  content: \"3\";\n}\n.icon-27:before {\n  content: \"a\";\n}\n.icon-28:before {\n  content: \"A\";\n}\n.icon-29:before {\n  content: \"a\";\n}\n.icon-30:before {\n  content: \"A\";\n}\n.icon-31:before {\n  content: \"6\";\n}\n.icon-32:before {\n  content: \"1\";\n}\n.icon-33:before {\n  content: \"6\";\n}\n.icon-34:before {\n  content: \"1\";\n}\n.icon-35:before {\n  content: \"W\";\n}\n.icon-36:before {\n  content: \"1\";\n}\n.icon-37:before {\n  content: \"S\";\n}\n.icon-38:before {\n  content: \"S\";\n}\n.icon-39:before {\n  content: \"S\";\n}\n.icon-40:before {\n  content: \"M\";\n}\n.icon-41:before {\n  content: \"W\";\n}\n.icon-42:before {\n  content: \"I\";\n}\n.icon-43:before {\n  content: \"W\";\n}\n.icon-44:before {\n  content: \"a\";\n}\n.icon-45:before {\n  content: \"S\";\n}\n.icon-46:before {\n  content: \"U\";\n}\n.icon-47:before {\n  content: \"S\";\n}\n.btn-file {\n  overflow: hidden;\n  position: relative;\n  vertical-align: middle;\n}\n.btn-file > input {\n  position: absolute;\n  top: 0;\n  right: 0;\n  margin: 0;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  font-size: 23px;\n  height: 100%;\n  width: 100%;\n  direction: ltr;\n  cursor: pointer;\n}\n.fileinput {\n  margin-bottom: 9px;\n  display: inline-block;\n}\n.fileinput .form-control {\n  padding-top: 7px;\n  padding-bottom: 5px;\n  display: inline-block;\n  margin-bottom: 0px;\n  vertical-align: middle;\n  cursor: text;\n}\n.fileinput .thumbnail {\n  overflow: hidden;\n  display: inline-block;\n  margin-bottom: 5px;\n  vertical-align: middle;\n  text-align: center;\n}\n.fileinput .thumbnail > img {\n  max-height: 100%;\n}\n.fileinput .btn {\n  vertical-align: middle;\n}\n.fileinput-exists .fileinput-new,\n.fileinput-new .fileinput-exists {\n  display: none;\n}\n.fileinput-inline .fileinput-controls {\n  display: inline;\n}\n.fileinput-filename {\n  vertical-align: middle;\n  display: inline-block;\n  overflow: hidden;\n}\n.form-control .fileinput-filename {\n  vertical-align: bottom;\n}\n.fileinput.input-group {\n  display: table;\n}\n.fileinput.input-group > * {\n  position: relative;\n  z-index: 2;\n}\n.fileinput.input-group > .btn-file {\n  z-index: 1;\n}\n.fileinput-new.input-group .btn-file,\n.fileinput-new .input-group .btn-file {\n  border-radius: 0 2px 2px 0;\n}\n.fileinput-new.input-group .btn-file.btn-xs,\n.fileinput-new .input-group .btn-file.btn-xs,\n.fileinput-new.input-group .btn-file.btn-sm,\n.fileinput-new .input-group .btn-file.btn-sm {\n  border-radius: 0 2px 2px 0;\n}\n.fileinput-new.input-group .btn-file.btn-lg,\n.fileinput-new .input-group .btn-file.btn-lg {\n  border-radius: 0 2px 2px 0;\n}\n.form-group.has-warning .fileinput .fileinput-preview {\n  color: #ffa829;\n}\n.form-group.has-warning .fileinput .thumbnail {\n  border-color: #ff760f;\n}\n.form-group.has-error .fileinput .fileinput-preview {\n  color: #f6675d;\n}\n.form-group.has-error .fileinput .thumbnail {\n  border-color: #f54556;\n}\n.form-group.has-success .fileinput .fileinput-preview {\n  color: #67bd6a;\n}\n.form-group.has-success .fileinput .thumbnail {\n  border-color: #61b555;\n}\n.input-group-addon:not(:first-child) {\n  border-left: 0;\n}\n/*!\n * Waves v0.7.4\n * http://fian.my.id/Waves \n * \n * Copyright 2014 Alfiana E. Sibuea and other contributors \n * Released under the MIT license \n * https://github.com/fians/Waves/blob/master/LICENSE \n */\n.waves-effect {\n  position: relative;\n  cursor: pointer;\n  display: inline-block;\n  overflow: hidden;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  -webkit-tap-highlight-color: transparent;\n}\n.waves-effect .waves-ripple {\n  position: absolute;\n  border-radius: 50%;\n  width: 100px;\n  height: 100px;\n  margin-top: -50px;\n  margin-left: -50px;\n  opacity: 0;\n  background: rgba(0, 0, 0, 0.2);\n  background: -webkit-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -o-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -moz-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  -webkit-transition: all 0.5s ease-out;\n  -moz-transition: all 0.5s ease-out;\n  -o-transition: all 0.5s ease-out;\n  transition: all 0.5s ease-out;\n  -webkit-transition-property: -webkit-transform, opacity;\n  -moz-transition-property: -moz-transform, opacity;\n  -o-transition-property: -o-transform, opacity;\n  transition-property: transform, opacity;\n  -webkit-transform: scale(0) translate(0, 0);\n  -moz-transform: scale(0) translate(0, 0);\n  -ms-transform: scale(0) translate(0, 0);\n  -o-transform: scale(0) translate(0, 0);\n  transform: scale(0) translate(0, 0);\n  pointer-events: none;\n}\n.waves-effect.waves-light .waves-ripple {\n  background: rgba(255, 255, 255, 0.4);\n  background: -webkit-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -o-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -moz-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n}\n.waves-effect.waves-classic .waves-ripple {\n  background: rgba(0, 0, 0, 0.2);\n}\n.waves-effect.waves-classic.waves-light .waves-ripple {\n  background: rgba(255, 255, 255, 0.4);\n}\n.waves-notransition {\n  -webkit-transition: none !important;\n  -moz-transition: none !important;\n  -o-transition: none !important;\n  transition: none !important;\n}\n.waves-button,\n.waves-circle {\n  -webkit-transform: translateZ(0);\n  -moz-transform: translateZ(0);\n  -ms-transform: translateZ(0);\n  -o-transform: translateZ(0);\n  transform: translateZ(0);\n  -webkit-mask-image: -webkit-radial-gradient(circle, #ffffff 100%, #000000 100%);\n}\n.waves-button,\n.waves-button:hover,\n.waves-button:visited,\n.waves-button-input {\n  white-space: nowrap;\n  vertical-align: middle;\n  cursor: pointer;\n  border: none;\n  outline: none;\n  color: inherit;\n  background-color: rgba(0, 0, 0, 0);\n  font-size: 1em;\n  line-height: 1em;\n  text-align: center;\n  text-decoration: none;\n  z-index: 1;\n}\n.waves-button {\n  padding: 0.85em 1.1em;\n  border-radius: 0.2em;\n}\n.waves-button-input {\n  margin: 0;\n  padding: 0.85em 1.1em;\n}\n.waves-input-wrapper {\n  border-radius: 0.2em;\n  vertical-align: bottom;\n}\n.waves-input-wrapper.waves-button {\n  padding: 0;\n}\n.waves-input-wrapper .waves-button-input {\n  position: relative;\n  top: 0;\n  left: 0;\n  z-index: 1;\n}\n.waves-circle {\n  text-align: center;\n  width: 2.5em;\n  height: 2.5em;\n  line-height: 2.5em;\n  border-radius: 50%;\n}\n.waves-float {\n  -webkit-mask-image: none;\n  -webkit-box-shadow: 0px 1px 1.5px 1px rgba(0, 0, 0, 0.12);\n  box-shadow: 0px 1px 1.5px 1px rgba(0, 0, 0, 0.12);\n  -webkit-transition: all 300ms;\n  -moz-transition: all 300ms;\n  -o-transition: all 300ms;\n  transition: all 300ms;\n}\n.waves-float:active {\n  -webkit-box-shadow: 0px 8px 20px 1px rgba(0, 0, 0, 0.3);\n  box-shadow: 0px 8px 20px 1px rgba(0, 0, 0, 0.3);\n}\n.waves-block {\n  display: block;\n}\n/* Firefox Bug: link not triggered */\na.waves-effect .waves-ripple {\n  z-index: -1;\n}\n/* \n * Load Website related LESS files \n */\n/*\n * Generate Margin Class\n * margin, margin-top, margin-bottom, margin-left, margin-right\n */\n.m-0 {\n  margin: 0px !important;\n}\n.m-t-0 {\n  margin-top: 0px !important;\n}\n.m-b-0 {\n  margin-bottom: 0px !important;\n}\n.m-l-0 {\n  margin-left: 0px !important;\n}\n.m-r-0 {\n  margin-right: 0px !important;\n}\n.m-5 {\n  margin: 5px !important;\n}\n.m-t-5 {\n  margin-top: 5px !important;\n}\n.m-b-5 {\n  margin-bottom: 5px !important;\n}\n.m-l-5 {\n  margin-left: 5px !important;\n}\n.m-r-5 {\n  margin-right: 5px !important;\n}\n.m-10 {\n  margin: 10px !important;\n}\n.m-t-10 {\n  margin-top: 10px !important;\n}\n.m-b-10 {\n  margin-bottom: 10px !important;\n}\n.m-l-10 {\n  margin-left: 10px !important;\n}\n.m-r-10 {\n  margin-right: 10px !important;\n}\n.m-15 {\n  margin: 15px !important;\n}\n.m-t-15 {\n  margin-top: 15px !important;\n}\n.m-b-15 {\n  margin-bottom: 15px !important;\n}\n.m-l-15 {\n  margin-left: 15px !important;\n}\n.m-r-15 {\n  margin-right: 15px !important;\n}\n.m-20 {\n  margin: 20px !important;\n}\n.m-t-20 {\n  margin-top: 20px !important;\n}\n.m-b-20 {\n  margin-bottom: 20px !important;\n}\n.m-l-20 {\n  margin-left: 20px !important;\n}\n.m-r-20 {\n  margin-right: 20px !important;\n}\n.m-25 {\n  margin: 25px !important;\n}\n.m-t-25 {\n  margin-top: 25px !important;\n}\n.m-b-25 {\n  margin-bottom: 25px !important;\n}\n.m-l-25 {\n  margin-left: 25px !important;\n}\n.m-r-25 {\n  margin-right: 25px !important;\n}\n.m-30 {\n  margin: 30px !important;\n}\n.m-t-30 {\n  margin-top: 30px !important;\n}\n.m-b-30 {\n  margin-bottom: 30px !important;\n}\n.m-l-30 {\n  margin-left: 30px !important;\n}\n.m-r-30 {\n  margin-right: 30px !important;\n}\n/*\n * Generate Padding Class\n * padding, padding-top, padding-bottom, padding-left, padding-right\n */\n.p-0 {\n  padding: 0px !important;\n}\n.p-t-0 {\n  padding-top: 0px !important;\n}\n.p-b-0 {\n  padding-bottom: 0px !important;\n}\n.p-l-0 {\n  padding-left: 0px !important;\n}\n.p-r-0 {\n  padding-right: 0px !important;\n}\n.p-5 {\n  padding: 5px !important;\n}\n.p-t-5 {\n  padding-top: 5px !important;\n}\n.p-b-5 {\n  padding-bottom: 5px !important;\n}\n.p-l-5 {\n  padding-left: 5px !important;\n}\n.p-r-5 {\n  padding-right: 5px !important;\n}\n.p-10 {\n  padding: 10px !important;\n}\n.p-t-10 {\n  padding-top: 10px !important;\n}\n.p-b-10 {\n  padding-bottom: 10px !important;\n}\n.p-l-10 {\n  padding-left: 10px !important;\n}\n.p-r-10 {\n  padding-right: 10px !important;\n}\n.p-15 {\n  padding: 15px !important;\n}\n.p-t-15 {\n  padding-top: 15px !important;\n}\n.p-b-15 {\n  padding-bottom: 15px !important;\n}\n.p-l-15 {\n  padding-left: 15px !important;\n}\n.p-r-15 {\n  padding-right: 15px !important;\n}\n.p-20 {\n  padding: 20px !important;\n}\n.p-t-20 {\n  padding-top: 20px !important;\n}\n.p-b-20 {\n  padding-bottom: 20px !important;\n}\n.p-l-20 {\n  padding-left: 20px !important;\n}\n.p-r-20 {\n  padding-right: 20px !important;\n}\n.p-25 {\n  padding: 25px !important;\n}\n.p-t-25 {\n  padding-top: 25px !important;\n}\n.p-b-25 {\n  padding-bottom: 25px !important;\n}\n.p-l-25 {\n  padding-left: 25px !important;\n}\n.p-r-25 {\n  padding-right: 25px !important;\n}\n.p-30 {\n  padding: 30px !important;\n}\n.p-t-30 {\n  padding-top: 30px !important;\n}\n.p-b-30 {\n  padding-bottom: 30px !important;\n}\n.p-l-30 {\n  padding-left: 30px !important;\n}\n.p-r-30 {\n  padding-right: 30px !important;\n}\n/*\n * Generate Font-Size Classes (8px - 20px)\n */\n.f-8 {\n  font-size: 8px !important;\n}\n.f-9 {\n  font-size: 9px !important;\n}\n.f-10 {\n  font-size: 10px !important;\n}\n.f-11 {\n  font-size: 11px !important;\n}\n.f-12 {\n  font-size: 12px !important;\n}\n.f-13 {\n  font-size: 13px !important;\n}\n.f-14 {\n  font-size: 14px !important;\n}\n.f-15 {\n  font-size: 15px !important;\n}\n.f-16 {\n  font-size: 16px !important;\n}\n.f-17 {\n  font-size: 17px !important;\n}\n.f-18 {\n  font-size: 18px !important;\n}\n.f-19 {\n  font-size: 19px !important;\n}\n.f-20 {\n  font-size: 20px !important;\n}\n/*\n * Font Weight\n */\n.f-300 {\n  font-weight: 300 !important;\n}\n.f-400 {\n  font-weight: 400 !important;\n}\n.f-500 {\n  font-weight: 500 !important;\n}\n.f-700 {\n  font-weight: 700 !important;\n}\n/*\n * Position Classes\n */\n.p-relative {\n  position: relative !important;\n}\n.p-absolute {\n  position: absolute !important;\n}\n.p-fixed {\n  position: fixed !important;\n}\n.p-static {\n  position: static !important;\n}\n/*\n * Overflow\n */\n.o-hidden {\n  overflow: hidden !important;\n}\n.o-visible {\n  overflow: visible !important;\n}\n.o-auto {\n  overflow: auto !important;\n}\n/*\n * Display\n */\n.d-block {\n  display: block !important;\n}\n.di-block {\n  display: inline-block !important;\n}\n/* \n * Material Background Colors\n */\n.bgm-white {\n  background-color: #ffffff !important;\n}\n.c-white {\n  color: #ffffff !important;\n}\n.bgm-black {\n  background-color: #000000 !important;\n}\n.c-black {\n  color: #000000 !important;\n}\n.bgm-brown {\n  background-color: #795548 !important;\n}\n.c-brown {\n  color: #795548 !important;\n}\n.bgm-pink {\n  background-color: #e91e63 !important;\n}\n.c-pink {\n  color: #e91e63 !important;\n}\n.bgm-red {\n  background-color: #f44336 !important;\n}\n.c-red {\n  color: #f44336 !important;\n}\n.bgm-blue {\n  background-color: #2196f3 !important;\n}\n.c-blue {\n  color: #2196f3 !important;\n}\n.bgm-purple {\n  background-color: #9c27b0 !important;\n}\n.c-purple {\n  color: #9c27b0 !important;\n}\n.bgm-deeppurple {\n  background-color: #673ab7 !important;\n}\n.c-deeppurple {\n  color: #673ab7 !important;\n}\n.bgm-lightblue {\n  background-color: #03a9f4 !important;\n}\n.c-lightblue {\n  color: #03a9f4 !important;\n}\n.bgm-cyan {\n  background-color: #00bcd4 !important;\n}\n.c-cyan {\n  color: #00bcd4 !important;\n}\n.bgm-teal {\n  background-color: #009688 !important;\n}\n.c-teal {\n  color: #009688 !important;\n}\n.bgm-green {\n  background-color: #4caf50 !important;\n}\n.c-green {\n  color: #4caf50 !important;\n}\n.bgm-lightgreen {\n  background-color: #8bc34a !important;\n}\n.c-lightgreen {\n  color: #8bc34a !important;\n}\n.bgm-lime {\n  background-color: #cddc39 !important;\n}\n.c-lime {\n  color: #cddc39 !important;\n}\n.bgm-yellow {\n  background-color: #ffeb3b !important;\n}\n.c-yellow {\n  color: #ffeb3b !important;\n}\n.bgm-amber {\n  background-color: #ffc107 !important;\n}\n.c-amber {\n  color: #ffc107 !important;\n}\n.bgm-orange {\n  background-color: #ff9800 !important;\n}\n.c-orange {\n  color: #ff9800 !important;\n}\n.bgm-deeporange {\n  background-color: #ff5722 !important;\n}\n.c-deeporange {\n  color: #ff5722 !important;\n}\n.bgm-gray {\n  background-color: #9e9e9e !important;\n}\n.c-gray {\n  color: #9e9e9e !important;\n}\n.bgm-bluegray {\n  background-color: #607d8b !important;\n}\n.c-bluegray {\n  color: #607d8b !important;\n}\n.bgm-indigo {\n  background-color: #3f51b5 !important;\n}\n.c-indigo {\n  color: #3f51b5 !important;\n}\n/*\n * Background Colors\n */\n.bg-black-trp {\n  background-color: rgba(0, 0, 0, 0.1) !important;\n}\n/*\n * Border\n */\n.b-0 {\n  border: 0 !important;\n}\n/*\n * width\n */\n.w-100 {\n  width: 100% !important;\n}\n/*\n * Border Radius \n */\n.brd-2 {\n  border-radius: 2px;\n}\n/*\n * Media - Overriding the Media object to 3.2 version in order to prevent issues like text overflow.\n */\n.media {\n  overflow: visible;\n}\n.media:before,\n.media:after {\n  content: \" \";\n  display: table;\n}\n.media:after {\n  clear: both;\n}\n.media:before,\n.media:after {\n  content: \" \";\n  display: table;\n}\n.media:after {\n  clear: both;\n}\n.media > .pull-left {\n  padding-right: 15px;\n}\n.media > .pull-right {\n  padding-left: 15px;\n}\n.media-heading {\n  font-size: 14px;\n  margin-bottom: 10px;\n}\n.media-body {\n  zoom: 1;\n  display: block;\n  width: auto;\n}\n.media-object {\n  border-radius: 2px;\n}\n.close {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-weight: normal;\n  text-shadow: none;\n}\n.close:hover {\n  color: inherit;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.dl-horizontal dt {\n  text-align: left;\n}\n*,\nbutton,\ninput,\ni,\na {\n  -webkit-font-smoothing: antialiased;\n}\n*,\n*:active,\n*:hover {\n  outline: none !important;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n}\nhtml {\n  overflow-x: hidden\\0/;\n  -ms-overflow-style: none;\n}\nhtml,\nbody {\n  min-height: 100vh;\n}\nbody {\n  font-weight: 400;\n  position: relative;\n}\naudio,\nvideo {\n  outline: none;\n}\np {\n  margin-bottom: 20px;\n}\nsmall {\n  font-size: 11px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small {\n  font-size: 12px;\n}\n#main {\n  position: relative;\n  padding-bottom: 110px;\n  padding-top: 100px;\n}\n.container.c-alt {\n  max-width: 1170px;\n}\n@media (min-width: 768px) and (max-width: 1199px) {\n  #content {\n    padding-left: 15px;\n    padding-right: 15px;\n  }\n}\n@media (min-width: 1200px) {\n  body.sw-toggled #content {\n    padding-left: 268px;\n  }\n}\n@media (min-width: 1200px) {\n  body.sw-toggled #content > .container {\n    width: calc(100% - 30px);\n  }\n}\n.clist {\n  list-style: none;\n}\n.clist > li:before {\n  font-family: 'Material-Design-Iconic-Font';\n  margin: 0 10px 0 -20px;\n  vertical-align: middle;\n}\n.clist.clist-angle > li:before {\n  content: \"\\f2fb\";\n}\n.clist.clist-check > li:before {\n  content: \"\\f26b\";\n}\n.clist.clist-star > li:before {\n  content: \"\\f27d\";\n}\n/*\n * Common header classes & IDs\n * Do not remove this\n */\n.header-inner {\n  list-style: none;\n  padding: 17px 0;\n  margin-bottom: 0;\n  position: relative;\n}\n.header-inner > li:not(.pull-right) {\n  float: left;\n}\n.header-inner > li:not(:last-child) {\n  margin-right: -2px;\n}\n.logo a {\n  color: #fff;\n  text-transform: uppercase;\n  display: block;\n  font-size: 16px;\n}\n#menu-trigger {\n  width: 65px;\n  height: 35px;\n  cursor: pointer;\n}\n#menu-trigger .line-wrap .line {\n  background-color: #fff;\n}\n#menu-trigger:before {\n  content: \"\";\n  position: absolute;\n  top: 13px;\n  left: 7px;\n  width: 45px;\n  height: 45px;\n  border-radius: 50%;\n  background: rgba(255, 255, 255, 0.22);\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  z-index: 0;\n}\n#menu-trigger.open:before {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.top-menu {\n  list-style: none;\n  padding: 0;\n}\n.top-menu > li {\n  display: inline-block;\n  margin: 0 1px;\n  vertical-align: top;\n  min-width: 50px;\n}\n@media (max-width: 767px) {\n  .top-menu > li {\n    position: static !important;\n  }\n}\n.top-menu > li .dropdown-menu-lg {\n  padding: 0;\n}\n.top-menu > li .dropdown-menu-lg .lv-body {\n  min-height: 295px;\n  overflow-x: hidden;\n}\n@media (min-width: 768px) {\n  .top-menu > li:not(#toggle-width) {\n    position: relative;\n  }\n  .top-menu > li:not(#toggle-width):before {\n    left: 0;\n    top: 0;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    -webkit-transform: scale3d(0, 0, 0);\n    -moz-transform: scale3d(0, 0, 0);\n    -ms-transform: scale3d(0, 0, 0);\n    -o-transform: scale3d(0, 0, 0);\n    transform: scale3d(0, 0, 0);\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 250ms;\n    transition-duration: 250ms;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    background-color: rgba(0, 0, 0, 0.12);\n    z-index: 0;\n    border-radius: 2px;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n  .top-menu > li:not(#toggle-width):hover:before,\n  .top-menu > li:not(#toggle-width).open:before {\n    -webkit-transform: scale3d(1, 1, 1);\n    -moz-transform: scale3d(1, 1, 1);\n    -ms-transform: scale3d(1, 1, 1);\n    -o-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n.top-menu > li > a {\n  color: #fff;\n  display: block;\n  text-align: center;\n  z-index: 1;\n  position: relative;\n}\n.top-menu > li > a > .tm-icon {\n  font-size: 24px;\n  line-height: 36px;\n}\n.top-menu > li > a > .tm-label {\n  line-height: 35px;\n  white-space: nowrap;\n  padding: 0 10px;\n  font-size: 14px;\n  text-transform: uppercase;\n}\n.top-menu > li > a > .tmn-counts {\n  position: absolute;\n  font-style: normal;\n  background: #f44336;\n  padding: 1px 5px;\n  border-radius: 2px;\n  right: 7px;\n  top: -3px;\n  font-size: 10px;\n  line-height: 15px;\n}\n@media (max-width: 767px) {\n  .top-menu .dropdown-menu-lg {\n    width: calc(100% - 28px) !important;\n  }\n  .top-menu .dropdown-menu {\n    right: 14px;\n    top: 55px;\n  }\n}\n#notifications {\n  position: relative;\n}\n#notifications .lv-body {\n  overflow-x: hidden;\n}\n#notifications:before {\n  content: \"\";\n  position: absolute;\n  width: 100%;\n  height: calc(100% - 70px);\n  background: url(../img/notifications.png) no-repeat center;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 400ms;\n  transition-duration: 400ms;\n  -webkit-transform: scale(0) rotate(-180deg);\n  -ms-transform: scale(0) rotate(-180deg);\n  -o-transform: scale(0) rotate(-180deg);\n  transform: scale(0) rotate(-180deg);\n  opacity: 0;\n  filter: alpha(opacity=0);\n  top: 42px;\n}\n#notifications.empty:before {\n  -webkit-transform: scale(1) rotate(0deg);\n  -ms-transform: scale(1) rotate(0deg);\n  -o-transform: scale(1) rotate(0deg);\n  transform: scale(1) rotate(0deg);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n/* Full Screen */\n:-webkit-full-screen [data-action=\"fullscreen\"] {\n  display: none;\n}\n:-moz-full-screen [data-action=\"fullscreen\"] {\n  display: none;\n}\n:-ms-fullscreen [data-action=\"fullscreen\"] {\n  display: none;\n}\n:full-screen [data-action=\"fullscreen\"] {\n  display: none;\n}\n:fullscreen [data-action=\"fullscreen\"] {\n  display: none;\n}\n/* ----------------------------- End common header classes and IDs------------------------------------- */\n/*\n * For header type 1 only\n * You may remove these if you opt header 2\n */\n#header {\n  box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);\n  min-height: 70px;\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  position: fixed;\n  z-index: 11;\n  width: 100%;\n  left: 0;\n  top: 0;\n  padding: 0 11px;\n}\n#header:not(.sidebar-toggled).header-up {\n  -webkit-transform: translate3d(0, -70px, 0);\n  transform: translate3d(0, -70px, 0);\n}\n#header .logo a {\n  padding: 7px 10px;\n}\n#top-search-wrap {\n  position: absolute;\n  top: -65px;\n  left: 0;\n  width: 100%;\n  height: 70px;\n  background: #fff;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  z-index: 10;\n}\n#top-search-wrap input[type=\"text\"] {\n  border: 0;\n  height: 40px;\n  padding: 0 10px 0 55px;\n  font-size: 18px;\n  width: 500px;\n  border-radius: 2px;\n  background-color: #efefef;\n  width: 100%;\n}\n#top-search-wrap #top-search-close {\n  position: absolute;\n  top: 15px;\n  font-size: 23px;\n  font-style: normal;\n  width: 45px;\n  text-align: center;\n  border-radius: 2px 0px 0px 2px;\n  cursor: pointer;\n  left: 15px;\n  height: 40px;\n  padding-top: 9px;\n}\n#top-search-wrap #top-search-close:hover {\n  background-color: #e3e3e3;\n}\n@media (max-width: 767px) {\n  #top-search-wrap #top-search-close {\n    right: 7px;\n  }\n}\n.tsw-inner {\n  position: relative;\n  padding: 15px;\n  max-width: 700px;\n  display: block;\n  margin: 0 auto;\n}\n.search-toggled #top-search-wrap {\n  top: 0;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n/* Full Width Layout */\n@media (min-width: 1200px) {\n  #toggle-width .toggle-switch {\n    margin: 9px 30px 0 0;\n  }\n  #toggle-width .toggle-switch .ts-helper {\n    height: 11px;\n    width: 33px;\n  }\n  #toggle-width .toggle-switch .ts-helper:before {\n    width: 20px;\n    height: 20px;\n    top: -5px;\n  }\n  #toggle-width .toggle-switch input:checked + .ts-helper {\n    background: rgba(0, 0, 0, 0.26);\n  }\n  #toggle-width .toggle-switch input:checked + .ts-helper:before {\n    left: 18px;\n    background: #fff;\n  }\n}\n@media (max-width: 1200px) {\n  #toggle-width {\n    display: none;\n  }\n}\n@media (min-width: 1200px) {\n  .sw-toggled #header {\n    padding-left: 15px;\n  }\n  .sw-toggled #menu-trigger {\n    display: none;\n  }\n}\n/* For Stupid IE9 */\n.ie9 #header:not(.sidebar-toggled).header-up {\n  display: none;\n}\n/* ----------------------------- End header type 1 ------------------------------------- */\n/*\n * For Header type 2 only\n * You may remove these if you opt header 1\n */\n#header-2 {\n  box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);\n  position: relative;\n  margin-bottom: -70px;\n  z-index: 10;\n}\n@media (min-width: 768px) {\n  #header-2 {\n    padding: 15px 30px 0;\n  }\n  #header-2:before {\n    content: \"\";\n    position: absolute;\n    bottom: 0;\n    left: 0;\n    background: rgba(0, 0, 0, 0.04);\n    width: 100%;\n    height: 49px;\n  }\n}\n#header-2 .search {\n  margin-bottom: 25px;\n}\n@media (max-width: 767px) {\n  #header-2 .search {\n    padding: 0 20px;\n  }\n}\n#header-2 .search input[type=\"text\"] {\n  width: 100%;\n  background: transparent;\n  border: 0;\n  border-bottom: 1px solid rgba(255, 255, 255, 0.24);\n  color: #fff;\n  font-size: 15px;\n  font-weight: 300;\n  padding: 6px 0 6px 30px;\n}\n#header-2 .search input[type=\"text\"]::-moz-placeholder {\n  color: #ffffff;\n  opacity: 1;\n}\n#header-2 .search input[type=\"text\"]:-ms-input-placeholder {\n  color: #ffffff;\n}\n#header-2 .search input[type=\"text\"]::-webkit-input-placeholder {\n  color: #ffffff;\n}\n#header-2 .search:after {\n  background: #ffeb3b;\n}\n#header-2 .search .fg-line {\n  max-width: 500px;\n  position: relative;\n}\n#header-2 .search .fg-line:after {\n  background: #ffeb3b;\n}\n#header-2 .search .fg-line:before {\n  content: '\\f1c3';\n  font-family: 'Material-Design-Iconic-Font';\n  position: absolute;\n  left: 0;\n  bottom: 1px;\n  color: #fff;\n  font-size: 22px;\n}\n.ha-menu > ul {\n  list-style: none;\n  padding: 0;\n  margin: 0;\n}\n.ha-menu > ul > li {\n  display: inline-block;\n  vertical-align: top;\n}\n@media (max-width: 767px) {\n  .ha-menu > ul > li {\n    display: block;\n  }\n}\n.ha-menu > ul > li:not(.active) > *:not(ul) {\n  color: rgba(255, 255, 255, 0.6);\n}\n.ha-menu > ul > li.active > *:not(ul) {\n  color: #fff;\n  box-shadow: inset 0px -3px 0 0px #ffeb3b;\n}\n@media (max-width: 767px) {\n  .ha-menu > ul > li.active > *:not(ul) {\n    display: block;\n  }\n}\n.ha-menu > ul > li > *:not(ul) {\n  text-transform: uppercase;\n  padding: 15px 12px;\n  display: block;\n}\n.ha-menu > ul > li.open > *:not(ul),\n.ha-menu > ul > li > *:not(ul):hover {\n  color: #fff;\n}\n.ha-menu > ul > li .dropdown-menu {\n  margin-top: -5px;\n  min-width: 100%;\n}\n@media (max-width: 767px) {\n  .ha-menu {\n    width: 200px;\n    position: absolute;\n    top: 65px;\n    left: 8px;\n    box-shadow: 0 0 10px;\n    z-index: 10;\n    padding: 0 10px;\n  }\n  .ha-menu:not(.toggled) {\n    display: none;\n  }\n}\n.sidebar {\n  position: fixed;\n  background: #fff;\n  box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n  height: calc(100% - 65px);\n  top: 65px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  z-index: 10;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  overflow-y: auto;\n}\n.sidebar.toggled {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n#sidebar {\n  width: 268px;\n  -webkit-transform: translate3d(-268px, 0, 0);\n  transform: translate3d(-268px, 0, 0);\n}\n#sidebar.toggled {\n  -webkit-transform: translate3d(0, 0, 0);\n  transform: translate3d(0, 0, 0);\n}\n.profile-menu > a {\n  display: block;\n  height: 129px;\n  margin-bottom: 5px;\n  width: 100%;\n  background: url(../img/profile-menu.png) no-repeat left top;\n  background-size: 100%;\n}\n.profile-menu > a .profile-pic {\n  padding: 12px;\n}\n.profile-menu > a .profile-pic > img {\n  width: 47px;\n  height: 47px;\n  border-radius: 50%;\n  border: 3px solid rgba(0, 0, 0, 0.14);\n  box-sizing: content-box;\n}\n.profile-menu > a .profile-info {\n  background: rgba(0, 0, 0, 0.37);\n  padding: 7px 14px;\n  color: #fff;\n  margin-top: 20px;\n  position: relative;\n}\n.profile-menu > a .profile-info > i {\n  font-size: 19px;\n  line-height: 100%;\n  position: absolute;\n  right: 15px;\n  top: 7px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.profile-menu .main-menu {\n  display: none;\n  margin: 0 0 0;\n  border-bottom: 1px solid #E6E6E6;\n}\n.profile-menu.toggled .profile-info > i {\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  -o-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.main-menu {\n  list-style: none;\n  padding-left: 0;\n  margin: 20px 0 0 0;\n}\n.main-menu > li > a {\n  padding: 14px 20px 14px 52px;\n  display: block;\n  color: #4C4C4C;\n  font-weight: 500;\n  position: relative;\n}\n.main-menu > li > a:hover {\n  color: #262626;\n  background-color: #f7f7f7;\n}\n.main-menu > li > a > i {\n  position: absolute;\n  left: 16px;\n  font-size: 20px;\n  top: 0;\n  width: 25px;\n  text-align: center;\n  padding: 13px 0;\n}\n.main-menu > li.active > a {\n  color: #262626;\n  background-color: #F4F4F4;\n}\n.sub-menu > a {\n  position: relative;\n}\n.sub-menu > a:before,\n.sub-menu > a:after {\n  position: absolute;\n  top: 12px;\n  color: #575757;\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 17px;\n  right: 15px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n}\n.sub-menu > a:before {\n  content: \"\\f278\";\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.sub-menu > a:after {\n  content: \"\\f273\";\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n.sub-menu .sub-menu > a:before,\n.sub-menu .sub-menu > a:after {\n  top: 5px;\n}\n.sub-menu.toggled > a:before {\n  content: \"\\f278\";\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n.sub-menu.toggled > a:after {\n  content: \"\\f273\";\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.sub-menu ul {\n  list-style: none;\n  display: none;\n  padding: 0;\n}\n.sub-menu ul > li > a {\n  color: #7f7f7f;\n  padding: 8px 20px 8px 50px;\n  font-weight: 500;\n  display: block;\n}\n.sub-menu ul > li > a.active,\n.sub-menu ul > li > a:hover {\n  color: #000;\n}\n.sub-menu ul > li:first-child > a {\n  padding-top: 14px;\n}\n.sub-menu ul > li:last-child > a {\n  padding-bottom: 16px;\n}\n.sub-menu ul > li ul {\n  font-size: 12px;\n  margin: 10px 0;\n  background-color: #f7f7f7;\n}\n.sub-menu.active > ul {\n  display: block;\n}\n/*\n * layout\n */\nbody:not(.sw-toggled) #sidebar {\n  box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n}\n@media (min-width: 1200px) {\n  body.sw-toggled #sidebar {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n    filter: alpha(opacity=100);\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  }\n}\n@media (max-width: 1199px) {\n  body.sw-toggled #sidebar {\n    box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n  }\n}\n/*\n * For Stupid IE9\n */\n@media (min-width: 1200px) {\n  .ie9 body.sw-toggled #sidebar {\n    display: block;\n  }\n}\n.ie9 body:not(.sw-toggled) #sidebar:not(.toggled) {\n  display: none;\n}\n.dropdown-menu {\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n.dropdown-menu > li > a {\n  padding: 8px 17px;\n  -webkit-transition: background-color;\n  -o-transition: background-color;\n  transition: background-color;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.dropdown-menu.dropdown-menu-lg {\n  width: 300px;\n}\n.dropdown-menu.dropdown-menu-sm {\n  width: 150px;\n}\n.dropdown-menu.dropdown-menu-right {\n  right: 0;\n  left: auto;\n}\n.dropdown-menu.dropdown-menu-right > li > a {\n  text-align: right;\n}\n.dropdown-menu.dm-icon > li > a > .zmdi {\n  line-height: 100%;\n  vertical-align: top;\n  font-size: 18px;\n  width: 28px;\n}\n.dropdown-menu:not([class*=\"bgm-\"]) > li > a {\n  color: #4C4C4C;\n}\n.dropdown-menu:not([class*=\"bgm-\"]) > li > a:hover {\n  color: #000;\n}\n.dropdown-menu[class*=\"bgm-\"] > li > a {\n  font-weight: 300;\n  color: #fff;\n}\n.dropdown:not([data-animation]) .dropdown-menu,\n.btn-group:not([data-animation]) .dropdown-menu {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  opacity: 0;\n  filter: alpha(opacity=0);\n  display: block;\n}\n.dropdown .dropdown-menu:not([data-animation]).pull-right,\n.bootstrap-select .dropdown-menu:not([data-animation]).pull-right,\n.btn-group .dropdown-menu:not([data-animation]).pull-right,\n.dropdown .dropdown-menu:not([data-animation]).dropdown-menu-right,\n.bootstrap-select .dropdown-menu:not([data-animation]).dropdown-menu-right,\n.btn-group .dropdown-menu:not([data-animation]).dropdown-menu-right {\n  -webkit-transform-origin: top right;\n  -moz-transform-origin: top right;\n  -ms-transform-origin: top right;\n  transform-origin: top right;\n}\n.dropdown .dropdown-menu:not([data-animation]):not(.pull-right):not(.dropdown-menu-right),\n.bootstrap-select .dropdown-menu:not([data-animation]):not(.pull-right):not(.dropdown-menu-right),\n.btn-group .dropdown-menu:not([data-animation]):not(.pull-right):not(.dropdown-menu-right) {\n  -webkit-transform-origin: top left;\n  -moz-transform-origin: top left;\n  -ms-transform-origin: top left;\n  transform-origin: top left;\n}\n.dropup .dropdown-menu:not([data-animation]).pull-right,\n.dropup .dropdown-menu:not([data-animation]).dropdown-menu-right {\n  -webkit-transform-origin: bottom right;\n  -moz-transform-origin: bottom right;\n  -ms-transform-origin: bottom right;\n  transform-origin: bottom right;\n}\n.dropup .dropdown-menu:not([data-animation]):not(.pull-right):not(.dropdown-menu-right) {\n  -webkit-transform-origin: bottom left;\n  -moz-transform-origin: bottom left;\n  -ms-transform-origin: bottom left;\n  transform-origin: bottom left;\n}\n.dropdown.open .dropdown-menu:not([data-animation]),\n.dropup.open .dropdown-menu:not([data-animation]),\n.bootstrap-select.open .dropdown-menu:not([data-animation]),\n.btn-group.open .dropdown-menu:not([data-animation]) {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.dropdown-header {\n  padding: 3px 17px;\n  margin-top: 10px;\n  color: #b1b1b1;\n  text-transform: uppercase;\n  font-weight: normal;\n}\n.btn-group.open .dropdown-toggle {\n  box-shadow: none;\n}\n.listview {\n  position: relative;\n}\n.listview:not(.lv-lg):not(.lv-message) .lv-item {\n  padding: 10px 20px;\n}\n@media (min-width: 480px) {\n  .listview.lv-lg .lv-item {\n    padding: 17px 35px 17px 25px;\n  }\n}\n@media (max-width: 767px) {\n  .listview.lv-lg .lv-item {\n    padding: 17px 35px 17px 20px;\n  }\n}\n.listview.lv-lg .lv-item:hover {\n  background-color: #FFFFDB;\n}\n.listview .lv-item {\n  position: relative;\n  display: block;\n  -webkit-transition: background-color;\n  -o-transition: background-color;\n  transition: background-color;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.listview .lv-item .lv-small {\n  font-size: 12px;\n  color: #A9A9A9;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  display: block;\n  width: 100%;\n}\n.listview .lv-item .checkbox,\n.listview .lv-item.media {\n  margin: 0;\n}\n.listview .lv-item .lv-actions {\n  position: absolute;\n  right: 15px;\n  top: 10px;\n}\n@media (max-width: 480px) {\n  .listview .lv-item .lv-actions {\n    right: 7px;\n  }\n}\n.listview .lv-title {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  display: block;\n}\n.listview a.lv-item:hover {\n  background: #ECF9FF;\n}\n.listview [class*=\"lv-img\"] {\n  border-radius: 50%;\n}\n.listview .lv-img {\n  width: 48px;\n  height: 48px;\n}\n.listview .lv-img-sm {\n  width: 35px;\n  height: 35px;\n}\n.listview.lv-bordered .lv-item:not(:last-child) {\n  border-bottom: 1px solid #f0f0f0;\n}\n.listview .lv-attrs {\n  list-style: none;\n  padding: 0;\n  margin: 5px 0 0 0;\n}\n.listview .lv-attrs > li {\n  display: inline-block;\n  padding: 2px 10px 3px;\n  font-size: 12px;\n  margin-top: 5px;\n  margin-right: 2px;\n}\n.listview .lv-attrs > li:not(.info):not(.primary):not(.warning):not(.danger) {\n  border: 1px solid #dedede;\n  background: #ffffff;\n  color: #5e5e5e;\n}\n.listview .lv-attrs > li.info {\n  border: 1px solid #00bcd4;\n  background: #00bcd4;\n  color: #ffffff;\n}\n.listview .lv-attrs > li.primary {\n  border: 1px solid #2196f3;\n  background: #2196f3;\n  color: #ffffff;\n}\n.listview .lv-attrs > li.warning {\n  border: 1px solid #ff9800;\n  background: #ff9800;\n  color: #ffffff;\n}\n.listview .lv-attrs > li.danger {\n  border: 1px solid #f44336;\n  background: #f44336;\n  color: #ffffff;\n}\n.listview .lv-attrs > li > a {\n  display: block;\n}\n.listview:not(.lv-message) .lv-title {\n  color: #000;\n}\n[class*=\"lv-img\"] {\n  border-radius: 50%;\n}\n.lv-img {\n  width: 48px;\n  height: 48px;\n}\n.lv-img-sm {\n  width: 35px;\n  height: 35px;\n}\n.lv-header {\n  text-align: center;\n  padding: 15px 10px 13px;\n  line-height: 100%;\n  text-transform: uppercase;\n  border-bottom: 1px solid #F0F0F0;\n  font-weight: 500;\n  color: #4C4C4C;\n  margin-bottom: 10px;\n}\n.lv-header .actions {\n  position: absolute;\n  top: 6px;\n  right: 8px;\n  z-index: 10;\n}\n.lvh-search {\n  position: absolute;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 4;\n  background: #fff;\n  display: none;\n}\n.lvh-search:before {\n  content: \"\\f1c3\";\n  font-family: 'Material-Design-Iconic-Font';\n  position: absolute;\n  left: 24px;\n  top: 17px;\n  font-size: 22px;\n}\n.lvhs-input {\n  border: 0;\n  padding: 0 26px 0 55px;\n  height: 63px;\n  font-size: 18px;\n  width: 100%;\n  font-weight: 100;\n  background: #fff;\n  border-bottom: 1px solid #EEE;\n}\n.lvh-search-close {\n  font-style: normal;\n  position: absolute;\n  top: 23px;\n  right: 22px;\n  font-size: 17px;\n  width: 18px;\n  height: 18px;\n  background-color: #ADADAD;\n  line-height: 100%;\n  color: #fff;\n  text-align: center;\n  cursor: pointer;\n  border-radius: 50%;\n}\n.lvh-search-close:hover {\n  background: #333;\n}\n.lv-header-alt {\n  position: relative;\n  background: #f8f8f8;\n  padding: 15px;\n}\n.lv-header-alt .lv-actions {\n  z-index: 3;\n  float: right;\n  margin-top: 3px;\n  position: relative;\n}\n.lv-header-alt .lv-actions > li > a {\n  margin: 0 3px;\n}\n.lvh-label {\n  color: #818181;\n  display: inline-block;\n  margin: 0;\n  font-size: 14px;\n  font-weight: normal;\n  padding: 0 6px;\n  line-height: 33px;\n  vertical-align: middle;\n  float: left;\n}\n.lv-footer {\n  display: block;\n  text-align: center;\n  padding: 7px 10px 8px;\n  border-top: 1px solid #F0F0F0;\n  line-height: 100%;\n  font-size: 11px;\n  margin-top: 20px;\n  color: #828282;\n}\na.lv-footer:hover {\n  color: #050505;\n}\n/*\n * Inside Card will have more padding\n */\n.card-body .lv-item {\n  padding: 12px 20px;\n}\n.progress {\n  box-shadow: none;\n  border-radius: 0;\n  height: 5px;\n  margin-bottom: 0;\n}\n.progress .progress-bar {\n  box-shadow: none;\n}\n#chat {\n  padding: 20px 0;\n  width: 280px;\n  right: -300px;\n}\n#chat.toggled {\n  right: 0;\n}\n#chat .chat-search {\n  padding: 20px 20px 15px 20px;\n}\n#chat .chat-search .form-control {\n  background-image: url(\"../img/icons/search-2.png\");\n  background-repeat: no-repeat;\n  background-position: left center;\n  padding-left: 30px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #chat .chat-search .form-control {\n    background-image: url(\"../img/icons/search-2@2x.png\");\n    background-size: 24px 24px;\n  }\n}\n#chat .chat-search .form-control:focus {\n  background-position: right center;\n  padding: 0 30px 0 0;\n}\n/*\n * Chat Status Icons\n */\n[class*=\"chat-status\"] {\n  position: absolute;\n  width: 10px;\n  height: 10px;\n  border-radius: 50%;\n  top: -3px;\n  right: 12px;\n  border: 2px solid #FFF;\n}\n/* Simple Mixin */\n.chat-status-online {\n  box-shadow: 0 0 0 1px #1ec01e;\n  background: #1ec01e;\n}\n.chat-status-offline {\n  box-shadow: 0 0 0 1px #e73f3f;\n  background: #e73f3f;\n}\n.chat-status-busy {\n  box-shadow: 0 0 0 1px #ffa500;\n  background: #ffa500;\n}\n/*\n * For Stupid IE9\n */\n.ie9 #chat {\n  right: 0;\n}\n.ie9 #chat:not(.toggled) {\n  display: none;\n}\n.tab-nav {\n  list-style: none;\n  padding: 0;\n  white-space: nowrap;\n  margin: 0;\n  overflow: auto;\n  box-shadow: inset 0 -2px 0 0 #eeeeee;\n  width: 100%;\n}\n.tab-nav li {\n  display: inline-block;\n  vertical-align: top;\n}\n.tab-nav li > a {\n  display: inline-block;\n  color: #7a7a7a;\n  text-transform: uppercase;\n  position: relative;\n  width: 100%;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  font-weight: 500;\n}\n.tab-nav li > a:after {\n  content: \"\";\n  height: 2px;\n  position: absolute;\n  width: 100%;\n  left: 0;\n  bottom: 0;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n@media (min-width: 768px) {\n  .tab-nav li > a {\n    padding: 15px;\n  }\n}\n@media (max-width: 768px) {\n  .tab-nav li > a {\n    padding: 15px 8px;\n  }\n}\n.tab-nav li.active > a {\n  color: #000;\n}\n.tab-nav li.active > a:after {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.tab-nav.tab-nav-right {\n  text-align: right;\n}\n.tab-nav.tn-justified > li {\n  display: table-cell;\n  width: 1%;\n  text-align: center;\n}\n.tab-nav.tn-icon > li .zmdi {\n  font-size: 22px;\n  line-height: 100%;\n  min-height: 25px;\n}\n.tab-nav:not([data-tab-color]) > li > a:after {\n  background: #2196f3;\n}\n.tab-nav[data-tab-color=\"green\"] > li > a:after {\n  background: #4caf50;\n}\n.tab-nav[data-tab-color=\"red\"] > li > a:after {\n  background: #f44336;\n}\n.tab-nav[data-tab-color=\"teal\"] > li > a:after {\n  background: #009688;\n}\n.tab-nav[data-tab-color=\"amber\"] > li > a:after {\n  background: #ffc107;\n}\n.tab-nav[data-tab-color=\"black\"] > li > a:after {\n  background: #000000;\n}\n.tab-nav[data-tab-color=\"cyan\"] > li > a:after {\n  background: #00bcd4;\n}\n.tab-content {\n  padding: 20px 0;\n}\n.card {\n  position: relative;\n  background: #fff;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  margin-bottom: 30px;\n}\n.card .card-header {\n  position: relative;\n}\n@media screen and (min-width: 768px) {\n  .card .card-header:not(.ch-alt) {\n    padding: 23px 25px;\n  }\n}\n@media screen and (max-width: 991px) {\n  .card .card-header:not(.ch-alt) {\n    padding: 18px;\n  }\n}\n.card .card-header h2 {\n  margin: 0;\n  line-height: 100%;\n  font-size: 17px;\n  font-weight: 400;\n}\n.card .card-header h2 small {\n  display: block;\n  margin-top: 8px;\n  color: #AEAEAE;\n  line-height: 160%;\n}\n@media screen and (min-width: 768px) {\n  .card .card-header.ch-alt {\n    padding: 23px 26px;\n  }\n}\n@media screen and (max-width: 991px) {\n  .card .card-header.ch-alt {\n    padding: 18px 18px 28px;\n  }\n}\n.card .card-header.ch-alt:not([class*=\"bgm-\"]) {\n  background-color: #f7f7f7;\n}\n.card .card-header[class*=\"bgm-\"] h2,\n.card .card-header[class*=\"bgm-\"] h2 small {\n  color: #fff;\n}\n.card .card-header .actions {\n  position: absolute;\n  right: 10px;\n  z-index: 2;\n  top: 15px;\n}\n.card .card-header .btn-float {\n  right: 25px;\n  bottom: -23px;\n  z-index: 1;\n}\n@media screen and (min-width: 768px) {\n  .card .card-body.card-padding {\n    padding: 23px 26px;\n  }\n}\n@media screen and (max-width: 991px) {\n  .card .card-body.card-padding {\n    padding: 18px;\n  }\n}\n.card .card-body.card-padding-sm {\n  padding: 15px;\n}\n.card-header:not(.ch-alt):not([class*=\"bgm-\"]) + .card-padding {\n  padding-top: 0;\n}\n.chart-edge {\n  margin: 20px -8px 0 -10px;\n  overflow: hidden;\n}\n.chart-edge .flot-chart {\n  bottom: -14px;\n}\n.charts-row {\n  margin-top: 50px;\n  margin-bottom: 20px;\n}\n.mini-charts-item {\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  position: relative;\n  margin-bottom: 30px;\n}\n.mini-charts-item .chart {\n  padding: 15px;\n  float: left;\n}\n.mini-charts-item .chart.chart-pie {\n  margin: 0 20px;\n}\n.mini-charts-item .count {\n  overflow: hidden;\n  color: rgba(255, 255, 255, 0.9);\n  padding: 16px 12px;\n}\n.mini-charts-item .count > h2 {\n  margin: 0;\n  line-height: 100%;\n  font-size: 22px;\n  font-weight: 300;\n  color: #fff;\n}\n.mini-charts-item .count > small {\n  margin-bottom: 2px;\n  display: block;\n}\n.mini-charts-item .count > h2,\n.mini-charts-item .count > small {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.mini-charts-item > .clearfix,\n.mini-charts-item > .dl-horizontal dd,\n.mini-charts-item > .container,\n.mini-charts-item > .container-fluid,\n.mini-charts-item > .row,\n.mini-charts-item > .form-horizontal .form-group,\n.mini-charts-item > .btn-toolbar,\n.mini-charts-item > .btn-group-vertical > .btn-group,\n.mini-charts-item > .nav,\n.mini-charts-item > .navbar,\n.mini-charts-item > .navbar-header,\n.mini-charts-item > .navbar-collapse,\n.mini-charts-item > .pager,\n.mini-charts-item > .panel-body,\n.mini-charts-item > .modal-header,\n.mini-charts-item > .modal-footer {\n  position: relative;\n  z-index: 1;\n}\n.mini-charts-item:before {\n  -webkit-transition: width;\n  -o-transition: width;\n  transition: width;\n  -webkit-transition-duration: 500ms;\n  transition-duration: 500ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  content: \"\";\n  width: 113px;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.1);\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n.mini-charts-item:hover .count {\n  color: #fff !important;\n}\n.mini-charts-item:hover:before {\n  width: 100%;\n}\n/*\n * Sparkline Tooltip\n */\n#jqstooltip {\n  min-width: 21px;\n  min-height: 23px;\n  text-align: center;\n  border: 0;\n  background: #fff;\n  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);\n  background-color: #fff;\n}\n#jqstooltip .jqsfield {\n  font-size: 12px;\n  font-weight: 700;\n  font-family: inherit;\n  text-align: center;\n  color: #333;\n}\n#jqstooltip .jqsfield > span {\n  display: none;\n}\n/*\n * Easy Pie Charts\n */\n.epc-item {\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  position: relative;\n  margin-bottom: 30px;\n  padding: 30px 20px;\n  text-align: center;\n}\n.easy-pie {\n  display: inline-block;\n  position: relative;\n  padding: 0 5px 10px;\n}\n.easy-pie .percent {\n  position: absolute;\n  font-weight: 300;\n  width: 100%;\n  line-height: 100%;\n  left: 0;\n}\n.easy-pie .percent:after {\n  content: \"%\";\n}\n.easy-pie.main-pie .percent {\n  margin-top: 49px;\n  font-size: 50px;\n  text-align: center;\n}\n.easy-pie.main-pie .percent:not([class*=\"c-\"]) {\n  color: rgba(255, 255, 255, 0.7);\n}\n.easy-pie.main-pie .percent:after {\n  font-size: 30px;\n}\n.easy-pie.main-pie .pie-title {\n  color: #fff;\n}\n.easy-pie:not(.main-pie) .percent {\n  font-size: 26px;\n  margin-top: 37px;\n}\n.easy-pie:not(.main-pie) .percent:after {\n  font-size: 20px;\n}\n.easy-pie .pie-title {\n  position: absolute;\n  width: 100%;\n  text-align: center;\n  bottom: -3px;\n  left: 0;\n}\n/*\n * Recet Items Table Chart\n */\n#recent-items-chart {\n  width: calc(100% + 19px);\n  height: 150px;\n  margin: -20px -10px 0;\n  bottom: -10px;\n}\n/*\n * Flot Chart\n */\n[class*=\"flot-chart\"] {\n  width: 100%;\n  display: block;\n}\n.flot-chart {\n  height: 200px;\n}\n.flot-chart-pie {\n  height: 300px;\n}\n@media (min-width: 768px) {\n  .flot-chart-pie {\n    margin-bottom: 20px;\n  }\n}\n.flot-tooltip,\n#flotTip {\n  position: absolute;\n  color: #333;\n  display: none;\n  font-size: 12px;\n  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);\n  padding: 3px 10px;\n  background-color: #fff;\n  z-index: 99999;\n}\n[class*=\"flc-\"] {\n  text-align: center;\n  margin: 10px 0 5px;\n}\n[class*=\"flc-\"] table {\n  display: inline-block;\n}\n[class*=\"flc-\"] .legendColorBox > div {\n  border: #fff !important;\n}\n[class*=\"flc-\"] .legendColorBox > div > div {\n  border-radius: 50%;\n}\n[class*=\"flc-\"] .legendLabel {\n  padding: 0 8px 0 3px;\n}\n.dash-widget-item {\n  position: relative;\n  min-height: 380px;\n  margin-bottom: 30px;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n}\n.dash-widget-item .dash-widget-header {\n  position: relative;\n}\n.dash-widget-item .dash-widget-header .actions {\n  display: none;\n  position: absolute;\n  right: 4px;\n  top: 6px;\n}\n.dash-widget-item .dash-widget-footer {\n  position: absolute;\n  left: 0;\n  bottom: 0;\n  width: 100%;\n}\n.dash-widget-item .dash-widget-title {\n  padding: 12px 20px;\n  position: absolute;\n  width: 100%;\n  left: 0;\n  font-weight: 300;\n}\n.dash-widget-item:hover .dash-widget-header .actions {\n  display: block;\n}\n/*\n * Site Visits\n */\n#site-visits {\n  color: rgba(255, 255, 255, 0.9);\n}\n#site-visits .dash-widget-header {\n  padding-bottom: 38px;\n  background-color: rgba(0, 0, 0, 0.13);\n}\n#site-visits .dash-widget-title {\n  bottom: 0;\n  background: rgba(0, 0, 0, 0.15);\n  color: rgba(255, 255, 255, 0.9);\n}\n#site-visits h3 {\n  color: rgba(255, 255, 255, 0.9);\n}\n/*\n * Best Selling Item\n */\n#best-selling {\n  background-color: #fff;\n}\n#best-selling .dash-widget-header > img {\n  width: 100%;\n  height: 155px;\n}\n#best-selling .dash-widget-header .dash-widget-title {\n  padding-bottom: 30px;\n  top: 0;\n  color: #fff;\n  background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n  background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#99000000', endColorstr='#00000000', GradientType=0);\n}\n#best-selling .dash-widget-header .main-item {\n  padding: 15px;\n  color: #fff;\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);\n  background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);\n  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#99000000', GradientType=0);\n}\n#best-selling .dash-widget-header .main-item > h2 {\n  font-weight: 400;\n  font-size: 20px;\n  margin: 5px 0 0 0;\n  line-height: 100%;\n  color: #fff;\n}\n/*\n * Weather\n */\n#weather-widget {\n  color: #fff;\n  padding: 20px 20px 0;\n}\n#weather-widget .weather-status {\n  font-size: 40px;\n  line-height: 100%;\n}\n#weather-widget .weather-icon {\n  text-align: center;\n  margin-top: 10px;\n  height: 150px;\n  background-repeat: no-repeat;\n  background-position: center;\n  /* Weather Icons */\n}\n#weather-widget .weather-icon.wi-0 {\n  background-image: url(\"../img/icons/weather/0.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-0 {\n    background-image: url(\"../img/icons/weather/0@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-1 {\n  background-image: url(\"../img/icons/weather/1.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-1 {\n    background-image: url(\"../img/icons/weather/1@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-2 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-2 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-3 {\n  background-image: url(\"../img/icons/weather/3.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-3 {\n    background-image: url(\"../img/icons/weather/3@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-4 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-4 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-5 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-5 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-6 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-6 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-7 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-7 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-8 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-8 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-9 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-9 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-10 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-10 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-11 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-11 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-12 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-12 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-13 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-13 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-14 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-14 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-15 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-15 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-16 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-16 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-17 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-17 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-18 {\n  background-image: url(\"../img/icons/weather/18.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-18 {\n    background-image: url(\"../img/icons/weather/18@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-19 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-19 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-20 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-20 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-21 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-21 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-22 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-22 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-23 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-23 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-24 {\n  background-image: url(\"../img/icons/weather/24.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-24 {\n    background-image: url(\"../img/icons/weather/24@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-25 {\n  background-image: url(\"../img/icons/weather/24.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-25 {\n    background-image: url(\"../img/icons/weather/24@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-26 {\n  background-image: url(\"../img/icons/weather/26.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-26 {\n    background-image: url(\"../img/icons/weather/26@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-27 {\n  background-image: url(\"../img/icons/weather/27.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-27 {\n    background-image: url(\"../img/icons/weather/27@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-28 {\n  background-image: url(\"../img/icons/weather/28.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-28 {\n    background-image: url(\"../img/icons/weather/28@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-29 {\n  background-image: url(\"../img/icons/weather/27.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-29 {\n    background-image: url(\"../img/icons/weather/27@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-30 {\n  background-image: url(\"../img/icons/weather/28.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-30 {\n    background-image: url(\"../img/icons/weather/28@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-31 {\n  background-image: url(\"../img/icons/weather/31.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-31 {\n    background-image: url(\"../img/icons/weather/31@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-32 {\n  background-image: url(\"../img/icons/weather/32.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-32 {\n    background-image: url(\"../img/icons/weather/32@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-33 {\n  background-image: url(\"../img/icons/weather/31.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-33 {\n    background-image: url(\"../img/icons/weather/31@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-34 {\n  background-image: url(\"../img/icons/weather/32.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-34 {\n    background-image: url(\"../img/icons/weather/32@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-35 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-35 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-36 {\n  background-image: url(\"../img/icons/weather/32.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-36 {\n    background-image: url(\"../img/icons/weather/32@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-37 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-37 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-38 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-38 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-39 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-39 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-40 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-40 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-41 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-41 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-42 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-42 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-43 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-43 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-44 {\n  background-image: url(\"../img/icons/weather/27.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-44 {\n    background-image: url(\"../img/icons/weather/27@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-45 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-45 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-46 {\n  background-image: url(\"../img/icons/weather/18.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-46 {\n    background-image: url(\"../img/icons/weather/18@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-icon.wi-47 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-47 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n#weather-widget .weather-info {\n  list-style: none;\n  padding: 0;\n  margin: 3px 0 0 0;\n}\n#weather-widget .weather-info > li {\n  display: inline-block;\n  border: 1px solid rgba(255, 255, 255, 0.39);\n  padding: 2px 10px 3px;\n  margin-right: 5px;\n}\n#weather-widget .weather-list {\n  background: rgba(0, 0, 0, 0.08);\n  padding: 5px 12px;\n  font-size: 16px;\n  height: 51px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n#weather-widget .weather-list > span {\n  margin-right: 7px;\n  font-weight: 300;\n  display: inline-block;\n  line-height: 40px;\n  vertical-align: top;\n}\n#weather-widget .weather-list > span.weather-list-icon {\n  width: 35px;\n  height: 35px;\n  background-repeat: no-repeat;\n  background-position: center;\n  background-size: 30px 30px;\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-0 {\n  background-image: url('../img/icons/weather/0.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-1 {\n  background-image: url('../img/icons/weather/1.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-2 {\n  background-image: url('../img/icons/weather/2.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-3 {\n  background-image: url('../img/icons/weather/3.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-4 {\n  background-image: url('../img/icons/weather/2.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-5 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-6 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-7 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-8 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-9 {\n  background-image: url('../img/icons/weather/9.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-10 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-11 {\n  background-image: url('../img/icons/weather/9.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-12 {\n  background-image: url('../img/icons/weather/9.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-13 {\n  background-image: url('../img/icons/weather/9.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-14 {\n  background-image: url('../img/icons/weather/9.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-15 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-16 {\n  background-image: url('../img/icons/weather/9.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-17 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-18 {\n  background-image: url('../img/icons/weather/18.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-19 {\n  background-image: url('../img/icons/weather/19.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-20 {\n  background-image: url('../img/icons/weather/19.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-21 {\n  background-image: url('../img/icons/weather/19.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-22 {\n  background-image: url('../img/icons/weather/19.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-23 {\n  background-image: url('../img/icons/weather/19.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-24 {\n  background-image: url('../img/icons/weather/24.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-25 {\n  background-image: url('../img/icons/weather/24.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-26 {\n  background-image: url('../img/icons/weather/26.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-27 {\n  background-image: url('../img/icons/weather/27.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-28 {\n  background-image: url('../img/icons/weather/28.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-29 {\n  background-image: url('../img/icons/weather/27.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-30 {\n  background-image: url('../img/icons/weather/28.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-31 {\n  background-image: url('../img/icons/weather/31.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-32 {\n  background-image: url('../img/icons/weather/32.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-33 {\n  background-image: url('../img/icons/weather/31.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-34 {\n  background-image: url('../img/icons/weather/32.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-35 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-36 {\n  background-image: url('../img/icons/weather/32.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-37 {\n  background-image: url('../img/icons/weather/2.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-38 {\n  background-image: url('../img/icons/weather/2.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-39 {\n  background-image: url('../img/icons/weather/2.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-40 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-41 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-42 {\n  background-image: url('../img/icons/weather/9.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-43 {\n  background-image: url('../img/icons/weather/5.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-44 {\n  background-image: url('../img/icons/weather/27.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-45 {\n  background-image: url('../img/icons/weather/2.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-46 {\n  background-image: url('../img/icons/weather/18.png');\n}\n#weather-widget .weather-list > span.weather-list-icon.wi-47 {\n  background-image: url('../img/icons/weather/2.png');\n}\n#weather-widget .weather-list > span > i {\n  line-height: 100%;\n  font-size: 39px;\n}\n/*\n * Pie Charts\n */\n#pie-charts {\n  background: #fff;\n}\n#pie-charts .dash-widget-header {\n  color: rgba(255, 255, 255, 0.9);\n}\n/*\n * Blog Post\n */\n.blog-post .bp-header {\n  position: relative;\n}\n.blog-post .bp-header > img {\n  width: 100%;\n}\n.blog-post .bp-header .bp-title {\n  background: #3f51b5;\n  width: 100%;\n  padding: 20px;\n  color: #FFF;\n  display: block;\n}\n.blog-post .bp-header .bp-title > h2 {\n  color: #FFF;\n  font-weight: 400;\n  margin: 0 0 2px;\n  line-height: 100%;\n  font-size: 21px;\n}\n/*\n * Profile View\n */\n.profile-view {\n  text-align: center;\n}\n.profile-view .pv-header {\n  position: relative;\n  height: 145px;\n  width: 100%;\n  background-image: url('../img/headers/sm/4.png');\n  background-repeat: no-repeat;\n  -webkit-background-size: cover;\n  -moz-background-size: cover;\n  -o-background-size: cover;\n  background-size: cover;\n  background-position: center;\n}\n.profile-view .pv-header > .pv-main {\n  border-radius: 50%;\n  width: 130px;\n  position: absolute;\n  height: 130px;\n  bottom: -50px;\n  left: 50%;\n  margin-left: -65px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.profile-view .pv-body {\n  margin-top: 70px;\n  padding: 0 20px 20px;\n}\n.profile-view .pv-body > h2 {\n  margin: 0;\n  line-height: 100%;\n  font-size: 20px;\n  font-weight: 400;\n}\n.profile-view .pv-body > small {\n  display: block;\n  color: #8E8E8E;\n  margin: 10px 0 15px;\n}\n.profile-view .pv-body .pv-contact,\n.profile-view .pv-body .pv-follow {\n  padding: 0;\n  list-style: none;\n}\n.profile-view .pv-body .pv-contact > li,\n.profile-view .pv-body .pv-follow > li {\n  display: inline-block;\n}\n.profile-view .pv-body .pv-follow {\n  margin: 20px -20px;\n  padding: 10px;\n  background-color: #F7F7F7;\n  border-top: 1px solid #EEE;\n  border-bottom: 1px solid #EEE;\n}\n.profile-view .pv-body .pv-follow > li {\n  padding: 0 10px;\n}\n.profile-view .pv-body .pv-contact > li {\n  margin: 0 5px;\n}\n.profile-view .pv-body .pv-contact > li > .zmdi {\n  line-height: 100%;\n  vertical-align: text-bottom;\n  font-size: 22px;\n}\n.profile-view .pv-body .pv-follow-btn {\n  padding: 7px 20px;\n  background: #00bcd4;\n  color: #FFF;\n  border-radius: 3px;\n  text-transform: uppercase;\n  display: block;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.profile-view .pv-body .pv-follow-btn:hover {\n  background: #00a5bb;\n}\n.profile-view:hover .pv-main {\n  -webkit-transform: scale(1.2);\n  -ms-transform: scale(1.2);\n  -o-transform: scale(1.2);\n  transform: scale(1.2);\n}\n/*\n * Picture List\n */\n.picture-list .pl-body {\n  padding: 2px;\n}\n.picture-list .pl-body [class*=\"col-\"] {\n  padding: 0;\n  padding: 2px;\n}\n.picture-list .pl-body [class*=\"col-\"] > a {\n  display: block;\n}\n@media (min-width: 768px) {\n  .picture-list .pl-body [class*=\"col-\"] > a {\n    position: relative;\n  }\n  .picture-list .pl-body [class*=\"col-\"] > a:before {\n    left: 0;\n    top: 0;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    -webkit-transform: scale3d(0, 0, 0);\n    -moz-transform: scale3d(0, 0, 0);\n    -ms-transform: scale3d(0, 0, 0);\n    -o-transform: scale3d(0, 0, 0);\n    transform: scale3d(0, 0, 0);\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 250ms;\n    transition-duration: 250ms;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    background-color: rgba(0, 0, 0, 0.3);\n    z-index: 0;\n    border-radius: 0;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n  .picture-list .pl-body [class*=\"col-\"] > a:hover:before,\n  .picture-list .pl-body [class*=\"col-\"] > a.open:before {\n    -webkit-transform: scale3d(1, 1, 1);\n    -moz-transform: scale3d(1, 1, 1);\n    -ms-transform: scale3d(1, 1, 1);\n    -o-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n.picture-list .pl-body [class*=\"col-\"] > a img {\n  width: 100%;\n}\n.picture-list .pl-body:before,\n.picture-list .pl-body:after {\n  content: \" \";\n  display: table;\n}\n.picture-list .pl-body:after {\n  clear: both;\n}\n.picture-list .pl-body:before,\n.picture-list .pl-body:after {\n  content: \" \";\n  display: table;\n}\n.picture-list .pl-body:after {\n  clear: both;\n}\n/*\n * Social\n */\n.go-social .card-body {\n  padding: 0 15px 20px;\n}\n.go-social .card-body [class*=\"col-\"] {\n  padding: 12px;\n}\n.go-social .card-body [class*=\"col-\"] img {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n}\n.go-social .card-body [class*=\"col-\"]:hover img {\n  -webkit-transform: scale(1.2);\n  -ms-transform: scale(1.2);\n  -o-transform: scale(1.2);\n  transform: scale(1.2);\n}\n/*\n * Rating\n */\n.rating-list {\n  padding: 0 0 10px;\n}\n.rating-list .rl-star {\n  margin-top: 10px;\n  margin-bottom: 4px;\n}\n.rating-list .rl-star .zmdi {\n  font-size: 20px;\n}\n.rating-list .rl-star .zmdi:not(.active) {\n  color: #ccc;\n}\n.rating-list .rl-star .zmdi.active {\n  color: #ff9800;\n}\n.rating-list .lv-item .media .zmdi-star {\n  line-height: 100%;\n  font-size: 22px;\n  color: #FF9800;\n  vertical-align: middle;\n  position: relative;\n  top: -2px;\n  left: 6px;\n}\n.rating-list .lv-item .media .media-body {\n  padding: 7px 10px 0 5px;\n}\n.table {\n  background-color: #ffffff;\n  margin-bottom: 0;\n}\n.table > thead > tr > th {\n  background-color: #fff;\n  vertical-align: middle;\n  font-weight: 500;\n  color: #333;\n  border-width: 1px;\n  text-transform: uppercase;\n}\n.table [class*=\"bg-\"] > tr > th {\n  color: #fff;\n  border-bottom: 0;\n}\n.table [class*=\"bg-\"] + tbody > tr > td {\n  border-top: 0;\n}\n.table.table-inner {\n  border: 0;\n}\n.table > thead > tr > th:first-child,\n.table > tbody > tr > th:first-child,\n.table > tfoot > tr > th:first-child,\n.table > thead > tr > td:first-child,\n.table > tbody > tr > td:first-child,\n.table > tfoot > tr > td:first-child {\n  padding-left: 30px;\n}\n.table > thead > tr > th:last-child,\n.table > tbody > tr > th:last-child,\n.table > tfoot > tr > th:last-child,\n.table > thead > tr > td:last-child,\n.table > tbody > tr > td:last-child,\n.table > tfoot > tr > td:last-child {\n  padding-right: 30px;\n}\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > tbody > tr.succes > td,\n.table > tfoot > tr.succes > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td {\n  border: 0;\n}\n.table > tbody > tr:last-child > td,\n.table > tfoot > tr:last-child > td {\n  padding-bottom: 20px;\n}\n.table-striped td,\n.table-striped th {\n  border: 0 !important;\n}\n.table-bordered {\n  border-bottom: 0;\n  border-left: 0;\n  border-right: 0;\n}\n.table-bordered > tbody > tr > td,\n.table-bordered > tbody > tr > th {\n  border-bottom: 0;\n  border-left: 0;\n}\n.table-bordered > tbody > tr > td:last-child,\n.table-bordered > tbody > tr > th:last-child {\n  border-right: 0;\n}\n.table-bordered > thead > tr > th {\n  border-left: 0;\n}\n.table-bordered > thead > tr > th:last-child {\n  border-right: 0;\n}\n.table-vmiddle td {\n  vertical-align: middle !important;\n}\n.table-responsive {\n  border: 0;\n}\n#todo-lists {\n  background: #ffc107;\n  color: #fff;\n  margin-bottom: 30px;\n  font-family: 'shadowsintolight', cursive;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n}\n.tl-header {\n  position: relative;\n  padding: 25px;\n}\n.tl-header > h2 {\n  margin: 0;\n  color: #fff;\n  line-height: 100%;\n}\n.tl-header > small {\n  font-size: 17px;\n  display: block;\n  margin-top: 3px;\n}\n.tl-header .actions {\n  position: absolute;\n  right: 10px;\n  padding: 0;\n  list-style: none;\n  top: 15px;\n}\n.tl-header .actions > li {\n  display: inline-block;\n  vertical-align: baseline;\n}\n.tl-body {\n  min-height: 300px;\n  position: relative;\n  padding: 20px 10px 20px 25px;\n  background: rgba(0, 0, 0, 0.03);\n}\n.tl-body .media-body {\n  padding-top: 3px;\n  font-size: 18px;\n}\n.tl-body .checkbox {\n  margin-bottom: 15px;\n}\n.tl-body .checkbox span {\n  display: inline-block;\n  margin-top: -3px;\n}\n.tl-body .checkbox input:checked + i + span {\n  text-decoration: line-through;\n}\n.tl-body .checkbox .input-helper:before {\n  border-color: rgba(255, 255, 255, 0.8);\n  border-width: 2px;\n}\n.tl-body .checkbox .input-helper:after {\n  border-color: #fff;\n}\n#add-tl-item {\n  width: 50px;\n  height: 50px;\n  border-radius: 50%;\n  position: absolute;\n  background: #fff;\n  top: -25px;\n  right: 23px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n}\n#add-tl-item .add-new-item {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n#add-tl-item .add-tl-body {\n  overflow: hidden;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n#add-tl-item .add-tl-body textarea {\n  padding: 25px 25px 45px;\n  resize: none;\n  width: 100%;\n  font-size: 24px;\n  color: #ffc107;\n  position: absolute;\n  height: 100%;\n  border: 0;\n  outline: none;\n}\n#add-tl-item:not(.toggled) {\n  overflow: hidden;\n}\n#add-tl-item:not(.toggled) .add-new-item {\n  position: relative;\n  z-index: 1;\n  display: inline-block;\n  width: 50px;\n  height: 50px;\n  background-repeat: no-repeat;\n  background-position: center;\n  cursor: pointer;\n  text-align: center;\n  font-size: 23px;\n  color: #ff9800;\n  line-height: 50px;\n}\n#add-tl-item.toggled {\n  width: calc(100% - 47px);\n  height: calc(100% - 25px);\n  border-radius: 2px;\n  top: 0;\n  z-index: 1;\n  box-shadow: 0 5px 8px rgba(0, 0, 0, 0.2);\n  max-height: 300px;\n  overflow: visible;\n}\n#add-tl-item.toggled .add-new-item {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  height: 0;\n  overflow: hidden;\n  float: left;\n}\n#add-tl-item.toggled .add-tl-body {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n#add-tl-item.toggled .add-tl-body .add-tl-actions {\n  position: absolute;\n  bottom: 0;\n  width: 100%;\n  padding: 5px 10px;\n  border-top: 1px solid #EEE;\n  z-index: 1;\n}\n#add-tl-item.toggled .add-tl-body .add-tl-actions > a {\n  font-size: 25px;\n  padding: 0 6px;\n  text-align: center;\n  height: 40px;\n  width: 40px;\n  display: inline-block;\n  line-height: 41px;\n  border-radius: 50%;\n  -webkit-transition: background-color;\n  -o-transition: background-color;\n  transition: background-color;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n#add-tl-item.toggled .add-tl-body .add-tl-actions > a:hover {\n  background-color: #eee;\n}\n#add-tl-item.toggled .add-tl-body .add-tl-actions [data-tl-action=\"dismiss\"] {\n  color: #f44336;\n}\n#add-tl-item.toggled .add-tl-body .add-tl-actions [data-tl-action=\"save\"] {\n  color: #4caf50;\n}\n.btn {\n  border: 0;\n  text-transform: uppercase;\n}\n.btn[class*=\"bgm-\"]:not(.bgm-white) {\n  color: #fff;\n}\n.btn .caret {\n  margin-top: -3px;\n}\n.btn:not(.btn-link) {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n.btn-group:not(.bootstrap-select),\n.btn-group-vertical:not(.bootstrap-select) {\n  box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.3);\n}\n.btn-group .btn,\n.btn-group-vertical .btn,\n.btn-group .btn:active,\n.btn-group-vertical .btn:active,\n.btn-group .btn:focus,\n.btn-group-vertical .btn:focus,\n.btn-group .btn-group,\n.btn-group-vertical .btn-group {\n  box-shadow: none !important;\n}\n.btn-group .btn,\n.btn-group-vertical .btn {\n  margin: 0;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 2px 5px;\n  font-size: 11px;\n  line-height: 1.5;\n  border-radius: 2px;\n}\n.btn-link {\n  color: #797979;\n  text-decoration: none;\n  border-radius: 2px;\n}\n.btn-link:hover {\n  color: #0a0a0a;\n}\n.btn-link:hover,\n.btn-link:active,\n.btn-link:focus {\n  text-decoration: none;\n}\n.btn-inverse {\n  color: #ffffff;\n  background-color: #454545;\n  border-color: transparent;\n}\n.btn-inverse:focus,\n.btn-inverse.focus {\n  color: #ffffff;\n  background-color: #2b2b2b;\n  border-color: rgba(0, 0, 0, 0);\n}\n.btn-inverse:hover {\n  color: #ffffff;\n  background-color: #2b2b2b;\n  border-color: rgba(0, 0, 0, 0);\n}\n.btn-inverse:active,\n.btn-inverse.active,\n.open > .dropdown-toggle.btn-inverse {\n  color: #ffffff;\n  background-color: #2b2b2b;\n  border-color: rgba(0, 0, 0, 0);\n}\n.btn-inverse:active:hover,\n.btn-inverse.active:hover,\n.open > .dropdown-toggle.btn-inverse:hover,\n.btn-inverse:active:focus,\n.btn-inverse.active:focus,\n.open > .dropdown-toggle.btn-inverse:focus,\n.btn-inverse:active.focus,\n.btn-inverse.active.focus,\n.open > .dropdown-toggle.btn-inverse.focus {\n  color: #ffffff;\n  background-color: #1a1a1a;\n  border-color: rgba(0, 0, 0, 0);\n}\n.btn-inverse:active,\n.btn-inverse.active,\n.open > .dropdown-toggle.btn-inverse {\n  background-image: none;\n}\n.btn-inverse.disabled:hover,\n.btn-inverse[disabled]:hover,\nfieldset[disabled] .btn-inverse:hover,\n.btn-inverse.disabled:focus,\n.btn-inverse[disabled]:focus,\nfieldset[disabled] .btn-inverse:focus,\n.btn-inverse.disabled.focus,\n.btn-inverse[disabled].focus,\nfieldset[disabled] .btn-inverse.focus {\n  background-color: #454545;\n  border-color: transparent;\n}\n.btn-inverse .badge {\n  color: #454545;\n  background-color: #ffffff;\n}\n.btn-inverse:hover,\n.btn-inverse:focus,\n.btn-inverse.focus,\n.btn-inverse:active,\n.open > .dropdown-toggle.btn-inverse {\n  color: #ffffff;\n  background-color: #454545;\n  border-color: transparent;\n}\n.btn-inverse:hover:hover,\n.btn-inverse:focus:hover,\n.btn-inverse.focus:hover,\n.btn-inverse:active:hover,\n.open > .dropdown-toggle.btn-inverse:hover,\n.btn-inverse:hover:focus,\n.btn-inverse:focus:focus,\n.btn-inverse.focus:focus,\n.btn-inverse:active:focus,\n.open > .dropdown-toggle.btn-inverse:focus,\n.btn-inverse:hover.focus,\n.btn-inverse:focus.focus,\n.btn-inverse.focus.focus,\n.btn-inverse:active.focus,\n.open > .dropdown-toggle.btn-inverse.focus {\n  color: #ffffff;\n  background-color: #454545;\n  border-color: transparent;\n}\n.btn-inverse:active,\n.btn-inverse.active,\n.open > .dropdown-toggle.btn-inverse {\n  background-image: none;\n}\n.btn-inverse.disabled,\n.btn-inverse[disabled],\nfieldset[disabled] .btn-inverse,\n.btn-inverse.disabled:hover,\n.btn-inverse[disabled]:hover,\nfieldset[disabled] .btn-inverse:hover,\n.btn-inverse.disabled:focus,\n.btn-inverse[disabled]:focus,\nfieldset[disabled] .btn-inverse:focus,\n.btn-inverse.disabled.focus,\n.btn-inverse[disabled].focus,\nfieldset[disabled] .btn-inverse.focus,\n.btn-inverse.disabled:active,\n.btn-inverse[disabled]:active,\nfieldset[disabled] .btn-inverse:active {\n  background-color: #454545;\n  border-color: transparent;\n}\n.btn-inverse .badge {\n  color: #454545;\n  background-color: #ffffff;\n}\n.btn-icon {\n  border-radius: 50%;\n  width: 40px;\n  line-height: 42px;\n  height: 40px;\n  padding: 0;\n  text-align: center;\n}\n.btn-icon .zmdi {\n  font-size: 17px;\n}\n.btn-icon-text > .zmdi {\n  font-size: 15px;\n  vertical-align: top;\n  display: inline-block;\n  margin-top: 2px;\n  line-height: 100%;\n  margin-right: 5px;\n}\n.btn-float {\n  width: 50px;\n  height: 50px;\n  border-radius: 50%;\n  line-height: 45px !important;\n}\n.btn-float:not(.m-btn) {\n  position: absolute !important;\n}\n.btn-float i {\n  font-size: 23px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 500ms;\n  transition-duration: 500ms;\n}\n.btn-float:hover i {\n  -webkit-transform: rotate(360deg);\n  -ms-transform: rotate(360deg);\n  -o-transform: rotate(360deg);\n  transform: rotate(360deg);\n}\n.btn-float:not(.bgm-white):not(.bgm-gray) > i {\n  color: #fff;\n}\n.btn-float:not(.bgm-white):not(.bgm-gray) > i {\n  color: #fff;\n}\n.btn-float.bgm-white > i,\n.btn-float.bgm-gray > i {\n  color: #333;\n}\n.open .btn {\n  outline: none !important;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n}\n.open .btn:focus,\n.open .btn:active {\n  outline: none !important;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n}\n/*\n * Material Design Add button\n */\n.m-btn {\n  z-index: 1;\n  bottom: 40px;\n  right: 40px;\n  position: fixed !important;\n}\nlabel {\n  font-weight: 500;\n}\n/*\n * Reset Focus and Active shadows\n */\ninput:active,\ninput:focus {\n  outline: 0;\n  box-shadow: none !important;\n}\n.form-control {\n  box-shadow: none !important;\n  resize: none;\n}\n.form-control:active,\n.form-control:focus {\n  box-shadow: none;\n}\n.form-control:not(.fc-alt) {\n  border-left: 0;\n  border-right: 0;\n  border-top: 0;\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  appearance: none;\n  padding: 0;\n}\n.form-control:not(.fc-alt).auto-size {\n  padding-top: 6px;\n}\n/*\n * Checkbox and Radio\n */\n.checkbox label,\n.radio label {\n  padding-left: 30px;\n  position: relative;\n}\n.checkbox input,\n.radio input {\n  top: 0;\n  left: 0;\n  margin-left: 0 !important;\n  z-index: 1;\n  cursor: pointer;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  margin-top: 0;\n}\n.checkbox .input-helper:before,\n.radio .input-helper:before,\n.checkbox .input-helper:after,\n.radio .input-helper:after {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  position: absolute;\n  content: \"\";\n}\n.checkbox .input-helper:before,\n.radio .input-helper:before {\n  left: 0;\n  border: 1px solid #ccc;\n}\n.checkbox.disabled,\n.radio.disabled {\n  opacity: 0.6;\n  filter: alpha(opacity=60);\n}\n.checkbox input {\n  width: 17px;\n  height: 17px;\n}\n.checkbox input:checked + .input-helper:before {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n.checkbox input:checked + .input-helper:after {\n  -webkit-transform: scale(1) rotate(-50deg);\n  -ms-transform: scale(1) rotate(-50deg);\n  -o-transform: scale(1) rotate(-50deg);\n  transform: scale(1) rotate(-50deg);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.checkbox .input-helper:before {\n  top: 0;\n  width: 17px;\n  height: 17px;\n}\n.checkbox .input-helper:after {\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transform: scale(0) rotate(80deg);\n  -ms-transform: scale(0) rotate(80deg);\n  -o-transform: scale(0) rotate(80deg);\n  transform: scale(0) rotate(80deg);\n  width: 22px;\n  height: 9px;\n  border-bottom: 2px solid #009688;\n  border-left: 2px solid #009688;\n  border-bottom-left-radius: 2px;\n  left: -1px;\n  top: 1px;\n}\n.radio input {\n  width: 19px;\n  height: 19px;\n}\n.radio input:checked + .input-helper:after {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.radio .input-helper:before {\n  top: -1px;\n  width: 19px;\n  height: 19px;\n  border-radius: 50%;\n}\n.radio .input-helper:after {\n  width: 11px;\n  height: 11px;\n  background: #009688;\n  border-radius: 50%;\n  top: 3px;\n  left: 4px;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n.checkbox-inline,\n.radio-inline {\n  vertical-align: top;\n  margin-top: 0;\n  padding-left: 25px;\n}\n/*\n * Select\n */\nhtml:not(.ie9) .select {\n  position: relative;\n}\nhtml:not(.ie9) .select:before {\n  position: absolute;\n  top: -1px;\n  content: \"\";\n  height: calc(100% - 1px);\n  width: 30px;\n  background-color: #FFF;\n  background-position: right calc(100% - 7px);\n  background-repeat: no-repeat;\n  background-image: url(\"../img/select.png\");\n  pointer-events: none;\n  z-index: 5;\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  html:not(.ie9) .select:before {\n    background-image: url(\"../img/select@2x.png\");\n    background-size: 12px 12px;\n  }\n}\nhtml:not(.ie9) .select:not(.fg-line):before {\n  right: 0;\n}\nhtml:not(.ie9) .select.fg-line:before {\n  right: 10px;\n}\n/*\n * Input Group Addon\n */\n.input-group:not(.input-group-lg):not(.input-group-sm) .input-group-addon {\n  font-size: 15px;\n}\n.input-group-addon {\n  border-width: 0px 0px 1px 0px;\n  min-width: 42px;\n}\n.input-group-addon > .zmdi {\n  position: relative;\n  top: 3px;\n}\n/*\n * Input Feilds\n */\n.fg-line {\n  position: relative;\n  vertical-align: top;\n}\n.fg-line:not(.form-group) {\n  display: inline-block;\n  width: 100%;\n}\n.fg-line .form-control:disabled {\n  color: #9d9d9d;\n  background: transparent;\n}\n.fg-line:not(.disabled):after,\n.fg-line:not(.readonly):after {\n  position: absolute;\n  z-index: 3;\n  bottom: 0;\n  left: 0;\n  height: 2px;\n  width: 0;\n  content: \"\";\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.fg-line:not([class*=has-]):after {\n  background: #2196f3;\n}\n.fg-line.readonly .form-control {\n  color: #9d9d9d;\n  background: transparent;\n}\n.fg-line.fg-toggled:after {\n  width: 100%;\n}\n.fg-float {\n  margin-top: 2px;\n  position: relative;\n}\n.fg-float .form-control {\n  position: relative;\n  background: transparent;\n  z-index: 1;\n}\n.fg-float .form-control::-moz-placeholder {\n  color: #ffffff;\n  opacity: 1;\n}\n.fg-float .form-control:-ms-input-placeholder {\n  color: #ffffff;\n}\n.fg-float .form-control::-webkit-input-placeholder {\n  color: #ffffff;\n}\n.fg-float .fg-label {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  position: absolute;\n  top: 5px;\n  font-weight: 400;\n  color: #959595;\n  pointer-events: none;\n  z-index: 0;\n  left: 0;\n  white-space: nowrap;\n}\n.fg-float .fg-toggled .fg-label {\n  top: -20px;\n  font-size: 11px;\n}\n.control-label {\n  font-weight: normal;\n}\n/*\n * Toggle Switch\n */\n.toggle-switch {\n  display: inline-block;\n  vertical-align: top;\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n.toggle-switch .ts-label {\n  display: inline-block;\n  margin: 0 20px 0 0;\n  vertical-align: top;\n  -webkit-transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1);\n  transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.toggle-switch .ts-helper {\n  display: inline-block;\n  position: relative;\n  width: 40px;\n  height: 16px;\n  border-radius: 8px;\n  background: rgba(0, 0, 0, 0.26);\n  -webkit-transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n  transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n  vertical-align: middle;\n  cursor: pointer;\n}\n.toggle-switch .ts-helper:before {\n  content: '';\n  position: absolute;\n  top: -4px;\n  left: -4px;\n  width: 24px;\n  height: 24px;\n  background: #fafafa;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);\n  border-radius: 50%;\n  webkit-transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n  transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n}\n.toggle-switch:not(.disabled) .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(128, 128, 128, 0.1);\n}\n.toggle-switch input {\n  position: absolute;\n  z-index: 1;\n  width: 46px;\n  margin: 0 0 0 -4px;\n  height: 24px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  cursor: pointer;\n}\n.toggle-switch input:checked + .ts-helper:before {\n  left: 20px;\n}\n.toggle-switch:not([data-ts-color]) input:not(:disabled):checked + .ts-helper {\n  background: rgba(0, 150, 136, 0.5);\n}\n.toggle-switch:not([data-ts-color]) input:not(:disabled):checked + .ts-helper:before {\n  background: #009688;\n}\n.toggle-switch:not([data-ts-color]) input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(0, 150, 136, 0.2);\n}\n.toggle-switch.disabled {\n  opacity: 0.6;\n  filter: alpha(opacity=60);\n}\n.toggle-switch[data-ts-color=\"red\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(244, 67, 54, 0.5);\n}\n.toggle-switch[data-ts-color=\"red\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #f44336;\n}\n.toggle-switch[data-ts-color=\"red\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(244, 67, 54, 0.2);\n}\n.toggle-switch[data-ts-color=\"blue\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(33, 150, 243, 0.5);\n}\n.toggle-switch[data-ts-color=\"blue\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #2196f3;\n}\n.toggle-switch[data-ts-color=\"blue\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(33, 150, 243, 0.2);\n}\n.toggle-switch[data-ts-color=\"amber\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(255, 193, 7, 0.5);\n}\n.toggle-switch[data-ts-color=\"amber\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #ffc107;\n}\n.toggle-switch[data-ts-color=\"amber\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(255, 193, 7, 0.2);\n}\n.toggle-switch[data-ts-color=\"purple\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(156, 39, 176, 0.5);\n}\n.toggle-switch[data-ts-color=\"purple\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #9c27b0;\n}\n.toggle-switch[data-ts-color=\"purple\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(156, 39, 176, 0.2);\n}\n.toggle-switch[data-ts-color=\"pink\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(233, 30, 99, 0.5);\n}\n.toggle-switch[data-ts-color=\"pink\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #e91e63;\n}\n.toggle-switch[data-ts-color=\"pink\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(233, 30, 99, 0.2);\n}\n.toggle-switch[data-ts-color=\"lime\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(205, 220, 57, 0.5);\n}\n.toggle-switch[data-ts-color=\"lime\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #cddc39;\n}\n.toggle-switch[data-ts-color=\"lime\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(205, 220, 57, 0.2);\n}\n.toggle-switch[data-ts-color=\"cyan\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(0, 188, 212, 0.5);\n}\n.toggle-switch[data-ts-color=\"cyan\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #00bcd4;\n}\n.toggle-switch[data-ts-color=\"cyan\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(0, 188, 212, 0.2);\n}\n.toggle-switch[data-ts-color=\"green\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(76, 175, 80, 0.5);\n}\n.toggle-switch[data-ts-color=\"green\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #4caf50;\n}\n.toggle-switch[data-ts-color=\"green\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(76, 175, 80, 0.2);\n}\n/*\n * IE 9 Placeholder\n */\n.ie9-placeholder {\n  color: #888 !important;\n  font-weight: normal;\n}\n/*\n * Validation\n */\n.has-error .checkbox .input-helper:before {\n  border-color: #f99d97;\n}\n.has-error .checkbox .input-helper:after {\n  border-bottom-color: #f77066;\n  border-left-color: #f77066;\n}\n.has-error .fg-line:after {\n  background: #f44336;\n}\n.has-success .checkbox .input-helper:before {\n  border-color: #92cf94;\n}\n.has-success .checkbox .input-helper:after {\n  border-bottom-color: #6ec071;\n  border-left-color: #6ec071;\n}\n.has-success .fg-line:after {\n  background: #4caf50;\n}\n.has-warning .checkbox .input-helper:before {\n  border-color: #ffc166;\n}\n.has-warning .checkbox .input-helper:after {\n  border-bottom-color: #ffad33;\n  border-left-color: #ffad33;\n}\n.has-warning .fg-line:after {\n  background: #ff9800;\n}\n.pagination {\n  border-radius: 0;\n}\n.pagination > li {\n  margin: 0 2px;\n  display: inline-block;\n  vertical-align: top;\n}\n.pagination > li > a,\n.pagination > li > span {\n  border-radius: 50% !important;\n  padding: 0;\n  width: 40px;\n  height: 40px;\n  line-height: 38px;\n  text-align: center;\n  font-size: 14px;\n  z-index: 1;\n  position: relative;\n  cursor: pointer;\n}\n.pagination > li > a > .zmdi,\n.pagination > li > span > .zmdi {\n  font-size: 22px;\n  line-height: 39px;\n}\n.pagination > li.disabled {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n/*\n * Listview Pagination\n */\n.lv-pagination {\n  width: 100%;\n  text-align: center;\n  padding: 40px 0;\n  border-top: 1px solid #F0F0F0;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n/*\n * Pager\n */\n.pager li > a,\n.pager li > span {\n  padding: 5px 10px 6px;\n  color: #7e7e7e;\n}\n.popover {\n  box-shadow: 0 2px 30px rgba(0, 0, 0, 0.2);\n}\n.popover-title {\n  border-bottom: 0;\n  padding: 15px;\n  font-size: 12px;\n  text-transform: uppercase;\n}\n.popover-title + .popover-content {\n  padding-top: 0;\n}\n.popover-content {\n  padding: 15px;\n}\n.popover-content p {\n  margin-bottom: 0;\n}\n.fw-container .tab-content {\n  padding: 25px 0;\n}\n.fw-container .fw-footer {\n  text-align: center;\n  margin: 30px 0 0;\n  width: 100%;\n  border-top: 2px solid #eee;\n  padding: 15px 0;\n}\n.alert {\n  padding-left: 30px;\n  font-size: 13px;\n}\n.alert span {\n  cursor: pointer;\n}\n.alert:not(.alert-dismissible) {\n  padding-right: 30px;\n}\n.alert.alert-dismissable {\n  padding-right: 44px;\n}\n.alert-inverse {\n  background-color: #333333;\n  border-color: transparent;\n  color: #ffffff;\n}\n.alert-inverse hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n.alert-inverse .alert-link {\n  color: #e6e6e6;\n}\n.growl-animated.alert-inverse {\n  box-shadow: 0 0 5px rgba(51, 51, 51, 0.5);\n}\n.growl-animated.alert-info {\n  box-shadow: 0 0 5px rgba(33, 150, 243, 0.5);\n}\n.growl-animated.alert-success {\n  box-shadow: 0 0 5px rgba(76, 175, 80, 0.5);\n}\n.growl-animated.alert-warning {\n  box-shadow: 0 0 5px rgba(255, 193, 7, 0.5);\n}\n.growl-animated.alert-danger {\n  box-shadow: 0 0 5px rgba(244, 67, 54, 0.5);\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #e0e0e0;\n  box-shadow: 0 0 6px #EAEAEA;\n}\n/*\n * Lightbox  \n */\n.lightbox .lightbox-item > img {\n  width: 100%;\n  border-radius: 2px;\n}\n@media (min-width: 768px) {\n  .lightbox .lightbox-item {\n    position: relative;\n  }\n  .lightbox .lightbox-item:before {\n    left: 0;\n    top: 0;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    -webkit-transform: scale3d(0, 0, 0);\n    -moz-transform: scale3d(0, 0, 0);\n    -ms-transform: scale3d(0, 0, 0);\n    -o-transform: scale3d(0, 0, 0);\n    transform: scale3d(0, 0, 0);\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 250ms;\n    transition-duration: 250ms;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    background-color: rgba(0, 0, 0, 0.1);\n    z-index: 0;\n    border-radius: 0;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n  .lightbox .lightbox-item:hover:before,\n  .lightbox .lightbox-item.open:before {\n    -webkit-transform: scale3d(1, 1, 1);\n    -moz-transform: scale3d(1, 1, 1);\n    -ms-transform: scale3d(1, 1, 1);\n    -o-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n.lightbox .lightbox-item:hover {\n  cursor: pointer;\n}\n.lightbox [data-src]:before,\n.lightbox [data-src]:after {\n  content: \" \";\n  display: table;\n}\n.lightbox [data-src]:after {\n  clear: both;\n}\n.lightbox [data-src]:before,\n.lightbox [data-src]:after {\n  content: \" \";\n  display: table;\n}\n.lightbox [data-src]:after {\n  clear: both;\n}\n.lightbox .lightbox-item:not(.p-item) {\n  position: relative;\n}\n/*\n * Carousel\n */\n.carousel .carousel-control {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.carousel .carousel-control .zmdi {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  line-height: 100%;\n}\n@media screen and (min-width: 768px) {\n  .carousel .carousel-control .zmdi {\n    font-size: 60px;\n    width: 60px;\n    height: 60px;\n    margin-top: -30px;\n    margin-left: -30px;\n  }\n}\n@media screen and (max-width: 991px) {\n  .carousel .carousel-control .zmdi {\n    width: 24px;\n    height: 24px;\n    margin-top: -12px;\n    margin-left: -12px;\n  }\n}\n.carousel:hover .carousel-control {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.carousel .carousel-caption {\n  background: rgba(0, 0, 0, 0.6);\n  left: 0;\n  right: 0;\n  bottom: 0;\n  width: 100%;\n  padding-bottom: 50px;\n}\n.carousel .carousel-caption > h3 {\n  color: #fff;\n  margin: 0 0 5px;\n  font-weight: 300;\n}\n.carousel .carousel-caption > p {\n  margin: 0;\n}\n@media screen and (max-width: 991px) {\n  .carousel .carousel-caption {\n    display: none;\n  }\n}\n.carousel .carousel-indicators {\n  bottom: 10px;\n  margin: 0;\n  left: 0;\n  bottom: 0;\n  width: 100%;\n  padding: 0 0 6px;\n  background: rgba(0, 0, 0, 0.6);\n}\n.carousel .carousel-indicators li {\n  border-radius: 0;\n  width: 15px;\n  border: 0;\n  background: #fff;\n  height: 3px;\n  margin: 0;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n.carousel .carousel-indicators li.active {\n  width: 25px;\n  height: 3px;\n  background: #ff9800;\n}\n.modal .modal-content {\n  box-shadow: 0 5px 20px rgba(0, 0, 0, 0.31);\n  border-radius: 3px;\n  border: 0;\n}\n.modal .modal-header {\n  padding: 23px 26px;\n}\n.modal .modal-body {\n  padding: 0 26px 10px;\n}\n.modal .modal-footer .btn-link {\n  font-size: 14px;\n  color: #000;\n  font-weight: 500;\n}\n.modal .modal-footer .btn-link:hover {\n  background-color: #eee;\n}\n.modal:not([data-modal-color]) .modal-footer .btn-link {\n  font-weight: 500;\n}\n.modal:not([data-modal-color]) .modal-footer .btn-link:hover {\n  background-color: #eee;\n}\n.modal[data-modal-color] {\n  color: #fff;\n}\n.modal[data-modal-color] .modal-title,\n.modal[data-modal-color] .modal-footer .btn-link {\n  color: #fff;\n}\n.modal[data-modal-color] .modal-footer {\n  background: rgba(0, 0, 0, 0.1);\n}\n.modal[data-modal-color] .modal-backdrop {\n  background: #fff;\n}\n.modal[data-modal-color] .modal-footer .btn-link {\n  font-weight: 400;\n}\n.modal[data-modal-color] .modal-footer .btn-link:hover {\n  background-color: rgba(0, 0, 0, 0.1);\n}\n.modal[data-modal-color=\"blue\"] .modal-content {\n  background: #2196f3;\n}\n.modal[data-modal-color=\"cyan\"] .modal-content {\n  background: #00bcd4;\n}\n.modal[data-modal-color=\"green\"] .modal-content {\n  background: #4caf50;\n}\n.modal[data-modal-color=\"lightgreen\"] .modal-content {\n  background: #8bc34a;\n}\n.modal[data-modal-color=\"lightblue\"] .modal-content {\n  background: #03a9f4;\n}\n.modal[data-modal-color=\"amber\"] .modal-content {\n  background: #ffc107;\n}\n.modal[data-modal-color=\"teal\"] .modal-content {\n  background: #009688;\n}\n.modal[data-modal-color=\"orange\"] .modal-content {\n  background: #ff9800;\n}\n.modal[data-modal-color=\"bluegray\"] .modal-content {\n  background: #607d8b;\n}\n.modal[data-modal-color=\"red\"] .modal-content {\n  background: #f44336;\n}\n.panel {\n  box-shadow: none;\n  border: 0;\n}\n.panel-heading {\n  padding: 0;\n}\n.panel-title > a {\n  padding: 10px 15px;\n  display: block;\n  font-size: 13px;\n}\n.panel-collapse .panel-heading {\n  position: relative;\n}\n.panel-collapse .panel-heading .panel-title > a {\n  padding: 8px 5px 16px 30px;\n  color: #000;\n  position: relative;\n}\n.panel-collapse .panel-heading .panel-title > a:after,\n.panel-collapse .panel-heading .panel-title > a:before {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  height: 2px;\n  width: 100%;\n  content: \"\";\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n}\n.panel-collapse .panel-heading .panel-title > a:after {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n.panel-collapse .panel-heading:not(.active) .panel-title > a:before {\n  background: #eee;\n}\n.panel-collapse .panel-heading:before,\n.panel-collapse .panel-heading:after {\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 17px;\n  position: absolute;\n  left: 0;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  top: 4px;\n}\n.panel-collapse .panel-heading:before {\n  content: \"\\f278\";\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.panel-collapse .panel-heading:after {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  content: \"\\f273\";\n}\n.panel-collapse .panel-heading.active .panel-title > a:after {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.panel-collapse .panel-heading.active:before {\n  -webkit-transform: scale(0) rotate(-90deg);\n  -ms-transform: scale(0) rotate(-90deg);\n  -o-transform: scale(0) rotate(-90deg);\n  transform: scale(0) rotate(-90deg);\n}\n.panel-collapse .panel-heading.active:after {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.panel-collapse .panel-body {\n  border-top: 0 !important;\n  padding-left: 5px;\n  padding-right: 5px;\n}\n.panel-group:not([data-collapse-color]) .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #2196f3;\n}\n.panel-group[data-collapse-color=\"red\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #f44336;\n}\n.panel-group[data-collapse-color=\"green\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #4caf50;\n}\n.panel-group[data-collapse-color=\"amber\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #ffc107;\n}\n.panel-group[data-collapse-color=\"teal\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #009688;\n}\n.panel-group[data-collapse-color=\"black\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #000000;\n}\n.panel-group[data-collapse-color=\"cyan\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #00bcd4;\n}\n.tooltip-inner {\n  border-radius: 1px;\n  padding: 3px 10px 5px;\n}\n.breadcrumb {\n  border-bottom: 1px solid #E5E5E5;\n  border-radius: 0;\n}\n.breadcrumb > li > a {\n  color: #A9A9A9;\n}\n.breadcrumb > li > a:hover {\n  color: #7c7c7c;\n}\n@media (min-width: 768px) {\n  body:not(.sw-toggled) .breadcrumb {\n    padding: 10px 33px 11px;\n  }\n}\n@media (min-width: 1199px) {\n  body.sw-toggled .breadcrumb {\n    padding: 10px 33px 11px 280px;\n  }\n}\n#messages-main {\n  position: relative;\n}\n#messages-main:before,\n#messages-main:after {\n  content: \" \";\n  display: table;\n}\n#messages-main:after {\n  clear: both;\n}\n#messages-main:before,\n#messages-main:after {\n  content: \" \";\n  display: table;\n}\n#messages-main:after {\n  clear: both;\n}\n#messages-main .ms-block {\n  padding: 23px 20px 0;\n}\n#messages-main .ms-menu {\n  position: absolute;\n  left: 0;\n  top: 0;\n  background: #F8F8F8;\n  border-right: 1px solid #EEE;\n  padding-bottom: 50px;\n  height: 100%;\n  width: 240px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n@media (max-width: 767px) {\n  #messages-main .ms-menu {\n    height: calc(100% - 58px);\n    -webkit-transform: translate3d(-240px, 58px, 0);\n    transform: translate3d(-240px, 58px, 0);\n    opacity: 0;\n    filter: alpha(opacity=0);\n    z-index: 1;\n  }\n  #messages-main .ms-menu.toggled {\n    -webkit-transform: translate3d(0, 58px, 0);\n    transform: translate3d(0, 58px, 0);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n#messages-main .ms-menu .lv-item {\n  padding-left: 20px;\n  padding-right: 20px;\n}\n#messages-main .ms-menu .lv-item.active {\n  background: #fff;\n}\n#messages-main .ms-menu .lv-item:not(.active):hover {\n  background: #F2F2F2;\n  cursor: pointer;\n}\n@media (min-width: 768px) {\n  #messages-main .ms-body {\n    padding-left: 240px;\n  }\n}\n@media (max-width: 767px) {\n  #messages-main .ms-body {\n    overflow: hidden;\n  }\n}\n#messages-main .ms-user:before,\n#messages-main .ms-user:after {\n  content: \" \";\n  display: table;\n}\n#messages-main .ms-user:after {\n  clear: both;\n}\n#messages-main .ms-user:before,\n#messages-main .ms-user:after {\n  content: \" \";\n  display: table;\n}\n#messages-main .ms-user:after {\n  clear: both;\n}\n#messages-main .ms-user > img {\n  border-radius: 50%;\n  width: 40px;\n  float: left;\n}\n#messages-main .ms-user > div {\n  overflow: hidden;\n  padding: 7px 5px 7px 15px;\n  font-size: 11px;\n}\n#ms-menu-trigger {\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  float: left;\n  margin: 1px 0 0 -7px;\n}\n@media (min-width: 768px) {\n  #ms-menu-trigger {\n    display: none;\n  }\n}\n#ms-menu-trigger .line-wrap .line {\n  background-color: #717171;\n}\n/*\n * For Message\n */\n.lv-message .lv-item {\n  padding: 20px;\n}\n.lv-message .lv-item.right {\n  text-align: right;\n}\n.lv-message .lv-item.right .lv-avatar {\n  margin-right: 0;\n  margin-left: 15px;\n}\n.lv-message .lv-item:not(.right) .ms-item {\n  background: #ffc107;\n  color: #fff;\n}\n.lv-message .lv-item.right .ms-item {\n  background: #eee;\n}\n.lv-avatar {\n  width: 35px;\n  height: 35px;\n  border-radius: 50%;\n  color: #FFF;\n  text-align: center;\n  line-height: 34px;\n  font-size: 15px;\n  margin-right: 15px;\n  padding: 0 !important;\n  text-transform: uppercase;\n}\n.lv-avatar > img {\n  width: 35px;\n  height: 35px;\n  border-radius: 50%;\n  vertical-align: top;\n}\n.ms-item {\n  padding: 13px 19px 15px;\n  border-radius: 2px;\n  display: inline-block;\n}\n@media (min-width: 768px) {\n  .ms-item {\n    max-width: 70%;\n  }\n}\n.ms-date {\n  display: block;\n  color: #B3B3B3;\n  margin-top: 7px;\n}\n.ms-date > i {\n  font-size: 14px;\n  vertical-align: bottom;\n  line-height: 100%;\n}\n.ms-reply {\n  box-shadow: 0 -20px 20px -5px #ffffff;\n  position: relative;\n  margin: 0 !important;\n}\n.ms-reply textarea {\n  width: 100%;\n  font-size: 13px;\n  border: 0;\n  padding: 10px 8px;\n  resize: none;\n  height: 60px;\n}\n.ms-reply button {\n  position: absolute;\n  top: 0;\n  right: 0;\n  border: 0;\n  height: 100%;\n  width: 60px;\n  font-size: 25px;\n  background: #F5F5F5;\n  color: #2196f3;\n}\n.ms-reply button:hover {\n  background: #f2f2f2;\n}\n.four-zero-content {\n  background: #fff;\n  padding: 20px;\n}\n.four-zero-content:before {\n  height: 50%;\n  width: 100%;\n  position: absolute;\n  top: 0;\n  left: 0;\n  background: #EDECEC;\n  content: \"\";\n}\n.four-zero {\n  background: #00bcd4;\n  box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);\n  border-radius: 2px;\n  position: absolute;\n  top: 50%;\n  margin-top: -150px;\n  color: #fff;\n  text-align: center;\n  padding: 15px;\n  height: 300px;\n  width: 500px;\n  left: 50%;\n  margin-left: -250px;\n}\n.four-zero h2 {\n  font-size: 130px;\n}\n@media (max-width: 767px) {\n  .four-zero {\n    width: calc(100% - 40px);\n    left: 20px;\n    margin-left: 0;\n    height: 260px;\n    margin-top: -130px;\n  }\n  .four-zero h2 {\n    font-size: 90px;\n  }\n}\n.four-zero h2 {\n  line-height: 100%;\n  color: #fff;\n  font-weight: 100;\n}\n.four-zero small {\n  display: block;\n  font-size: 26px;\n  margin-top: -10px;\n}\n.four-zero footer {\n  background: rgba(0, 0, 0, 0.13);\n  position: absolute;\n  left: 0;\n  bottom: 0;\n  width: 100%;\n  padding: 10px;\n}\n.four-zero footer > a {\n  font-size: 21px;\n  display: inline-block;\n  color: #FFF;\n  margin: 0 1px;\n  line-height: 40px;\n  width: 40px;\n  height: 40px;\n  background: rgba(0, 0, 0, 0.09);\n  border-radius: 50%;\n  text-align: center;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.four-zero footer > a:hover {\n  background: rgba(0, 0, 0, 0.2);\n}\n.login-content {\n  overflow: hidden;\n  height: 100%;\n}\n.lc-block {\n  background: #fff;\n  box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);\n  border-radius: 2px;\n  width: 500px;\n  display: inline-block;\n  margin-top: 42px;\n  vertical-align: middle;\n  position: relative;\n}\n.lc-block:not(.toggled) {\n  display: none;\n}\n.lc-block.toggled {\n  -webkit-animation-name: fadeInUp;\n  animation-name: fadeInUp;\n  -webkit-animation-duration: 300ms;\n  animation-duration: 300ms;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n  z-index: 10;\n}\n.lc-block:not(.lcb-alt) {\n  padding: 35px 55px 35px;\n}\n@media (max-width: 767px) {\n  .lc-block {\n    padding: 15px 35px 25px 20px;\n    width: calc(100% - 60px);\n  }\n}\n.lc-block .checkbox {\n  margin: 5px 0 0 42px;\n  text-align: left;\n}\n.lc-block:not(.lcb-alt) .btn-login {\n  top: 50%;\n  margin-top: -25px;\n  right: -25px;\n}\n.login-navigation {\n  list-style: none;\n  padding: 0;\n  margin: 0;\n  position: absolute;\n  width: 100%;\n  text-align: center;\n  left: 0%;\n  bottom: -45px;\n}\n.login-navigation > li {\n  display: inline-block;\n  margin: 0 2px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 150ms;\n  transition-duration: 150ms;\n  cursor: pointer;\n  vertical-align: top;\n  color: #fff;\n  line-height: 16px;\n  min-width: 16px;\n  min-height: 16px;\n  text-transform: uppercase;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n}\n.login-navigation > li > span {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.login-navigation > li:not(:hover) {\n  font-size: 0px;\n  border-radius: 100%;\n}\n.login-navigation > li:hover {\n  border-radius: 10px;\n  padding: 0 5px;\n  font-size: 8px;\n}\n.login-navigation > li:hover > span {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.lcb-alt {\n  padding: 70px 55px 60px;\n}\n.lcb-alt .btn-login {\n  bottom: -25px;\n  left: 50%;\n  margin-left: -25px;\n}\n.lcb-alt .login-navigation {\n  bottom: -75px;\n}\n.lcb-user {\n  width: 100px;\n  height: 100px;\n  border-radius: 50%;\n  border: 5px solid #fff;\n  position: absolute;\n  top: -50px;\n  left: 50%;\n  margin-left: -50px;\n  box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.18);\n}\nbody.login-content {\n  text-align: center;\n}\nbody.login-content:after {\n  content: \"\";\n  vertical-align: middle;\n  display: inline-block;\n  width: 1px;\n  height: 100%;\n}\nbody.login-content:before {\n  height: 50%;\n  width: 100%;\n  position: absolute;\n  top: 0;\n  left: 0;\n  background: #00bcd4;\n  content: \"\";\n  z-index: 0;\n}\n#profile-main {\n  min-height: 500px;\n  position: relative;\n}\n#profile-main .pm-overview {\n  overflow-y: auto;\n}\n@media (min-width: 1200px) {\n  #profile-main .pm-overview {\n    width: 300px;\n  }\n}\n@media (min-width: 768px) and (max-width: 1200px) {\n  #profile-main .pm-overview {\n    width: 250px;\n  }\n}\n@media (min-width: 768px) {\n  #profile-main .pm-overview {\n    position: absolute;\n    left: 0;\n    top: 0;\n    height: 100%;\n    background: #f8f8f8;\n    border-right: 1px solid #eee;\n  }\n}\n@media (max-width: 767px) {\n  #profile-main .pm-overview {\n    width: 100%;\n    background: #333;\n    text-align: center;\n  }\n}\n@media (min-width: 1200px) {\n  #profile-main .pm-body {\n    padding-left: 300px;\n  }\n}\n@media (min-width: 768px) and (max-width: 1200px) {\n  #profile-main .pm-body {\n    padding-left: 250px;\n  }\n}\n@media (max-width: 767px) {\n  #profile-main .pm-body {\n    padding-left: 0;\n  }\n}\n#profile-main .pmo-pic {\n  position: relative;\n  margin: 20px;\n}\n@media (min-width: 768px) {\n  #profile-main .pmo-pic img {\n    width: 100%;\n    border-radius: 2px 2px 0 0;\n  }\n}\n@media (max-width: 767px) {\n  #profile-main .pmo-pic img {\n    width: 180px;\n    display: inline-block;\n    height: 180px;\n    border-radius: 50%;\n    border: 4px solid #fff;\n    box-shadow: 0 8px 17px rgba(0, 0, 0, 0.2), 0 6px 20px rgba(0, 0, 0, 0.19);\n  }\n}\n#profile-main .pmo-pic .pmo-stat {\n  border-radius: 0 0 2px 2px;\n  color: #fff;\n  text-align: center;\n  padding: 30px 5px 0;\n}\n@media (min-width: 768px) {\n  #profile-main .pmo-pic .pmo-stat {\n    background: #ffc107;\n    padding-bottom: 15px;\n  }\n}\n#profile-main .pmo-pic .pmop-edit {\n  position: absolute;\n  top: 0;\n  left: 0;\n  color: #fff;\n  background: rgba(0, 0, 0, 0.38);\n  text-align: center;\n  padding: 10px 10px 11px;\n  -webkit-transition: opacity;\n  -o-transition: opacity;\n  transition: opacity;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n#profile-main .pmo-pic .pmop-edit:hover {\n  background: rgba(0, 0, 0, 0.8);\n}\n#profile-main .pmo-pic .pmop-edit i {\n  font-size: 18px;\n  vertical-align: middle;\n  margin-top: -3px;\n}\n@media (min-width: 768px) {\n  #profile-main .pmo-pic .pmop-edit {\n    width: 100%;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n  #profile-main .pmo-pic .pmop-edit i {\n    margin-right: 4px;\n  }\n}\n#profile-main .pmo-pic:hover .pmop-edit {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n#profile-main .pmo-pic .pmop-message {\n  position: absolute;\n  bottom: 27px;\n  left: 50%;\n  margin-left: -25px;\n}\n#profile-main .pmo-pic .pmop-message .dropdown-menu {\n  padding: 5px 0 55px;\n  left: -90px;\n  width: 228px;\n  height: 150px;\n  top: -74px;\n  -webkit-transform-origin: center;\n  -moz-transform-origin: center;\n  -ms-transform-origin: center;\n  transform-origin: center;\n}\n#profile-main .pmo-pic .pmop-message .dropdown-menu textarea {\n  width: 100%;\n  height: 95px;\n  border: 0;\n  resize: none;\n  padding: 10px 19px;\n}\n#profile-main .pmo-pic .pmop-message .dropdown-menu button {\n  bottom: 5px;\n  left: 88px;\n}\n#profile-main .pmb-block {\n  margin-bottom: 20px;\n}\n@media (min-width: 1200px) {\n  #profile-main .pmb-block {\n    padding: 40px 42px 0;\n  }\n}\n@media (max-width: 1199px) {\n  #profile-main .pmb-block {\n    padding: 30px 20px 0;\n  }\n}\n#profile-main .pmb-block:last-child {\n  margin-bottom: 50px;\n}\n#profile-main .pmb-block .pmbb-header {\n  margin-bottom: 25px;\n  position: relative;\n}\n#profile-main .pmb-block .pmbb-header .actions {\n  position: absolute;\n  top: -2px;\n  right: 0;\n}\n#profile-main .pmb-block .pmbb-header h2 {\n  margin: 0;\n  font-weight: 100;\n  font-size: 20px;\n}\n#profile-main .pmb-block .pmbb-edit {\n  position: relative;\n  z-index: 1;\n  display: none;\n}\n#profile-main .pmb-block .pmbb-edit,\n#profile-main .pmb-block .pmbb-view {\n  -webkit-animation-name: fadeIn;\n  animation-name: fadeIn;\n  -webkit-animation-duration: 1000ms;\n  animation-duration: 1000ms;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n#profile-main .pmb-block.toggled .pmbb-edit {\n  display: block;\n}\n#profile-main .pmb-block.toggled .pmbb-view {\n  display: none;\n}\n#profile-main .pmo-block {\n  padding: 25px;\n}\n#profile-main .pmo-block > h2 {\n  font-size: 16px;\n  margin: 0 0 15px;\n}\n#profile-main .pmo-items .pmob-body {\n  padding: 0 10px;\n}\n#profile-main .pmo-items a {\n  display: block;\n  padding: 4px;\n}\n#profile-main .pmo-items a img {\n  width: 100%;\n}\n.pmo-contact ul {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n}\n.pmo-contact ul li {\n  position: relative;\n  padding: 8px 0 8px 35px;\n}\n.pmo-contact ul li i {\n  font-size: 18px;\n  vertical-align: top;\n  line-height: 100%;\n  position: absolute;\n  left: 0;\n  width: 18px;\n  text-align: center;\n}\n.pmo-map {\n  margin: 20px -21px -18px;\n  display: block;\n}\n.pmo-map img {\n  width: 100%;\n}\n@media (max-width: 767px) {\n  .c-timeline {\n    background: #edecec;\n    box-shadow: none;\n  }\n  .c-timeline .tab-nav {\n    background: #fff;\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  }\n}\n.timeline {\n  position: relative;\n}\n@media (min-width: 768px) {\n  .timeline {\n    padding: 50px;\n    padding-left: 100px;\n  }\n}\n@media (max-width: 767px) {\n  .timeline {\n    margin-top: 30px;\n  }\n}\n.t-view {\n  border: 1px solid #eee;\n  position: relative;\n  margin-bottom: 35px;\n}\n@media (max-width: 767px) {\n  .t-view {\n    background: #fff;\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  }\n}\n.t-view .tv-header {\n  padding: 16px 18px;\n  border-bottom: 1px solid #eee;\n  background: #F9F9F9;\n}\n.t-view .tv-header .actions {\n  position: absolute;\n  top: 5px;\n  right: 10px;\n}\n.t-view .tv-body {\n  padding: 23px 25px;\n}\n.t-view .tv-body .tvb-lightbox {\n  margin: 0 -8px 15px;\n}\n.t-view .tv-body .tvb-lightbox [data-src] {\n  padding: 0 5px;\n  margin-bottom: 5px;\n}\n.t-view .tvh-user {\n  display: block;\n}\n.t-view .tvh-user img {\n  width: 46px;\n  height: 46px;\n  border-radius: 50%;\n}\n.t-view:before {\n  position: absolute;\n  width: 40px;\n  height: 40px;\n  border-radius: 50%;\n  left: -70px;\n  top: 0;\n  border: 3px solid #FFF;\n  text-align: center;\n  font-size: 16px;\n  line-height: 34px;\n  color: #FFF;\n  font-family: 'Material-Design-Iconic-Font';\n  z-index: 1;\n}\n.t-view:after {\n  content: \"\";\n  position: absolute;\n  top: 0;\n  left: -50px;\n  width: 1px;\n  height: calc(100% + 37px);\n}\n.t-view[data-tv-type=\"text\"]:before {\n  content: \"\\f24f\";\n  background: #00bcd4;\n  box-shadow: 0 0 0 1px #00bcd4;\n}\n.t-view[data-tv-type=\"text\"]:after {\n  background: #00bcd4;\n}\n.t-view[data-tv-type=\"image\"]:before {\n  content: \"\\f17f\";\n  background: #4caf50;\n  box-shadow: 0 0 0 1px #4caf50;\n}\n.t-view[data-tv-type=\"image\"]:after {\n  background: #4caf50;\n}\n.t-view[data-tv-type=\"video\"]:before {\n  content: \"\\f3a9\";\n  background: #ffc107;\n  box-shadow: 0 0 0 1px #ffc107;\n}\n.t-view[data-tv-type=\"video\"]:after {\n  background: #ffc107;\n}\n.t-view .tvb-stats {\n  list-style: none;\n  padding: 0;\n  margin: 10px 0 20px;\n}\n.t-view .tvb-stats > li {\n  display: inline-block;\n  padding: 5px 10px 6px;\n  border: 1px solid #ccc;\n  margin-right: 2px;\n}\n.t-view .tvb-stats > li i {\n  font-size: 15px;\n  line-height: 100%;\n  vertical-align: top;\n  margin-top: 2px;\n}\n.t-view .tvb-stats > li.tvbs-comments {\n  border-color: #4caf50;\n  color: #4caf50;\n}\n.t-view .tvb-stats > li.tvbs-likes {\n  border-color: #03a9f4;\n  color: #03a9f4;\n}\n.t-view .tvb-stats > li.tvbs-views {\n  border-color: #ff9800;\n  color: #ff9800;\n}\n.tv-comments .tvc-lists {\n  padding: 0;\n  list-style: none;\n  margin: 0;\n}\n.tv-comments .tvc-lists > li {\n  padding: 15px 20px;\n  margin: 0;\n  border-top: 1px solid #eee;\n}\n.tvc-more {\n  color: #333;\n  display: block;\n  margin-bottom: -10px;\n}\n.tvc-more:hover {\n  color: #000;\n}\n.tvc-more i {\n  vertical-align: middle;\n  margin-right: 5px;\n}\n.p-header {\n  position: relative;\n  margin: 0 -7px;\n}\n.p-header .actions {\n  position: absolute;\n  top: -18px;\n  right: 0;\n}\n.p-menu {\n  list-style: none;\n  padding: 0 5px;\n  margin: 0 0 30px;\n}\n.p-menu > li {\n  display: inline-block;\n  vertical-align: top;\n}\n.p-menu > li > a {\n  display: block;\n  padding: 5px 20px 5px 0;\n  font-weight: 500;\n  text-transform: uppercase;\n  font-size: 15px;\n}\n.p-menu > li > a > i {\n  margin-right: 4px;\n  font-size: 20px;\n  vertical-align: middle;\n  margin-top: -5px;\n}\n.p-menu > li:not(.active) > a {\n  color: #4285F4;\n}\n.p-menu > li:not(.active) > a:hover {\n  color: #333;\n}\n.p-menu > li.active > a {\n  color: #000;\n}\n@media (max-width: 991px) {\n  .p-menu .pm-search {\n    margin: 20px 2px 30px;\n    display: block;\n  }\n  .p-menu .pm-search input[type=\"text\"] {\n    width: 100%;\n    border: 1px solid #ccc;\n  }\n}\n.p-menu .pms-inner {\n  margin: -2px 0 0;\n  position: relative;\n  top: -2px;\n  overflow: hidden;\n  white-space: nowrap;\n}\n.p-menu .pms-inner i {\n  vertical-align: top;\n  font-size: 20px;\n  line-height: 100%;\n  position: absolute;\n  left: 9px;\n  top: 8px;\n  color: #333;\n}\n.p-menu .pms-inner input[type=\"text\"] {\n  height: 35px;\n  border-radius: 2px;\n  padding: 0 10px 0 40px;\n}\n@media (min-width: 768px) {\n  .p-menu .pms-inner input[type=\"text\"] {\n    border: 1px solid #fff;\n    width: 50px;\n    background: transparent;\n    position: relative;\n    z-index: 1;\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 300ms;\n    transition-duration: 300ms;\n  }\n  .p-menu .pms-inner input[type=\"text\"]:focus {\n    border-color: #DFDFDF;\n    width: 200px;\n  }\n}\n.photos {\n  margin: 2px 0 0;\n}\n.photos .lightbox {\n  margin: 0 -8px;\n}\n.photos:not(.p-timeline) [data-src] {\n  padding: 3px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 150ms;\n  transition-duration: 150ms;\n}\n.p-timeline {\n  position: relative;\n  padding-left: 80px;\n  margin-bottom: 75px;\n}\n.p-timeline [data-src] {\n  float: left;\n  width: 70px;\n  height: 70px;\n  margin: 0 3px 3px 0;\n}\n.p-timeline:last-child .pt-line:before {\n  height: 100%;\n}\n.ptb-title {\n  font-size: 15px;\n  font-weight: 400;\n  margin-bottom: 20px;\n}\n.pt-line {\n  position: absolute;\n  left: 0;\n  top: 0;\n  height: 100%;\n  line-height: 14px;\n}\n.pt-line:before,\n.pt-line:after {\n  content: \"\";\n  position: absolute;\n}\n.pt-line:before {\n  width: 1px;\n  height: calc(100% + 63px);\n  background: #E2E2E2;\n  top: 14px;\n  right: -20px;\n}\n.pt-line:after {\n  top: 2px;\n  right: -26px;\n  width: 13px;\n  height: 13px;\n  border: 1px solid #C1C1C1;\n  border-radius: 50%;\n}\n.contacts:not(.c-profile) {\n  padding: 0 8px;\n}\n.contacts > [class*=\"col-\"] {\n  padding: 0 10px;\n}\n.contacts .c-item {\n  border: 1px solid #e2e2e2;\n  border-radius: 2px;\n  margin-bottom: 24px;\n}\n.contacts .c-item .ci-avatar {\n  display: block;\n}\n.contacts .c-item .ci-avatar img {\n  width: 100%;\n  border-radius: 2px 2px 0 0;\n}\n.contacts .ci-avatar {\n  margin: -1px -1px 0;\n}\n.contacts .c-info {\n  text-align: center;\n  margin-top: 15px;\n  padding: 0 5px;\n}\n.contacts .c-info strong {\n  color: #000;\n  font-size: 14px;\n  font-weight: 500;\n}\n.contacts .c-info small {\n  color: #999;\n  margin-top: 3px;\n}\n.contacts .c-info strong,\n.contacts .c-info small {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  display: block;\n}\n.contacts .c-footer {\n  border-top: 1px solid #e2e2e2;\n  margin-top: 18px;\n}\n.contacts .c-footer > button {\n  padding: 4px 10px 3px;\n  display: block;\n  width: 100%;\n  text-align: center;\n  color: #333;\n  font-weight: 500;\n  border-radius: 2px;\n  background: #fff;\n  border: 0;\n}\n.contacts .c-footer > button > i {\n  font-size: 16px;\n  vertical-align: middle;\n  margin-top: -3px;\n}\n.z-depth-1 {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n.z-depth-1-top {\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n.z-depth-1-bottom {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16);\n}\n.z-depth-2 {\n  box-shadow: 0 8px 17px rgba(0, 0, 0, 0.2), 0 6px 20px rgba(0, 0, 0, 0.19);\n}\n.z-depth-2-top {\n  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.19);\n}\n.z-depth-2-bottom {\n  box-shadow: 0 8px 17px rgba(0, 0, 0, 0.2);\n}\n.z-depth-3 {\n  box-shadow: 0 12px 15px rgba(0, 0, 0, 0.24), 0 17px 50px rgba(0, 0, 0, 0.19);\n}\n.z-depth-3-top {\n  box-shadow: 0 17px 50px rgba(0, 0, 0, 0.19);\n}\n.z-depth-3-bottom {\n  box-shadow: 0 12px 15px rgba(0, 0, 0, 0.24);\n}\n.z-depth-4 {\n  box-shadow: 0 16px 28px rgba(0, 0, 0, 0.22), 0 25px 55px rgba(0, 0, 0, 0.21);\n}\n.z-depth-4-top {\n  box-shadow: 0 25px 55px rgba(0, 0, 0, 0.21);\n}\n.z-depth-4-bottom {\n  box-shadow: 0 16px 28px rgba(0, 0, 0, 0.22);\n}\n.z-depth-5 {\n  box-shadow: 0 27px 24px rgba(0, 0, 0, 0.2), 0 40px 77px rgba(0, 0, 0, 0.22);\n}\n.z-depth-5-top {\n  box-shadow: 0 40px 77px rgba(0, 0, 0, 0.22);\n}\n.z-depth-5-bottom {\n  box-shadow: 0 27px 24px rgba(0, 0, 0, 0.2);\n}\n.z-depth-animation .z-depth-1,\n.z-depth-animation .z-depth-2,\n.z-depth-animation .z-depth-3,\n.z-depth-animation .z-depth-4,\n.z-depth-animation .z-depth-5 {\n  transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n}\n/*\n * Block Header\n * Used for Heading outside the Cards.\n */\n.block-header {\n  margin-bottom: 25px;\n  position: relative;\n}\n@media screen and (min-width: 768px) {\n  .block-header {\n    padding: 0 22px;\n  }\n}\n@media screen and (max-width: 991px) {\n  .block-header {\n    padding: 0 18px;\n  }\n}\n.block-header > h2 {\n  font-size: 15px;\n  color: #777;\n  margin: 0;\n  font-weight: 400;\n  text-transform: uppercase;\n}\n.block-header > h2 > small {\n  display: block;\n  text-transform: none;\n  margin-top: 8px;\n  margin-bottom: 20px;\n  color: #9E9E9E;\n  line-height: 140%;\n}\n.block-header .actions {\n  position: absolute;\n  right: 10px;\n  top: -5px;\n  z-index: 4;\n}\n/*\n * Header Actions\n */\n.actions {\n  list-style: none;\n  padding: 0;\n  z-index: 3;\n  margin: 0;\n}\n.actions > li {\n  display: inline-block;\n  vertical-align: baseline;\n}\n.actions > li > a,\n.actions > a {\n  width: 30px;\n  height: 30px;\n  display: inline-block;\n  text-align: center;\n  padding-top: 5px;\n}\n.actions > li > a > i,\n.actions > a > i {\n  color: #adadad;\n  font-size: 20px;\n}\n.actions > li > a:hover > i,\n.actions > a:hover > i {\n  color: #000;\n}\n@media (min-width: 768px) {\n  .actions > li > a,\n  .actions > a {\n    position: relative;\n  }\n  .actions > li > a:before,\n  .actions > a:before {\n    left: 0;\n    top: 0;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    -webkit-transform: scale3d(0, 0, 0);\n    -moz-transform: scale3d(0, 0, 0);\n    -ms-transform: scale3d(0, 0, 0);\n    -o-transform: scale3d(0, 0, 0);\n    transform: scale3d(0, 0, 0);\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 250ms;\n    transition-duration: 250ms;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    background-color: rgba(0, 0, 0, 0.1);\n    z-index: 0;\n    border-radius: 50%;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n  .actions > li > a:hover:before,\n  .actions > a:hover:before,\n  .actions > li > a.open:before,\n  .actions > a.open:before {\n    -webkit-transform: scale3d(1, 1, 1);\n    -moz-transform: scale3d(1, 1, 1);\n    -ms-transform: scale3d(1, 1, 1);\n    -o-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n.actions > li.open > a > i,\n.actions.open > a > i {\n  color: #000;\n}\n.actions > li.open > a:before,\n.actions.open > a:before {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.actions.actions-alt > li > a > i {\n  color: #fff;\n}\n.actions.actions-alt > li > a > i:hover {\n  color: #fff;\n}\n.actions.actions-alt > li.open > a > i {\n  color: #fff;\n}\n.actions.open {\n  z-index: 3;\n}\n/*\n * Collapse Menu Icons\n */\n.line-wrap {\n  width: 18px;\n  height: 12px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  margin: 12px 20px;\n}\n.line-wrap .line {\n  width: 18px;\n  height: 2px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.line-wrap .line.center {\n  margin: 3px 0;\n}\n.open .line-wrap {\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  -o-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.open .line-wrap .line.top {\n  width: 12px;\n  transform: translateX(8px) translateY(1px) rotate(45deg);\n  -webkit-transform: translateX(8px) translateY(1px) rotate(45deg);\n}\n.open .line-wrap .line.bottom {\n  width: 12px;\n  transform: translateX(8px) translateY(-1px) rotate(-45deg);\n  -webkit-transform: translateX(8px) translateY(-1px) rotate(-45deg);\n}\n/*\n * Load More\n */\n.load-more {\n  text-align: center;\n  margin-top: 30px;\n}\n.load-more a {\n  padding: 5px 10px 3px;\n  display: inline-block;\n  background-color: #f44336;\n  color: #FFF;\n  border-radius: 2px;\n  white-space: nowrap;\n}\n.load-more a i {\n  font-size: 20px;\n  vertical-align: middle;\n  position: relative;\n  margin-top: -2px;\n}\n.load-more a:hover {\n  background-color: #ea1c0d;\n}\n/*\n * Page Loader\n */\nhtml:not(.ismobile) .page-loader {\n  background: #fff;\n  position: fixed;\n  width: 100%;\n  height: 100%;\n  top: 0;\n  left: 0;\n  z-index: 1000;\n}\nhtml:not(.ismobile) .page-loader .preloader {\n  width: 50px;\n  position: absolute;\n  left: 50%;\n  margin-left: -25px;\n  top: 50%;\n  margin-top: -55px;\n  -webkit-animation-name: fadeIn;\n  animation-name: fadeIn;\n  -webkit-animation-duration: 3000ms;\n  animation-duration: 3000ms;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\nhtml:not(.ismobile) .page-loader .preloader p {\n  white-space: nowrap;\n  position: relative;\n  left: -9px;\n  top: 22px;\n  color: #CCC;\n}\nhtml.ismobile .page-loader {\n  display: none;\n}\n.ie-warning {\n  position: fixed;\n  top: 0;\n  left: 0;\n  z-index: 9999;\n  background: #000000;\n  width: 100%;\n  height: 100%;\n  text-align: center;\n  color: #fff;\n  font-family: \"Courier New\", Courier, monospace;\n  padding: 50px 0;\n}\n.ie-warning p {\n  font-size: 17px;\n}\n.ie-warning .iew-container {\n  min-width: 1024px;\n  width: 100%;\n  height: 200px;\n  background: #fff;\n  margin: 50px 0;\n}\n.ie-warning .iew-download {\n  list-style: none;\n  padding: 30px 0;\n  margin: 0 auto;\n  width: 720px;\n}\n.ie-warning .iew-download > li {\n  float: left;\n  vertical-align: top;\n}\n.ie-warning .iew-download > li > a {\n  display: block;\n  color: #000;\n  width: 140px;\n  font-size: 15px;\n  padding: 15px 0;\n}\n.ie-warning .iew-download > li > a > div {\n  margin-top: 10px;\n}\n.ie-warning .iew-download > li > a:hover {\n  background-color: #eee;\n}\n#footer {\n  position: absolute;\n  bottom: 0;\n  text-align: center;\n  width: 100%;\n  height: 110px;\n  color: #a2a2a2;\n  padding-top: 35px;\n  padding-bottom: 15px;\n}\n#footer .f-menu {\n  display: block;\n  width: 100%;\n  padding-left: 0;\n  list-style: none;\n  margin-left: -5px;\n  margin-top: 8px;\n}\n#footer .f-menu > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\n#footer .f-menu > li > a {\n  color: #a2a2a2;\n}\n#footer .f-menu > li > a:hover {\n  color: #777;\n}\n@media (min-width: 1199px) {\n  body.sw-toggled #footer {\n    padding-left: 268px;\n  }\n}\n.pt-inner {\n  text-align: center;\n}\n.pt-inner .pti-header {\n  padding: 45px 10px 70px;\n  color: #fff;\n  position: relative;\n  margin-bottom: 15px;\n}\n.pt-inner .pti-header > h2 {\n  margin: 0;\n  line-height: 100%;\n  color: #fff;\n  font-weight: 100;\n  font-size: 50px;\n}\n.pt-inner .pti-header > h2 small {\n  color: #fff;\n  letter-spacing: 0;\n  vertical-align: top;\n  font-size: 16px;\n  font-weight: 100;\n}\n.pt-inner .pti-header .ptih-title {\n  background-color: rgba(0, 0, 0, 0.1);\n  padding: 8px 10px 9px;\n  text-transform: uppercase;\n  margin: 0 -10px;\n  position: absolute;\n  width: 100%;\n  bottom: 0;\n}\n.pt-inner .pti-body {\n  padding: 0 23px;\n}\n.pt-inner .pti-body .ptib-item {\n  padding: 15px 0;\n  font-weight: 400;\n}\n.pt-inner .pti-body .ptib-item:not(:last-child) {\n  border-bottom: 1px solid #eee;\n}\n.pt-inner .pti-footer {\n  padding: 10px 20px 30px;\n}\n.pt-inner .pti-footer > a {\n  width: 60px;\n  height: 60px;\n  border-radius: 50%;\n  text-align: center;\n  color: #fff;\n  display: inline-block;\n  line-height: 60px;\n  font-size: 30px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.pt-inner .pti-footer > a:hover {\n  opacity: 0.85;\n  filter: alpha(opacity=85);\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n.invoice {\n  min-width: 1100px;\n  max-width: 1170px;\n}\n.i-logo {\n  width: 150px;\n}\n.i-table .highlight {\n  background-color: #eee;\n  border-bottom: 1px solid #e6e6e6;\n}\n.i-table td.highlight {\n  font-size: 14px;\n  font-weight: 500;\n}\n.wall-attrs {\n  margin-bottom: 0;\n}\n.wa-stats {\n  float: left;\n}\n.wa-stats > span {\n  margin-right: -1px;\n  padding: 7px 12px;\n  border: 1px solid #E0E0E0;\n  float: left;\n  font-weight: 500;\n}\n.wa-stats > span.active {\n  color: #4caf50;\n}\n.wa-stats > span:first-child {\n  border-radius: 2px 0 0 2px;\n}\n.wa-stats > span:last-child {\n  border-radius: 0 2px 2px 0;\n}\n.wa-stats > span > i {\n  line-height: 100%;\n  vertical-align: top;\n  position: relative;\n  top: 2px;\n  font-size: 15px;\n  margin-right: 2px;\n}\n.wa-users {\n  float: right;\n  padding: 0 !important;\n  margin-right: -5px;\n}\n.wa-users > a {\n  display: inline-block;\n  margin-left: 2px;\n}\n.wa-users > a > img {\n  width: 33px;\n  height: 33px;\n  border-radius: 50%;\n}\n.wa-users > a > img:hover {\n  opacity: 0.85;\n  filter: alpha(opacity=85);\n}\n.wcc-inner {\n  border: 1px solid #E4E4E4;\n  padding: 10px 15px;\n  resize: none;\n  border-radius: 2px;\n  background: #fff;\n  color: #9A9A9A;\n  cursor: pointer;\n}\n.wcci-text {\n  border: 0;\n  display: block;\n  width: 100%;\n  resize: none;\n  padding: 0;\n}\n.wall-comment-list {\n  padding: 20px;\n  background: #f7f7f7;\n}\n.wall-comment-list .media {\n  position: relative;\n}\n.wall-comment-list .media:hover .actions {\n  display: block;\n}\n.wall-comment-list .actions {\n  display: none;\n  position: absolute;\n  right: -20px;\n  top: -1px;\n}\n.wcl-list + .wcl-form {\n  margin-top: 25px;\n}\n.wp-text {\n  border: 0;\n  padding: 0;\n  display: block;\n  width: 100%;\n  resize: none;\n}\n.wp-media {\n  background: #f7f7f7;\n  border: 1px solid #E4E4E4;\n  padding: 12px 15px;\n  margin-top: 25px;\n  text-align: center;\n}\n.wpb-actions {\n  background: #f7f7f7;\n  margin: 0;\n  padding: 10px 20px;\n}\n.wpb-actions > li:not(.pull-right) {\n  float: left;\n}\n[data-wpba=\"image\"] {\n  color: #4caf50;\n}\n[data-wpba=\"image\"]:hover {\n  color: #449d48;\n}\n[data-wpba=\"video\"] {\n  color: #ff9800;\n}\n[data-wpba=\"video\"]:hover {\n  color: #e68900;\n}\n[data-wpba=\"link\"] {\n  color: #00bcd4;\n}\n[data-wpba=\"link\"]:hover {\n  color: #00a5bb;\n}\n.wpba-attrs > ul > li {\n  padding: 0;\n  margin-right: 5px;\n}\n.wpba-attrs > ul > li > a {\n  display: block;\n  width: 22px;\n}\n.wpba-attrs > ul > li > a > i {\n  font-size: 20px;\n}\n.wpba-attrs > ul > li.active i {\n  color: #333;\n}\n.wall-img-preview {\n  text-align: center;\n}\n@media screen and (min-width: 768px) {\n  .wall-img-preview {\n    margin: 0 -23px 20px;\n  }\n}\n@media screen and (max-width: 991px) {\n  .wall-img-preview {\n    margin: 0 -16px 20px;\n  }\n}\n.wall-img-preview .wip-item {\n  display: block;\n  float: left;\n  position: relative;\n  overflow: hidden;\n  border: 2px solid #fff;\n  background-repeat: no-repeat;\n  -webkit-background-size: cover;\n  -moz-background-size: cover;\n  -o-background-size: cover;\n  background-size: cover;\n  background-position: center;\n}\n.wall-img-preview .wip-item > img {\n  display: none;\n}\n.wall-img-preview .wip-item:first-child:nth-last-child(2),\n.wall-img-preview .wip-item:first-child:nth-last-child(2) ~ div {\n  width: 50%;\n  padding-bottom: 40%;\n}\n.wall-img-preview .wip-item:first-child:nth-last-child(3),\n.wall-img-preview .wip-item:first-child:nth-last-child(3) ~ div,\n.wall-img-preview .wip-item:first-child:nth-last-child(4),\n.wall-img-preview .wip-item:first-child:nth-last-child(4) ~ div:not(:last-child),\n.wall-img-preview .wip-item:first-child:nth-last-child(5),\n.wall-img-preview .wip-item:first-child:nth-last-child(5) ~ div:not( :nth-last-of-type(-n+2)),\n.wall-img-preview .wip-item:first-child:nth-last-child(6),\n.wall-img-preview .wip-item:first-child:nth-last-child(6) ~ div,\n.wall-img-preview .wip-item:first-child:nth-last-child(7) ~ div:nth-last-of-type(-n+3) {\n  width: 33.333333%;\n  padding-bottom: 30%;\n}\n.wall-img-preview .wip-item:first-child:nth-last-child(5) ~ div:nth-last-of-type(-n+2) {\n  width: 50%;\n  padding-bottom: 40%;\n}\n.wall-img-preview .wip-item:first-child:nth-last-child(7),\n.wall-img-preview .wip-item:first-child:nth-last-child(7) ~ div:not( :nth-last-of-type(-n+3)),\n.wall-img-preview .wip-item:first-child:nth-last-child(n+8),\n.wall-img-preview .wip-item:first-child:nth-last-child(n+8) ~ div {\n  width: 25%;\n  padding-bottom: 22%;\n}\n.wall-img-preview .wip-item:only-child,\n.wall-img-preview .wip-item:first-child:nth-last-child(4) ~ div:nth-child(4) {\n  width: 100%;\n  padding-bottom: 50%;\n}\n/*\n * For header type 1 only\n * You may remove these if you opt header 2\n */\n#header .skin-switch {\n  padding: 10px 0 2px;\n  text-align: center;\n}\n#header .ss-skin {\n  width: 16px;\n  height: 16px;\n  border-radius: 50%;\n  cursor: pointer;\n  display: inline-block;\n  margin: 2px 3px;\n}\n/* ----------------------------- End header type 1 ------------------------------------- */\n/*\n * For header type 2 only\n * You may remove these if you opt header 1\n */\n#header-2 .skin-switch {\n  position: absolute;\n  right: 50px;\n  bottom: 23px;\n  z-index: 1;\n}\n#header-2 .skin-switch .btn {\n  background: #fff;\n  width: 50px;\n  height: 50px;\n  border-radius: 50%;\n  font-size: 25px;\n  z-index: 2;\n}\n#header-2 .skin-switch .dropdown-menu {\n  min-width: 130px;\n  height: 130px;\n  border-radius: 50%;\n  width: 130px;\n  top: -42px;\n  left: -40px;\n  z-index: 1;\n  -webkit-transform-origin: center;\n  -moz-transform-origin: center;\n  -ms-transform-origin: center;\n  transform-origin: center;\n  -webkit-transform: scale(0) rotate(-360deg);\n  -ms-transform: scale(0) rotate(-360deg);\n  -o-transform: scale(0) rotate(-360deg);\n  transform: scale(0) rotate(-360deg);\n  -webkit-transition-duration: 500ms;\n  transition-duration: 500ms;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin {\n  position: absolute;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-1 {\n  margin-left: -8px;\n  top: 12px;\n  left: 50%;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-2 {\n  right: 24px;\n  top: 26px;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-3 {\n  top: 50%;\n  margin-top: -8px;\n  right: 12px;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-4 {\n  right: 24px;\n  bottom: 26px;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-5 {\n  margin-left: -8px;\n  bottom: 12px;\n  left: 50%;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-6 {\n  left: 24px;\n  bottom: 26px;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-7 {\n  top: 50%;\n  margin-top: -8px;\n  left: 12px;\n}\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-8 {\n  left: 24px;\n  top: 26px;\n}\n#header-2 .skin-switch.open .dropdown-menu {\n  -webkit-transform: scale(1) rotate(0deg);\n  -ms-transform: scale(1) rotate(0deg);\n  -o-transform: scale(1) rotate(0deg);\n  transform: scale(1) rotate(0deg);\n}\n/* ----------------------------- End header type 2 ------------------------------------- */\n/*\n * Do not remove these\n * This is common for both\n */\n.ss-skin {\n  width: 16px;\n  height: 16px;\n  border-radius: 50%;\n  cursor: pointer;\n}\n.ss-skin:hover {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n[data-current-skin=\"lightblue\"] {\n  background-color: #03a9f4;\n}\n[data-current-skin=\"lightblue\"] .ss-icon {\n  color: #03a9f4;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"lightblue\"] .ha-menu {\n    background: #03a9f4;\n  }\n}\n[data-current-skin=\"bluegray\"] {\n  background-color: #607d8b;\n}\n[data-current-skin=\"bluegray\"] .ss-icon {\n  color: #607d8b;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"bluegray\"] .ha-menu {\n    background: #607d8b;\n  }\n}\n[data-current-skin=\"blue\"] {\n  background-color: #2196f3;\n}\n[data-current-skin=\"blue\"] .ss-icon {\n  color: #2196f3;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"blue\"] .ha-menu {\n    background: #2196f3;\n  }\n}\n[data-current-skin=\"purple\"] {\n  background-color: #9c27b0;\n}\n[data-current-skin=\"purple\"] .ss-icon {\n  color: #9c27b0;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"purple\"] .ha-menu {\n    background: #9c27b0;\n  }\n}\n[data-current-skin=\"orange\"] {\n  background-color: #ff9800;\n}\n[data-current-skin=\"orange\"] .ss-icon {\n  color: #ff9800;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"orange\"] .ha-menu {\n    background: #ff9800;\n  }\n}\n[data-current-skin=\"cyan\"] {\n  background-color: #00bcd4;\n}\n[data-current-skin=\"cyan\"] .ss-icon {\n  color: #00bcd4;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"cyan\"] .ha-menu {\n    background: #00bcd4;\n  }\n}\n[data-current-skin=\"green\"] {\n  background-color: #4caf50;\n}\n[data-current-skin=\"green\"] .ss-icon {\n  color: #4caf50;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"green\"] .ha-menu {\n    background: #4caf50;\n  }\n}\n[data-current-skin=\"teal\"] {\n  background-color: #009688;\n}\n[data-current-skin=\"teal\"] .ss-icon {\n  color: #009688;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"teal\"] .ha-menu {\n    background: #009688;\n  }\n}\n[data-current-skin=\"pink\"] {\n  background-color: #e91e63;\n}\n[data-current-skin=\"pink\"] .ss-icon {\n  color: #e91e63;\n}\n@media (max-width: 767px) {\n  [data-current-skin=\"pink\"] .ha-menu {\n    background: #e91e63;\n  }\n}\n.preloader {\n  position: relative;\n  margin: 0px auto;\n  display: inline-block;\n}\n.preloader:not([class*=\"pl-\"]) {\n  width: 40px;\n}\n.preloader:before {\n  content: '';\n  display: block;\n  padding-top: 100%;\n}\n.preloader.pl-xs {\n  width: 20px;\n}\n.preloader.pl-sm {\n  width: 30px;\n}\n.preloader.pl-lg {\n  width: 50px;\n}\n.preloader.pl-xl {\n  width: 80px;\n}\n.preloader.pl-xxl {\n  width: 100px;\n}\n.preloader:not([class*=\"pls-\"]) .plc-path {\n  animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;\n}\n.preloader[class*=\"pls-\"] .plc-path {\n  animation: dash 1.5s ease-in-out infinite;\n}\n.preloader.pls-red .plc-path {\n  stroke: #f44336;\n}\n.preloader.pls-blue .plc-path {\n  stroke: #2196f3;\n}\n.preloader.pls-green .plc-path {\n  stroke: #4caf50;\n}\n.preloader.pls-yellow .plc-path {\n  stroke: #ffeb3b;\n}\n.preloader.pls-bluegray .plc-path {\n  stroke: #607d8b;\n}\n.preloader.pls-amber .plc-path {\n  stroke: #ffc107;\n}\n.preloader.pls-teal .plc-path {\n  stroke: #009688;\n}\n.preloader.pls-gray .plc-path {\n  stroke: #9e9e9e;\n}\n.preloader.pls-pink .plc-path {\n  stroke: #e91e63;\n}\n.preloader.pls-purple .plc-path {\n  stroke: #9c27b0;\n}\n.preloader.pls-white .plc-path {\n  stroke: #fff;\n}\n.pl-circular {\n  animation: rotate 2s linear infinite;\n  height: 100%;\n  transform-origin: center center;\n  width: 100%;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  margin: auto;\n}\n.plc-path {\n  stroke-dasharray: 1,200;\n  stroke-dashoffset: 0;\n  stroke-linecap: round;\n  stroke-width: 2;\n  stroke-miterlimit: 10;\n  fill: none;\n}\n@keyframes rotate {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n@keyframes dash {\n  0% {\n    stroke-dasharray: 1,200;\n    stroke-dashoffset: 0;\n  }\n  50% {\n    stroke-dasharray: 89,200;\n    stroke-dashoffset: -35px;\n  }\n  100% {\n    stroke-dasharray: 89,200;\n    stroke-dashoffset: -124px;\n  }\n}\n@keyframes color {\n  100%,\n  0% {\n    stroke: #f44336;\n  }\n  40% {\n    stroke: #2196f3;\n  }\n  66% {\n    stroke: #4caf50;\n  }\n  80%,\n  90% {\n    stroke: #ffc107;\n  }\n}\n@media print {\n  @page {\n    margin: 0;\n    size: auto;\n  }\n  body {\n    margin: 0mm 0mm 0mm 0mm !important;\n    padding: 0mm !important;\n  }\n  #header,\n  #footer,\n  #sidebar,\n  #chat,\n  .growl-animated,\n  .m-btn {\n    display: none !important;\n  }\n  /*\n     * INVOICE\n     */\n  .invoice {\n    padding: 30px !important;\n    -webkit-print-color-adjust: exact !important;\n  }\n  .invoice .card-header {\n    background: #eee !important;\n    padding: 20px;\n    margin-bottom: 20px;\n    margin: -60px -30px 25px -30px;\n  }\n  .invoice .block-header {\n    display: none;\n  }\n  .invoice .highlight {\n    background: #eee !important;\n  }\n}\n/*\n * Vendor Overrides\n */\n.mejs-container {\n  outline: none;\n}\n.mejs-container .mejs-controls {\n  background: #ec592f;\n  height: 50px;\n  padding: 10px 5px 0;\n}\n.mejs-container .mejs-controls div {\n  height: 5px;\n}\n.mejs-container .mejs-controls div.mejs-time-rail {\n  position: absolute;\n  left: 0;\n  top: 0;\n  padding: 0;\n  width: 100% !important;\n}\n.mejs-container .mejs-controls div.mejs-time-rail .mejs-time-total {\n  margin: 0;\n  width: 100% !important;\n  background: #ec592f;\n}\n.mejs-container .mejs-controls div.mejs-time-rail .mejs-time-loaded {\n  background: #D04B25;\n}\n.mejs-container .mejs-controls div.mejs-time-rail .mejs-time-current {\n  background: #ffea00;\n}\n.mejs-container .mejs-controls div.mejs-time-rail .mejs-time-buffering {\n  background: #ec592f;\n}\n.mejs-container .mejs-controls div.mejs-time-rail span:not(.mejs-time-float),\n.mejs-container .mejs-controls div.mejs-time-rail a {\n  border-radius: 0;\n  height: 3px;\n}\n.mejs-container .mejs-controls .mejs-button button {\n  background-color: #ec592f;\n  width: 15px;\n  height: 15px;\n  background-position: center;\n}\n.mejs-container .mejs-controls .mejs-button button:focus {\n  outline: none !important;\n}\n.mejs-container .mejs-controls .mejs-volume-button {\n  position: absolute;\n  right: 35px;\n}\n.mejs-container .mejs-controls .mejs-play button {\n  background-image: url(\"../img/icons/play.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-play button {\n    background-image: url(\"../img/icons/play@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n.mejs-container .mejs-controls .mejs-pause button {\n  background-image: url(\"../img/icons/pause.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-pause button {\n    background-image: url(\"../img/icons/pause@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n.mejs-container .mejs-controls .mejs-mute button {\n  background-image: url(\"../img/icons/speaker.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-mute button {\n    background-image: url(\"../img/icons/speaker@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n.mejs-container .mejs-controls .mejs-unmute button {\n  background-image: url(\"../img/icons/speaker-2.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-unmute button {\n    background-image: url(\"../img/icons/speaker-2@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n.mejs-container .mejs-controls .mejs-fullscreen-button {\n  position: absolute;\n  right: 5px;\n}\n.mejs-container .mejs-controls .mejs-fullscreen-button button {\n  background-image: url(\"../img/icons/fullscreen.png\");\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-fullscreen-button button {\n    background-image: url(\"../img/icons/fullscreen@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n/** CALENDAR WIDGET **/\n#calendar-widget {\n  margin-bottom: 30px;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n}\n#fc-actions {\n  position: absolute;\n  bottom: 10px;\n  right: 12px;\n}\n.fc {\n  background-color: #fff;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  margin-bottom: 30px;\n}\n.fc td,\n.fc th {\n  border-color: #f0f0f0;\n}\n.fc th {\n  font-weight: 400;\n}\n.fc table {\n  background: transparent;\n}\n.fc table tr > td:first-child {\n  border-left-width: 0;\n}\n#calendar-widget .fc-toolbar {\n  background: #009688;\n}\n#calendar-widget .fc-day-header {\n  color: #fff;\n  background: #007d71;\n  padding: 5px 0;\n  border-width: 0;\n}\n#calendar-widget .fc-day-number {\n  text-align: center;\n  color: #ADADAD;\n  padding: 5px 0;\n}\n#calendar-widget .fc-day-grid-event {\n  margin: 1px 3px 1px;\n}\n#calendar-widget .ui-widget-header th,\n#calendar-widget .ui-widget-header {\n  border-width: 0;\n}\n#calendar .fc-toolbar {\n  height: 300px;\n  background-image: url('../img/cal-header.jpg');\n  background-repeat: no-repeat;\n  -webkit-background-size: cover;\n  -moz-background-size: cover;\n  -o-background-size: cover;\n  background-size: cover;\n  background-position: center;\n  background-position: inherit;\n}\n#calendar .fc-toolbar:before {\n  content: \"\";\n  height: 50px;\n  width: 100%;\n  background: rgba(0, 0, 0, 0.36);\n  position: absolute;\n  bottom: 0;\n  left: 0;\n}\n#calendar .fc-toolbar .fc-center {\n  margin-top: 238px;\n  position: relative;\n}\n@media screen and (max-width: 991px) {\n  #calendar .fc-toolbar {\n    height: 200px;\n  }\n  #calendar .fc-toolbar .fc-center {\n    margin-top: 138px;\n  }\n}\n#calendar .fc-day-header {\n  color: #ADADAD;\n  text-align: left;\n  font-size: 14px;\n  border-bottom-width: 0;\n  border-right-color: #eee;\n  padding: 10px 12px;\n}\n#calendar .fc-day-number {\n  padding-left: 10px !important;\n  color: #CCC;\n  text-align: left !important;\n}\n@media screen and (min-width: 991px) {\n  #calendar .fc-day-number {\n    font-size: 25px;\n    letter-spacing: -2px;\n  }\n}\n#calendar .fc-day-grid-event {\n  margin: 1px 9px 0;\n}\n.fc-today {\n  color: #ffc107;\n}\n.fc-toolbar {\n  margin-bottom: 0;\n  padding: 20px 7px 19px;\n  position: relative;\n}\n.fc-toolbar h2 {\n  margin-top: 7px;\n  font-size: 20px;\n  font-weight: 400;\n  text-transform: uppercase;\n  color: #fff;\n}\n.fc-toolbar .ui-button {\n  border: 0;\n  background: 0 0;\n  padding: 0;\n  outline: none !important;\n  text-align: center;\n  width: 30px;\n  height: 30px;\n  border-radius: 50%;\n  margin-top: 2px;\n  color: #fff;\n}\n.fc-toolbar .ui-button:hover {\n  background: #fff;\n  color: #009688;\n}\n.fc-toolbar .ui-button > span {\n  position: relative;\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 20px;\n  line-height: 100%;\n  width: 30px;\n  display: block;\n  margin-top: 2px;\n}\n.fc-toolbar .ui-button > span:before {\n  position: relative;\n  z-index: 1;\n}\n.fc-toolbar .ui-button > span.ui-icon-circle-triangle-w:before {\n  content: \"\\f2fa\";\n}\n.fc-toolbar .ui-button > span.ui-icon-circle-triangle-e:before {\n  content: \"\\f2fb\";\n}\n.fc-event {\n  padding: 0;\n  font-size: 11px;\n  border-radius: 0;\n  border: 0;\n}\n.fc-event .fc-title {\n  padding: 2px 8px;\n  display: block;\n}\n.fc-event .fc-time {\n  float: left;\n  background: rgba(0, 0, 0, 0.2);\n  padding: 2px 6px;\n  margin: 0 0 0 -1px;\n}\n.fc-view,\n.fc-view > table {\n  border: 0;\n  overflow: hidden;\n}\n.fc-view > table > tbody > tr > .ui-widget-content {\n  border-top: 0;\n}\ndiv.fc-row {\n  margin-right: 0 !important;\n  border: 0 !important;\n}\n.fc-today {\n  color: #ffc107 !important;\n}\n/* Even Tag Color */\n.event-tag {\n  margin-top: 5px;\n}\n.event-tag > span {\n  border-radius: 50%;\n  width: 30px;\n  height: 30px;\n  margin-right: 3px;\n  position: relative;\n  display: inline-block;\n  cursor: pointer;\n}\n.event-tag > span:hover {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n.event-tag > span.selected:before {\n  font-family: 'Material-Design-Iconic-Font';\n  content: \"\\f26b\";\n  position: absolute;\n  text-align: center;\n  top: 3px;\n  width: 100%;\n  font-size: 17px;\n  color: #FFF;\n}\nhr.fc-divider {\n  border-width: 1px;\n  border-color: #eee;\n}\n.fc-day-grid-container.fc-scroller {\n  height: auto !important;\n  overflow: hidden !important;\n}\n.bootgrid-footer .infoBar,\n.bootgrid-header .actionBar {\n  text-align: left;\n}\n.bootgrid-footer .search,\n.bootgrid-header .search {\n  vertical-align: top;\n}\n.bootgrid-header {\n  padding: 0 25px 10px;\n}\n.bootgrid-header .search {\n  border: 1px solid #e0e0e0;\n}\n.bootgrid-header .search .form-control,\n.bootgrid-header .search .input-group-addon {\n  border: 0;\n}\n.bootgrid-header .search .glyphicon-search {\n  vertical-align: top;\n  padding: 9px 10px 0;\n}\n.bootgrid-header .search .glyphicon-search:before {\n  content: \"\\f1c3\";\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 17px;\n  vertical-align: top;\n  line-height: 100%;\n}\n@media (min-width: 480px) {\n  .bootgrid-header .search {\n    width: 300px;\n  }\n}\n@media (max-width: 480px) {\n  .bootgrid-header .search {\n    width: 100%;\n    padding-right: 90px;\n  }\n}\n.bootgrid-header .actions {\n  box-shadow: none;\n}\n.bootgrid-header .actions .btn-group {\n  border: 1px solid #e0e0e0;\n}\n.bootgrid-header .actions .btn-group .btn {\n  height: 35px;\n  box-shadow: none !important;\n  background: transparent;\n}\n.bootgrid-header .actions .btn-group .dropdown-menu {\n  padding: 10px 20px;\n}\n.bootgrid-header .actions .btn-group .dropdown-menu .dropdown-item {\n  padding: 0 0 0 27px !important;\n}\n.bootgrid-header .actions .btn-group .dropdown-menu .dropdown-item:hover {\n  background-color: #fff !important;\n}\n@media (min-width: 768px) {\n  .bootgrid-header .actions .btn-group .dropdown-menu {\n    left: 0;\n    -webkit-transform-origin: top left;\n    -moz-transform-origin: top left;\n    -ms-transform-origin: top left;\n    transform-origin: top left;\n    margin-top: 1px;\n  }\n}\n.bootgrid-header .actions .btn-group .caret {\n  display: none;\n}\n.bootgrid-header .actions .btn-group .zmdi {\n  line-height: 100%;\n  font-size: 18px;\n  vertical-align: top;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n.bootgrid-header .actions .btn-group.open .zmdi {\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  -o-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n@media (max-width: 480px) {\n  .bootgrid-header .actions {\n    position: absolute;\n    top: 0;\n    right: 15px;\n  }\n}\n.bootgrid-table th > .column-header-anchor > .icon {\n  top: 0px;\n  font-size: 20px;\n  line-height: 100%;\n}\n.bootgrid-footer .col-sm-6 {\n  padding: 10px 30px 20px;\n}\n@media (max-width: 768px) {\n  .bootgrid-footer .col-sm-6 {\n    text-align: center;\n  }\n}\n@media (max-width: 768px) {\n  .bootgrid-footer .infoBar {\n    display: none;\n  }\n}\n.bootgrid-footer .infoBar .infos {\n  border: 1px solid #EEE;\n  display: inline-block;\n  float: right;\n  padding: 7px 30px;\n  font-size: 12px;\n  margin-top: 5px;\n}\n.select-cell .checkbox {\n  margin: 0;\n}\n.command-edit,\n.command-delete {\n  background: #fff;\n}\n.bootstrap-select .dropdown-menu {\n  padding: 0;\n}\n.bootstrap-select .dropdown-toggle:focus {\n  outline: none !important;\n}\n.bootstrap-select > .btn-default {\n  background: none !important;\n  border-bottom: 1px solid #e0e0e0 !important;\n  border-radius: 0;\n  padding-left: 0;\n  padding-right: 0;\n}\n.bootstrap-select > .btn-default:before {\n  position: absolute;\n  top: 0;\n  right: 0;\n  content: \"\";\n  height: calc(100% - 2px);\n  width: 30px;\n  background-color: #FFF;\n  background-position: right calc(100% - 7px);\n  background-repeat: no-repeat;\n  background-image: url(\"../img/select.png\");\n  pointer-events: none;\n  z-index: 5;\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .bootstrap-select > .btn-default:before {\n    background-image: url(\"../img/select@2x.png\");\n    background-size: 12px 12px;\n  }\n}\n.bootstrap-select > .btn-default:after {\n  position: absolute;\n  z-index: 3;\n  bottom: -1px;\n  left: 0;\n  height: 2px;\n  width: 0;\n  content: \"\";\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.bootstrap-select > .btn-default:not(.disabled):after,\n.bootstrap-select > .btn-default:not(.readonly):after {\n  background: #2196f3;\n}\n.bootstrap-select > .btn-default.disabled:after,\n.bootstrap-select > .btn-default.readonly:after {\n  background: #ccc;\n}\n.bootstrap-select.open > .btn-default:after {\n  width: 100%;\n}\n.bootstrap-select .bs-searchbox {\n  padding: 5px 5px 5px 40px;\n  position: relative;\n  background: #f7f7f7;\n}\n.bootstrap-select .bs-searchbox:before {\n  position: absolute;\n  left: 0;\n  top: 0;\n  width: 40px;\n  height: 100%;\n  content: \"\\f1c3\";\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 25px;\n  padding: 4px 0 0 15px;\n}\n.bootstrap-select .bs-searchbox input {\n  border: 0;\n  background: transparent;\n}\n.bootstrap-select.btn-group .dropdown-menu li a.opt {\n  padding-left: 17px;\n}\n.bootstrap-select .check-mark {\n  margin-top: -5px !important;\n  font-size: 19px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  display: block !important;\n  position: absolute;\n  top: 11px;\n  right: 15px;\n}\n.bootstrap-select .check-mark:before {\n  content: \"\\f26b\";\n  font-family: 'Material-Design-Iconic-Font';\n}\n.bootstrap-select .selected .check-mark {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n.bootstrap-select .notify {\n  bottom: 0 !important;\n  margin: 0 !important;\n  width: 100% !important;\n  border: 0 !important;\n  background: #f44336 !important;\n  color: #fff !important;\n  text-align: center;\n}\n.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {\n  width: 100%;\n}\n.chosen-container .chosen-drop {\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  margin-top: 1px;\n  border: 0;\n  left: 0;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transform-origin: top left;\n  -moz-transform-origin: top left;\n  -ms-transform-origin: top left;\n  transform-origin: top left;\n  -webkit-transition: transform opacity;\n  -o-transition: transform opacity;\n  transition: transform opacity;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n.chosen-container.chosen-with-drop .chosen-drop {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.chosen-container.chosen-with-drop .chosen-single:after {\n  width: 100%;\n}\n.chosen-container .chosen-results {\n  margin: 0;\n  padding: 0;\n  max-height: 300px;\n}\n.chosen-container .chosen-results li {\n  padding: 10px 17px;\n  width: 100%;\n}\n.chosen-container .chosen-results li.highlighted {\n  background: rgba(0, 0, 0, 0.075);\n  color: #333333;\n}\n.chosen-container .chosen-results li.result-selected {\n  background: transparent;\n  color: #5e5e5e;\n  position: relative;\n}\n.chosen-container .chosen-results li.result-selected:before {\n  content: \"\\f26b\";\n  font-family: 'Material-Design-Iconic-Font';\n  position: absolute;\n  right: 15px;\n  top: 10px;\n  font-size: 19px;\n}\n.chosen-container .chosen-results li.group-result {\n  color: #B2B2B2;\n  font-weight: normal;\n  padding: 16px 15px 6px;\n  margin-top: 9px;\n}\n.chosen-container .chosen-results li.group-result:not(:first-child) {\n  border-top: 1px solid #eee;\n}\n.chosen-container-single .chosen-single {\n  border-radius: 0;\n  overflow: visible;\n  height: 34px;\n  padding: 6px 0 6px;\n  text-transform: uppercase;\n  border: 0;\n  border-bottom: 1px solid #e0e0e0;\n  background: none;\n  box-shadow: none;\n}\n.chosen-container-single .chosen-single:after {\n  content: \"\";\n  width: 0;\n  background: #2196f3;\n  height: 2px;\n  position: absolute;\n  left: 0;\n  bottom: -1px;\n  -webkit-transition: width;\n  -o-transition: width;\n  transition: width;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n.chosen-container-single .chosen-single div b {\n  background-image: url(\"../img/select.png\");\n  background-repeat: no-repeat;\n  background-position: right 12px;\n}\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .chosen-container-single .chosen-single div b {\n    background-image: url(\"../img/select@2x.png\");\n    background-size: 12px 12px;\n  }\n}\n.chosen-container-single .chosen-search {\n  padding: 5px 5px 5px 40px;\n  background: #f7f7f7;\n}\n.chosen-container-single .chosen-search:before {\n  content: \"\\f1c3\";\n  font-family: 'Material-Design-Iconic-Font';\n  position: absolute;\n  left: 0;\n  top: 0;\n  width: 40px;\n  height: 100%;\n  font-size: 25px;\n  padding: 5px 0 0 15px;\n}\n.chosen-container-single .chosen-search input[type=text] {\n  border: 0;\n  height: 35px;\n  line-height: 1.42857143;\n  background: none;\n}\n.chosen-container-active.chosen-with-drop .chosen-single {\n  border: 0;\n  background: none;\n}\n.chosen-container-multi .chosen-choices {\n  padding: 0;\n  border: 0;\n  border-bottom: 1px solid #e0e0e0;\n  background: none;\n  box-shadow: none;\n}\n.chosen-container-multi .chosen-choices li.search-choice {\n  border-radius: 2px;\n  margin: 4px 4px 0 0;\n  background: #eaeaea;\n  padding: 5px 23px 5px 8px;\n  border: 0;\n  box-shadow: none;\n}\n.chosen-container-multi .chosen-choices li.search-choice .search-choice-close {\n  background-image: none;\n}\n.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:before {\n  display: inline-block;\n  font-family: 'Material-Design-Iconic-Font';\n  content: \"\\f135\";\n  position: relative;\n  top: 1px;\n  color: #9C9C9C;\n  z-index: 2;\n  font-size: 12px;\n}\n.chosen-container-multi .chosen-choices li.search-field input[type=text] {\n  padding: 0;\n  height: 31px;\n}\nselect.chosen {\n  display: none;\n}\n.noUi-target {\n  border-radius: 0;\n  box-shadow: none;\n  border: 0;\n}\n.noUi-background {\n  background: #d4d4d4;\n  box-shadow: none;\n}\n.noUi-horizontal {\n  height: 3px;\n}\n.noUi-horizontal .noUi-handle {\n  top: -8px;\n}\n.noUi-vertical {\n  width: 3px;\n}\n.noUi-horizontal .noUi-handle,\n.noUi-vertical .noUi-handle {\n  width: 19px;\n  height: 19px;\n  border: 0;\n  border-radius: 100%;\n  box-shadow: none;\n  -webkit-transition: box-shadow;\n  -o-transition: box-shadow;\n  transition: box-shadow;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  cursor: pointer;\n  position: relative;\n}\n.noUi-horizontal .noUi-handle:before,\n.noUi-vertical .noUi-handle:before,\n.noUi-horizontal .noUi-handle:after,\n.noUi-vertical .noUi-handle:after {\n  display: none;\n}\n.noUi-horizontal .noUi-handle:active,\n.noUi-vertical .noUi-handle:active {\n  background: #ccc !important;\n}\n.noUi-horizontal .noUi-handle .is-tooltip,\n.noUi-vertical .noUi-handle .is-tooltip {\n  position: absolute;\n  bottom: 32px;\n  height: 35px;\n  border-radius: 2px;\n  color: #fff;\n  text-align: center;\n  line-height: 33px;\n  width: 50px;\n  left: 50%;\n  margin-left: -25px;\n  padding: 0 10px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n.noUi-horizontal .noUi-handle .is-tooltip:after,\n.noUi-vertical .noUi-handle .is-tooltip:after {\n  width: 0;\n  height: 0;\n  border-style: solid;\n  border-width: 15px 10px 0 10px;\n  position: absolute;\n  bottom: -8px;\n  left: 50%;\n  margin-left: -9px;\n  content: \"\";\n}\n.noUi-horizontal .noUi-active,\n.noUi-vertical .noUi-active {\n  box-shadow: 0 0 0 13px rgba(0, 0, 0, 0.1);\n}\n.noUi-horizontal .noUi-active .is-tooltip,\n.noUi-vertical .noUi-active .is-tooltip {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  bottom: 40px;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.input-slider:not([data-is-color]) .noUi-handle,\n.input-slider-range:not([data-is-color]) .noUi-handle,\n.input-slider-values:not([data-is-color]) .noUi-handle,\n.input-slider:not([data-is-color]) .noUi-connect,\n.input-slider-range:not([data-is-color]) .noUi-connect,\n.input-slider-values:not([data-is-color]) .noUi-connect {\n  background: #009688 !important;\n}\n.input-slider:not([data-is-color]) .is-tooltip,\n.input-slider-range:not([data-is-color]) .is-tooltip,\n.input-slider-values:not([data-is-color]) .is-tooltip {\n  background: #009688;\n}\n.input-slider:not([data-is-color]) .is-tooltip:after,\n.input-slider-range:not([data-is-color]) .is-tooltip:after,\n.input-slider-values:not([data-is-color]) .is-tooltip:after {\n  border-color: #009688 transparent transparent transparent;\n}\n.input-slider[data-is-color=red] .noUi-handle,\n.input-slider-range[data-is-color=red] .noUi-handle,\n.input-slider-values[data-is-color=red] .noUi-handle,\n.input-slider[data-is-color=red] .noUi-connect,\n.input-slider-range[data-is-color=red] .noUi-connect,\n.input-slider-values[data-is-color=red] .noUi-connect {\n  background: #f44336 !important;\n}\n.input-slider[data-is-color=blue] .noUi-handle,\n.input-slider-range[data-is-color=blue] .noUi-handle,\n.input-slider-values[data-is-color=blue] .noUi-handle,\n.input-slider[data-is-color=blue] .noUi-connect,\n.input-slider-range[data-is-color=blue] .noUi-connect,\n.input-slider-values[data-is-color=blue] .noUi-connect {\n  background: #2196f3 !important;\n}\n.input-slider[data-is-color=cyan] .noUi-handle,\n.input-slider-range[data-is-color=cyan] .noUi-handle,\n.input-slider-values[data-is-color=cyan] .noUi-handle,\n.input-slider[data-is-color=cyan] .noUi-connect,\n.input-slider-range[data-is-color=cyan] .noUi-connect,\n.input-slider-values[data-is-color=cyan] .noUi-connect {\n  background: #00bcd4 !important;\n}\n.input-slider[data-is-color=amber] .noUi-handle,\n.input-slider-range[data-is-color=amber] .noUi-handle,\n.input-slider-values[data-is-color=amber] .noUi-handle,\n.input-slider[data-is-color=amber] .noUi-connect,\n.input-slider-range[data-is-color=amber] .noUi-connect,\n.input-slider-values[data-is-color=amber] .noUi-connect {\n  background: #ffc107 !important;\n}\n.input-slider[data-is-color=green] .noUi-handle,\n.input-slider-range[data-is-color=green] .noUi-handle,\n.input-slider-values[data-is-color=green] .noUi-handle,\n.input-slider[data-is-color=green] .noUi-connect,\n.input-slider-range[data-is-color=green] .noUi-connect,\n.input-slider-values[data-is-color=green] .noUi-connect {\n  background: #4caf50 !important;\n}\n.input-slider .noUi-origin {\n  background: #d4d4d4;\n}\n.input-slider:not([data-is-color]) .noUi-base {\n  background: #009688 !important;\n}\n.input-slider[data-is-color=red] .noUi-base {\n  background: #f44336 !important;\n}\n.input-slider[data-is-color=blue] .noUi-base {\n  background: #2196f3 !important;\n}\n.input-slider[data-is-color=cyan] .noUi-base {\n  background: #00bcd4 !important;\n}\n.input-slider[data-is-color=amber] .noUi-base {\n  background: #ffc107 !important;\n}\n.input-slider[data-is-color=green] .noUi-base {\n  background: #4caf50 !important;\n}\n.cp-container {\n  position: relative;\n}\n.cp-container > .input-group input.cp-value {\n  color: #000 !important;\n  background: transparent !important;\n}\n.cp-container > .input-group .dropdown-menu {\n  padding: 20px;\n  margin-left: 10px;\n}\n.cp-container i.cp-value {\n  width: 25px;\n  height: 25px;\n  border-radius: 2px;\n  position: absolute;\n  top: 0;\n  right: 15px;\n}\n.note-editor .note-toolbar,\n.note-popover .note-toolbar,\n.note-editor .popover-content,\n.note-popover .popover-content {\n  background: #fff;\n  border-color: #e4e4e4;\n  margin: 0;\n  padding: 10px 0 15px;\n  text-align: center;\n}\n.note-editor .note-toolbar > .btn-group,\n.note-popover .note-toolbar > .btn-group,\n.note-editor .popover-content > .btn-group,\n.note-popover .popover-content > .btn-group {\n  display: inline-block;\n  float: none;\n  box-shadow: none;\n}\n.note-editor .note-toolbar > .btn-group .btn,\n.note-popover .note-toolbar > .btn-group .btn,\n.note-editor .popover-content > .btn-group .btn,\n.note-popover .popover-content > .btn-group .btn {\n  margin: 0 1px;\n}\n.note-editor .note-toolbar > .btn-group > .active,\n.note-popover .note-toolbar > .btn-group > .active,\n.note-editor .popover-content > .btn-group > .active,\n.note-popover .popover-content > .btn-group > .active {\n  background: #00bcd4;\n  color: #fff;\n}\n.note-editor .note-toolbar .btn,\n.note-popover .note-toolbar .btn,\n.note-editor .popover-content .btn,\n.note-popover .popover-content .btn {\n  height: 40px;\n  border-radius: 2px !important;\n  box-shadow: none !important;\n}\n.note-editor .note-toolbar .btn:active,\n.note-popover .note-toolbar .btn:active,\n.note-editor .popover-content .btn:active,\n.note-popover .popover-content .btn:active {\n  box-shadow: none;\n}\n.note-editor .note-toolbar .note-palette-title,\n.note-popover .note-toolbar .note-palette-title,\n.note-editor .popover-content .note-palette-title,\n.note-popover .popover-content .note-palette-title {\n  margin: 0 !important;\n  padding: 10px 0 !important;\n  font-size: 13px !important;\n  text-align: center !important;\n  border: 0 !important;\n}\n.note-editor .note-toolbar .note-color-reset,\n.note-popover .note-toolbar .note-color-reset,\n.note-editor .popover-content .note-color-reset,\n.note-popover .popover-content .note-color-reset {\n  padding: 0 0 10px !important;\n  margin: 0 !important;\n  background: none;\n  text-align: center;\n}\n.note-editor .note-toolbar .note-color .dropdown-menu,\n.note-popover .note-toolbar .note-color .dropdown-menu,\n.note-editor .popover-content .note-color .dropdown-menu,\n.note-popover .popover-content .note-color .dropdown-menu {\n  min-width: 335px;\n}\n.note-editor .note-statusbar .note-resizebar,\n.note-popover .note-statusbar .note-resizebar {\n  border-color: #E8E8E8;\n}\n.note-editor .note-statusbar .note-resizebar .note-icon-bar,\n.note-popover .note-statusbar .note-resizebar .note-icon-bar {\n  border-color: #BCBCBC;\n}\n.note-editor .fa,\n.note-popover .fa {\n  font-style: normal;\n  font-size: 20px;\n  vertical-align: middle;\n}\n.note-editor .fa:before,\n.note-popover .fa:before {\n  font-family: 'Material-Design-Iconic-Font';\n}\n.note-editor .fa.fa-magic:before,\n.note-popover .fa.fa-magic:before {\n  content: \"\\f16a\";\n}\n.note-editor .fa.fa-bold:before,\n.note-popover .fa.fa-bold:before {\n  content: \"\\f23d\";\n}\n.note-editor .fa.fa-italic:before,\n.note-popover .fa.fa-italic:before {\n  content: \"\\f245\";\n}\n.note-editor .fa.fa-underline:before,\n.note-popover .fa.fa-underline:before {\n  content: \"\\f24f\";\n}\n.note-editor .fa.fa-font:before,\n.note-popover .fa.fa-font:before {\n  content: \"\\f242\";\n}\n.note-editor .fa.fa-list-ul:before,\n.note-popover .fa.fa-list-ul:before {\n  content: \"\\f247\";\n}\n.note-editor .fa.fa-list-ol:before,\n.note-popover .fa.fa-list-ol:before {\n  content: \"\\f248\";\n}\n.note-editor .fa.fa-align-left:before,\n.note-popover .fa.fa-align-left:before {\n  content: \"\\f23b\";\n}\n.note-editor .fa.fa-align-right:before,\n.note-popover .fa.fa-align-right:before {\n  content: \"\\f23c\";\n}\n.note-editor .fa.fa-align-center:before,\n.note-popover .fa.fa-align-center:before {\n  content: \"\\f239\";\n}\n.note-editor .fa.fa-align-justify:before,\n.note-popover .fa.fa-align-justify:before {\n  content: \"\\f23a\";\n}\n.note-editor .fa.fa-indent:before,\n.note-popover .fa.fa-indent:before {\n  content: \"\\f244\";\n}\n.note-editor .fa.fa-outdent:before,\n.note-popover .fa.fa-outdent:before {\n  content: \"\\f243\";\n}\n.note-editor .fa.fa-text-height:before,\n.note-popover .fa.fa-text-height:before {\n  content: \"\\f246\";\n}\n.note-editor .fa.fa-table:before,\n.note-popover .fa.fa-table:before {\n  content: \"\\f320\";\n}\n.note-editor .fa.fa-link:before,\n.note-popover .fa.fa-link:before {\n  content: \"\\f18e\";\n}\n.note-editor .fa.fa-picture-o:before,\n.note-popover .fa.fa-picture-o:before {\n  content: \"\\f17f\";\n}\n.note-editor .fa.fa-minus:before,\n.note-popover .fa.fa-minus:before {\n  content: \"\\f22f\";\n}\n.note-editor .fa.fa-arrows-alt:before,\n.note-popover .fa.fa-arrows-alt:before {\n  content: \"\\f16d\";\n}\n.note-editor .fa.fa-code:before,\n.note-popover .fa.fa-code:before {\n  content: \"\\f13a\";\n}\n.note-editor .fa.fa-question:before,\n.note-popover .fa.fa-question:before {\n  content: \"\\f1f5\";\n}\n.note-editor .fa.fa-eraser:before,\n.note-popover .fa.fa-eraser:before {\n  content: \"\\f23f\";\n}\n.note-editor .fa.fa-square:before,\n.note-popover .fa.fa-square:before {\n  content: \"\\f279\";\n}\n.note-editor .fa.fa-circle-o:before,\n.note-popover .fa.fa-circle-o:before {\n  content: \"\\f26c\";\n}\n.note-editor .fa.fa-times:before,\n.note-popover .fa.fa-times:before {\n  content: \"\\f136\";\n}\n.note-editor .note-air-popover .arrow,\n.note-popover .note-air-popover .arrow {\n  left: 20px;\n}\n.note-editor {\n  overflow: visible;\n  border: 1px solid #e4e4e4;\n}\n.note-editor .note-editable {\n  padding: 20px 23px;\n}\n.bootstrap-datetimepicker-widget {\n  padding: 0 !important;\n  margin: 0 !important;\n  width: auto !important;\n}\n.bootstrap-datetimepicker-widget:after,\n.bootstrap-datetimepicker-widget:before {\n  display: none !important;\n}\n.bootstrap-datetimepicker-widget table td {\n  text-shadow: none;\n}\n.bootstrap-datetimepicker-widget table td span {\n  margin: 0;\n}\n.bootstrap-datetimepicker-widget table td span:hover {\n  background: transparent;\n}\n.bootstrap-datetimepicker-widget .glyphicon {\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 18px;\n}\n.bootstrap-datetimepicker-widget .glyphicon-chevron-left:before {\n  content: \"\\f2ff\";\n}\n.bootstrap-datetimepicker-widget .glyphicon-chevron-right:before {\n  content: \"\\f301\";\n}\n.bootstrap-datetimepicker-widget .glyphicon-time:before {\n  content: \"\\f337\";\n}\n.bootstrap-datetimepicker-widget .glyphicon-calendar:before {\n  content: \"\\f32e\";\n}\n.bootstrap-datetimepicker-widget .glyphicon-chevron-up:before {\n  content: \"\\f1e5\";\n}\n.bootstrap-datetimepicker-widget .glyphicon-chevron-down:before {\n  content: \"\\f1e4\";\n}\n.bootstrap-datetimepicker-widget [data-action=\"togglePicker\"] span {\n  font-size: 25px;\n  color: #ccc;\n}\n.bootstrap-datetimepicker-widget [data-action=\"togglePicker\"] span:hover {\n  color: #333;\n}\n.bootstrap-datetimepicker-widget a[data-action] {\n  color: #009688;\n}\n.timepicker-picker .btn {\n  box-shadow: none !important;\n}\n.timepicker-picker table tbody tr + tr:not(:last-child) {\n  background: #009688;\n  color: #fff;\n}\n.timepicker-picker table tbody tr + tr:not(:last-child) td {\n  border-radius: 0;\n}\n.timepicker-picker .btn,\n.timepicker-picker .btn:hover {\n  background: #fff;\n  color: #333;\n}\n.datepicker.top {\n  -webkit-transform-origin: 0 100% !important;\n  -moz-transform-origin: 0 100% !important;\n  -ms-transform-origin: 0 100% !important;\n  transform-origin: 0 100% !important;\n}\n.datepicker table thead tr th {\n  border-radius: 0;\n  color: #fff;\n}\n.datepicker table thead tr th .glyphicon {\n  width: 30px;\n  height: 30px;\n  border-radius: 50%;\n  line-height: 29px;\n}\n.datepicker table thead tr th:hover .glyphicon {\n  background: rgba(0, 0, 0, 0.2);\n}\n.datepicker table thead tr:first-child th {\n  background: #009688;\n  padding: 20px 0;\n}\n.datepicker table thead tr:first-child th:hover {\n  background: #009688;\n}\n.datepicker table thead tr:first-child th.picker-switch {\n  font-size: 16px;\n  font-weight: 400;\n  text-transform: uppercase;\n}\n.datepicker table thead tr:last-child th {\n  text-transform: uppercase;\n  font-weight: normal;\n  font-size: 11px;\n}\n.datepicker table thead tr:last-child th:first-child {\n  padding-left: 20px;\n}\n.datepicker table thead tr:last-child th:last-child {\n  padding-right: 20px;\n}\n.datepicker table thead tr:last-child:not(:only-child) {\n  background: #00877a;\n}\n.datepicker table tbody tr:last-child td {\n  padding-bottom: 25px;\n}\n.datepicker table tbody tr td:first-child {\n  padding-left: 13px;\n}\n.datepicker table tbody tr td:last-child {\n  padding-right: 13px;\n}\n.datepicker table td.day {\n  width: 35px;\n  height: 35px;\n  line-height: 20px;\n  color: #333;\n  position: relative;\n  padding: 0;\n  background: transparent;\n}\n.datepicker table td.day:hover {\n  background: none;\n}\n.datepicker table td.day:before {\n  content: \"\";\n  width: 35px;\n  height: 35px;\n  border-radius: 50%;\n  margin-bottom: -33px;\n  display: inline-block;\n  background: transparent;\n  position: static;\n  text-shadow: none;\n}\n.datepicker table td.day.old,\n.datepicker table td.day.new {\n  color: #CDCDCD;\n}\n.datepicker table td:not(.today):not(.active):hover:before {\n  background: #F0F0F0;\n}\n.datepicker table td.today {\n  color: #333;\n}\n.datepicker table td.today:before {\n  background-color: #E2E2E2;\n}\n.datepicker table td.active {\n  color: #fff;\n}\n.datepicker table td.active:before {\n  background-color: #009688;\n}\n.datepicker-months .month,\n.datepicker-years .year,\n.timepicker-minutes .minute,\n.timepicker-hours .hour {\n  border-radius: 50%;\n}\n.datepicker-months .month:not(.active):hover,\n.datepicker-years .year:not(.active):hover,\n.timepicker-minutes .minute:not(.active):hover,\n.timepicker-hours .hour:not(.active):hover {\n  background: #F0F0F0;\n}\n.datepicker-months .month.active,\n.datepicker-years .year.active,\n.timepicker-minutes .minute.active,\n.timepicker-hours .hour.active {\n  background: #009688;\n}\n.timepicker-minutes .minute,\n.timepicker-hours .hour {\n  padding: 0;\n}\n.fileinput {\n  position: relative;\n  padding-right: 35px;\n}\n.fileinput .close {\n  position: absolute;\n  top: 5px;\n  font-size: 12px;\n  float: none;\n  opacity: 1;\n  font-weight: 500;\n  border: 1px solid #ccc;\n  width: 19px;\n  text-align: center;\n  height: 19px;\n  line-height: 15px;\n  border-radius: 50%;\n  right: 0;\n}\n.fileinput .close:hover {\n  background: #eee;\n}\n.fileinput .input-group-addon {\n  padding: 0 10px;\n  vertical-align: middle;\n}\n.fileinput .fileinput-preview {\n  width: 200px;\n  height: 150px;\n  position: relative;\n}\n.fileinput .fileinput-preview img {\n  display: inline-block;\n  vertical-align: middle;\n  margin-top: -13px;\n}\n.fileinput .fileinput-preview:after {\n  content: \"\";\n  display: inline-block;\n  vertical-align: middle;\n}\n#lg-slider:after {\n  content: \"\";\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n  height: 50px;\n  width: 50px;\n  border-radius: 100%;\n  border: 2px solid #2196f3;\n  -webkit-animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);\n  animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);\n  position: absolute;\n  left: 50%;\n  margin-left: -25px;\n  top: 50%;\n  margin-top: -25px;\n  z-index: -1;\n}\n#lg-outer {\n  background: rgba(255, 255, 255, 0.95);\n}\n#lg-outer .object {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n  border-radius: 2px;\n}\n#lg-close {\n  display: none;\n}\n#lg-action {\n  top: 0;\n  width: 100%;\n  left: 0;\n  margin-left: 0 !important;\n  height: 40px;\n  text-align: center;\n}\n#lg-action > a {\n  background: transparent;\n  color: #9D9D9D;\n  font-size: 18px;\n  width: 28px;\n  height: 37px;\n}\n#lg-action > a:hover {\n  background: transparent;\n  color: #000;\n}\n#lg-action .cl-thumb {\n  position: fixed;\n  right: 20px;\n  bottom: 20px;\n  width: 50px;\n  height: 50px;\n  border-radius: 50%;\n  line-height: 38px;\n  background: #f44336;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n#lg-action .cl-thumb:after {\n  text-align: center;\n  left: 16px !important;\n  bottom: 6px !important;\n  color: #fff;\n}\n#lg-action .cl-thumb:hover {\n  background: #f32c1e;\n}\n#lg-gallery .thumb-cont {\n  background: #f44336;\n  text-align: center;\n}\n#lg-gallery .thumb-cont .thumb-info {\n  background: #f44336;\n}\n#lg-gallery .thumb-cont .thumb-info .count {\n  display: none;\n}\n#lg-gallery .thumb-cont .thumb-info .close {\n  width: 14px;\n  margin-top: 0;\n  background: none;\n}\n#lg-gallery .thumb-cont .thumb-info .close:hover {\n  background: none;\n}\n#lg-gallery .thumb-cont .thumb {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n#lg-gallery .thumb-cont .thumb-inner {\n  display: inline-block;\n  padding: 12px 12px 15px;\n}\n.lg-slide {\n  background: none !important;\n}\n.lg-slide em {\n  font-style: normal;\n}\n.lg-slide em h3 {\n  margin-bottom: 5px;\n}\n.lg-slide .video-cont {\n  box-shadow: 0 8px 17px rgba(0, 0, 0, 0.2), 0 6px 20px rgba(0, 0, 0, 0.19);\n}\n@-webkit-keyframes ball-scale-ripple {\n  0% {\n    -webkit-transform: scale(0.1);\n    transform: scale(0.1);\n    opacity: 1;\n  }\n  70% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n    opacity: 0.7;\n  }\n  100% {\n    opacity: 0.0;\n  }\n}\n@keyframes ball-scale-ripple {\n  0% {\n    -webkit-transform: scale(0.1);\n    transform: scale(0.1);\n    opacity: 1;\n  }\n  70% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n    opacity: 0.7;\n  }\n  100% {\n    opacity: 0.0;\n  }\n}\n.sweet-alert {\n  border-radius: 2px;\n  padding: 10px 30px;\n}\n.sweet-alert h2 {\n  font-size: 16px;\n  font-weight: 400;\n  position: relative;\n  z-index: 1;\n}\n.sweet-alert .lead {\n  font-size: 13px;\n}\n.sweet-alert .btn {\n  padding: 6px 12px;\n  font-size: 13px;\n  margin: 20px 2px 0;\n}\n.twitter-typeahead {\n  width: 100%;\n}\n.twitter-typeahead .tt-menu {\n  min-width: 200px;\n  background: #fff;\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  display: block !important;\n  z-index: 2 !important;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  -webkit-transform-origin: top left;\n  -moz-transform-origin: top left;\n  -ms-transform-origin: top left;\n  transform-origin: top left;\n}\n.twitter-typeahead .tt-menu.tt-open:not(.tt-empty) {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n.twitter-typeahead .tt-suggestion {\n  padding: 8px 17px;\n  color: #333;\n  cursor: pointer;\n}\n.twitter-typeahead .tt-suggestion:hover,\n.twitter-typeahead .tt-cursor {\n  background-color: rgba(0, 0, 0, 0.075);\n}\n.twitter-typeahead .tt-hint {\n  color: #818181 !important;\n}\n.mCSB_scrollTools {\n  width: 5px;\n}\n.mCSB_scrollTools .mCSB_dragger_bar {\n  border-radius: 0 !important;\n}\n.mCSB_scrollTools.mCSB_scrollTools_horizontal,\n.mCSB_scrollTools.mCSB_scrollTools_vertical {\n  margin: 0 !important;\n}\n.mCSB_scrollTools.mCSB_scrollTools_horizontal {\n  height: 10px;\n}\n.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {\n  background: rgba(0, 0, 0, 0.4);\n}\n.mCS-minimal-dark.mCSB_scrollTools_onDrag .mCSB_dragger .mCSB_dragger_bar {\n  background: rgba(0, 0, 0, 0.5) !important;\n}\n.mCSB_inside > .mCSB_container {\n  margin-right: 0;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/app.min.1.css",
    "content": "/*\n * Load Main Bootstrap LESS files\n */\n\n/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\nhtml {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\n\nbody {\n  margin: 0;\n}\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block;\n  vertical-align: baseline;\n}\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n[hidden],\ntemplate {\n  display: none;\n}\n\na {\n  background-color: transparent;\n}\n\na:active,\na:hover {\n  outline: 0;\n}\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\nb,\nstrong {\n  font-weight: bold;\n}\n\ndfn {\n  font-style: italic;\n}\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\nsmall {\n  font-size: 80%;\n}\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\nimg {\n  border: 0;\n}\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\nfigure {\n  margin: 1em 40px;\n}\n\nhr {\n  box-sizing: content-box;\n  height: 0;\n}\n\npre {\n  overflow: auto;\n}\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit;\n  font: inherit;\n  margin: 0;\n}\n\nbutton {\n  overflow: visible;\n}\n\nbutton,\nselect {\n  text-transform: none;\n}\n\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\ninput {\n  line-height: normal;\n}\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield;\n  box-sizing: content-box;\n}\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\nlegend {\n  border: 0;\n  padding: 0;\n}\n\ntextarea {\n  overflow: auto;\n}\n\noptgroup {\n  font-weight: bold;\n}\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n@media print {\n  *,\n  *:before,\n  *:after {\n    background: transparent !important;\n    color: #000 !important;\n    box-shadow: none !important;\n    text-shadow: none !important;\n  }\n\n  a,\n  a:visited {\n    text-decoration: underline;\n  }\n\n  a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n\n  abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n\n  a[href^=\"#\"]:after,\n  a[href^=\"javascript:\"]:after {\n    content: \"\";\n  }\n\n  pre,\n  blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n\n  thead {\n    display: table-header-group;\n  }\n\n  tr,\n  img {\n    page-break-inside: avoid;\n  }\n\n  img {\n    max-width: 100% !important;\n  }\n\n  p,\n  h2,\n  h3 {\n    orphans: 3;\n    widows: 3;\n  }\n\n  h2,\n  h3 {\n    page-break-after: avoid;\n  }\n\n  .navbar {\n    display: none;\n  }\n\n  .btn > .caret,\n  .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n\n  .label {\n    border: 1px solid #000;\n  }\n\n  .table {\n    border-collapse: collapse !important;\n  }\n\n  .table td,\n  .table th {\n    background-color: #fff !important;\n  }\n\n  .table-bordered th,\n  .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n\n@font-face {\n  font-family: 'Glyphicons Halflings';\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\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  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.glyphicon-asterisk:before {\n  content: \"\\002a\";\n}\n\n.glyphicon-plus:before {\n  content: \"\\002b\";\n}\n\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n  content: \"\\20ac\";\n}\n\n.glyphicon-minus:before {\n  content: \"\\2212\";\n}\n\n.glyphicon-cloud:before {\n  content: \"\\2601\";\n}\n\n.glyphicon-envelope:before {\n  content: \"\\2709\";\n}\n\n.glyphicon-pencil:before {\n  content: \"\\270f\";\n}\n\n.glyphicon-glass:before {\n  content: \"\\e001\";\n}\n\n.glyphicon-music:before {\n  content: \"\\e002\";\n}\n\n.glyphicon-search:before {\n  content: \"\\e003\";\n}\n\n.glyphicon-heart:before {\n  content: \"\\e005\";\n}\n\n.glyphicon-star:before {\n  content: \"\\e006\";\n}\n\n.glyphicon-star-empty:before {\n  content: \"\\e007\";\n}\n\n.glyphicon-user:before {\n  content: \"\\e008\";\n}\n\n.glyphicon-film:before {\n  content: \"\\e009\";\n}\n\n.glyphicon-th-large:before {\n  content: \"\\e010\";\n}\n\n.glyphicon-th:before {\n  content: \"\\e011\";\n}\n\n.glyphicon-th-list:before {\n  content: \"\\e012\";\n}\n\n.glyphicon-ok:before {\n  content: \"\\e013\";\n}\n\n.glyphicon-remove:before {\n  content: \"\\e014\";\n}\n\n.glyphicon-zoom-in:before {\n  content: \"\\e015\";\n}\n\n.glyphicon-zoom-out:before {\n  content: \"\\e016\";\n}\n\n.glyphicon-off:before {\n  content: \"\\e017\";\n}\n\n.glyphicon-signal:before {\n  content: \"\\e018\";\n}\n\n.glyphicon-cog:before {\n  content: \"\\e019\";\n}\n\n.glyphicon-trash:before {\n  content: \"\\e020\";\n}\n\n.glyphicon-home:before {\n  content: \"\\e021\";\n}\n\n.glyphicon-file:before {\n  content: \"\\e022\";\n}\n\n.glyphicon-time:before {\n  content: \"\\e023\";\n}\n\n.glyphicon-road:before {\n  content: \"\\e024\";\n}\n\n.glyphicon-download-alt:before {\n  content: \"\\e025\";\n}\n\n.glyphicon-download:before {\n  content: \"\\e026\";\n}\n\n.glyphicon-upload:before {\n  content: \"\\e027\";\n}\n\n.glyphicon-inbox:before {\n  content: \"\\e028\";\n}\n\n.glyphicon-play-circle:before {\n  content: \"\\e029\";\n}\n\n.glyphicon-repeat:before {\n  content: \"\\e030\";\n}\n\n.glyphicon-refresh:before {\n  content: \"\\e031\";\n}\n\n.glyphicon-list-alt:before {\n  content: \"\\e032\";\n}\n\n.glyphicon-lock:before {\n  content: \"\\e033\";\n}\n\n.glyphicon-flag:before {\n  content: \"\\e034\";\n}\n\n.glyphicon-headphones:before {\n  content: \"\\e035\";\n}\n\n.glyphicon-volume-off:before {\n  content: \"\\e036\";\n}\n\n.glyphicon-volume-down:before {\n  content: \"\\e037\";\n}\n\n.glyphicon-volume-up:before {\n  content: \"\\e038\";\n}\n\n.glyphicon-qrcode:before {\n  content: \"\\e039\";\n}\n\n.glyphicon-barcode:before {\n  content: \"\\e040\";\n}\n\n.glyphicon-tag:before {\n  content: \"\\e041\";\n}\n\n.glyphicon-tags:before {\n  content: \"\\e042\";\n}\n\n.glyphicon-book:before {\n  content: \"\\e043\";\n}\n\n.glyphicon-bookmark:before {\n  content: \"\\e044\";\n}\n\n.glyphicon-print:before {\n  content: \"\\e045\";\n}\n\n.glyphicon-camera:before {\n  content: \"\\e046\";\n}\n\n.glyphicon-font:before {\n  content: \"\\e047\";\n}\n\n.glyphicon-bold:before {\n  content: \"\\e048\";\n}\n\n.glyphicon-italic:before {\n  content: \"\\e049\";\n}\n\n.glyphicon-text-height:before {\n  content: \"\\e050\";\n}\n\n.glyphicon-text-width:before {\n  content: \"\\e051\";\n}\n\n.glyphicon-align-left:before {\n  content: \"\\e052\";\n}\n\n.glyphicon-align-center:before {\n  content: \"\\e053\";\n}\n\n.glyphicon-align-right:before {\n  content: \"\\e054\";\n}\n\n.glyphicon-align-justify:before {\n  content: \"\\e055\";\n}\n\n.glyphicon-list:before {\n  content: \"\\e056\";\n}\n\n.glyphicon-indent-left:before {\n  content: \"\\e057\";\n}\n\n.glyphicon-indent-right:before {\n  content: \"\\e058\";\n}\n\n.glyphicon-facetime-video:before {\n  content: \"\\e059\";\n}\n\n.glyphicon-picture:before {\n  content: \"\\e060\";\n}\n\n.glyphicon-map-marker:before {\n  content: \"\\e062\";\n}\n\n.glyphicon-adjust:before {\n  content: \"\\e063\";\n}\n\n.glyphicon-tint:before {\n  content: \"\\e064\";\n}\n\n.glyphicon-edit:before {\n  content: \"\\e065\";\n}\n\n.glyphicon-share:before {\n  content: \"\\e066\";\n}\n\n.glyphicon-check:before {\n  content: \"\\e067\";\n}\n\n.glyphicon-move:before {\n  content: \"\\e068\";\n}\n\n.glyphicon-step-backward:before {\n  content: \"\\e069\";\n}\n\n.glyphicon-fast-backward:before {\n  content: \"\\e070\";\n}\n\n.glyphicon-backward:before {\n  content: \"\\e071\";\n}\n\n.glyphicon-play:before {\n  content: \"\\e072\";\n}\n\n.glyphicon-pause:before {\n  content: \"\\e073\";\n}\n\n.glyphicon-stop:before {\n  content: \"\\e074\";\n}\n\n.glyphicon-forward:before {\n  content: \"\\e075\";\n}\n\n.glyphicon-fast-forward:before {\n  content: \"\\e076\";\n}\n\n.glyphicon-step-forward:before {\n  content: \"\\e077\";\n}\n\n.glyphicon-eject:before {\n  content: \"\\e078\";\n}\n\n.glyphicon-chevron-left:before {\n  content: \"\\e079\";\n}\n\n.glyphicon-chevron-right:before {\n  content: \"\\e080\";\n}\n\n.glyphicon-plus-sign:before {\n  content: \"\\e081\";\n}\n\n.glyphicon-minus-sign:before {\n  content: \"\\e082\";\n}\n\n.glyphicon-remove-sign:before {\n  content: \"\\e083\";\n}\n\n.glyphicon-ok-sign:before {\n  content: \"\\e084\";\n}\n\n.glyphicon-question-sign:before {\n  content: \"\\e085\";\n}\n\n.glyphicon-info-sign:before {\n  content: \"\\e086\";\n}\n\n.glyphicon-screenshot:before {\n  content: \"\\e087\";\n}\n\n.glyphicon-remove-circle:before {\n  content: \"\\e088\";\n}\n\n.glyphicon-ok-circle:before {\n  content: \"\\e089\";\n}\n\n.glyphicon-ban-circle:before {\n  content: \"\\e090\";\n}\n\n.glyphicon-arrow-left:before {\n  content: \"\\e091\";\n}\n\n.glyphicon-arrow-right:before {\n  content: \"\\e092\";\n}\n\n.glyphicon-arrow-up:before {\n  content: \"\\e093\";\n}\n\n.glyphicon-arrow-down:before {\n  content: \"\\e094\";\n}\n\n.glyphicon-share-alt:before {\n  content: \"\\e095\";\n}\n\n.glyphicon-resize-full:before {\n  content: \"\\e096\";\n}\n\n.glyphicon-resize-small:before {\n  content: \"\\e097\";\n}\n\n.glyphicon-exclamation-sign:before {\n  content: \"\\e101\";\n}\n\n.glyphicon-gift:before {\n  content: \"\\e102\";\n}\n\n.glyphicon-leaf:before {\n  content: \"\\e103\";\n}\n\n.glyphicon-fire:before {\n  content: \"\\e104\";\n}\n\n.glyphicon-eye-open:before {\n  content: \"\\e105\";\n}\n\n.glyphicon-eye-close:before {\n  content: \"\\e106\";\n}\n\n.glyphicon-warning-sign:before {\n  content: \"\\e107\";\n}\n\n.glyphicon-plane:before {\n  content: \"\\e108\";\n}\n\n.glyphicon-calendar:before {\n  content: \"\\e109\";\n}\n\n.glyphicon-random:before {\n  content: \"\\e110\";\n}\n\n.glyphicon-comment:before {\n  content: \"\\e111\";\n}\n\n.glyphicon-magnet:before {\n  content: \"\\e112\";\n}\n\n.glyphicon-chevron-up:before {\n  content: \"\\e113\";\n}\n\n.glyphicon-chevron-down:before {\n  content: \"\\e114\";\n}\n\n.glyphicon-retweet:before {\n  content: \"\\e115\";\n}\n\n.glyphicon-shopping-cart:before {\n  content: \"\\e116\";\n}\n\n.glyphicon-folder-close:before {\n  content: \"\\e117\";\n}\n\n.glyphicon-folder-open:before {\n  content: \"\\e118\";\n}\n\n.glyphicon-resize-vertical:before {\n  content: \"\\e119\";\n}\n\n.glyphicon-resize-horizontal:before {\n  content: \"\\e120\";\n}\n\n.glyphicon-hdd:before {\n  content: \"\\e121\";\n}\n\n.glyphicon-bullhorn:before {\n  content: \"\\e122\";\n}\n\n.glyphicon-bell:before {\n  content: \"\\e123\";\n}\n\n.glyphicon-certificate:before {\n  content: \"\\e124\";\n}\n\n.glyphicon-thumbs-up:before {\n  content: \"\\e125\";\n}\n\n.glyphicon-thumbs-down:before {\n  content: \"\\e126\";\n}\n\n.glyphicon-hand-right:before {\n  content: \"\\e127\";\n}\n\n.glyphicon-hand-left:before {\n  content: \"\\e128\";\n}\n\n.glyphicon-hand-up:before {\n  content: \"\\e129\";\n}\n\n.glyphicon-hand-down:before {\n  content: \"\\e130\";\n}\n\n.glyphicon-circle-arrow-right:before {\n  content: \"\\e131\";\n}\n\n.glyphicon-circle-arrow-left:before {\n  content: \"\\e132\";\n}\n\n.glyphicon-circle-arrow-up:before {\n  content: \"\\e133\";\n}\n\n.glyphicon-circle-arrow-down:before {\n  content: \"\\e134\";\n}\n\n.glyphicon-globe:before {\n  content: \"\\e135\";\n}\n\n.glyphicon-wrench:before {\n  content: \"\\e136\";\n}\n\n.glyphicon-tasks:before {\n  content: \"\\e137\";\n}\n\n.glyphicon-filter:before {\n  content: \"\\e138\";\n}\n\n.glyphicon-briefcase:before {\n  content: \"\\e139\";\n}\n\n.glyphicon-fullscreen:before {\n  content: \"\\e140\";\n}\n\n.glyphicon-dashboard:before {\n  content: \"\\e141\";\n}\n\n.glyphicon-paperclip:before {\n  content: \"\\e142\";\n}\n\n.glyphicon-heart-empty:before {\n  content: \"\\e143\";\n}\n\n.glyphicon-link:before {\n  content: \"\\e144\";\n}\n\n.glyphicon-phone:before {\n  content: \"\\e145\";\n}\n\n.glyphicon-pushpin:before {\n  content: \"\\e146\";\n}\n\n.glyphicon-usd:before {\n  content: \"\\e148\";\n}\n\n.glyphicon-gbp:before {\n  content: \"\\e149\";\n}\n\n.glyphicon-sort:before {\n  content: \"\\e150\";\n}\n\n.glyphicon-sort-by-alphabet:before {\n  content: \"\\e151\";\n}\n\n.glyphicon-sort-by-alphabet-alt:before {\n  content: \"\\e152\";\n}\n\n.glyphicon-sort-by-order:before {\n  content: \"\\e153\";\n}\n\n.glyphicon-sort-by-order-alt:before {\n  content: \"\\e154\";\n}\n\n.glyphicon-sort-by-attributes:before {\n  content: \"\\e155\";\n}\n\n.glyphicon-sort-by-attributes-alt:before {\n  content: \"\\e156\";\n}\n\n.glyphicon-unchecked:before {\n  content: \"\\e157\";\n}\n\n.glyphicon-expand:before {\n  content: \"\\e158\";\n}\n\n.glyphicon-collapse-down:before {\n  content: \"\\e159\";\n}\n\n.glyphicon-collapse-up:before {\n  content: \"\\e160\";\n}\n\n.glyphicon-log-in:before {\n  content: \"\\e161\";\n}\n\n.glyphicon-flash:before {\n  content: \"\\e162\";\n}\n\n.glyphicon-log-out:before {\n  content: \"\\e163\";\n}\n\n.glyphicon-new-window:before {\n  content: \"\\e164\";\n}\n\n.glyphicon-record:before {\n  content: \"\\e165\";\n}\n\n.glyphicon-save:before {\n  content: \"\\e166\";\n}\n\n.glyphicon-open:before {\n  content: \"\\e167\";\n}\n\n.glyphicon-saved:before {\n  content: \"\\e168\";\n}\n\n.glyphicon-import:before {\n  content: \"\\e169\";\n}\n\n.glyphicon-export:before {\n  content: \"\\e170\";\n}\n\n.glyphicon-send:before {\n  content: \"\\e171\";\n}\n\n.glyphicon-floppy-disk:before {\n  content: \"\\e172\";\n}\n\n.glyphicon-floppy-saved:before {\n  content: \"\\e173\";\n}\n\n.glyphicon-floppy-remove:before {\n  content: \"\\e174\";\n}\n\n.glyphicon-floppy-save:before {\n  content: \"\\e175\";\n}\n\n.glyphicon-floppy-open:before {\n  content: \"\\e176\";\n}\n\n.glyphicon-credit-card:before {\n  content: \"\\e177\";\n}\n\n.glyphicon-transfer:before {\n  content: \"\\e178\";\n}\n\n.glyphicon-cutlery:before {\n  content: \"\\e179\";\n}\n\n.glyphicon-header:before {\n  content: \"\\e180\";\n}\n\n.glyphicon-compressed:before {\n  content: \"\\e181\";\n}\n\n.glyphicon-earphone:before {\n  content: \"\\e182\";\n}\n\n.glyphicon-phone-alt:before {\n  content: \"\\e183\";\n}\n\n.glyphicon-tower:before {\n  content: \"\\e184\";\n}\n\n.glyphicon-stats:before {\n  content: \"\\e185\";\n}\n\n.glyphicon-sd-video:before {\n  content: \"\\e186\";\n}\n\n.glyphicon-hd-video:before {\n  content: \"\\e187\";\n}\n\n.glyphicon-subtitles:before {\n  content: \"\\e188\";\n}\n\n.glyphicon-sound-stereo:before {\n  content: \"\\e189\";\n}\n\n.glyphicon-sound-dolby:before {\n  content: \"\\e190\";\n}\n\n.glyphicon-sound-5-1:before {\n  content: \"\\e191\";\n}\n\n.glyphicon-sound-6-1:before {\n  content: \"\\e192\";\n}\n\n.glyphicon-sound-7-1:before {\n  content: \"\\e193\";\n}\n\n.glyphicon-copyright-mark:before {\n  content: \"\\e194\";\n}\n\n.glyphicon-registration-mark:before {\n  content: \"\\e195\";\n}\n\n.glyphicon-cloud-download:before {\n  content: \"\\e197\";\n}\n\n.glyphicon-cloud-upload:before {\n  content: \"\\e198\";\n}\n\n.glyphicon-tree-conifer:before {\n  content: \"\\e199\";\n}\n\n.glyphicon-tree-deciduous:before {\n  content: \"\\e200\";\n}\n\n.glyphicon-cd:before {\n  content: \"\\e201\";\n}\n\n.glyphicon-save-file:before {\n  content: \"\\e202\";\n}\n\n.glyphicon-open-file:before {\n  content: \"\\e203\";\n}\n\n.glyphicon-level-up:before {\n  content: \"\\e204\";\n}\n\n.glyphicon-copy:before {\n  content: \"\\e205\";\n}\n\n.glyphicon-paste:before {\n  content: \"\\e206\";\n}\n\n.glyphicon-alert:before {\n  content: \"\\e209\";\n}\n\n.glyphicon-equalizer:before {\n  content: \"\\e210\";\n}\n\n.glyphicon-king:before {\n  content: \"\\e211\";\n}\n\n.glyphicon-queen:before {\n  content: \"\\e212\";\n}\n\n.glyphicon-pawn:before {\n  content: \"\\e213\";\n}\n\n.glyphicon-bishop:before {\n  content: \"\\e214\";\n}\n\n.glyphicon-knight:before {\n  content: \"\\e215\";\n}\n\n.glyphicon-baby-formula:before {\n  content: \"\\e216\";\n}\n\n.glyphicon-tent:before {\n  content: \"\\26fa\";\n}\n\n.glyphicon-blackboard:before {\n  content: \"\\e218\";\n}\n\n.glyphicon-bed:before {\n  content: \"\\e219\";\n}\n\n.glyphicon-apple:before {\n  content: \"\\f8ff\";\n}\n\n.glyphicon-erase:before {\n  content: \"\\e221\";\n}\n\n.glyphicon-hourglass:before {\n  content: \"\\231b\";\n}\n\n.glyphicon-lamp:before {\n  content: \"\\e223\";\n}\n\n.glyphicon-duplicate:before {\n  content: \"\\e224\";\n}\n\n.glyphicon-piggy-bank:before {\n  content: \"\\e225\";\n}\n\n.glyphicon-scissors:before {\n  content: \"\\e226\";\n}\n\n.glyphicon-bitcoin:before {\n  content: \"\\e227\";\n}\n\n.glyphicon-btc:before {\n  content: \"\\e227\";\n}\n\n.glyphicon-xbt:before {\n  content: \"\\e227\";\n}\n\n.glyphicon-yen:before {\n  content: \"\\00a5\";\n}\n\n.glyphicon-jpy:before {\n  content: \"\\00a5\";\n}\n\n.glyphicon-ruble:before {\n  content: \"\\20bd\";\n}\n\n.glyphicon-rub:before {\n  content: \"\\20bd\";\n}\n\n.glyphicon-scale:before {\n  content: \"\\e230\";\n}\n\n.glyphicon-ice-lolly:before {\n  content: \"\\e231\";\n}\n\n.glyphicon-ice-lolly-tasted:before {\n  content: \"\\e232\";\n}\n\n.glyphicon-education:before {\n  content: \"\\e233\";\n}\n\n.glyphicon-option-horizontal:before {\n  content: \"\\e234\";\n}\n\n.glyphicon-option-vertical:before {\n  content: \"\\e235\";\n}\n\n.glyphicon-menu-hamburger:before {\n  content: \"\\e236\";\n}\n\n.glyphicon-modal-window:before {\n  content: \"\\e237\";\n}\n\n.glyphicon-oil:before {\n  content: \"\\e238\";\n}\n\n.glyphicon-grain:before {\n  content: \"\\e239\";\n}\n\n.glyphicon-sunglasses:before {\n  content: \"\\e240\";\n}\n\n.glyphicon-text-size:before {\n  content: \"\\e241\";\n}\n\n.glyphicon-text-color:before {\n  content: \"\\e242\";\n}\n\n.glyphicon-text-background:before {\n  content: \"\\e243\";\n}\n\n.glyphicon-object-align-top:before {\n  content: \"\\e244\";\n}\n\n.glyphicon-object-align-bottom:before {\n  content: \"\\e245\";\n}\n\n.glyphicon-object-align-horizontal:before {\n  content: \"\\e246\";\n}\n\n.glyphicon-object-align-left:before {\n  content: \"\\e247\";\n}\n\n.glyphicon-object-align-vertical:before {\n  content: \"\\e248\";\n}\n\n.glyphicon-object-align-right:before {\n  content: \"\\e249\";\n}\n\n.glyphicon-triangle-right:before {\n  content: \"\\e250\";\n}\n\n.glyphicon-triangle-left:before {\n  content: \"\\e251\";\n}\n\n.glyphicon-triangle-bottom:before {\n  content: \"\\e252\";\n}\n\n.glyphicon-triangle-top:before {\n  content: \"\\e253\";\n}\n\n.glyphicon-console:before {\n  content: \"\\e254\";\n}\n\n.glyphicon-superscript:before {\n  content: \"\\e255\";\n}\n\n.glyphicon-subscript:before {\n  content: \"\\e256\";\n}\n\n.glyphicon-menu-left:before {\n  content: \"\\e257\";\n}\n\n.glyphicon-menu-right:before {\n  content: \"\\e258\";\n}\n\n.glyphicon-menu-down:before {\n  content: \"\\e259\";\n}\n\n.glyphicon-menu-up:before {\n  content: \"\\e260\";\n}\n\n* {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\n*:before,\n*:after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\nhtml {\n  font-size: 10px;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n\nbody {\n  font-family: roboto;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #5e5e5e;\n  background-color: #edecec;\n}\n\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\na {\n  color: #2196f3;\n  text-decoration: none;\n}\n\na:hover,\na:focus {\n  color: #0a6ebd;\n  text-decoration: none;\n}\n\na:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n  outline: none !important;\n}\n\nfigure {\n  margin: 0;\n}\n\nimg {\n  vertical-align: middle;\n}\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\n.img-rounded {\n  border-radius: 2px;\n}\n\n.img-thumbnail {\n  padding: 3px;\n  line-height: 1.42857143;\n  background-color: #ffffff;\n  border: 1px solid #ededed;\n  border-radius: 2px;\n  -webkit-transition: all 0.2s ease-in-out;\n  -o-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n}\n\n.img-circle {\n  border-radius: 50%;\n}\n\nhr {\n  margin-top: 18px;\n  margin-bottom: 18px;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n}\n\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\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\n[role=\"button\"] {\n  cursor: pointer;\n}\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: #000000;\n}\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: #777777;\n}\n\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n  margin-top: 18px;\n  margin-bottom: 9px;\n}\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}\n\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n  margin-top: 9px;\n  margin-bottom: 9px;\n}\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}\n\nh1,\n.h1 {\n  font-size: 33px;\n}\n\nh2,\n.h2 {\n  font-size: 27px;\n}\n\nh3,\n.h3 {\n  font-size: 23px;\n}\n\nh4,\n.h4 {\n  font-size: 17px;\n}\n\nh5,\n.h5 {\n  font-size: 13px;\n}\n\nh6,\n.h6 {\n  font-size: 12px;\n}\n\np {\n  margin: 0 0 9px;\n}\n\n.lead {\n  margin-bottom: 18px;\n  font-size: 14px;\n  font-weight: 300;\n  line-height: 1.4;\n}\n\n@media (min-width: 768px) {\n  .lead {\n    font-size: 19.5px;\n  }\n}\n\nsmall,\n.small {\n  font-size: 92%;\n}\n\nmark,\n.mark {\n  background-color: #ffa829;\n  padding: .2em;\n}\n\n.text-left {\n  text-align: left;\n}\n\n.text-right {\n  text-align: right;\n}\n\n.text-center {\n  text-align: center;\n}\n\n.text-justify {\n  text-align: justify;\n}\n\n.text-nowrap {\n  white-space: nowrap;\n}\n\n.text-lowercase {\n  text-transform: lowercase;\n}\n\n.text-uppercase {\n  text-transform: uppercase;\n}\n\n.text-capitalize {\n  text-transform: capitalize;\n}\n\n.text-muted {\n  color: #777777;\n}\n\n.text-primary {\n  color: #2196f3;\n}\n\na.text-primary:hover,\na.text-primary:focus {\n  color: #0c7cd5;\n}\n\n.text-success {\n  color: #67bd6a;\n}\n\na.text-success:hover,\na.text-success:focus {\n  color: #49a84d;\n}\n\n.text-info {\n  color: #31708f;\n}\n\na.text-info:hover,\na.text-info:focus {\n  color: #245269;\n}\n\n.text-warning {\n  color: #ffa829;\n}\n\na.text-warning:hover,\na.text-warning:focus {\n  color: #f59200;\n}\n\n.text-danger {\n  color: #f6675d;\n}\n\na.text-danger:hover,\na.text-danger:focus {\n  color: #f33a2c;\n}\n\n.bg-primary {\n  color: #fff;\n  background-color: #2196f3;\n}\n\na.bg-primary:hover,\na.bg-primary:focus {\n  background-color: #0c7cd5;\n}\n\n.bg-success {\n  background-color: #67bd6a;\n}\n\na.bg-success:hover,\na.bg-success:focus {\n  background-color: #49a84d;\n}\n\n.bg-info {\n  background-color: #d9edf7;\n}\n\na.bg-info:hover,\na.bg-info:focus {\n  background-color: #afd9ee;\n}\n\n.bg-warning {\n  background-color: #ffa829;\n}\n\na.bg-warning:hover,\na.bg-warning:focus {\n  background-color: #f59200;\n}\n\n.bg-danger {\n  background-color: #f6675d;\n}\n\na.bg-danger:hover,\na.bg-danger:focus {\n  background-color: #f33a2c;\n}\n\n.page-header {\n  padding-bottom: 8px;\n  margin: 36px 0 18px;\n  border-bottom: 1px solid #eeeeee;\n}\n\nul,\nol {\n  margin-top: 0;\n  margin-bottom: 9px;\n}\n\nul ul,\nol ul,\nul ol,\nol ol {\n  margin-bottom: 0;\n}\n\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n\n.list-inline {\n  padding-left: 0;\n  list-style: none;\n  margin-left: -5px;\n}\n\n.list-inline > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\n\ndl {\n  margin-top: 0;\n  margin-bottom: 18px;\n}\n\ndt,\ndd {\n  line-height: 1.42857143;\n}\n\ndt {\n  font-weight: bold;\n}\n\ndd {\n  margin-left: 0;\n}\n\n@media (min-width: 768px) {\n  .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    clear: left;\n    text-align: right;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n\n  .dl-horizontal dd {\n    margin-left: 180px;\n  }\n}\n\nabbr[title],\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #777777;\n}\n\n.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n\nblockquote {\n  padding: 9px 18px;\n  margin: 0 0 18px;\n  font-size: 16.25px;\n  border-left: 5px solid #eeeeee;\n}\n\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n  margin-bottom: 0;\n}\n\nblockquote footer,\nblockquote small,\nblockquote .small {\n  display: block;\n  font-size: 80%;\n  line-height: 1.42857143;\n  color: #777777;\n}\n\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n  content: '\\2014 \\00A0';\n}\n\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n  text-align: right;\n}\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\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}\n\naddress {\n  margin-bottom: 18px;\n  font-style: normal;\n  line-height: 1.42857143;\n}\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\n\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  border-radius: 2px;\n}\n\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #ffffff;\n  background-color: #333333;\n  border-radius: 2px;\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n\nkbd kbd {\n  padding: 0;\n  font-size: 100%;\n  font-weight: bold;\n  box-shadow: none;\n}\n\npre {\n  display: block;\n  padding: 8.5px;\n  margin: 0 0 9px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: #333333;\n  background-color: #f5f5f5;\n  border: 1px solid #cccccc;\n  border-radius: 2px;\n}\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\n.pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n\n.container {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n\n@media (min-width: 768px) {\n  .container {\n    width: 100%;\n  }\n}\n\n@media (min-width: 992px) {\n  .container {\n    width: 100%;\n  }\n}\n\n@media (min-width: 1200px) {\n  .container {\n    width: 1170px;\n  }\n}\n\n.container-fluid {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n\n.row {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n\n.col-xs-1,\n.col-sm-1,\n.col-md-1,\n.col-lg-1,\n.col-xs-2,\n.col-sm-2,\n.col-md-2,\n.col-lg-2,\n.col-xs-3,\n.col-sm-3,\n.col-md-3,\n.col-lg-3,\n.col-xs-4,\n.col-sm-4,\n.col-md-4,\n.col-lg-4,\n.col-xs-5,\n.col-sm-5,\n.col-md-5,\n.col-lg-5,\n.col-xs-6,\n.col-sm-6,\n.col-md-6,\n.col-lg-6,\n.col-xs-7,\n.col-sm-7,\n.col-md-7,\n.col-lg-7,\n.col-xs-8,\n.col-sm-8,\n.col-md-8,\n.col-lg-8,\n.col-xs-9,\n.col-sm-9,\n.col-md-9,\n.col-lg-9,\n.col-xs-10,\n.col-sm-10,\n.col-md-10,\n.col-lg-10,\n.col-xs-11,\n.col-sm-11,\n.col-md-11,\n.col-lg-11,\n.col-xs-12,\n.col-sm-12,\n.col-md-12,\n.col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n\n.col-xs-1,\n.col-xs-2,\n.col-xs-3,\n.col-xs-4,\n.col-xs-5,\n.col-xs-6,\n.col-xs-7,\n.col-xs-8,\n.col-xs-9,\n.col-xs-10,\n.col-xs-11,\n.col-xs-12 {\n  float: left;\n}\n\n.col-xs-12 {\n  width: 100%;\n}\n\n.col-xs-11 {\n  width: 91.66666667%;\n}\n\n.col-xs-10 {\n  width: 83.33333333%;\n}\n\n.col-xs-9 {\n  width: 75%;\n}\n\n.col-xs-8 {\n  width: 66.66666667%;\n}\n\n.col-xs-7 {\n  width: 58.33333333%;\n}\n\n.col-xs-6 {\n  width: 50%;\n}\n\n.col-xs-5 {\n  width: 41.66666667%;\n}\n\n.col-xs-4 {\n  width: 33.33333333%;\n}\n\n.col-xs-3 {\n  width: 25%;\n}\n\n.col-xs-2 {\n  width: 16.66666667%;\n}\n\n.col-xs-1 {\n  width: 8.33333333%;\n}\n\n.col-xs-pull-12 {\n  right: 100%;\n}\n\n.col-xs-pull-11 {\n  right: 91.66666667%;\n}\n\n.col-xs-pull-10 {\n  right: 83.33333333%;\n}\n\n.col-xs-pull-9 {\n  right: 75%;\n}\n\n.col-xs-pull-8 {\n  right: 66.66666667%;\n}\n\n.col-xs-pull-7 {\n  right: 58.33333333%;\n}\n\n.col-xs-pull-6 {\n  right: 50%;\n}\n\n.col-xs-pull-5 {\n  right: 41.66666667%;\n}\n\n.col-xs-pull-4 {\n  right: 33.33333333%;\n}\n\n.col-xs-pull-3 {\n  right: 25%;\n}\n\n.col-xs-pull-2 {\n  right: 16.66666667%;\n}\n\n.col-xs-pull-1 {\n  right: 8.33333333%;\n}\n\n.col-xs-pull-0 {\n  right: auto;\n}\n\n.col-xs-push-12 {\n  left: 100%;\n}\n\n.col-xs-push-11 {\n  left: 91.66666667%;\n}\n\n.col-xs-push-10 {\n  left: 83.33333333%;\n}\n\n.col-xs-push-9 {\n  left: 75%;\n}\n\n.col-xs-push-8 {\n  left: 66.66666667%;\n}\n\n.col-xs-push-7 {\n  left: 58.33333333%;\n}\n\n.col-xs-push-6 {\n  left: 50%;\n}\n\n.col-xs-push-5 {\n  left: 41.66666667%;\n}\n\n.col-xs-push-4 {\n  left: 33.33333333%;\n}\n\n.col-xs-push-3 {\n  left: 25%;\n}\n\n.col-xs-push-2 {\n  left: 16.66666667%;\n}\n\n.col-xs-push-1 {\n  left: 8.33333333%;\n}\n\n.col-xs-push-0 {\n  left: auto;\n}\n\n.col-xs-offset-12 {\n  margin-left: 100%;\n}\n\n.col-xs-offset-11 {\n  margin-left: 91.66666667%;\n}\n\n.col-xs-offset-10 {\n  margin-left: 83.33333333%;\n}\n\n.col-xs-offset-9 {\n  margin-left: 75%;\n}\n\n.col-xs-offset-8 {\n  margin-left: 66.66666667%;\n}\n\n.col-xs-offset-7 {\n  margin-left: 58.33333333%;\n}\n\n.col-xs-offset-6 {\n  margin-left: 50%;\n}\n\n.col-xs-offset-5 {\n  margin-left: 41.66666667%;\n}\n\n.col-xs-offset-4 {\n  margin-left: 33.33333333%;\n}\n\n.col-xs-offset-3 {\n  margin-left: 25%;\n}\n\n.col-xs-offset-2 {\n  margin-left: 16.66666667%;\n}\n\n.col-xs-offset-1 {\n  margin-left: 8.33333333%;\n}\n\n.col-xs-offset-0 {\n  margin-left: 0%;\n}\n\n@media (min-width: 768px) {\n  .col-sm-1,\n  .col-sm-2,\n  .col-sm-3,\n  .col-sm-4,\n  .col-sm-5,\n  .col-sm-6,\n  .col-sm-7,\n  .col-sm-8,\n  .col-sm-9,\n  .col-sm-10,\n  .col-sm-11,\n  .col-sm-12 {\n    float: left;\n  }\n\n  .col-sm-12 {\n    width: 100%;\n  }\n\n  .col-sm-11 {\n    width: 91.66666667%;\n  }\n\n  .col-sm-10 {\n    width: 83.33333333%;\n  }\n\n  .col-sm-9 {\n    width: 75%;\n  }\n\n  .col-sm-8 {\n    width: 66.66666667%;\n  }\n\n  .col-sm-7 {\n    width: 58.33333333%;\n  }\n\n  .col-sm-6 {\n    width: 50%;\n  }\n\n  .col-sm-5 {\n    width: 41.66666667%;\n  }\n\n  .col-sm-4 {\n    width: 33.33333333%;\n  }\n\n  .col-sm-3 {\n    width: 25%;\n  }\n\n  .col-sm-2 {\n    width: 16.66666667%;\n  }\n\n  .col-sm-1 {\n    width: 8.33333333%;\n  }\n\n  .col-sm-pull-12 {\n    right: 100%;\n  }\n\n  .col-sm-pull-11 {\n    right: 91.66666667%;\n  }\n\n  .col-sm-pull-10 {\n    right: 83.33333333%;\n  }\n\n  .col-sm-pull-9 {\n    right: 75%;\n  }\n\n  .col-sm-pull-8 {\n    right: 66.66666667%;\n  }\n\n  .col-sm-pull-7 {\n    right: 58.33333333%;\n  }\n\n  .col-sm-pull-6 {\n    right: 50%;\n  }\n\n  .col-sm-pull-5 {\n    right: 41.66666667%;\n  }\n\n  .col-sm-pull-4 {\n    right: 33.33333333%;\n  }\n\n  .col-sm-pull-3 {\n    right: 25%;\n  }\n\n  .col-sm-pull-2 {\n    right: 16.66666667%;\n  }\n\n  .col-sm-pull-1 {\n    right: 8.33333333%;\n  }\n\n  .col-sm-pull-0 {\n    right: auto;\n  }\n\n  .col-sm-push-12 {\n    left: 100%;\n  }\n\n  .col-sm-push-11 {\n    left: 91.66666667%;\n  }\n\n  .col-sm-push-10 {\n    left: 83.33333333%;\n  }\n\n  .col-sm-push-9 {\n    left: 75%;\n  }\n\n  .col-sm-push-8 {\n    left: 66.66666667%;\n  }\n\n  .col-sm-push-7 {\n    left: 58.33333333%;\n  }\n\n  .col-sm-push-6 {\n    left: 50%;\n  }\n\n  .col-sm-push-5 {\n    left: 41.66666667%;\n  }\n\n  .col-sm-push-4 {\n    left: 33.33333333%;\n  }\n\n  .col-sm-push-3 {\n    left: 25%;\n  }\n\n  .col-sm-push-2 {\n    left: 16.66666667%;\n  }\n\n  .col-sm-push-1 {\n    left: 8.33333333%;\n  }\n\n  .col-sm-push-0 {\n    left: auto;\n  }\n\n  .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n\n  .col-sm-offset-11 {\n    margin-left: 91.66666667%;\n  }\n\n  .col-sm-offset-10 {\n    margin-left: 83.33333333%;\n  }\n\n  .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n\n  .col-sm-offset-8 {\n    margin-left: 66.66666667%;\n  }\n\n  .col-sm-offset-7 {\n    margin-left: 58.33333333%;\n  }\n\n  .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n\n  .col-sm-offset-5 {\n    margin-left: 41.66666667%;\n  }\n\n  .col-sm-offset-4 {\n    margin-left: 33.33333333%;\n  }\n\n  .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n\n  .col-sm-offset-2 {\n    margin-left: 16.66666667%;\n  }\n\n  .col-sm-offset-1 {\n    margin-left: 8.33333333%;\n  }\n\n  .col-sm-offset-0 {\n    margin-left: 0%;\n  }\n}\n\n@media (min-width: 992px) {\n  .col-md-1,\n  .col-md-2,\n  .col-md-3,\n  .col-md-4,\n  .col-md-5,\n  .col-md-6,\n  .col-md-7,\n  .col-md-8,\n  .col-md-9,\n  .col-md-10,\n  .col-md-11,\n  .col-md-12 {\n    float: left;\n  }\n\n  .col-md-12 {\n    width: 100%;\n  }\n\n  .col-md-11 {\n    width: 91.66666667%;\n  }\n\n  .col-md-10 {\n    width: 83.33333333%;\n  }\n\n  .col-md-9 {\n    width: 75%;\n  }\n\n  .col-md-8 {\n    width: 66.66666667%;\n  }\n\n  .col-md-7 {\n    width: 58.33333333%;\n  }\n\n  .col-md-6 {\n    width: 50%;\n  }\n\n  .col-md-5 {\n    width: 41.66666667%;\n  }\n\n  .col-md-4 {\n    width: 33.33333333%;\n  }\n\n  .col-md-3 {\n    width: 25%;\n  }\n\n  .col-md-2 {\n    width: 16.66666667%;\n  }\n\n  .col-md-1 {\n    width: 8.33333333%;\n  }\n\n  .col-md-pull-12 {\n    right: 100%;\n  }\n\n  .col-md-pull-11 {\n    right: 91.66666667%;\n  }\n\n  .col-md-pull-10 {\n    right: 83.33333333%;\n  }\n\n  .col-md-pull-9 {\n    right: 75%;\n  }\n\n  .col-md-pull-8 {\n    right: 66.66666667%;\n  }\n\n  .col-md-pull-7 {\n    right: 58.33333333%;\n  }\n\n  .col-md-pull-6 {\n    right: 50%;\n  }\n\n  .col-md-pull-5 {\n    right: 41.66666667%;\n  }\n\n  .col-md-pull-4 {\n    right: 33.33333333%;\n  }\n\n  .col-md-pull-3 {\n    right: 25%;\n  }\n\n  .col-md-pull-2 {\n    right: 16.66666667%;\n  }\n\n  .col-md-pull-1 {\n    right: 8.33333333%;\n  }\n\n  .col-md-pull-0 {\n    right: auto;\n  }\n\n  .col-md-push-12 {\n    left: 100%;\n  }\n\n  .col-md-push-11 {\n    left: 91.66666667%;\n  }\n\n  .col-md-push-10 {\n    left: 83.33333333%;\n  }\n\n  .col-md-push-9 {\n    left: 75%;\n  }\n\n  .col-md-push-8 {\n    left: 66.66666667%;\n  }\n\n  .col-md-push-7 {\n    left: 58.33333333%;\n  }\n\n  .col-md-push-6 {\n    left: 50%;\n  }\n\n  .col-md-push-5 {\n    left: 41.66666667%;\n  }\n\n  .col-md-push-4 {\n    left: 33.33333333%;\n  }\n\n  .col-md-push-3 {\n    left: 25%;\n  }\n\n  .col-md-push-2 {\n    left: 16.66666667%;\n  }\n\n  .col-md-push-1 {\n    left: 8.33333333%;\n  }\n\n  .col-md-push-0 {\n    left: auto;\n  }\n\n  .col-md-offset-12 {\n    margin-left: 100%;\n  }\n\n  .col-md-offset-11 {\n    margin-left: 91.66666667%;\n  }\n\n  .col-md-offset-10 {\n    margin-left: 83.33333333%;\n  }\n\n  .col-md-offset-9 {\n    margin-left: 75%;\n  }\n\n  .col-md-offset-8 {\n    margin-left: 66.66666667%;\n  }\n\n  .col-md-offset-7 {\n    margin-left: 58.33333333%;\n  }\n\n  .col-md-offset-6 {\n    margin-left: 50%;\n  }\n\n  .col-md-offset-5 {\n    margin-left: 41.66666667%;\n  }\n\n  .col-md-offset-4 {\n    margin-left: 33.33333333%;\n  }\n\n  .col-md-offset-3 {\n    margin-left: 25%;\n  }\n\n  .col-md-offset-2 {\n    margin-left: 16.66666667%;\n  }\n\n  .col-md-offset-1 {\n    margin-left: 8.33333333%;\n  }\n\n  .col-md-offset-0 {\n    margin-left: 0%;\n  }\n}\n\n@media (min-width: 1200px) {\n  .col-lg-1,\n  .col-lg-2,\n  .col-lg-3,\n  .col-lg-4,\n  .col-lg-5,\n  .col-lg-6,\n  .col-lg-7,\n  .col-lg-8,\n  .col-lg-9,\n  .col-lg-10,\n  .col-lg-11,\n  .col-lg-12 {\n    float: left;\n  }\n\n  .col-lg-12 {\n    width: 100%;\n  }\n\n  .col-lg-11 {\n    width: 91.66666667%;\n  }\n\n  .col-lg-10 {\n    width: 83.33333333%;\n  }\n\n  .col-lg-9 {\n    width: 75%;\n  }\n\n  .col-lg-8 {\n    width: 66.66666667%;\n  }\n\n  .col-lg-7 {\n    width: 58.33333333%;\n  }\n\n  .col-lg-6 {\n    width: 50%;\n  }\n\n  .col-lg-5 {\n    width: 41.66666667%;\n  }\n\n  .col-lg-4 {\n    width: 33.33333333%;\n  }\n\n  .col-lg-3 {\n    width: 25%;\n  }\n\n  .col-lg-2 {\n    width: 16.66666667%;\n  }\n\n  .col-lg-1 {\n    width: 8.33333333%;\n  }\n\n  .col-lg-pull-12 {\n    right: 100%;\n  }\n\n  .col-lg-pull-11 {\n    right: 91.66666667%;\n  }\n\n  .col-lg-pull-10 {\n    right: 83.33333333%;\n  }\n\n  .col-lg-pull-9 {\n    right: 75%;\n  }\n\n  .col-lg-pull-8 {\n    right: 66.66666667%;\n  }\n\n  .col-lg-pull-7 {\n    right: 58.33333333%;\n  }\n\n  .col-lg-pull-6 {\n    right: 50%;\n  }\n\n  .col-lg-pull-5 {\n    right: 41.66666667%;\n  }\n\n  .col-lg-pull-4 {\n    right: 33.33333333%;\n  }\n\n  .col-lg-pull-3 {\n    right: 25%;\n  }\n\n  .col-lg-pull-2 {\n    right: 16.66666667%;\n  }\n\n  .col-lg-pull-1 {\n    right: 8.33333333%;\n  }\n\n  .col-lg-pull-0 {\n    right: auto;\n  }\n\n  .col-lg-push-12 {\n    left: 100%;\n  }\n\n  .col-lg-push-11 {\n    left: 91.66666667%;\n  }\n\n  .col-lg-push-10 {\n    left: 83.33333333%;\n  }\n\n  .col-lg-push-9 {\n    left: 75%;\n  }\n\n  .col-lg-push-8 {\n    left: 66.66666667%;\n  }\n\n  .col-lg-push-7 {\n    left: 58.33333333%;\n  }\n\n  .col-lg-push-6 {\n    left: 50%;\n  }\n\n  .col-lg-push-5 {\n    left: 41.66666667%;\n  }\n\n  .col-lg-push-4 {\n    left: 33.33333333%;\n  }\n\n  .col-lg-push-3 {\n    left: 25%;\n  }\n\n  .col-lg-push-2 {\n    left: 16.66666667%;\n  }\n\n  .col-lg-push-1 {\n    left: 8.33333333%;\n  }\n\n  .col-lg-push-0 {\n    left: auto;\n  }\n\n  .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n\n  .col-lg-offset-11 {\n    margin-left: 91.66666667%;\n  }\n\n  .col-lg-offset-10 {\n    margin-left: 83.33333333%;\n  }\n\n  .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n\n  .col-lg-offset-8 {\n    margin-left: 66.66666667%;\n  }\n\n  .col-lg-offset-7 {\n    margin-left: 58.33333333%;\n  }\n\n  .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n\n  .col-lg-offset-5 {\n    margin-left: 41.66666667%;\n  }\n\n  .col-lg-offset-4 {\n    margin-left: 33.33333333%;\n  }\n\n  .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n\n  .col-lg-offset-2 {\n    margin-left: 16.66666667%;\n  }\n\n  .col-lg-offset-1 {\n    margin-left: 8.33333333%;\n  }\n\n  .col-lg-offset-0 {\n    margin-left: 0%;\n  }\n}\n\ntable {\n  background-color: #ffffff;\n}\n\ncaption {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  color: #777777;\n  text-align: left;\n}\n\nth {\n  text-align: left;\n}\n\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: 18px;\n}\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: 10px;\n  line-height: 1.42857143;\n  vertical-align: top;\n  border-top: 1px solid #f0f0f0;\n}\n\n.table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #f0f0f0;\n}\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\n.table > tbody + tbody {\n  border-top: 2px solid #f0f0f0;\n}\n\n.table .table {\n  background-color: #edecec;\n}\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: 7px;\n}\n\n.table-bordered {\n  border: 1px solid #f0f0f0;\n}\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 #f0f0f0;\n}\n\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n\n.table-striped > tbody > tr:nth-of-type(odd) {\n  background-color: #f4f4f4;\n}\n\n.table-hover > tbody > tr:hover {\n  background-color: #f5f5f5;\n}\n\ntable col[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-column;\n}\n\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n  position: static;\n  float: none;\n  display: table-cell;\n}\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: #fffcbe;\n}\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: #fffba4;\n}\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: #67bd6a;\n}\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: #55b559;\n}\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\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\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: #ffa829;\n}\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: #ff9e0f;\n}\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: #f6675d;\n}\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: #f55145;\n}\n\n.table-responsive {\n  overflow-x: auto;\n  min-height: 0.01%;\n}\n\n@media screen and (max-width: 767px) {\n  .table-responsive {\n    width: 100%;\n    margin-bottom: 13.5px;\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #f0f0f0;\n  }\n\n  .table-responsive > .table {\n    margin-bottom: 0;\n  }\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\n  .table-responsive > .table-bordered {\n    border: 0;\n  }\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\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\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}\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  min-width: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 18px;\n  font-size: 19.5px;\n  line-height: inherit;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\n\nlabel {\n  display: inline-block;\n  max-width: 100%;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\ninput[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  line-height: normal;\n}\n\ninput[type=\"file\"] {\n  display: block;\n}\n\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\n\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  outline: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n  outline: none !important;\n}\n\noutput {\n  display: block;\n  padding-top: 7px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #000000;\n}\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: 35px;\n  padding: 6px 12px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  color: #000000;\n  background-color: #ffffff;\n  background-image: none;\n  border: 1px solid #e0e0e0;\n  border-radius: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-transition: border-color ease-in-out .15s, 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\n.form-control:focus {\n  border-color: #b4b4b4;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(180, 180, 180, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(180, 180, 180, 0.6);\n}\n\n.form-control::-moz-placeholder {\n  color: #999999;\n  opacity: 1;\n}\n\n.form-control:-ms-input-placeholder {\n  color: #999999;\n}\n\n.form-control::-webkit-input-placeholder {\n  color: #999999;\n}\n\n.form-control::-ms-expand {\n  border: 0;\n  background-color: transparent;\n}\n\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n  background-color: #eeeeee;\n  opacity: 1;\n}\n\n.form-control[disabled],\nfieldset[disabled] .form-control {\n  cursor: not-allowed;\n}\n\ntextarea.form-control {\n  height: auto;\n}\n\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\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: 35px;\n  }\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\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: 40px;\n  }\n}\n\n.form-group {\n  margin-bottom: 15px;\n}\n\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n\n.radio label,\n.checkbox label {\n  min-height: 18px;\n  padding-left: 20px;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\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-left: -20px;\n  margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px;\n}\n\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\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\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n  cursor: not-allowed;\n}\n\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n  cursor: not-allowed;\n}\n\n.form-control-static {\n  padding-top: 7px;\n  padding-bottom: 7px;\n  margin-bottom: 0;\n  min-height: 31px;\n}\n\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n  padding-left: 0;\n  padding-right: 0;\n}\n\n.input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 2px;\n}\n\nselect.input-sm {\n  height: 30px;\n  line-height: 30px;\n}\n\ntextarea.input-sm,\nselect[multiple].input-sm {\n  height: auto;\n}\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: 2px;\n}\n\n.form-group-sm select.form-control {\n  height: 30px;\n  line-height: 30px;\n}\n\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n  height: auto;\n}\n\n.form-group-sm .form-control-static {\n  height: 30px;\n  min-height: 30px;\n  padding: 6px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n}\n\n.input-lg {\n  height: 40px;\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n  border-radius: 0px;\n}\n\nselect.input-lg {\n  height: 40px;\n  line-height: 40px;\n}\n\ntextarea.input-lg,\nselect[multiple].input-lg {\n  height: auto;\n}\n\n.form-group-lg .form-control {\n  height: 40px;\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n  border-radius: 0px;\n}\n\n.form-group-lg select.form-control {\n  height: 40px;\n  line-height: 40px;\n}\n\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n  height: auto;\n}\n\n.form-group-lg .form-control-static {\n  height: 40px;\n  min-height: 35px;\n  padding: 11px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n}\n\n.has-feedback {\n  position: relative;\n}\n\n.has-feedback .form-control {\n  padding-right: 43.75px;\n}\n\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2;\n  display: block;\n  width: 35px;\n  height: 35px;\n  line-height: 35px;\n  text-align: center;\n  pointer-events: none;\n}\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: 40px;\n  height: 40px;\n  line-height: 40px;\n}\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\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: #67bd6a;\n}\n\n.has-success .form-control {\n  border-color: #67bd6a;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\n.has-success .form-control:focus {\n  border-color: #49a84d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #aedcb0;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #aedcb0;\n}\n\n.has-success .input-group-addon {\n  color: #67bd6a;\n  border-color: #67bd6a;\n  background-color: #67bd6a;\n}\n\n.has-success .form-control-feedback {\n  color: #67bd6a;\n}\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: #ffa829;\n}\n\n.has-warning .form-control {\n  border-color: #ffa829;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\n.has-warning .form-control:focus {\n  border-color: #f59200;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffd28f;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ffd28f;\n}\n\n.has-warning .input-group-addon {\n  color: #ffa829;\n  border-color: #ffa829;\n  background-color: #ffa829;\n}\n\n.has-warning .form-control-feedback {\n  color: #ffa829;\n}\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: #f6675d;\n}\n\n.has-error .form-control {\n  border-color: #f6675d;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n\n.has-error .form-control:focus {\n  border-color: #f33a2c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #fbc2bd;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #fbc2bd;\n}\n\n.has-error .input-group-addon {\n  color: #f6675d;\n  border-color: #f6675d;\n  background-color: #f6675d;\n}\n\n.has-error .form-control-feedback {\n  color: #f6675d;\n}\n\n.has-feedback label ~ .form-control-feedback {\n  top: 23px;\n}\n\n.has-feedback label.sr-only ~ .form-control-feedback {\n  top: 0;\n}\n\n.help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #9e9e9e;\n}\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\n  .form-inline .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n\n  .form-inline .form-control-static {\n    display: inline-block;\n  }\n\n  .form-inline .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\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\n  .form-inline .input-group > .form-control {\n    width: 100%;\n  }\n\n  .form-inline .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\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\n  .form-inline .radio label,\n  .form-inline .checkbox label {\n    padding-left: 0;\n  }\n\n  .form-inline .radio input[type=\"radio\"],\n  .form-inline .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n\n  .form-inline .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 7px;\n}\n\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n  min-height: 25px;\n}\n\n.form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n\n@media (min-width: 768px) {\n  .form-horizontal .control-label {\n    text-align: right;\n    margin-bottom: 0;\n    padding-top: 7px;\n  }\n}\n\n.form-horizontal .has-feedback .form-control-feedback {\n  right: 15px;\n}\n\n@media (min-width: 768px) {\n  .form-horizontal .form-group-lg .control-label {\n    padding-top: 11px;\n    font-size: 17px;\n  }\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\n.btn {\n  display: inline-block;\n  margin-bottom: 0;\n  font-weight: 400;\n  text-align: center;\n  vertical-align: middle;\n  touch-action: manipulation;\n  cursor: pointer;\n  background-image: none;\n  border: 1px solid transparent;\n  white-space: nowrap;\n  padding: 6px 12px;\n  font-size: 13px;\n  line-height: 1.42857143;\n  border-radius: 2px;\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\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: thin dotted;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n  outline: none !important;\n}\n\n.btn:hover,\n.btn:focus,\n.btn.focus {\n  color: #333333;\n  text-decoration: none;\n}\n\n.btn:active,\n.btn.active {\n  outline: 0;\n  background-image: none;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n  cursor: not-allowed;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n\na.btn.disabled,\nfieldset[disabled] a.btn {\n  pointer-events: none;\n}\n\n.btn-default {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n\n.btn-default:focus,\n.btn-default.focus {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #8c8c8c;\n}\n\n.btn-default:hover {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\n\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  color: #333333;\n  background-color: #e6e6e6;\n  border-color: #adadad;\n}\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: #333333;\n  background-color: #d4d4d4;\n  border-color: #8c8c8c;\n}\n\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\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: #ffffff;\n  border-color: #cccccc;\n}\n\n.btn-default .badge {\n  color: #ffffff;\n  background-color: #333333;\n}\n\n.btn-default:hover,\n.btn-default:focus,\n.btn-default.focus,\n.btn-default:active,\n.open > .dropdown-toggle.btn-default {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: transparent;\n}\n\n.btn-default:hover:hover,\n.btn-default:focus:hover,\n.btn-default.focus:hover,\n.btn-default:active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:hover:focus,\n.btn-default:focus:focus,\n.btn-default.focus:focus,\n.btn-default:active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:hover.focus,\n.btn-default:focus.focus,\n.btn-default.focus.focus,\n.btn-default:active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: transparent;\n}\n\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n  background-image: none;\n}\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  background-color: #ffffff;\n  border-color: #cccccc;\n}\n\n.btn-default .badge {\n  color: #ffffff;\n  background-color: #333333;\n}\n\n.btn-primary {\n  color: #ffffff;\n  background-color: #2196f3;\n  border-color: #0d8aee;\n}\n\n.btn-primary:focus,\n.btn-primary.focus {\n  color: #ffffff;\n  background-color: #0c7cd5;\n  border-color: #064475;\n}\n\n.btn-primary:hover {\n  color: #ffffff;\n  background-color: #0c7cd5;\n  border-color: #0a68b4;\n}\n\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  color: #ffffff;\n  background-color: #0c7cd5;\n  border-color: #0a68b4;\n}\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: #ffffff;\n  background-color: #0a68b4;\n  border-color: #064475;\n}\n\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\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: #2196f3;\n  border-color: #0d8aee;\n}\n\n.btn-primary .badge {\n  color: #2196f3;\n  background-color: #ffffff;\n}\n\n.btn-primary:hover,\n.btn-primary:focus,\n.btn-primary.focus,\n.btn-primary:active,\n.open > .dropdown-toggle.btn-primary {\n  color: #ffffff;\n  background-color: #2196f3;\n  border-color: transparent;\n}\n\n.btn-primary:hover:hover,\n.btn-primary:focus:hover,\n.btn-primary.focus:hover,\n.btn-primary:active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:hover:focus,\n.btn-primary:focus:focus,\n.btn-primary.focus:focus,\n.btn-primary:active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:hover.focus,\n.btn-primary:focus.focus,\n.btn-primary.focus.focus,\n.btn-primary:active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n  color: #ffffff;\n  background-color: #2196f3;\n  border-color: transparent;\n}\n\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n  background-image: none;\n}\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  background-color: #2196f3;\n  border-color: #0d8aee;\n}\n\n.btn-primary .badge {\n  color: #2196f3;\n  background-color: #ffffff;\n}\n\n.btn-success {\n  color: #ffffff;\n  background-color: #4caf50;\n  border-color: #449d48;\n}\n\n.btn-success:focus,\n.btn-success.focus {\n  color: #ffffff;\n  background-color: #3d8b40;\n  border-color: #1e441f;\n}\n\n.btn-success:hover {\n  color: #ffffff;\n  background-color: #3d8b40;\n  border-color: #327334;\n}\n\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  color: #ffffff;\n  background-color: #3d8b40;\n  border-color: #327334;\n}\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: #ffffff;\n  background-color: #327334;\n  border-color: #1e441f;\n}\n\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\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: #4caf50;\n  border-color: #449d48;\n}\n\n.btn-success .badge {\n  color: #4caf50;\n  background-color: #ffffff;\n}\n\n.btn-success:hover,\n.btn-success:focus,\n.btn-success.focus,\n.btn-success:active,\n.open > .dropdown-toggle.btn-success {\n  color: #ffffff;\n  background-color: #4caf50;\n  border-color: transparent;\n}\n\n.btn-success:hover:hover,\n.btn-success:focus:hover,\n.btn-success.focus:hover,\n.btn-success:active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:hover:focus,\n.btn-success:focus:focus,\n.btn-success.focus:focus,\n.btn-success:active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:hover.focus,\n.btn-success:focus.focus,\n.btn-success.focus.focus,\n.btn-success:active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n  color: #ffffff;\n  background-color: #4caf50;\n  border-color: transparent;\n}\n\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n  background-image: none;\n}\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  background-color: #4caf50;\n  border-color: #449d48;\n}\n\n.btn-success .badge {\n  color: #4caf50;\n  background-color: #ffffff;\n}\n\n.btn-info {\n  color: #ffffff;\n  background-color: #00bcd4;\n  border-color: #00a5bb;\n}\n\n.btn-info:focus,\n.btn-info.focus {\n  color: #ffffff;\n  background-color: #008fa1;\n  border-color: #00343b;\n}\n\n.btn-info:hover {\n  color: #ffffff;\n  background-color: #008fa1;\n  border-color: #006f7d;\n}\n\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  color: #ffffff;\n  background-color: #008fa1;\n  border-color: #006f7d;\n}\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: #ffffff;\n  background-color: #006f7d;\n  border-color: #00343b;\n}\n\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\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: #00bcd4;\n  border-color: #00a5bb;\n}\n\n.btn-info .badge {\n  color: #00bcd4;\n  background-color: #ffffff;\n}\n\n.btn-info:hover,\n.btn-info:focus,\n.btn-info.focus,\n.btn-info:active,\n.open > .dropdown-toggle.btn-info {\n  color: #ffffff;\n  background-color: #00bcd4;\n  border-color: transparent;\n}\n\n.btn-info:hover:hover,\n.btn-info:focus:hover,\n.btn-info.focus:hover,\n.btn-info:active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:hover:focus,\n.btn-info:focus:focus,\n.btn-info.focus:focus,\n.btn-info:active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:hover.focus,\n.btn-info:focus.focus,\n.btn-info.focus.focus,\n.btn-info:active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n  color: #ffffff;\n  background-color: #00bcd4;\n  border-color: transparent;\n}\n\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n  background-image: none;\n}\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  background-color: #00bcd4;\n  border-color: #00a5bb;\n}\n\n.btn-info .badge {\n  color: #00bcd4;\n  background-color: #ffffff;\n}\n\n.btn-warning {\n  color: #ffffff;\n  background-color: #ff9800;\n  border-color: #e68900;\n}\n\n.btn-warning:focus,\n.btn-warning.focus {\n  color: #ffffff;\n  background-color: #cc7a00;\n  border-color: #663d00;\n}\n\n.btn-warning:hover {\n  color: #ffffff;\n  background-color: #cc7a00;\n  border-color: #a86400;\n}\n\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  color: #ffffff;\n  background-color: #cc7a00;\n  border-color: #a86400;\n}\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: #ffffff;\n  background-color: #a86400;\n  border-color: #663d00;\n}\n\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\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: #ff9800;\n  border-color: #e68900;\n}\n\n.btn-warning .badge {\n  color: #ff9800;\n  background-color: #ffffff;\n}\n\n.btn-warning:hover,\n.btn-warning:focus,\n.btn-warning.focus,\n.btn-warning:active,\n.open > .dropdown-toggle.btn-warning {\n  color: #ffffff;\n  background-color: #ff9800;\n  border-color: transparent;\n}\n\n.btn-warning:hover:hover,\n.btn-warning:focus:hover,\n.btn-warning.focus:hover,\n.btn-warning:active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:hover:focus,\n.btn-warning:focus:focus,\n.btn-warning.focus:focus,\n.btn-warning:active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:hover.focus,\n.btn-warning:focus.focus,\n.btn-warning.focus.focus,\n.btn-warning:active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n  color: #ffffff;\n  background-color: #ff9800;\n  border-color: transparent;\n}\n\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n  background-image: none;\n}\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  background-color: #ff9800;\n  border-color: #e68900;\n}\n\n.btn-warning .badge {\n  color: #ff9800;\n  background-color: #ffffff;\n}\n\n.btn-danger {\n  color: #ffffff;\n  background-color: #f44336;\n  border-color: #f32c1e;\n}\n\n.btn-danger:focus,\n.btn-danger.focus {\n  color: #ffffff;\n  background-color: #ea1c0d;\n  border-color: #891008;\n}\n\n.btn-danger:hover {\n  color: #ffffff;\n  background-color: #ea1c0d;\n  border-color: #c8180b;\n}\n\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  color: #ffffff;\n  background-color: #ea1c0d;\n  border-color: #c8180b;\n}\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: #ffffff;\n  background-color: #c8180b;\n  border-color: #891008;\n}\n\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\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: #f44336;\n  border-color: #f32c1e;\n}\n\n.btn-danger .badge {\n  color: #f44336;\n  background-color: #ffffff;\n}\n\n.btn-danger:hover,\n.btn-danger:focus,\n.btn-danger.focus,\n.btn-danger:active,\n.open > .dropdown-toggle.btn-danger {\n  color: #ffffff;\n  background-color: #f44336;\n  border-color: transparent;\n}\n\n.btn-danger:hover:hover,\n.btn-danger:focus:hover,\n.btn-danger.focus:hover,\n.btn-danger:active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:hover:focus,\n.btn-danger:focus:focus,\n.btn-danger.focus:focus,\n.btn-danger:active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:hover.focus,\n.btn-danger:focus.focus,\n.btn-danger.focus.focus,\n.btn-danger:active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n  color: #ffffff;\n  background-color: #f44336;\n  border-color: transparent;\n}\n\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n  background-image: none;\n}\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  background-color: #f44336;\n  border-color: #f32c1e;\n}\n\n.btn-danger .badge {\n  color: #f44336;\n  background-color: #ffffff;\n}\n\n.btn-link {\n  color: #2196f3;\n  font-weight: normal;\n  border-radius: 0;\n}\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\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n  border-color: transparent;\n}\n\n.btn-link:hover,\n.btn-link:focus {\n  color: #0a6ebd;\n  text-decoration: none;\n  background-color: transparent;\n}\n\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n  color: #777777;\n  text-decoration: none;\n}\n\n.btn-lg,\n.btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n  border-radius: 2px;\n}\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: 2px;\n}\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: 2px;\n}\n\n.btn-block {\n  display: block;\n  width: 100%;\n}\n\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n  width: 100%;\n}\n\n.fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n  -o-transition: opacity 0.15s linear;\n  transition: opacity 0.15s linear;\n}\n\n.fade.in {\n  opacity: 1;\n}\n\n.collapse {\n  display: none;\n}\n\n.collapse.in {\n  display: block;\n}\n\ntr.collapse.in {\n  display: table-row;\n}\n\ntbody.collapse.in {\n  display: table-row-group;\n}\n\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition-property: height, visibility;\n  transition-property: height, visibility;\n  -webkit-transition-duration: 0.35s;\n  transition-duration: 0.35s;\n  -webkit-transition-timing-function: ease;\n  transition-timing-function: ease;\n}\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\n.dropup,\n.dropdown {\n  position: relative;\n}\n\n.dropdown-toggle:focus {\n  outline: 0;\n}\n\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: 9;\n  display: none;\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0;\n  list-style: none;\n  font-size: 13px;\n  text-align: left;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  background-clip: padding-box;\n}\n\n.dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n\n.dropdown-menu .divider {\n  height: 1px;\n  margin: 8px 0;\n  overflow: hidden;\n  background-color: rgba(0, 0, 0, 0.08);\n}\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: #333333;\n  white-space: nowrap;\n}\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  text-decoration: none;\n  color: #333333;\n  background-color: rgba(0, 0, 0, 0.075);\n}\n\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  color: #333333;\n  text-decoration: none;\n  outline: 0;\n  background-color: rgba(0, 0, 0, 0.075);\n}\n\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  color: #e4e4e4;\n}\n\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  cursor: not-allowed;\n}\n\n.open > .dropdown-menu {\n  display: block;\n}\n\n.open > a {\n  outline: 0;\n}\n\n.dropdown-menu-right {\n  left: auto;\n  right: 0;\n}\n\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.42857143;\n  color: #777777;\n  white-space: nowrap;\n}\n\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: -1;\n}\n\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n  border-top: 0;\n  border-bottom: 4px dashed;\n  border-bottom: 4px solid \\9;\n  content: \"\";\n}\n\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 2px;\n}\n\n@media (min-width: 768px) {\n  .navbar-right .dropdown-menu {\n    left: auto;\n    right: 0;\n  }\n\n  .navbar-right .dropdown-menu-left {\n    left: 0;\n    right: auto;\n  }\n}\n\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\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\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\n.btn-toolbar {\n  margin-left: -5px;\n}\n\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n  float: left;\n}\n\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n  margin-left: 5px;\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n\n.btn-group > .btn:first-child {\n  margin-left: 0;\n}\n\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.btn-group > .btn-group {\n  float: left;\n}\n\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\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-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n\n.btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n\n.btn-group.open .dropdown-toggle.btn-link {\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n\n.btn .caret {\n  margin-left: 0;\n}\n\n.btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n\n.dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\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\n.btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\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\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 2px;\n  border-top-left-radius: 2px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n  border-bottom-right-radius: 2px;\n  border-bottom-left-radius: 2px;\n}\n\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\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\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n  float: none;\n  display: table-cell;\n  width: 1%;\n}\n\n.btn-group-justified > .btn-group .btn {\n  width: 100%;\n}\n\n.btn-group-justified > .btn-group .dropdown-menu {\n  left: auto;\n}\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\n.input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n\n.input-group[class*=\"col-\"] {\n  float: none;\n  padding-left: 0;\n  padding-right: 0;\n}\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\n.input-group .form-control:focus {\n  z-index: 3;\n}\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  height: 40px;\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n  border-radius: 0px;\n}\n\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n  height: 40px;\n  line-height: 40px;\n}\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\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: 2px;\n}\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}\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\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n}\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\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n\n.input-group-addon {\n  padding: 6px 12px;\n  font-size: 13px;\n  font-weight: normal;\n  line-height: 1;\n  color: #000000;\n  text-align: center;\n  background-color: transparent;\n  border: 1px solid transparent;\n  border-radius: 0;\n}\n\n.input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 2px;\n}\n\n.input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 17px;\n  border-radius: 0px;\n}\n\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\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-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n\n.input-group-addon:first-child {\n  border-right: 0;\n}\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-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.input-group-addon:last-child {\n  border-left: 0;\n}\n\n.input-group-btn {\n  position: relative;\n  font-size: 0;\n  white-space: nowrap;\n}\n\n.input-group-btn > .btn {\n  position: relative;\n}\n\n.input-group-btn > .btn + .btn {\n  margin-left: -1px;\n}\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\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n  margin-right: -1px;\n}\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\n.nav {\n  margin-bottom: 0;\n  padding-left: 0;\n  list-style: none;\n}\n\n.nav > li {\n  position: relative;\n  display: block;\n}\n\n.nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n\n.nav > li > a:hover,\n.nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n\n.nav > li.disabled > a {\n  color: #777777;\n}\n\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n  color: #777777;\n  text-decoration: none;\n  background-color: transparent;\n  cursor: not-allowed;\n}\n\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n  background-color: #eeeeee;\n  border-color: #2196f3;\n}\n\n.nav .nav-divider {\n  height: 1px;\n  margin: 8px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n\n.nav > li > a > img {\n  max-width: none;\n}\n\n.nav-tabs {\n  border-bottom: 1px solid #ffffff;\n}\n\n.nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n\n.nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.42857143;\n  border: 1px solid transparent;\n  border-radius: 2px 2px 0 0;\n}\n\n.nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #ffffff;\n}\n\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n  color: #555555;\n  background-color: transparent;\n  border: 1px solid #ffffff;\n  border-bottom-color: transparent;\n  cursor: default;\n}\n\n.nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n\n.nav-tabs.nav-justified > li {\n  float: none;\n}\n\n.nav-tabs.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n\n  .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n\n.nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 2px;\n}\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 #dddddd;\n}\n\n@media (min-width: 768px) {\n  .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 2px 2px 0 0;\n  }\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: #edecec;\n  }\n}\n\n.nav-pills > li {\n  float: left;\n}\n\n.nav-pills > li > a {\n  border-radius: 2px;\n}\n\n.nav-pills > li + li {\n  margin-left: 2px;\n}\n\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n  color: #ffffff;\n  background-color: #2196f3;\n}\n\n.nav-stacked > li {\n  float: none;\n}\n\n.nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n\n.nav-justified {\n  width: 100%;\n}\n\n.nav-justified > li {\n  float: none;\n}\n\n.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n\n.nav-justified > .dropdown .dropdown-menu {\n  top: auto;\n  left: auto;\n}\n\n@media (min-width: 768px) {\n  .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n\n  .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n\n.nav-tabs-justified {\n  border-bottom: 0;\n}\n\n.nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 2px;\n}\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 #dddddd;\n}\n\n@media (min-width: 768px) {\n  .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 2px 2px 0 0;\n  }\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: #edecec;\n  }\n}\n\n.tab-content > .tab-pane {\n  display: none;\n}\n\n.tab-content > .active {\n  display: block;\n}\n\n.nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.navbar {\n  position: relative;\n  min-height: 50px;\n  margin-bottom: 18px;\n  border: 1px solid transparent;\n}\n\n@media (min-width: 768px) {\n  .navbar {\n    border-radius: 2px;\n  }\n}\n\n@media (min-width: 768px) {\n  .navbar-header {\n    float: left;\n  }\n}\n\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: 15px;\n  padding-left: 15px;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n  -webkit-overflow-scrolling: touch;\n}\n\n.navbar-collapse.in {\n  overflow-y: auto;\n}\n\n@media (min-width: 768px) {\n  .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n  }\n\n  .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n\n  .navbar-collapse.in {\n    overflow-y: visible;\n  }\n\n  .navbar-fixed-top .navbar-collapse,\n  .navbar-static-top .navbar-collapse,\n  .navbar-fixed-bottom .navbar-collapse {\n    padding-left: 0;\n    padding-right: 0;\n  }\n}\n\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n  max-height: 340px;\n}\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\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\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\n.navbar-static-top {\n  z-index: 1000;\n  border-width: 0 0 1px;\n}\n\n@media (min-width: 768px) {\n  .navbar-static-top {\n    border-radius: 0;\n  }\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\n@media (min-width: 768px) {\n  .navbar-fixed-top,\n  .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n\n.navbar-fixed-top {\n  top: 0;\n  border-width: 0 0 1px;\n}\n\n.navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n  border-width: 1px 0 0;\n}\n\n.navbar-brand {\n  float: left;\n  padding: 16px 15px;\n  font-size: 17px;\n  line-height: 18px;\n  height: 50px;\n}\n\n.navbar-brand:hover,\n.navbar-brand:focus {\n  text-decoration: none;\n}\n\n.navbar-brand > img {\n  display: block;\n}\n\n@media (min-width: 768px) {\n  .navbar > .container .navbar-brand,\n  .navbar > .container-fluid .navbar-brand {\n    margin-left: -15px;\n  }\n}\n\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: 15px;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  background-image: none;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n\n.navbar-toggle:focus {\n  outline: 0;\n}\n\n.navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n\n.navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n\n@media (min-width: 768px) {\n  .navbar-toggle {\n    display: none;\n  }\n}\n\n.navbar-nav {\n  margin: 8px -15px;\n}\n\n.navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 18px;\n}\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    box-shadow: none;\n  }\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\n  .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 18px;\n  }\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\n@media (min-width: 768px) {\n  .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n\n  .navbar-nav > li {\n    float: left;\n  }\n\n  .navbar-nav > li > a {\n    padding-top: 16px;\n    padding-bottom: 16px;\n  }\n}\n\n.navbar-form {\n  margin-left: -15px;\n  margin-right: -15px;\n  padding: 10px 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, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  margin-top: 7.5px;\n  margin-bottom: 7.5px;\n}\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\n  .navbar-form .form-control {\n    display: inline-block;\n    width: auto;\n    vertical-align: middle;\n  }\n\n  .navbar-form .form-control-static {\n    display: inline-block;\n  }\n\n  .navbar-form .input-group {\n    display: inline-table;\n    vertical-align: middle;\n  }\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\n  .navbar-form .input-group > .form-control {\n    width: 100%;\n  }\n\n  .navbar-form .control-label {\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\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\n  .navbar-form .radio label,\n  .navbar-form .checkbox label {\n    padding-left: 0;\n  }\n\n  .navbar-form .radio input[type=\"radio\"],\n  .navbar-form .checkbox input[type=\"checkbox\"] {\n    position: relative;\n    margin-left: 0;\n  }\n\n  .navbar-form .has-feedback .form-control-feedback {\n    top: 0;\n  }\n}\n\n@media (max-width: 767px) {\n  .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n\n  .navbar-form .form-group:last-child {\n    margin-bottom: 0;\n  }\n}\n\n@media (min-width: 768px) {\n  .navbar-form {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n}\n\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  border-top-right-radius: 2px;\n  border-top-left-radius: 2px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n\n.navbar-btn {\n  margin-top: 7.5px;\n  margin-bottom: 7.5px;\n}\n\n.navbar-btn.btn-sm {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n\n.navbar-btn.btn-xs {\n  margin-top: 14px;\n  margin-bottom: 14px;\n}\n\n.navbar-text {\n  margin-top: 16px;\n  margin-bottom: 16px;\n}\n\n@media (min-width: 768px) {\n  .navbar-text {\n    float: left;\n    margin-left: 15px;\n    margin-right: 15px;\n  }\n}\n\n@media (min-width: 768px) {\n  .navbar-left {\n    float: left !important;\n  }\n\n  .navbar-right {\n    float: right !important;\n    margin-right: -15px;\n  }\n\n  .navbar-right ~ .navbar-right {\n    margin-right: 0;\n  }\n}\n\n.navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n\n.navbar-default .navbar-brand {\n  color: #777777;\n}\n\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n\n.navbar-default .navbar-text {\n  color: #777777;\n}\n\n.navbar-default .navbar-nav > li > a {\n  color: #777777;\n}\n\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n  color: #333333;\n  background-color: transparent;\n}\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: #555555;\n  background-color: #e7e7e7;\n}\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: #cccccc;\n  background-color: transparent;\n}\n\n.navbar-default .navbar-toggle {\n  border-color: #dddddd;\n}\n\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n  background-color: #dddddd;\n}\n\n.navbar-default .navbar-toggle .icon-bar {\n  background-color: #888888;\n}\n\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\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  background-color: #e7e7e7;\n  color: #555555;\n}\n\n@media (max-width: 767px) {\n  .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777777;\n  }\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: #333333;\n    background-color: transparent;\n  }\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: #555555;\n    background-color: #e7e7e7;\n  }\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: #cccccc;\n    background-color: transparent;\n  }\n}\n\n.navbar-default .navbar-link {\n  color: #777777;\n}\n\n.navbar-default .navbar-link:hover {\n  color: #333333;\n}\n\n.navbar-default .btn-link {\n  color: #777777;\n}\n\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n  color: #333333;\n}\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: #cccccc;\n}\n\n.navbar-inverse {\n  background-color: #222222;\n  border-color: #080808;\n}\n\n.navbar-inverse .navbar-brand {\n  color: #9d9d9d;\n}\n\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n\n.navbar-inverse .navbar-text {\n  color: #9d9d9d;\n}\n\n.navbar-inverse .navbar-nav > li > a {\n  color: #9d9d9d;\n}\n\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\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: #ffffff;\n  background-color: #080808;\n}\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: #444444;\n  background-color: transparent;\n}\n\n.navbar-inverse .navbar-toggle {\n  border-color: #333333;\n}\n\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n  background-color: #333333;\n}\n\n.navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #ffffff;\n}\n\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n  border-color: #101010;\n}\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  background-color: #080808;\n  color: #ffffff;\n}\n\n@media (max-width: 767px) {\n  .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n\n  .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n    background-color: #080808;\n  }\n\n  .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #9d9d9d;\n  }\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: #ffffff;\n    background-color: transparent;\n  }\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: #ffffff;\n    background-color: #080808;\n  }\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: #444444;\n    background-color: transparent;\n  }\n}\n\n.navbar-inverse .navbar-link {\n  color: #9d9d9d;\n}\n\n.navbar-inverse .navbar-link:hover {\n  color: #ffffff;\n}\n\n.navbar-inverse .btn-link {\n  color: #9d9d9d;\n}\n\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n  color: #ffffff;\n}\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: #444444;\n}\n\n.breadcrumb {\n  padding: 8px 20px;\n  margin-bottom: 18px;\n  list-style: none;\n  background-color: transparent;\n  border-radius: 2px;\n}\n\n.breadcrumb > li {\n  display: inline-block;\n}\n\n.breadcrumb > li + li:before {\n  content: \"/\\00a0\";\n  padding: 0 5px;\n  color: #cccccc;\n}\n\n.breadcrumb > .active {\n  color: #7c7c7c;\n}\n\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 18px 0;\n  border-radius: 2px;\n}\n\n.pagination > li {\n  display: inline;\n}\n\n.pagination > li > a,\n.pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  line-height: 1.42857143;\n  text-decoration: none;\n  color: #7e7e7e;\n  background-color: #e2e2e2;\n  border: 1px solid #ffffff;\n  margin-left: -1px;\n}\n\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n  margin-left: 0;\n  border-bottom-left-radius: 2px;\n  border-top-left-radius: 2px;\n}\n\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n  border-bottom-right-radius: 2px;\n  border-top-right-radius: 2px;\n}\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: #333333;\n  background-color: #d7d7d7;\n  border-color: #ffffff;\n}\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: #ffffff;\n  background-color: #00bcd4;\n  border-color: #ffffff;\n  cursor: default;\n}\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: #777777;\n  background-color: #e2e2e2;\n  border-color: #ffffff;\n  cursor: not-allowed;\n}\n\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 17px;\n  line-height: 1.3333333;\n}\n\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n  border-bottom-left-radius: 2px;\n  border-top-left-radius: 2px;\n}\n\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n  border-bottom-right-radius: 2px;\n  border-top-right-radius: 2px;\n}\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\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n  border-bottom-left-radius: 2px;\n  border-top-left-radius: 2px;\n}\n\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n  border-bottom-right-radius: 2px;\n  border-top-right-radius: 2px;\n}\n\n.pager {\n  padding-left: 0;\n  margin: 18px 0;\n  list-style: none;\n  text-align: center;\n}\n\n.pager li {\n  display: inline;\n}\n\n.pager li > a,\n.pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #e2e2e2;\n  border: 1px solid #ffffff;\n  border-radius: 5px;\n}\n\n.pager li > a:hover,\n.pager li > a:focus {\n  text-decoration: none;\n  background-color: #d7d7d7;\n}\n\n.pager .next > a,\n.pager .next > span {\n  float: right;\n}\n\n.pager .previous > a,\n.pager .previous > span {\n  float: left;\n}\n\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n  color: #777777;\n  background-color: #e2e2e2;\n  cursor: not-allowed;\n}\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: #ffffff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\n\na.label:hover,\na.label:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.label:empty {\n  display: none;\n}\n\n.btn .label {\n  position: relative;\n  top: -1px;\n}\n\n.label-default {\n  background-color: #777777;\n}\n\n.label-default[href]:hover,\n.label-default[href]:focus {\n  background-color: #5e5e5e;\n}\n\n.label-primary {\n  background-color: #2196f3;\n}\n\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n  background-color: #0c7cd5;\n}\n\n.label-success {\n  background-color: #4caf50;\n}\n\n.label-success[href]:hover,\n.label-success[href]:focus {\n  background-color: #3d8b40;\n}\n\n.label-info {\n  background-color: #00bcd4;\n}\n\n.label-info[href]:hover,\n.label-info[href]:focus {\n  background-color: #008fa1;\n}\n\n.label-warning {\n  background-color: #ff9800;\n}\n\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n  background-color: #cc7a00;\n}\n\n.label-danger {\n  background-color: #f44336;\n}\n\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n  background-color: #ea1c0d;\n}\n\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: 400;\n  color: #ffffff;\n  line-height: 1;\n  vertical-align: middle;\n  white-space: nowrap;\n  text-align: center;\n  background-color: #2196f3;\n  border-radius: 2px;\n}\n\n.badge:empty {\n  display: none;\n}\n\n.btn .badge {\n  position: relative;\n  top: -1px;\n}\n\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n  top: 0;\n  padding: 1px 5px;\n}\n\na.badge:hover,\na.badge:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n  color: #ffffff;\n  background-color: #2196f3;\n}\n\n.list-group-item > .badge {\n  float: right;\n}\n\n.list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n\n.nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n\n.jumbotron {\n  padding-top: 30px;\n  padding-bottom: 30px;\n  margin-bottom: 30px;\n  color: inherit;\n  background-color: #f7f7f7;\n}\n\n.jumbotron h1,\n.jumbotron .h1 {\n  color: inherit;\n}\n\n.jumbotron p {\n  margin-bottom: 15px;\n  font-size: 20px;\n  font-weight: 200;\n}\n\n.jumbotron > hr {\n  border-top-color: #dedede;\n}\n\n.container .jumbotron,\n.container-fluid .jumbotron {\n  border-radius: 2px;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n\n.jumbotron .container {\n  max-width: 100%;\n}\n\n@media screen and (min-width: 768px) {\n  .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n\n  .container .jumbotron,\n  .container-fluid .jumbotron {\n    padding-left: 60px;\n    padding-right: 60px;\n  }\n\n  .jumbotron h1,\n  .jumbotron .h1 {\n    font-size: 59px;\n  }\n}\n\n.thumbnail {\n  display: block;\n  padding: 3px;\n  margin-bottom: 18px;\n  line-height: 1.42857143;\n  background-color: #ffffff;\n  border: 1px solid #ededed;\n  border-radius: 2px;\n  -webkit-transition: border 0.2s ease-in-out;\n  -o-transition: border 0.2s ease-in-out;\n  transition: border 0.2s ease-in-out;\n}\n\n.thumbnail > img,\n.thumbnail a > img {\n  margin-left: auto;\n  margin-right: auto;\n}\n\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #2196f3;\n}\n\n.thumbnail .caption {\n  padding: 9px;\n  color: #5e5e5e;\n}\n\n.alert {\n  padding: 15px;\n  margin-bottom: 18px;\n  border: 1px solid transparent;\n  border-radius: 2px;\n}\n\n.alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n\n.alert .alert-link {\n  font-weight: bold;\n}\n\n.alert > p,\n.alert > ul {\n  margin-bottom: 0;\n}\n\n.alert > p + p {\n  margin-top: 5px;\n}\n\n.alert-dismissable,\n.alert-dismissible {\n  padding-right: 35px;\n}\n\n.alert-dismissable .close,\n.alert-dismissible .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n\n.alert-success {\n  background-color: rgba(76, 175, 80, 0.7);\n  border-color: transparent;\n  color: #ffffff;\n}\n\n.alert-success hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n\n.alert-success .alert-link {\n  color: #e6e6e6;\n}\n\n.alert-info {\n  background-color: rgba(33, 150, 243, 0.7);\n  border-color: transparent;\n  color: #ffffff;\n}\n\n.alert-info hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n\n.alert-info .alert-link {\n  color: #e6e6e6;\n}\n\n.alert-warning {\n  background-color: rgba(255, 193, 7, 0.7);\n  border-color: transparent;\n  color: #ffffff;\n}\n\n.alert-warning hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n\n.alert-warning .alert-link {\n  color: #e6e6e6;\n}\n\n.alert-danger {\n  background-color: rgba(244, 67, 54, 0.7);\n  border-color: transparent;\n  color: #ffffff;\n}\n\n.alert-danger hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n\n.alert-danger .alert-link {\n  color: #e6e6e6;\n}\n\n@-webkit-keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n\n  to {\n    background-position: 0 0;\n  }\n}\n\n@keyframes progress-bar-stripes {\n  from {\n    background-position: 40px 0;\n  }\n\n  to {\n    background-position: 0 0;\n  }\n}\n\n.progress {\n  overflow: hidden;\n  height: 18px;\n  margin-bottom: 18px;\n  background-color: #f5f5f5;\n  border-radius: 2px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: 12px;\n  line-height: 18px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #2196f3;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  -o-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-size: 40px 40px;\n}\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\n.progress-bar-success {\n  background-color: #4caf50;\n}\n\n.progress-striped .progress-bar-success {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-bar-info {\n  background-color: #00bcd4;\n}\n\n.progress-striped .progress-bar-info {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-bar-warning {\n  background-color: #ff9800;\n}\n\n.progress-striped .progress-bar-warning {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.progress-bar-danger {\n  background-color: #f44336;\n}\n\n.progress-striped .progress-bar-danger {\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n\n.media {\n  margin-top: 15px;\n}\n\n.media:first-child {\n  margin-top: 0;\n}\n\n.media,\n.media-body {\n  zoom: 1;\n  overflow: hidden;\n}\n\n.media-body {\n  width: 10000px;\n}\n\n.media-object {\n  display: block;\n}\n\n.media-object.img-thumbnail {\n  max-width: none;\n}\n\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n\n.media-middle {\n  vertical-align: middle;\n}\n\n.media-bottom {\n  vertical-align: bottom;\n}\n\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n\n.list-group {\n  margin-bottom: 20px;\n  padding-left: 0;\n}\n\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #ffffff;\n  border: 1px solid #e9e9e9;\n}\n\n.list-group-item:first-child {\n  border-top-right-radius: 2px;\n  border-top-left-radius: 2px;\n}\n\n.list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 2px;\n  border-bottom-left-radius: 2px;\n}\n\na.list-group-item,\nbutton.list-group-item {\n  color: #555555;\n}\n\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n  color: #333333;\n}\n\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n  text-decoration: none;\n  color: #555555;\n  background-color: #f5f5f5;\n}\n\nbutton.list-group-item {\n  width: 100%;\n  text-align: left;\n}\n\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n  background-color: #ffffff;\n  color: #b5b4b4;\n  cursor: not-allowed;\n}\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\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: #b5b4b4;\n}\n\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n  z-index: 2;\n  color: #000000;\n  background-color: #f5f5f5;\n  border-color: #e9e9e9;\n}\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\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: #ffffff;\n}\n\n.list-group-item-success {\n  color: #67bd6a;\n  background-color: #67bd6a;\n}\n\na.list-group-item-success,\nbutton.list-group-item-success {\n  color: #67bd6a;\n}\n\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n  color: inherit;\n}\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: #67bd6a;\n  background-color: #55b559;\n}\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: #67bd6a;\n  border-color: #67bd6a;\n}\n\n.list-group-item-info {\n  color: #31708f;\n  background-color: #d9edf7;\n}\n\na.list-group-item-info,\nbutton.list-group-item-info {\n  color: #31708f;\n}\n\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n  color: inherit;\n}\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}\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\n.list-group-item-warning {\n  color: #ffa829;\n  background-color: #ffa829;\n}\n\na.list-group-item-warning,\nbutton.list-group-item-warning {\n  color: #ffa829;\n}\n\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n  color: inherit;\n}\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: #ffa829;\n  background-color: #ff9e0f;\n}\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: #ffa829;\n  border-color: #ffa829;\n}\n\n.list-group-item-danger {\n  color: #f6675d;\n  background-color: #f6675d;\n}\n\na.list-group-item-danger,\nbutton.list-group-item-danger {\n  color: #f6675d;\n}\n\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n  color: inherit;\n}\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: #f6675d;\n  background-color: #f55145;\n}\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: #f6675d;\n  border-color: #f6675d;\n}\n\n.list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n\n.list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n\n.panel {\n  margin-bottom: 18px;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n.panel-body {\n  padding: 15px;\n}\n\n.panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-right-radius: 1px;\n  border-top-left-radius: 1px;\n}\n\n.panel-heading > .dropdown .dropdown-toggle {\n  color: inherit;\n}\n\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 15px;\n  color: inherit;\n}\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\n.panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #dddddd;\n  border-bottom-right-radius: 1px;\n  border-bottom-left-radius: 1px;\n}\n\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n  margin-bottom: 0;\n}\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\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-right-radius: 1px;\n  border-top-left-radius: 1px;\n}\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: 1px;\n  border-bottom-left-radius: 1px;\n}\n\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n\n.panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n  margin-bottom: 0;\n}\n\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n  padding-left: 15px;\n  padding-right: 15px;\n}\n\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n  border-top-right-radius: 1px;\n  border-top-left-radius: 1px;\n}\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: 1px;\n  border-top-right-radius: 1px;\n}\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: 1px;\n}\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: 1px;\n}\n\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n  border-bottom-right-radius: 1px;\n  border-bottom-left-radius: 1px;\n}\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-left-radius: 1px;\n  border-bottom-right-radius: 1px;\n}\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: 1px;\n}\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: 1px;\n}\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 #f0f0f0;\n}\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\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n  border: 0;\n}\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\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\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\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\n.panel > .table-responsive {\n  border: 0;\n  margin-bottom: 0;\n}\n\n.panel-group {\n  margin-bottom: 18px;\n}\n\n.panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 2px;\n}\n\n.panel-group .panel + .panel {\n  margin-top: 5px;\n}\n\n.panel-group .panel-heading {\n  border-bottom: 0;\n}\n\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n  border-top: 1px solid #dddddd;\n}\n\n.panel-group .panel-footer {\n  border-top: 0;\n}\n\n.panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #dddddd;\n}\n\n.panel-default {\n  border-color: #dddddd;\n}\n\n.panel-default > .panel-heading {\n  color: #333333;\n  background-color: #f5f5f5;\n  border-color: #dddddd;\n}\n\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #dddddd;\n}\n\n.panel-default > .panel-heading .badge {\n  color: #f5f5f5;\n  background-color: #333333;\n}\n\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #dddddd;\n}\n\n.panel-primary {\n  border-color: #2196f3;\n}\n\n.panel-primary > .panel-heading {\n  color: #ffffff;\n  background-color: #2196f3;\n  border-color: #2196f3;\n}\n\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #2196f3;\n}\n\n.panel-primary > .panel-heading .badge {\n  color: #2196f3;\n  background-color: #ffffff;\n}\n\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #2196f3;\n}\n\n.panel-success {\n  border-color: #61b555;\n}\n\n.panel-success > .panel-heading {\n  color: #67bd6a;\n  background-color: #67bd6a;\n  border-color: #61b555;\n}\n\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #61b555;\n}\n\n.panel-success > .panel-heading .badge {\n  color: #67bd6a;\n  background-color: #67bd6a;\n}\n\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #61b555;\n}\n\n.panel-info {\n  border-color: #bce8f1;\n}\n\n.panel-info > .panel-heading {\n  color: #31708f;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #bce8f1;\n}\n\n.panel-info > .panel-heading .badge {\n  color: #d9edf7;\n  background-color: #31708f;\n}\n\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #bce8f1;\n}\n\n.panel-warning {\n  border-color: #ff760f;\n}\n\n.panel-warning > .panel-heading {\n  color: #ffa829;\n  background-color: #ffa829;\n  border-color: #ff760f;\n}\n\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #ff760f;\n}\n\n.panel-warning > .panel-heading .badge {\n  color: #ffa829;\n  background-color: #ffa829;\n}\n\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #ff760f;\n}\n\n.panel-danger {\n  border-color: #f54556;\n}\n\n.panel-danger > .panel-heading {\n  color: #f6675d;\n  background-color: #f6675d;\n  border-color: #f54556;\n}\n\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n  border-top-color: #f54556;\n}\n\n.panel-danger > .panel-heading .badge {\n  color: #f6675d;\n  background-color: #f6675d;\n}\n\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n  border-bottom-color: #f54556;\n}\n\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n}\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  left: 0;\n  bottom: 0;\n  height: 100%;\n  width: 100%;\n  border: 0;\n}\n\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\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: 2px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n\n.well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n\n.well-lg {\n  padding: 24px;\n  border-radius: 2px;\n}\n\n.well-sm {\n  padding: 9px;\n  border-radius: 2px;\n}\n\n.close {\n  float: right;\n  font-size: 19.5px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n\n.close:hover,\n.close:focus {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\nbutton.close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n\n.modal-open {\n  overflow: hidden;\n}\n\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1050;\n  -webkit-overflow-scrolling: touch;\n  outline: 0;\n}\n\n.modal.fade .modal-dialog {\n  -webkit-transform: translate(0, -25%);\n  -ms-transform: translate(0, -25%);\n  -o-transform: translate(0, -25%);\n  transform: translate(0, -25%);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -moz-transition: -moz-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\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\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n\n.modal-content {\n  position: relative;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  background-clip: padding-box;\n  outline: 0;\n}\n\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 11;\n  background-color: #000000;\n}\n\n.modal-backdrop.fade {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n\n.modal-backdrop.in {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid transparent;\n}\n\n.modal-header .close {\n  margin-top: -2px;\n}\n\n.modal-title {\n  margin: 0;\n  line-height: transparent;\n}\n\n.modal-body {\n  position: relative;\n  padding: 15px;\n}\n\n.modal-footer {\n  padding: 15px;\n  text-align: right;\n  border-top: 1px solid transparent;\n}\n\n.modal-footer .btn + .btn {\n  margin-left: 5px;\n  margin-bottom: 0;\n}\n\n.modal-footer .btn-group .btn + .btn {\n  margin-left: -1px;\n}\n\n.modal-footer .btn-block + .btn-block {\n  margin-left: 0;\n}\n\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n\n@media (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    margin: 30px auto;\n  }\n\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n  }\n\n  .modal-sm {\n    width: 300px;\n  }\n}\n\n@media (min-width: 992px) {\n  .modal-lg {\n    width: 900px;\n  }\n}\n\n.tooltip {\n  position: absolute;\n  z-index: 1070;\n  display: block;\n  font-family: roboto;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\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  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 12px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n\n.tooltip.in {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.tooltip.top {\n  margin-top: -3px;\n  padding: 5px 0;\n}\n\n.tooltip.right {\n  margin-left: 3px;\n  padding: 0 5px;\n}\n\n.tooltip.bottom {\n  margin-top: 3px;\n  padding: 5px 0;\n}\n\n.tooltip.left {\n  margin-left: -3px;\n  padding: 0 5px;\n}\n\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #737373;\n  border-radius: 2px;\n}\n\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\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: #737373;\n}\n\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  right: 5px;\n  margin-bottom: -5px;\n  border-width: 5px 5px 0;\n  border-top-color: #737373;\n}\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: #737373;\n}\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: #737373;\n}\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: #737373;\n}\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: #737373;\n}\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: #737373;\n}\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: #737373;\n}\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 9;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  font-family: roboto;\n  font-style: normal;\n  font-weight: normal;\n  letter-spacing: normal;\n  line-break: auto;\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  white-space: normal;\n  word-break: normal;\n  word-spacing: normal;\n  word-wrap: normal;\n  font-size: 13px;\n  background-color: #ffffff;\n  background-clip: padding-box;\n  border: 1px solid #ffffff;\n  border-radius: 2px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n\n.popover.top {\n  margin-top: -10px;\n}\n\n.popover.right {\n  margin-left: 10px;\n}\n\n.popover.bottom {\n  margin-top: 10px;\n}\n\n.popover.left {\n  margin-left: -10px;\n}\n\n.popover-title {\n  margin: 0;\n  padding: 8px 14px;\n  font-size: 13px;\n  background-color: #ffffff;\n  border-bottom: 1px solid #f2f2f2;\n  border-radius: 1px 1px 0 0;\n}\n\n.popover-content {\n  padding: 9px 14px;\n}\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\n.popover > .arrow {\n  border-width: 11px;\n}\n\n.popover > .arrow:after {\n  border-width: 10px;\n  content: \"\";\n}\n\n.popover.top > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-width: 0;\n  border-top-color: #cccccc;\n  border-top-color: #ffffff;\n  bottom: -11px;\n}\n\n.popover.top > .arrow:after {\n  content: \" \";\n  bottom: 1px;\n  margin-left: -10px;\n  border-bottom-width: 0;\n  border-top-color: #ffffff;\n}\n\n.popover.right > .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-left-width: 0;\n  border-right-color: #cccccc;\n  border-right-color: #ffffff;\n}\n\n.popover.right > .arrow:after {\n  content: \" \";\n  left: 1px;\n  bottom: -10px;\n  border-left-width: 0;\n  border-right-color: #ffffff;\n}\n\n.popover.bottom > .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #cccccc;\n  border-bottom-color: #ffffff;\n  top: -11px;\n}\n\n.popover.bottom > .arrow:after {\n  content: \" \";\n  top: 1px;\n  margin-left: -10px;\n  border-top-width: 0;\n  border-bottom-color: #ffffff;\n}\n\n.popover.left > .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #cccccc;\n  border-left-color: #ffffff;\n}\n\n.popover.left > .arrow:after {\n  content: \" \";\n  right: 1px;\n  border-right-width: 0;\n  border-left-color: #ffffff;\n  bottom: -10px;\n}\n\n.carousel {\n  position: relative;\n}\n\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n\n.carousel-inner > .item {\n  display: none;\n  position: relative;\n  -webkit-transition: 0.6s ease-in-out left;\n  -o-transition: 0.6s ease-in-out left;\n  transition: 0.6s ease-in-out left;\n}\n\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  line-height: 1;\n}\n\n@media all and (transform-3d), (-webkit-transform-3d) {\n  .carousel-inner > .item {\n    -webkit-transition: -webkit-transform 0.6s ease-in-out;\n    -moz-transition: -moz-transform 0.6s ease-in-out;\n    -o-transition: -o-transform 0.6s ease-in-out;\n    transition: transform 0.6s ease-in-out;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    -webkit-perspective: 1000px;\n    -moz-perspective: 1000px;\n    perspective: 1000px;\n  }\n\n  .carousel-inner > .item.next,\n  .carousel-inner > .item.active.right {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    left: 0;\n  }\n\n  .carousel-inner > .item.prev,\n  .carousel-inner > .item.active.left {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    left: 0;\n  }\n\n  .carousel-inner > .item.next.left,\n  .carousel-inner > .item.prev.right,\n  .carousel-inner > .item.active {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    left: 0;\n  }\n}\n\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  display: block;\n}\n\n.carousel-inner > .active {\n  left: 0;\n}\n\n.carousel-inner > .next,\n.carousel-inner > .prev {\n  position: absolute;\n  top: 0;\n  width: 100%;\n}\n\n.carousel-inner > .next {\n  left: 100%;\n}\n\n.carousel-inner > .prev {\n  left: -100%;\n}\n\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n  left: 0;\n}\n\n.carousel-inner > .active.left {\n  left: -100%;\n}\n\n.carousel-inner > .active.right {\n  left: 100%;\n}\n\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: 15%;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-size: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n  background-color: rgba(0, 0, 0, 0);\n}\n\n.carousel-control.left {\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n\n.carousel-control.right {\n  left: auto;\n  right: 0;\n  background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n\n.carousel-control:hover,\n.carousel-control:focus {\n  outline: 0;\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\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  margin-top: -10px;\n  z-index: 5;\n  display: inline-block;\n}\n\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n  margin-left: -10px;\n}\n\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n  margin-right: -10px;\n}\n\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  line-height: 1;\n  font-family: serif;\n}\n\n.carousel-control .icon-prev:before {\n  content: '\\2039';\n}\n\n.carousel-control .icon-next:before {\n  content: '\\203a';\n}\n\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n}\n\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  border: 1px solid #ffffff;\n  border-radius: 10px;\n  cursor: pointer;\n  background-color: #000 \\9;\n  background-color: rgba(0, 0, 0, 0);\n}\n\n.carousel-indicators .active {\n  margin: 0;\n  width: 12px;\n  height: 12px;\n  background-color: #ffffff;\n}\n\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n\n.carousel-caption .btn {\n  text-shadow: none;\n}\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\n  .carousel-control .glyphicon-chevron-left,\n  .carousel-control .icon-prev {\n    margin-left: -10px;\n  }\n\n  .carousel-control .glyphicon-chevron-right,\n  .carousel-control .icon-next {\n    margin-right: -10px;\n  }\n\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n\n  .carousel-indicators {\n    bottom: 20px;\n  }\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  content: \" \";\n  display: table;\n}\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\n.center-block {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n\n.pull-right {\n  float: right !important;\n}\n\n.pull-left {\n  float: left !important;\n}\n\n.hide {\n  display: none !important;\n}\n\n.show {\n  display: block !important;\n}\n\n.invisible {\n  visibility: hidden;\n}\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\n.hidden {\n  display: none !important;\n}\n\n.affix {\n  position: fixed;\n}\n\n@-ms-viewport {\n  width: device-width;\n}\n\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  display: none !important;\n}\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\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !important;\n  }\n\n  table.visible-xs {\n    display: table !important;\n  }\n\n  tr.visible-xs {\n    display: table-row !important;\n  }\n\n  th.visible-xs,\n  td.visible-xs {\n    display: table-cell !important;\n  }\n}\n\n@media (max-width: 767px) {\n  .visible-xs-block {\n    display: block !important;\n  }\n}\n\n@media (max-width: 767px) {\n  .visible-xs-inline {\n    display: inline !important;\n  }\n}\n\n@media (max-width: 767px) {\n  .visible-xs-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !important;\n  }\n\n  table.visible-sm {\n    display: table !important;\n  }\n\n  tr.visible-sm {\n    display: table-row !important;\n  }\n\n  th.visible-sm,\n  td.visible-sm {\n    display: table-cell !important;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-block {\n    display: block !important;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline {\n    display: inline !important;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !important;\n  }\n\n  table.visible-md {\n    display: table !important;\n  }\n\n  tr.visible-md {\n    display: table-row !important;\n  }\n\n  th.visible-md,\n  td.visible-md {\n    display: table-cell !important;\n  }\n}\n\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-block {\n    display: block !important;\n  }\n}\n\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline {\n    display: inline !important;\n  }\n}\n\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !important;\n  }\n\n  table.visible-lg {\n    display: table !important;\n  }\n\n  tr.visible-lg {\n    display: table-row !important;\n  }\n\n  th.visible-lg,\n  td.visible-lg {\n    display: table-cell !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .visible-lg-block {\n    display: block !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .visible-lg-inline {\n    display: inline !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .visible-lg-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media (max-width: 767px) {\n  .hidden-xs {\n    display: none !important;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm {\n    display: none !important;\n  }\n}\n\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md {\n    display: none !important;\n  }\n}\n\n@media (min-width: 1200px) {\n  .hidden-lg {\n    display: none !important;\n  }\n}\n\n.visible-print {\n  display: none !important;\n}\n\n@media print {\n  .visible-print {\n    display: block !important;\n  }\n\n  table.visible-print {\n    display: table !important;\n  }\n\n  tr.visible-print {\n    display: table-row !important;\n  }\n\n  th.visible-print,\n  td.visible-print {\n    display: table-cell !important;\n  }\n}\n\n.visible-print-block {\n  display: none !important;\n}\n\n@media print {\n  .visible-print-block {\n    display: block !important;\n  }\n}\n\n.visible-print-inline {\n  display: none !important;\n}\n\n@media print {\n  .visible-print-inline {\n    display: inline !important;\n  }\n}\n\n.visible-print-inline-block {\n  display: none !important;\n}\n\n@media print {\n  .visible-print-inline-block {\n    display: inline-block !important;\n  }\n}\n\n@media print {\n  .hidden-print {\n    display: none !important;\n  }\n}\n\n/*\n * LESS Plugins\n */\n\n/*\n * Variable and Mixin\n */\n\n/*\n * Font Icon Family\n */\n\n/*\n * Grid System\n */\n\n/* Typography + Scaffolding + Links */\n\n/* Border Radius */\n\n/* Tabs */\n\n/* Form */\n\n/* Table */\n\n/*\n * Input Group\n */\n\n/*\n * Pagination\n */\n\n/*\n * Popover\n */\n\n/*\n * Dropdown\n */\n\n/*\n * Thumbnail\n */\n\n/*\n * Alerts\n */\n\n/*\n * Form Validations\n */\n\n/*\n * Buttons\n */\n\n/*\n * Thumbnail\n */\n\n/*\n * Carousel\n */\n\n/*\n * Modal\n */\n\n/*\n * Tooltips\n */\n\n/*\n * Popover\n */\n\n/*\n * Breadcrumbs\n */\n\n/*\n * Jumbotron\n */\n\n/*\n * List Groups\n */\n\n/*\n * Badges\n */\n\n/*\n * Material Colors\n */\n\n/* Bootstrap Branding */\n\n/*\n * Colors\n */\n\n/*\n * Blocks\n */\n\n/*\n * Misc\n */\n\n/*\n * Font Face\n */\n\n/*\n * Background Repeat + Position\n */\n\n/*\n * CSS Animations based on animate.css\n */\n\n/*\n * CSS Transform - Scale and Rotate\n */\n\n/*\n * User Select\n */\n\n/*\n * Background Image Cover\n */\n\n/*\n * Tab Focus\n */\n\n/*\n * Pop-in Hover effects\n */\n\n/*\n *  Override Bootstrap Button Mixin\n */\n\n/*\n * Scale 3d\n */\n\n/* \n * Load Font\n */\n\n/*\n * Roboto Light\n */\n\n@font-face {\n  font-family: roboto;\n  src: url('../fonts/roboto/Roboto-Light-webfont.eot');\n  src: url('../fonts/roboto/Roboto-Light-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/roboto/Roboto-Light-webfont.woff') format('woff'), url('../fonts/roboto/Roboto-Light-webfont.ttf') format('truetype'), url('../fonts/roboto/Roboto-Light-webfont.svg#icon') format('svg');\n  font-weight: 300;\n  font-style: normal;\n}\n\n/*\n * Roboto Regular\n */\n\n@font-face {\n  font-family: roboto;\n  src: url('../fonts/roboto/Roboto-Regular-webfont.eot');\n  src: url('../fonts/roboto/Roboto-Regular-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/roboto/Roboto-Regular-webfont.woff') format('woff'), url('../fonts/roboto/Roboto-Regular-webfont.ttf') format('truetype'), url('../fonts/roboto/Roboto-Regular-webfont.svg#icon') format('svg');\n  font-weight: 400;\n  font-style: normal;\n}\n\n/*\n * Roboto Medium\n */\n\n@font-face {\n  font-family: roboto;\n  src: url('../fonts/roboto/Roboto-Medium-webfont.eot');\n  src: url('../fonts/roboto/Roboto-Medium-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/roboto/Roboto-Medium-webfont.woff') format('woff'), url('../fonts/roboto/Roboto-Medium-webfont.ttf') format('truetype'), url('../fonts/roboto/Roboto-Medium-webfont.svg#icon') format('svg');\n  font-weight: 500;\n  font-style: normal;\n}\n\n/*\n * Roboto Bold\n */\n\n@font-face {\n  font-family: roboto;\n  src: url('../fonts/roboto/Roboto-Bold-webfont.eot');\n  src: url('../fonts/roboto/Roboto-Bold-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/roboto/Roboto-Bold-webfont.woff') format('woff'), url('../fonts/roboto/Roboto-Bold-webfont.ttf') format('truetype'), url('../fonts/roboto/Roboto-Bold-webfont.svg#icon') format('svg');\n  font-weight: 700;\n  font-style: normal;\n}\n\n/*\n * Shadow Light\n */\n\n@font-face {\n  font-family: shadowsintolight;\n  src: url('../fonts/shadowsintolight/shadowsintolight-webfont.eot');\n  src: url('../fonts/shadowsintolight/shadowsintolight-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/shadowsintolight/shadowsintolight-webfont.woff') format('woff'), url('../fonts/shadowsintolight/shadowsintolight-webfont.ttf') format('truetype'), url('../fonts/shadowsintolight/shadowsintolight-webfont.svg#icon') format('svg');\n  font-weight: 400;\n  font-style: normal;\n}\n\n/*\n * Vendors\n */\n\n@font-face {\n  font-family: weather-icons;\n  src: url('../fonts/weather-icons/weather-icons.eot');\n  src: url('../fonts/weather-icons/weather-icons.eot?#iefix') format('embedded-opentype'), url('../fonts/weather-icons/weather-icons.woff') format('woff'), url('../fonts/weather-icons/weather-icons.ttf') format('truetype'), url('../fonts/weather-icons/weather-icons.svg#icon') format('svg');\n  font-weight: 400;\n  font-style: normal;\n}\n\n#weather-widget [class*=\"icon-\"] {\n  font-family: 'weather-icons';\n  font-style: normal;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n.icon-0:before {\n  content: \":\";\n}\n\n.icon-1:before {\n  content: \"p\";\n}\n\n.icon-2:before {\n  content: \"S\";\n}\n\n.icon-3:before {\n  content: \"Q\";\n}\n\n.icon-4:before {\n  content: \"S\";\n}\n\n.icon-5:before {\n  content: \"W\";\n}\n\n.icon-6:before {\n  content: \"W\";\n}\n\n.icon-7:before {\n  content: \"W\";\n}\n\n.icon-8:before {\n  content: \"W\";\n}\n\n.icon-9:before {\n  content: \"I\";\n}\n\n.icon-10:before {\n  content: \"W\";\n}\n\n.icon-11:before {\n  content: \"I\";\n}\n\n.icon-12:before {\n  content: \"I\";\n}\n\n.icon-13:before {\n  content: \"I\";\n}\n\n.icon-14:before {\n  content: \"I\";\n}\n\n.icon-15:before {\n  content: \"W\";\n}\n\n.icon-16:before {\n  content: \"I\";\n}\n\n.icon-17:before {\n  content: \"W\";\n}\n\n.icon-18:before {\n  content: \"U\";\n}\n\n.icon-19:before {\n  content: \"Z\";\n}\n\n.icon-20:before {\n  content: \"Z\";\n}\n\n.icon-21:before {\n  content: \"Z\";\n}\n\n.icon-22:before {\n  content: \"Z\";\n}\n\n.icon-23:before {\n  content: \"Z\";\n}\n\n.icon-24:before {\n  content: \"E\";\n}\n\n.icon-25:before {\n  content: \"E\";\n}\n\n.icon-26:before {\n  content: \"3\";\n}\n\n.icon-27:before {\n  content: \"a\";\n}\n\n.icon-28:before {\n  content: \"A\";\n}\n\n.icon-29:before {\n  content: \"a\";\n}\n\n.icon-30:before {\n  content: \"A\";\n}\n\n.icon-31:before {\n  content: \"6\";\n}\n\n.icon-32:before {\n  content: \"1\";\n}\n\n.icon-33:before {\n  content: \"6\";\n}\n\n.icon-34:before {\n  content: \"1\";\n}\n\n.icon-35:before {\n  content: \"W\";\n}\n\n.icon-36:before {\n  content: \"1\";\n}\n\n.icon-37:before {\n  content: \"S\";\n}\n\n.icon-38:before {\n  content: \"S\";\n}\n\n.icon-39:before {\n  content: \"S\";\n}\n\n.icon-40:before {\n  content: \"M\";\n}\n\n.icon-41:before {\n  content: \"W\";\n}\n\n.icon-42:before {\n  content: \"I\";\n}\n\n.icon-43:before {\n  content: \"W\";\n}\n\n.icon-44:before {\n  content: \"a\";\n}\n\n.icon-45:before {\n  content: \"S\";\n}\n\n.icon-46:before {\n  content: \"U\";\n}\n\n.icon-47:before {\n  content: \"S\";\n}\n\n.btn-file {\n  overflow: hidden;\n  position: relative;\n  vertical-align: middle;\n}\n\n.btn-file > input {\n  position: absolute;\n  top: 0;\n  right: 0;\n  margin: 0;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  font-size: 23px;\n  height: 100%;\n  width: 100%;\n  direction: ltr;\n  cursor: pointer;\n}\n\n.fileinput {\n  margin-bottom: 9px;\n  display: inline-block;\n}\n\n.fileinput .form-control {\n  padding-top: 7px;\n  padding-bottom: 5px;\n  display: inline-block;\n  margin-bottom: 0px;\n  vertical-align: middle;\n  cursor: text;\n}\n\n.fileinput .thumbnail {\n  overflow: hidden;\n  display: inline-block;\n  margin-bottom: 5px;\n  vertical-align: middle;\n  text-align: center;\n}\n\n.fileinput .thumbnail > img {\n  max-height: 100%;\n}\n\n.fileinput .btn {\n  vertical-align: middle;\n}\n\n.fileinput-exists .fileinput-new,\n.fileinput-new .fileinput-exists {\n  display: none;\n}\n\n.fileinput-inline .fileinput-controls {\n  display: inline;\n}\n\n.fileinput-filename {\n  vertical-align: middle;\n  display: inline-block;\n  overflow: hidden;\n}\n\n.form-control .fileinput-filename {\n  vertical-align: bottom;\n}\n\n.fileinput.input-group {\n  display: table;\n}\n\n.fileinput.input-group > * {\n  position: relative;\n  z-index: 2;\n}\n\n.fileinput.input-group > .btn-file {\n  z-index: 1;\n}\n\n.fileinput-new.input-group .btn-file,\n.fileinput-new .input-group .btn-file {\n  border-radius: 0 2px 2px 0;\n}\n\n.fileinput-new.input-group .btn-file.btn-xs,\n.fileinput-new .input-group .btn-file.btn-xs,\n.fileinput-new.input-group .btn-file.btn-sm,\n.fileinput-new .input-group .btn-file.btn-sm {\n  border-radius: 0 2px 2px 0;\n}\n\n.fileinput-new.input-group .btn-file.btn-lg,\n.fileinput-new .input-group .btn-file.btn-lg {\n  border-radius: 0 2px 2px 0;\n}\n\n.form-group.has-warning .fileinput .fileinput-preview {\n  color: #ffa829;\n}\n\n.form-group.has-warning .fileinput .thumbnail {\n  border-color: #ff760f;\n}\n\n.form-group.has-error .fileinput .fileinput-preview {\n  color: #f6675d;\n}\n\n.form-group.has-error .fileinput .thumbnail {\n  border-color: #f54556;\n}\n\n.form-group.has-success .fileinput .fileinput-preview {\n  color: #67bd6a;\n}\n\n.form-group.has-success .fileinput .thumbnail {\n  border-color: #61b555;\n}\n\n.input-group-addon:not(:first-child) {\n  border-left: 0;\n}\n\n/*!\n * Waves v0.7.4\n * http://fian.my.id/Waves \n * \n * Copyright 2014 Alfiana E. Sibuea and other contributors \n * Released under the MIT license \n * https://github.com/fians/Waves/blob/master/LICENSE \n */\n\n.waves-effect {\n  position: relative;\n  cursor: pointer;\n  display: inline-block;\n  overflow: hidden;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  -webkit-tap-highlight-color: transparent;\n}\n\n.waves-effect .waves-ripple {\n  position: absolute;\n  border-radius: 50%;\n  width: 100px;\n  height: 100px;\n  margin-top: -50px;\n  margin-left: -50px;\n  opacity: 0;\n  background: rgba(0, 0, 0, 0.2);\n  background: -webkit-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -o-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -moz-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  -webkit-transition: all 0.5s ease-out;\n  -moz-transition: all 0.5s ease-out;\n  -o-transition: all 0.5s ease-out;\n  transition: all 0.5s ease-out;\n  -webkit-transition-property: -webkit-transform, opacity;\n  -moz-transition-property: -moz-transform, opacity;\n  -o-transition-property: -o-transform, opacity;\n  transition-property: transform, opacity;\n  -webkit-transform: scale(0) translate(0, 0);\n  -moz-transform: scale(0) translate(0, 0);\n  -ms-transform: scale(0) translate(0, 0);\n  -o-transform: scale(0) translate(0, 0);\n  transform: scale(0) translate(0, 0);\n  pointer-events: none;\n}\n\n.waves-effect.waves-light .waves-ripple {\n  background: rgba(255, 255, 255, 0.4);\n  background: -webkit-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -o-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -moz-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n}\n\n.waves-effect.waves-classic .waves-ripple {\n  background: rgba(0, 0, 0, 0.2);\n}\n\n.waves-effect.waves-classic.waves-light .waves-ripple {\n  background: rgba(255, 255, 255, 0.4);\n}\n\n.waves-notransition {\n  -webkit-transition: none !important;\n  -moz-transition: none !important;\n  -o-transition: none !important;\n  transition: none !important;\n}\n\n.waves-button,\n.waves-circle {\n  -webkit-transform: translateZ(0);\n  -moz-transform: translateZ(0);\n  -ms-transform: translateZ(0);\n  -o-transform: translateZ(0);\n  transform: translateZ(0);\n  -webkit-mask-image: -webkit-radial-gradient(circle, #ffffff 100%, #000000 100%);\n}\n\n.waves-button,\n.waves-button:hover,\n.waves-button:visited,\n.waves-button-input {\n  white-space: nowrap;\n  vertical-align: middle;\n  cursor: pointer;\n  border: none;\n  outline: none;\n  color: inherit;\n  background-color: rgba(0, 0, 0, 0);\n  font-size: 1em;\n  line-height: 1em;\n  text-align: center;\n  text-decoration: none;\n  z-index: 1;\n}\n\n.waves-button {\n  padding: 0.85em 1.1em;\n  border-radius: 0.2em;\n}\n\n.waves-button-input {\n  margin: 0;\n  padding: 0.85em 1.1em;\n}\n\n.waves-input-wrapper {\n  border-radius: 0.2em;\n  vertical-align: bottom;\n}\n\n.waves-input-wrapper.waves-button {\n  padding: 0;\n}\n\n.waves-input-wrapper .waves-button-input {\n  position: relative;\n  top: 0;\n  left: 0;\n  z-index: 1;\n}\n\n.waves-circle {\n  text-align: center;\n  width: 2.5em;\n  height: 2.5em;\n  line-height: 2.5em;\n  border-radius: 50%;\n}\n\n.waves-float {\n  -webkit-mask-image: none;\n  -webkit-box-shadow: 0px 1px 1.5px 1px rgba(0, 0, 0, 0.12);\n  box-shadow: 0px 1px 1.5px 1px rgba(0, 0, 0, 0.12);\n  -webkit-transition: all 300ms;\n  -moz-transition: all 300ms;\n  -o-transition: all 300ms;\n  transition: all 300ms;\n}\n\n.waves-float:active {\n  -webkit-box-shadow: 0px 8px 20px 1px rgba(0, 0, 0, 0.3);\n  box-shadow: 0px 8px 20px 1px rgba(0, 0, 0, 0.3);\n}\n\n.waves-block {\n  display: block;\n}\n\n/* Firefox Bug: link not triggered */\n\na.waves-effect .waves-ripple {\n  z-index: -1;\n}\n\n/* \n * Load Website related LESS files \n */\n\n/*\n * Generate Margin Class\n * margin, margin-top, margin-bottom, margin-left, margin-right\n */\n\n.m-0 {\n  margin: 0px !important;\n}\n\n.m-t-0 {\n  margin-top: 0px !important;\n}\n\n.m-b-0 {\n  margin-bottom: 0px !important;\n}\n\n.m-l-0 {\n  margin-left: 0px !important;\n}\n\n.m-r-0 {\n  margin-right: 0px !important;\n}\n\n.m-5 {\n  margin: 5px !important;\n}\n\n.m-t-5 {\n  margin-top: 5px !important;\n}\n\n.m-b-5 {\n  margin-bottom: 5px !important;\n}\n\n.m-l-5 {\n  margin-left: 5px !important;\n}\n\n.m-r-5 {\n  margin-right: 5px !important;\n}\n\n.m-10 {\n  margin: 10px !important;\n}\n\n.m-t-10 {\n  margin-top: 10px !important;\n}\n\n.m-b-10 {\n  margin-bottom: 10px !important;\n}\n\n.m-l-10 {\n  margin-left: 10px !important;\n}\n\n.m-r-10 {\n  margin-right: 10px !important;\n}\n\n.m-15 {\n  margin: 15px !important;\n}\n\n.m-t-15 {\n  margin-top: 15px !important;\n}\n\n.m-b-15 {\n  margin-bottom: 15px !important;\n}\n\n.m-l-15 {\n  margin-left: 15px !important;\n}\n\n.m-r-15 {\n  margin-right: 15px !important;\n}\n\n.m-20 {\n  margin: 20px !important;\n}\n\n.m-t-20 {\n  margin-top: 20px !important;\n}\n\n.m-b-20 {\n  margin-bottom: 20px !important;\n}\n\n.m-l-20 {\n  margin-left: 20px !important;\n}\n\n.m-r-20 {\n  margin-right: 20px !important;\n}\n\n.m-25 {\n  margin: 25px !important;\n}\n\n.m-t-25 {\n  margin-top: 25px !important;\n}\n\n.m-b-25 {\n  margin-bottom: 25px !important;\n}\n\n.m-l-25 {\n  margin-left: 25px !important;\n}\n\n.m-r-25 {\n  margin-right: 25px !important;\n}\n\n.m-30 {\n  margin: 30px !important;\n}\n\n.m-t-30 {\n  margin-top: 30px !important;\n}\n\n.m-b-30 {\n  margin-bottom: 30px !important;\n}\n\n.m-l-30 {\n  margin-left: 30px !important;\n}\n\n.m-r-30 {\n  margin-right: 30px !important;\n}\n\n/*\n * Generate Padding Class\n * padding, padding-top, padding-bottom, padding-left, padding-right\n */\n\n.p-0 {\n  padding: 0px !important;\n}\n\n.p-t-0 {\n  padding-top: 0px !important;\n}\n\n.p-b-0 {\n  padding-bottom: 0px !important;\n}\n\n.p-l-0 {\n  padding-left: 0px !important;\n}\n\n.p-r-0 {\n  padding-right: 0px !important;\n}\n\n.p-5 {\n  padding: 5px !important;\n}\n\n.p-t-5 {\n  padding-top: 5px !important;\n}\n\n.p-b-5 {\n  padding-bottom: 5px !important;\n}\n\n.p-l-5 {\n  padding-left: 5px !important;\n}\n\n.p-r-5 {\n  padding-right: 5px !important;\n}\n\n.p-10 {\n  padding: 10px !important;\n}\n\n.p-t-10 {\n  padding-top: 10px !important;\n}\n\n.p-b-10 {\n  padding-bottom: 10px !important;\n}\n\n.p-l-10 {\n  padding-left: 10px !important;\n}\n\n.p-r-10 {\n  padding-right: 10px !important;\n}\n\n.p-15 {\n  padding: 15px !important;\n}\n\n.p-t-15 {\n  padding-top: 15px !important;\n}\n\n.p-b-15 {\n  padding-bottom: 15px !important;\n}\n\n.p-l-15 {\n  padding-left: 15px !important;\n}\n\n.p-r-15 {\n  padding-right: 15px !important;\n}\n\n.p-20 {\n  padding: 20px !important;\n}\n\n.p-t-20 {\n  padding-top: 20px !important;\n}\n\n.p-b-20 {\n  padding-bottom: 20px !important;\n}\n\n.p-l-20 {\n  padding-left: 20px !important;\n}\n\n.p-r-20 {\n  padding-right: 20px !important;\n}\n\n.p-25 {\n  padding: 25px !important;\n}\n\n.p-t-25 {\n  padding-top: 25px !important;\n}\n\n.p-b-25 {\n  padding-bottom: 25px !important;\n}\n\n.p-l-25 {\n  padding-left: 25px !important;\n}\n\n.p-r-25 {\n  padding-right: 25px !important;\n}\n\n.p-30 {\n  padding: 30px !important;\n}\n\n.p-t-30 {\n  padding-top: 30px !important;\n}\n\n.p-b-30 {\n  padding-bottom: 30px !important;\n}\n\n.p-l-30 {\n  padding-left: 30px !important;\n}\n\n.p-r-30 {\n  padding-right: 30px !important;\n}\n\n/*\n * Generate Font-Size Classes (8px - 20px)\n */\n\n.f-8 {\n  font-size: 8px !important;\n}\n\n.f-9 {\n  font-size: 9px !important;\n}\n\n.f-10 {\n  font-size: 10px !important;\n}\n\n.f-11 {\n  font-size: 11px !important;\n}\n\n.f-12 {\n  font-size: 12px !important;\n}\n\n.f-13 {\n  font-size: 13px !important;\n}\n\n.f-14 {\n  font-size: 14px !important;\n}\n\n.f-15 {\n  font-size: 15px !important;\n}\n\n.f-16 {\n  font-size: 16px !important;\n}\n\n.f-17 {\n  font-size: 17px !important;\n}\n\n.f-18 {\n  font-size: 18px !important;\n}\n\n.f-19 {\n  font-size: 19px !important;\n}\n\n.f-20 {\n  font-size: 20px !important;\n}\n\n/*\n * Font Weight\n */\n\n.f-300 {\n  font-weight: 300 !important;\n}\n\n.f-400 {\n  font-weight: 400 !important;\n}\n\n.f-500 {\n  font-weight: 500 !important;\n}\n\n.f-700 {\n  font-weight: 700 !important;\n}\n\n/*\n * Position Classes\n */\n\n.p-relative {\n  position: relative !important;\n}\n\n.p-absolute {\n  position: absolute !important;\n}\n\n.p-fixed {\n  position: fixed !important;\n}\n\n.p-static {\n  position: static !important;\n}\n\n/*\n * Overflow\n */\n\n.o-hidden {\n  overflow: hidden !important;\n}\n\n.o-visible {\n  overflow: visible !important;\n}\n\n.o-auto {\n  overflow: auto !important;\n}\n\n/*\n * Display\n */\n\n.d-block {\n  display: block !important;\n}\n\n.di-block {\n  display: inline-block !important;\n}\n\n/* \n * Material Background Colors\n */\n\n.bgm-white {\n  background-color: #ffffff !important;\n}\n\n.c-white {\n  color: #ffffff !important;\n}\n\n.bgm-black {\n  background-color: #000000 !important;\n}\n\n.c-black {\n  color: #000000 !important;\n}\n\n.bgm-brown {\n  background-color: #795548 !important;\n}\n\n.c-brown {\n  color: #795548 !important;\n}\n\n.bgm-pink {\n  background-color: #e91e63 !important;\n}\n\n.c-pink {\n  color: #e91e63 !important;\n}\n\n.bgm-red {\n  background-color: #f44336 !important;\n}\n\n.c-red {\n  color: #f44336 !important;\n}\n\n.bgm-blue {\n  background-color: #2196f3 !important;\n}\n\n.c-blue {\n  color: #2196f3 !important;\n}\n\n.bgm-purple {\n  background-color: #9c27b0 !important;\n}\n\n.c-purple {\n  color: #9c27b0 !important;\n}\n\n.bgm-deeppurple {\n  background-color: #673ab7 !important;\n}\n\n.c-deeppurple {\n  color: #673ab7 !important;\n}\n\n.bgm-lightblue {\n  background-color: #03a9f4 !important;\n}\n\n.c-lightblue {\n  color: #03a9f4 !important;\n}\n\n.bgm-cyan {\n  background-color: #00bcd4 !important;\n}\n\n.c-cyan {\n  color: #00bcd4 !important;\n}\n\n.bgm-teal {\n  background-color: #009688 !important;\n}\n\n.c-teal {\n  color: #009688 !important;\n}\n\n.bgm-green {\n  background-color: #4caf50 !important;\n}\n\n.c-green {\n  color: #4caf50 !important;\n}\n\n.bgm-lightgreen {\n  background-color: #8bc34a !important;\n}\n\n.c-lightgreen {\n  color: #8bc34a !important;\n}\n\n.bgm-lime {\n  background-color: #cddc39 !important;\n}\n\n.c-lime {\n  color: #cddc39 !important;\n}\n\n.bgm-yellow {\n  background-color: #ffeb3b !important;\n}\n\n.c-yellow {\n  color: #ffeb3b !important;\n}\n\n.bgm-amber {\n  background-color: #ffc107 !important;\n}\n\n.c-amber {\n  color: #ffc107 !important;\n}\n\n.bgm-orange {\n  background-color: #ff9800 !important;\n}\n\n.c-orange {\n  color: #ff9800 !important;\n}\n\n.bgm-deeporange {\n  background-color: #ff5722 !important;\n}\n\n.c-deeporange {\n  color: #ff5722 !important;\n}\n\n.bgm-gray {\n  background-color: #9e9e9e !important;\n}\n\n.c-gray {\n  color: #9e9e9e !important;\n}\n\n.bgm-bluegray {\n  background-color: #607d8b !important;\n}\n\n.c-bluegray {\n  color: #607d8b !important;\n}\n\n.bgm-indigo {\n  background-color: #3f51b5 !important;\n}\n\n.c-indigo {\n  color: #3f51b5 !important;\n}\n\n/*\n * Background Colors\n */\n\n.bg-black-trp {\n  background-color: rgba(0, 0, 0, 0.1) !important;\n}\n\n/*\n * Border\n */\n\n.b-0 {\n  border: 0 !important;\n}\n\n/*\n * width\n */\n\n.w-100 {\n  width: 100% !important;\n}\n\n/*\n * Border Radius \n */\n\n.brd-2 {\n  border-radius: 2px;\n}\n\n/*\n * Media - Overriding the Media object to 3.2 version in order to prevent issues like text overflow.\n */\n\n.media {\n  overflow: visible;\n}\n\n.media:before,\n.media:after {\n  content: \" \";\n  display: table;\n}\n\n.media:after {\n  clear: both;\n}\n\n.media:before,\n.media:after {\n  content: \" \";\n  display: table;\n}\n\n.media:after {\n  clear: both;\n}\n\n.media > .pull-left {\n  padding-right: 15px;\n}\n\n.media > .pull-right {\n  padding-left: 15px;\n}\n\n.media-heading {\n  font-size: 14px;\n  margin-bottom: 10px;\n}\n\n.media-body {\n  zoom: 1;\n  display: block;\n  width: auto;\n}\n\n.media-object {\n  border-radius: 2px;\n}\n\n.close {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-weight: normal;\n  text-shadow: none;\n}\n\n.close:hover {\n  color: inherit;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.dl-horizontal dt {\n  text-align: left;\n}\n\n*,\nbutton,\ninput,\ni,\na {\n  -webkit-font-smoothing: antialiased;\n}\n\n*,\n*:active,\n*:hover {\n  outline: none !important;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n}\n\nhtml {\n  overflow-x: hidden\\0/;\n  -ms-overflow-style: none;\n}\n\nhtml,\nbody {\n  min-height: 100vh;\n}\n\nbody {\n  font-weight: 400;\n  position: relative;\n}\n\naudio,\nvideo {\n  outline: none;\n}\n\np {\n  margin-bottom: 20px;\n}\n\nsmall {\n  font-size: 11px;\n}\n\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small {\n  font-size: 12px;\n}\n\n#main {\n  position: relative;\n  padding-bottom: 110px;\n  padding-top: 65px;\n}\n\n.container.c-alt {\n  max-width: 1170px;\n}\n\n@media (min-width: 768px) and (max-width: 1199px) {\n  #content {\n    padding-left: 15px;\n    padding-right: 15px;\n  }\n}\n\n@media (min-width: 1200px) {\n  body.sw-toggled #content {\n    padding-left: 220px;\n  }\n}\n\n@media (min-width: 1200px) {\n  body.sw-toggled #content > .container {\n    width: calc(100% - 30px);\n  }\n}\n\n.clist {\n  list-style: none;\n}\n\n.clist > li:before {\n  font-family: 'Material-Design-Iconic-Font';\n  margin: 0 10px 0 -20px;\n  vertical-align: middle;\n}\n\n.clist.clist-angle > li:before {\n  content: \"\\f2fb\";\n}\n\n.clist.clist-check > li:before {\n  content: \"\\f26b\";\n}\n\n.clist.clist-star > li:before {\n  content: \"\\f27d\";\n}\n\n/*\n * Common header classes & IDs\n * Do not remove this\n */\n\n.header-inner {\n  list-style: none;\n  padding: 10px 0;\n  margin-bottom: 0;\n  position: relative;\n}\n\n.header-inner > li:not(.pull-right) {\n  float: left;\n}\n\n.header-inner > li:not(:last-child) {\n  margin-right: -2px;\n}\n\n.logo a {\n  color: #fff;\n  text-transform: uppercase;\n  display: block;\n  font-size: 16px;\n}\n\n#menu-trigger {\n  width: 65px;\n  height: 35px;\n  cursor: pointer;\n}\n\n#menu-trigger .line-wrap .line {\n  background-color: #fff;\n}\n\n#menu-trigger:before {\n  content: \"\";\n  position: absolute;\n  top: 13px;\n  left: 7px;\n  width: 45px;\n  height: 45px;\n  border-radius: 50%;\n  background: rgba(255, 255, 255, 0.22);\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  z-index: 0;\n}\n\n#menu-trigger.open:before {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.top-menu {\n  list-style: none;\n  padding: 0;\n}\n\n.top-menu > li {\n  display: inline-block;\n  margin: 0 1px;\n  vertical-align: top;\n  min-width: 50px;\n}\n\n@media (max-width: 767px) {\n  .top-menu > li {\n    position: static !important;\n  }\n}\n\n.top-menu > li .dropdown-menu-lg {\n  padding: 0;\n}\n\n.top-menu > li .dropdown-menu-lg .lv-body {\n  min-height: 295px;\n  overflow-x: hidden;\n}\n\n@media (min-width: 768px) {\n  .top-menu > li:not(#toggle-width) {\n    position: relative;\n  }\n\n  .top-menu > li:not(#toggle-width):before {\n    left: 0;\n    top: 0;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    -webkit-transform: scale3d(0, 0, 0);\n    -moz-transform: scale3d(0, 0, 0);\n    -ms-transform: scale3d(0, 0, 0);\n    -o-transform: scale3d(0, 0, 0);\n    transform: scale3d(0, 0, 0);\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 250ms;\n    transition-duration: 250ms;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    background-color: rgba(0, 0, 0, 0.12);\n    z-index: 0;\n    border-radius: 2px;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n\n  .top-menu > li:not(#toggle-width):hover:before,\n  .top-menu > li:not(#toggle-width).open:before {\n    -webkit-transform: scale3d(1, 1, 1);\n    -moz-transform: scale3d(1, 1, 1);\n    -ms-transform: scale3d(1, 1, 1);\n    -o-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n\n.top-menu > li > a {\n  color: #fff;\n  display: block;\n  text-align: center;\n  z-index: 1;\n  position: relative;\n}\n\n.top-menu > li > a > .tm-icon {\n  font-size: 24px;\n  line-height: 36px;\n}\n\n.top-menu > li > a > .tm-label {\n  line-height: 35px;\n  white-space: nowrap;\n  padding: 0 10px;\n  font-size: 14px;\n  text-transform: uppercase;\n}\n\n.top-menu > li > a > .tmn-counts {\n  position: absolute;\n  font-style: normal;\n  background: #f44336;\n  padding: 1px 5px;\n  border-radius: 2px;\n  right: 7px;\n  top: -3px;\n  font-size: 10px;\n  line-height: 15px;\n}\n\n@media (max-width: 767px) {\n  .top-menu .dropdown-menu-lg {\n    width: calc(100% - 28px) !important;\n  }\n\n  .top-menu .dropdown-menu {\n    right: 14px;\n    top: 55px;\n  }\n}\n\n#notifications {\n  position: relative;\n}\n\n#notifications .lv-body {\n  overflow-x: hidden;\n}\n\n#notifications:before {\n  content: \"\";\n  position: absolute;\n  width: 100%;\n  height: calc(100% - 70px);\n  background: url(../img/notifications.png) no-repeat center;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 400ms;\n  transition-duration: 400ms;\n  -webkit-transform: scale(0) rotate(-180deg);\n  -ms-transform: scale(0) rotate(-180deg);\n  -o-transform: scale(0) rotate(-180deg);\n  transform: scale(0) rotate(-180deg);\n  opacity: 0;\n  filter: alpha(opacity=0);\n  top: 42px;\n}\n\n#notifications.empty:before {\n  -webkit-transform: scale(1) rotate(0deg);\n  -ms-transform: scale(1) rotate(0deg);\n  -o-transform: scale(1) rotate(0deg);\n  transform: scale(1) rotate(0deg);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n/* Full Screen */\n\n:-webkit-full-screen [data-action=\"fullscreen\"] {\n  display: none;\n}\n\n:-moz-full-screen [data-action=\"fullscreen\"] {\n  display: none;\n}\n\n:-ms-fullscreen [data-action=\"fullscreen\"] {\n  display: none;\n}\n\n:full-screen [data-action=\"fullscreen\"] {\n  display: none;\n}\n\n:fullscreen [data-action=\"fullscreen\"] {\n  display: none;\n}\n\n/* ----------------------------- End common header classes and IDs------------------------------------- */\n\n/*\n * For header type 1 only\n * You may remove these if you opt header 2\n */\n\n#header {\n  box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);\n  min-height: 50px;\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  position: fixed;\n  z-index: 11;\n  width: 100%;\n  left: 0;\n  top: 0;\n  padding: 0 11px;\n}\n\n#header:not(.sidebar-toggled).header-up {\n  -webkit-transform: translate3d(0, -70px, 0);\n  transform: translate3d(0, -70px, 0);\n}\n\n#header .logo a {\n  padding: 7px 10px;\n}\n\n#top-search-wrap {\n  position: absolute;\n  top: -65px;\n  left: 0;\n  width: 100%;\n  height: 70px;\n  background: #fff;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  z-index: 10;\n}\n\n#top-search-wrap input[type=\"text\"] {\n  border: 0;\n  height: 40px;\n  padding: 0 10px 0 55px;\n  font-size: 18px;\n  width: 500px;\n  border-radius: 2px;\n  background-color: #efefef;\n  width: 100%;\n}\n\n#top-search-wrap #top-search-close {\n  position: absolute;\n  top: 15px;\n  font-size: 23px;\n  font-style: normal;\n  width: 45px;\n  text-align: center;\n  border-radius: 2px 0px 0px 2px;\n  cursor: pointer;\n  left: 15px;\n  height: 40px;\n  padding-top: 9px;\n}\n\n#top-search-wrap #top-search-close:hover {\n  background-color: #e3e3e3;\n}\n\n@media (max-width: 767px) {\n  #top-search-wrap #top-search-close {\n    right: 7px;\n  }\n}\n\n.tsw-inner {\n  position: relative;\n  padding: 15px;\n  max-width: 700px;\n  display: block;\n  margin: 0 auto;\n}\n\n.search-toggled #top-search-wrap {\n  top: 0;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n/* Full Width Layout */\n\n@media (min-width: 1200px) {\n  #toggle-width .toggle-switch {\n    margin: 9px 30px 0 0;\n  }\n\n  #toggle-width .toggle-switch .ts-helper {\n    height: 11px;\n    width: 33px;\n  }\n\n  #toggle-width .toggle-switch .ts-helper:before {\n    width: 20px;\n    height: 20px;\n    top: -5px;\n  }\n\n  #toggle-width .toggle-switch input:checked + .ts-helper {\n    background: rgba(0, 0, 0, 0.26);\n  }\n\n  #toggle-width .toggle-switch input:checked + .ts-helper:before {\n    left: 18px;\n    background: #fff;\n  }\n}\n\n@media (max-width: 1200px) {\n  #toggle-width {\n    display: none;\n  }\n}\n\n@media (min-width: 1200px) {\n  .sw-toggled #header {\n    padding-left: 15px;\n  }\n\n  .sw-toggled #menu-trigger {\n    display: none;\n  }\n}\n\n/* For Stupid IE9 */\n\n.ie9 #header:not(.sidebar-toggled).header-up {\n  display: none;\n}\n\n/* ----------------------------- End header type 1 ------------------------------------- */\n\n/*\n * For Header type 2 only\n * You may remove these if you opt header 1\n */\n\n#header-2 {\n  box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);\n  position: relative;\n  margin-bottom: -70px;\n  z-index: 10;\n}\n\n@media (min-width: 768px) {\n  #header-2 {\n    padding: 15px 30px 0;\n  }\n\n  #header-2:before {\n    content: \"\";\n    position: absolute;\n    bottom: 0;\n    left: 0;\n    background: rgba(0, 0, 0, 0.04);\n    width: 100%;\n    height: 49px;\n  }\n}\n\n#header-2 .search {\n  margin-bottom: 25px;\n}\n\n@media (max-width: 767px) {\n  #header-2 .search {\n    padding: 0 20px;\n  }\n}\n\n#header-2 .search input[type=\"text\"] {\n  width: 100%;\n  background: transparent;\n  border: 0;\n  border-bottom: 1px solid rgba(255, 255, 255, 0.24);\n  color: #fff;\n  font-size: 15px;\n  font-weight: 300;\n  padding: 6px 0 6px 30px;\n}\n\n#header-2 .search input[type=\"text\"]::-moz-placeholder {\n  color: #ffffff;\n  opacity: 1;\n}\n\n#header-2 .search input[type=\"text\"]:-ms-input-placeholder {\n  color: #ffffff;\n}\n\n#header-2 .search input[type=\"text\"]::-webkit-input-placeholder {\n  color: #ffffff;\n}\n\n#header-2 .search:after {\n  background: #ffeb3b;\n}\n\n#header-2 .search .fg-line {\n  max-width: 500px;\n  position: relative;\n}\n\n#header-2 .search .fg-line:after {\n  background: #ffeb3b;\n}\n\n#header-2 .search .fg-line:before {\n  content: '\\f1c3';\n  font-family: 'Material-Design-Iconic-Font';\n  position: absolute;\n  left: 0;\n  bottom: 1px;\n  color: #fff;\n  font-size: 22px;\n}\n\n.ha-menu > ul {\n  list-style: none;\n  padding: 0;\n  margin: 0;\n}\n\n.ha-menu > ul > li {\n  display: inline-block;\n  vertical-align: top;\n}\n\n@media (max-width: 767px) {\n  .ha-menu > ul > li {\n    display: block;\n  }\n}\n\n.ha-menu > ul > li:not(.active) > *:not(ul) {\n  color: rgba(255, 255, 255, 0.6);\n}\n\n.ha-menu > ul > li.active > *:not(ul) {\n  color: #fff;\n  box-shadow: inset 0px -3px 0 0px #ffeb3b;\n}\n\n@media (max-width: 767px) {\n  .ha-menu > ul > li.active > *:not(ul) {\n    display: block;\n  }\n}\n\n.ha-menu > ul > li > *:not(ul) {\n  text-transform: uppercase;\n  padding: 15px 12px;\n  display: block;\n}\n\n.ha-menu > ul > li.open > *:not(ul),\n.ha-menu > ul > li > *:not(ul):hover {\n  color: #fff;\n}\n\n.ha-menu > ul > li .dropdown-menu {\n  margin-top: -5px;\n  min-width: 100%;\n}\n\n@media (max-width: 767px) {\n  .ha-menu {\n    width: 200px;\n    position: absolute;\n    top: 65px;\n    left: 8px;\n    box-shadow: 0 0 10px;\n    z-index: 10;\n    padding: 0 10px;\n  }\n\n  .ha-menu:not(.toggled) {\n    display: none;\n  }\n}\n\n.sidebar {\n  position: fixed;\n  background: #fff;\n  box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n  height: calc(100% - 50px);\n  top: 50px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  z-index: 10;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  overflow-y: auto;\n}\n\n.sidebar.toggled {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n#sidebar {\n  width: 220px;\n  -webkit-transform: translate3d(-220px, 0, 0);\n  transform: translate3d(-220px, 0, 0);\n}\n\n#sidebar.toggled {\n  -webkit-transform: translate3d(0, 0, 0);\n  transform: translate3d(0, 0, 0);\n}\n\n.profile-menu > a {\n  display: block;\n  height: 96px;\n  margin-bottom: 5px;\n  width: 100%;\n  background: url(../img/profile-menu.png) no-repeat left top;\n  background-size: 100%;\n}\n\n.profile-menu > a .profile-pic {\n  padding: 5px;\n}\n\n.profile-menu > a .profile-pic > img {\n  width: 47px;\n  height: 47px;\n  border-radius: 50%;\n  border: 3px solid rgba(0, 0, 0, 0.14);\n  box-sizing: content-box;\n}\n\n.profile-menu > a .profile-info {\n  background: rgba(0, 0, 0, 0.37);\n  padding: 7px 14px;\n  color: #fff;\n  margin-top: 0px;\n  position: relative;\n}\n\n.profile-menu > a .profile-info > i {\n  font-size: 19px;\n  line-height: 100%;\n  position: absolute;\n  right: 15px;\n  top: 7px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.profile-menu .main-menu {\n  display: none;\n  margin: 0 0 0;\n  border-bottom: 1px solid #E6E6E6;\n}\n\n.profile-menu.toggled .profile-info > i {\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  -o-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n\n.main-menu {\n  list-style: none;\n  padding-left: 0;\n  margin: 20px 0 0 0;\n}\n\n.main-menu > li > a {\n  padding: 14px 20px 14px 52px;\n  display: block;\n  color: #4C4C4C;\n  font-weight: 500;\n  position: relative;\n}\n\n.main-menu > li > a:hover {\n  color: #262626;\n  background-color: #f7f7f7;\n}\n\n.main-menu > li > a > i {\n  position: absolute;\n  left: 16px;\n  font-size: 20px;\n  top: 0;\n  width: 25px;\n  text-align: center;\n  padding: 13px 0;\n}\n\n.main-menu > li.active > a {\n  color: #262626;\n  background-color: #F4F4F4;\n}\n\n.sub-menu > a {\n  position: relative;\n}\n\n.sub-menu > a:before,\n.sub-menu > a:after {\n  position: absolute;\n  top: 12px;\n  color: #575757;\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 17px;\n  right: 15px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n}\n\n.sub-menu > a:before {\n  content: \"\\f278\";\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.sub-menu > a:after {\n  content: \"\\f273\";\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n\n.sub-menu .sub-menu > a:before,\n.sub-menu .sub-menu > a:after {\n  top: 5px;\n}\n\n.sub-menu.toggled > a:before {\n  content: \"\\f278\";\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n\n.sub-menu.toggled > a:after {\n  content: \"\\f273\";\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.sub-menu ul {\n  list-style: none;\n  display: none;\n  padding: 0;\n}\n\n.sub-menu ul > li > a {\n  color: #7f7f7f;\n  padding: 8px 20px 8px 50px;\n  font-weight: 500;\n  display: block;\n}\n\n.sub-menu ul > li > a.active,\n.sub-menu ul > li > a:hover {\n  color: #2196f3;\n}\n\n.sub-menu ul > li:first-child > a {\n  padding-top: 14px;\n}\n\n.sub-menu ul > li:last-child > a {\n  padding-bottom: 16px;\n}\n\n.sub-menu ul > li ul {\n  font-size: 12px;\n  margin: 10px 0;\n  background-color: #f7f7f7;\n}\n\n.sub-menu.active > ul {\n  display: block;\n}\n\n/*\n * layout\n */\n\nbody:not(.sw-toggled) #sidebar {\n  box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n}\n\n@media (min-width: 1200px) {\n  body.sw-toggled #sidebar {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n    opacity: 1;\n    filter: alpha(opacity=100);\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  }\n}\n\n@media (max-width: 1199px) {\n  body.sw-toggled #sidebar {\n    box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n  }\n}\n\n/*\n * For Stupid IE9\n */\n\n@media (min-width: 1200px) {\n  .ie9 body.sw-toggled #sidebar {\n    display: block;\n  }\n}\n\n.ie9 body:not(.sw-toggled) #sidebar:not(.toggled) {\n  display: none;\n}\n\n.dropdown-menu {\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n\n.dropdown-menu > li > a {\n  padding: 8px 17px;\n  -webkit-transition: background-color;\n  -o-transition: background-color;\n  transition: background-color;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.dropdown-menu.dropdown-menu-lg {\n  width: 300px;\n}\n\n.dropdown-menu.dropdown-menu-sm {\n  width: 150px;\n}\n\n.dropdown-menu.dropdown-menu-right {\n  right: 0;\n  left: auto;\n}\n\n.dropdown-menu.dropdown-menu-right > li > a {\n  text-align: right;\n}\n\n.dropdown-menu.dm-icon > li > a > .zmdi {\n  line-height: 100%;\n  vertical-align: top;\n  font-size: 18px;\n  width: 28px;\n}\n\n.dropdown-menu:not([class*=\"bgm-\"]) > li > a {\n  color: #4C4C4C;\n}\n\n.dropdown-menu:not([class*=\"bgm-\"]) > li > a:hover {\n  color: #000;\n}\n\n.dropdown-menu[class*=\"bgm-\"] > li > a {\n  font-weight: 300;\n  color: #fff;\n}\n\n.dropdown:not([data-animation]) .dropdown-menu,\n.btn-group:not([data-animation]) .dropdown-menu {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  opacity: 0;\n  filter: alpha(opacity=0);\n  display: block;\n}\n\n.dropdown .dropdown-menu:not([data-animation]).pull-right,\n.bootstrap-select .dropdown-menu:not([data-animation]).pull-right,\n.btn-group .dropdown-menu:not([data-animation]).pull-right,\n.dropdown .dropdown-menu:not([data-animation]).dropdown-menu-right,\n.bootstrap-select .dropdown-menu:not([data-animation]).dropdown-menu-right,\n.btn-group .dropdown-menu:not([data-animation]).dropdown-menu-right {\n  -webkit-transform-origin: top right;\n  -moz-transform-origin: top right;\n  -ms-transform-origin: top right;\n  transform-origin: top right;\n}\n\n.dropdown .dropdown-menu:not([data-animation]):not(.pull-right):not(.dropdown-menu-right),\n.bootstrap-select .dropdown-menu:not([data-animation]):not(.pull-right):not(.dropdown-menu-right),\n.btn-group .dropdown-menu:not([data-animation]):not(.pull-right):not(.dropdown-menu-right) {\n  -webkit-transform-origin: top left;\n  -moz-transform-origin: top left;\n  -ms-transform-origin: top left;\n  transform-origin: top left;\n}\n\n.dropup .dropdown-menu:not([data-animation]).pull-right,\n.dropup .dropdown-menu:not([data-animation]).dropdown-menu-right {\n  -webkit-transform-origin: bottom right;\n  -moz-transform-origin: bottom right;\n  -ms-transform-origin: bottom right;\n  transform-origin: bottom right;\n}\n\n.dropup .dropdown-menu:not([data-animation]):not(.pull-right):not(.dropdown-menu-right) {\n  -webkit-transform-origin: bottom left;\n  -moz-transform-origin: bottom left;\n  -ms-transform-origin: bottom left;\n  transform-origin: bottom left;\n}\n\n.dropdown.open .dropdown-menu:not([data-animation]),\n.dropup.open .dropdown-menu:not([data-animation]),\n.bootstrap-select.open .dropdown-menu:not([data-animation]),\n.btn-group.open .dropdown-menu:not([data-animation]) {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.dropdown-header {\n  padding: 3px 17px;\n  margin-top: 10px;\n  color: #b1b1b1;\n  text-transform: uppercase;\n  font-weight: normal;\n}\n\n.btn-group.open .dropdown-toggle {\n  box-shadow: none;\n}\n\n.listview {\n  position: relative;\n}\n\n.listview:not(.lv-lg):not(.lv-message) .lv-item {\n  padding: 10px 20px;\n}\n\n@media (min-width: 480px) {\n  .listview.lv-lg .lv-item {\n    padding: 17px 35px 17px 25px;\n  }\n}\n\n@media (max-width: 767px) {\n  .listview.lv-lg .lv-item {\n    padding: 17px 35px 17px 20px;\n  }\n}\n\n.listview.lv-lg .lv-item:hover {\n  background-color: #FFFFDB;\n}\n\n.listview .lv-item {\n  position: relative;\n  display: block;\n  -webkit-transition: background-color;\n  -o-transition: background-color;\n  transition: background-color;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.listview .lv-item .lv-small {\n  font-size: 12px;\n  color: #A9A9A9;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  display: block;\n  width: 100%;\n}\n\n.listview .lv-item .checkbox,\n.listview .lv-item.media {\n  margin: 0;\n}\n\n.listview .lv-item .lv-actions {\n  position: absolute;\n  right: 15px;\n  top: 10px;\n}\n\n@media (max-width: 480px) {\n  .listview .lv-item .lv-actions {\n    right: 7px;\n  }\n}\n\n.listview .lv-title {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  display: block;\n}\n\n.listview a.lv-item:hover {\n  background: #ECF9FF;\n}\n\n.listview [class*=\"lv-img\"] {\n  border-radius: 50%;\n}\n\n.listview .lv-img {\n  width: 48px;\n  height: 48px;\n}\n\n.listview .lv-img-sm {\n  width: 35px;\n  height: 35px;\n}\n\n.listview.lv-bordered .lv-item:not(:last-child) {\n  border-bottom: 1px solid #f0f0f0;\n}\n\n.listview .lv-attrs {\n  list-style: none;\n  padding: 0;\n  margin: 5px 0 0 0;\n}\n\n.listview .lv-attrs > li {\n  display: inline-block;\n  padding: 2px 10px 3px;\n  font-size: 12px;\n  margin-top: 5px;\n  margin-right: 2px;\n}\n\n.listview .lv-attrs > li:not(.info):not(.primary):not(.warning):not(.danger) {\n  border: 1px solid #dedede;\n  background: #ffffff;\n  color: #5e5e5e;\n}\n\n.listview .lv-attrs > li.info {\n  border: 1px solid #00bcd4;\n  background: #00bcd4;\n  color: #ffffff;\n}\n\n.listview .lv-attrs > li.primary {\n  border: 1px solid #2196f3;\n  background: #2196f3;\n  color: #ffffff;\n}\n\n.listview .lv-attrs > li.warning {\n  border: 1px solid #ff9800;\n  background: #ff9800;\n  color: #ffffff;\n}\n\n.listview .lv-attrs > li.danger {\n  border: 1px solid #f44336;\n  background: #f44336;\n  color: #ffffff;\n}\n\n.listview .lv-attrs > li > a {\n  display: block;\n}\n\n.listview:not(.lv-message) .lv-title {\n  color: #000;\n}\n\n[class*=\"lv-img\"] {\n  border-radius: 50%;\n}\n\n.lv-img {\n  width: 48px;\n  height: 48px;\n}\n\n.lv-img-sm {\n  width: 35px;\n  height: 35px;\n}\n\n.lv-header {\n  text-align: center;\n  padding: 15px 10px 13px;\n  line-height: 100%;\n  text-transform: uppercase;\n  border-bottom: 1px solid #F0F0F0;\n  font-weight: 500;\n  color: #4C4C4C;\n  margin-bottom: 10px;\n}\n\n.lv-header .actions {\n  position: absolute;\n  top: 6px;\n  right: 8px;\n  z-index: 10;\n}\n\n.lvh-search {\n  position: absolute;\n  top: 0;\n  left: 0;\n  height: 100%;\n  width: 100%;\n  z-index: 4;\n  background: #fff;\n  display: none;\n}\n\n.lvh-search:before {\n  content: \"\\f1c3\";\n  font-family: 'Material-Design-Iconic-Font';\n  position: absolute;\n  left: 24px;\n  top: 17px;\n  font-size: 22px;\n}\n\n.lvhs-input {\n  border: 0;\n  padding: 0 26px 0 55px;\n  height: 63px;\n  font-size: 18px;\n  width: 100%;\n  font-weight: 100;\n  background: #fff;\n  border-bottom: 1px solid #EEE;\n}\n\n.lvh-search-close {\n  font-style: normal;\n  position: absolute;\n  top: 23px;\n  right: 22px;\n  font-size: 17px;\n  width: 18px;\n  height: 18px;\n  background-color: #ADADAD;\n  line-height: 100%;\n  color: #fff;\n  text-align: center;\n  cursor: pointer;\n  border-radius: 50%;\n}\n\n.lvh-search-close:hover {\n  background: #333;\n}\n\n.lv-header-alt {\n  position: relative;\n  background: #f8f8f8;\n  padding: 15px;\n}\n\n.lv-header-alt .lv-actions {\n  z-index: 3;\n  float: right;\n  margin-top: 3px;\n  position: relative;\n}\n\n.lv-header-alt .lv-actions > li > a {\n  margin: 0 3px;\n}\n\n.lvh-label {\n  color: #818181;\n  display: inline-block;\n  margin: 0;\n  font-size: 14px;\n  font-weight: normal;\n  padding: 0 6px;\n  line-height: 33px;\n  vertical-align: middle;\n  float: left;\n}\n\n.lv-footer {\n  display: block;\n  text-align: center;\n  padding: 7px 10px 8px;\n  border-top: 1px solid #F0F0F0;\n  line-height: 100%;\n  font-size: 11px;\n  margin-top: 20px;\n  color: #828282;\n}\n\na.lv-footer:hover {\n  color: #050505;\n}\n\n/*\n * Inside Card will have more padding\n */\n\n.card-body .lv-item {\n  padding: 12px 20px;\n}\n\n.progress {\n  box-shadow: none;\n  border-radius: 0;\n  height: 5px;\n  margin-bottom: 0;\n}\n\n.progress .progress-bar {\n  box-shadow: none;\n}\n\n#chat {\n  padding: 20px 0;\n  width: 280px;\n  right: -300px;\n}\n\n#chat.toggled {\n  right: 0;\n}\n\n#chat .chat-search {\n  padding: 20px 20px 15px 20px;\n}\n\n#chat .chat-search .form-control {\n  background-image: url(\"../img/icons/search-2.png\");\n  background-repeat: no-repeat;\n  background-position: left center;\n  padding-left: 30px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #chat .chat-search .form-control {\n    background-image: url(\"../img/icons/search-2@2x.png\");\n    background-size: 24px 24px;\n  }\n}\n\n#chat .chat-search .form-control:focus {\n  background-position: right center;\n  padding: 0 30px 0 0;\n}\n\n/*\n * Chat Status Icons\n */\n\n[class*=\"chat-status\"] {\n  position: absolute;\n  width: 10px;\n  height: 10px;\n  border-radius: 50%;\n  top: -3px;\n  right: 12px;\n  border: 2px solid #FFF;\n}\n\n/* Simple Mixin */\n\n.chat-status-online {\n  box-shadow: 0 0 0 1px #1ec01e;\n  background: #1ec01e;\n}\n\n.chat-status-offline {\n  box-shadow: 0 0 0 1px #e73f3f;\n  background: #e73f3f;\n}\n\n.chat-status-busy {\n  box-shadow: 0 0 0 1px #ffa500;\n  background: #ffa500;\n}\n\n/*\n * For Stupid IE9\n */\n\n.ie9 #chat {\n  right: 0;\n}\n\n.ie9 #chat:not(.toggled) {\n  display: none;\n}\n\n.tab-nav {\n  list-style: none;\n  padding: 0;\n  white-space: nowrap;\n  margin: 0;\n  overflow: auto;\n  box-shadow: inset 0 -2px 0 0 #eeeeee;\n  width: 100%;\n}\n\n.tab-nav li {\n  display: inline-block;\n  vertical-align: top;\n}\n\n.tab-nav li > a {\n  display: inline-block;\n  color: #7a7a7a;\n  text-transform: uppercase;\n  position: relative;\n  width: 100%;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  font-weight: 500;\n}\n\n.tab-nav li > a:after {\n  content: \"\";\n  height: 2px;\n  position: absolute;\n  width: 100%;\n  left: 0;\n  bottom: 0;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n\n@media (min-width: 768px) {\n  .tab-nav li > a {\n    padding: 15px;\n  }\n}\n\n@media (max-width: 768px) {\n  .tab-nav li > a {\n    padding: 15px 8px;\n  }\n}\n\n.tab-nav li.active > a {\n  color: #000;\n}\n\n.tab-nav li.active > a:after {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.tab-nav.tab-nav-right {\n  text-align: right;\n}\n\n.tab-nav.tn-justified > li {\n  display: table-cell;\n  width: 1%;\n  text-align: center;\n}\n\n.tab-nav.tn-icon > li .zmdi {\n  font-size: 22px;\n  line-height: 100%;\n  min-height: 25px;\n}\n\n.tab-nav:not([data-tab-color]) > li > a:after {\n  background: #2196f3;\n}\n\n.tab-nav[data-tab-color=\"green\"] > li > a:after {\n  background: #4caf50;\n}\n\n.tab-nav[data-tab-color=\"red\"] > li > a:after {\n  background: #f44336;\n}\n\n.tab-nav[data-tab-color=\"teal\"] > li > a:after {\n  background: #009688;\n}\n\n.tab-nav[data-tab-color=\"amber\"] > li > a:after {\n  background: #ffc107;\n}\n\n.tab-nav[data-tab-color=\"black\"] > li > a:after {\n  background: #000000;\n}\n\n.tab-nav[data-tab-color=\"cyan\"] > li > a:after {\n  background: #00bcd4;\n}\n\n.tab-content {\n  padding: 20px 0;\n}\n\n.card {\n  position: relative;\n  background: #fff;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  margin-bottom: 30px;\n}\n\n.card .card-header {\n  position: relative;\n}\n\n@media screen and (min-width: 768px) {\n  .card .card-header:not(.ch-alt) {\n    padding: 23px 25px;\n  }\n}\n\n@media screen and (max-width: 991px) {\n  .card .card-header:not(.ch-alt) {\n    padding: 18px;\n  }\n}\n\n.card .card-header h2 {\n  margin: 0;\n  line-height: 100%;\n  font-size: 17px;\n  font-weight: 400;\n}\n\n.card .card-header h2 small {\n  display: block;\n  margin-top: 8px;\n  color: #AEAEAE;\n  line-height: 160%;\n}\n\n@media screen and (min-width: 768px) {\n  .card .card-header.ch-alt {\n    padding: 23px 26px;\n  }\n}\n\n@media screen and (max-width: 991px) {\n  .card .card-header.ch-alt {\n    padding: 18px 18px 28px;\n  }\n}\n\n.card .card-header.ch-alt:not([class*=\"bgm-\"]) {\n  background-color: #f7f7f7;\n}\n\n.card .card-header[class*=\"bgm-\"] h2,\n.card .card-header[class*=\"bgm-\"] h2 small {\n  color: #fff;\n}\n\n.card .card-header .actions {\n  position: absolute;\n  right: 10px;\n  z-index: 2;\n  top: 15px;\n}\n\n.card .card-header .btn-float {\n  right: 25px;\n  bottom: -23px;\n  z-index: 1;\n}\n\n@media screen and (min-width: 768px) {\n  .card .card-body.card-padding {\n    padding: 23px 26px;\n  }\n}\n\n@media screen and (max-width: 991px) {\n  .card .card-body.card-padding {\n    padding: 18px;\n  }\n}\n\n.card .card-body.card-padding-sm {\n  padding: 15px;\n}\n\n.card-header:not(.ch-alt):not([class*=\"bgm-\"]) + .card-padding {\n  padding-top: 0;\n}\n\n.chart-edge {\n  margin: 20px -8px 0 -10px;\n  overflow: hidden;\n}\n\n.chart-edge .flot-chart {\n  bottom: -14px;\n}\n\n.charts-row {\n  margin-top: 50px;\n  margin-bottom: 20px;\n}\n\n.mini-charts-item {\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  position: relative;\n  margin-bottom: 30px;\n}\n\n.mini-charts-item .chart {\n  padding: 15px;\n  float: left;\n}\n\n.mini-charts-item .chart.chart-pie {\n  margin: 0 20px;\n}\n\n.mini-charts-item .count {\n  overflow: hidden;\n  color: rgba(255, 255, 255, 0.9);\n  padding: 16px 12px;\n}\n\n.mini-charts-item .count > h2 {\n  margin: 0;\n  line-height: 100%;\n  font-size: 22px;\n  font-weight: 300;\n  color: #fff;\n}\n\n.mini-charts-item .count > small {\n  margin-bottom: 2px;\n  display: block;\n}\n\n.mini-charts-item .count > h2,\n.mini-charts-item .count > small {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n.mini-charts-item > .clearfix,\n.mini-charts-item > .dl-horizontal dd,\n.mini-charts-item > .container,\n.mini-charts-item > .container-fluid,\n.mini-charts-item > .row,\n.mini-charts-item > .form-horizontal .form-group,\n.mini-charts-item > .btn-toolbar,\n.mini-charts-item > .btn-group-vertical > .btn-group,\n.mini-charts-item > .nav,\n.mini-charts-item > .navbar,\n.mini-charts-item > .navbar-header,\n.mini-charts-item > .navbar-collapse,\n.mini-charts-item > .pager,\n.mini-charts-item > .panel-body,\n.mini-charts-item > .modal-header,\n.mini-charts-item > .modal-footer {\n  position: relative;\n  z-index: 1;\n}\n\n.mini-charts-item:before {\n  -webkit-transition: width;\n  -o-transition: width;\n  transition: width;\n  -webkit-transition-duration: 500ms;\n  transition-duration: 500ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  content: \"\";\n  width: 113px;\n  height: 100%;\n  background: rgba(0, 0, 0, 0.1);\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n\n.mini-charts-item:hover .count {\n  color: #fff !important;\n}\n\n.mini-charts-item:hover:before {\n  width: 100%;\n}\n\n/*\n * Sparkline Tooltip\n */\n\n#jqstooltip {\n  min-width: 21px;\n  min-height: 23px;\n  text-align: center;\n  border: 0;\n  background: #fff;\n  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);\n  background-color: #fff;\n}\n\n#jqstooltip .jqsfield {\n  font-size: 12px;\n  font-weight: 700;\n  font-family: inherit;\n  text-align: center;\n  color: #333;\n}\n\n#jqstooltip .jqsfield > span {\n  display: none;\n}\n\n/*\n * Easy Pie Charts\n */\n\n.epc-item {\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  position: relative;\n  margin-bottom: 30px;\n  padding: 30px 20px;\n  text-align: center;\n}\n\n.easy-pie {\n  display: inline-block;\n  position: relative;\n  padding: 0 5px 10px;\n}\n\n.easy-pie .percent {\n  position: absolute;\n  font-weight: 300;\n  width: 100%;\n  line-height: 100%;\n  left: 0;\n}\n\n.easy-pie .percent:after {\n  content: \"%\";\n}\n\n.easy-pie.main-pie .percent {\n  margin-top: 49px;\n  font-size: 50px;\n  text-align: center;\n}\n\n.easy-pie.main-pie .percent:not([class*=\"c-\"]) {\n  color: rgba(255, 255, 255, 0.7);\n}\n\n.easy-pie.main-pie .percent:after {\n  font-size: 30px;\n}\n\n.easy-pie.main-pie .pie-title {\n  color: #fff;\n}\n\n.easy-pie:not(.main-pie) .percent {\n  font-size: 26px;\n  margin-top: 37px;\n}\n\n.easy-pie:not(.main-pie) .percent:after {\n  font-size: 20px;\n}\n\n.easy-pie .pie-title {\n  position: absolute;\n  width: 100%;\n  text-align: center;\n  bottom: -3px;\n  left: 0;\n}\n\n/*\n * Recet Items Table Chart\n */\n\n#recent-items-chart {\n  width: calc(100% + 19px);\n  height: 150px;\n  margin: -20px -10px 0;\n  bottom: -10px;\n}\n\n/*\n * Flot Chart\n */\n\n[class*=\"flot-chart\"] {\n  width: 100%;\n  display: block;\n}\n\n.flot-chart {\n  height: 200px;\n}\n\n.flot-chart-pie {\n  height: 300px;\n}\n\n@media (min-width: 768px) {\n  .flot-chart-pie {\n    margin-bottom: 20px;\n  }\n}\n\n.flot-tooltip,\n#flotTip {\n  position: absolute;\n  color: #333;\n  display: none;\n  font-size: 12px;\n  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1);\n  padding: 3px 10px;\n  background-color: #fff;\n  z-index: 99999;\n}\n\n[class*=\"flc-\"] {\n  text-align: center;\n  margin: 10px 0 5px;\n}\n\n[class*=\"flc-\"] table {\n  display: inline-block;\n}\n\n[class*=\"flc-\"] .legendColorBox > div {\n  border: #fff !important;\n}\n\n[class*=\"flc-\"] .legendColorBox > div > div {\n  border-radius: 50%;\n}\n\n[class*=\"flc-\"] .legendLabel {\n  padding: 0 8px 0 3px;\n}\n\n.dash-widget-item {\n  position: relative;\n  min-height: 380px;\n  margin-bottom: 30px;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n}\n\n.dash-widget-item .dash-widget-header {\n  position: relative;\n}\n\n.dash-widget-item .dash-widget-header .actions {\n  display: none;\n  position: absolute;\n  right: 4px;\n  top: 6px;\n}\n\n.dash-widget-item .dash-widget-footer {\n  position: absolute;\n  left: 0;\n  bottom: 0;\n  width: 100%;\n}\n\n.dash-widget-item .dash-widget-title {\n  padding: 12px 20px;\n  position: absolute;\n  width: 100%;\n  left: 0;\n  font-weight: 300;\n}\n\n.dash-widget-item:hover .dash-widget-header .actions {\n  display: block;\n}\n\n/*\n * Site Visits\n */\n\n#site-visits {\n  color: rgba(255, 255, 255, 0.9);\n}\n\n#site-visits .dash-widget-header {\n  padding-bottom: 38px;\n  background-color: rgba(0, 0, 0, 0.13);\n}\n\n#site-visits .dash-widget-title {\n  bottom: 0;\n  background: rgba(0, 0, 0, 0.15);\n  color: rgba(255, 255, 255, 0.9);\n}\n\n#site-visits h3 {\n  color: rgba(255, 255, 255, 0.9);\n}\n\n/*\n * Best Selling Item\n */\n\n#best-selling {\n  background-color: #fff;\n}\n\n#best-selling .dash-widget-header > img {\n  width: 100%;\n  height: 155px;\n}\n\n#best-selling .dash-widget-header .dash-widget-title {\n  padding-bottom: 30px;\n  top: 0;\n  color: #fff;\n  background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n  background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#99000000', endColorstr='#00000000', GradientType=0);\n}\n\n#best-selling .dash-widget-header .main-item {\n  padding: 15px;\n  color: #fff;\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  width: 100%;\n  background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);\n  background-image: -o-linear-gradient(top, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);\n  background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.6) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#99000000', GradientType=0);\n}\n\n#best-selling .dash-widget-header .main-item > h2 {\n  font-weight: 400;\n  font-size: 20px;\n  margin: 5px 0 0 0;\n  line-height: 100%;\n  color: #fff;\n}\n\n/*\n * Weather\n */\n\n#weather-widget {\n  color: #fff;\n  padding: 20px 20px 0;\n}\n\n#weather-widget .weather-status {\n  font-size: 40px;\n  line-height: 100%;\n}\n\n#weather-widget .weather-icon {\n  text-align: center;\n  margin-top: 10px;\n  height: 150px;\n  background-repeat: no-repeat;\n  background-position: center;\n  /* Weather Icons */\n}\n\n#weather-widget .weather-icon.wi-0 {\n  background-image: url(\"../img/icons/weather/0.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-0 {\n    background-image: url(\"../img/icons/weather/0@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-1 {\n  background-image: url(\"../img/icons/weather/1.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-1 {\n    background-image: url(\"../img/icons/weather/1@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-2 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-2 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-3 {\n  background-image: url(\"../img/icons/weather/3.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-3 {\n    background-image: url(\"../img/icons/weather/3@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-4 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-4 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-5 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-5 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-6 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-6 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-7 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-7 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-8 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-8 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-9 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-9 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-10 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-10 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-11 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-11 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-12 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-12 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-13 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-13 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-14 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-14 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-15 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-15 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-16 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-16 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-17 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-17 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-18 {\n  background-image: url(\"../img/icons/weather/18.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-18 {\n    background-image: url(\"../img/icons/weather/18@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-19 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-19 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-20 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-20 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-21 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-21 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-22 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-22 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-23 {\n  background-image: url(\"../img/icons/weather/19.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-23 {\n    background-image: url(\"../img/icons/weather/19@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-24 {\n  background-image: url(\"../img/icons/weather/24.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-24 {\n    background-image: url(\"../img/icons/weather/24@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-25 {\n  background-image: url(\"../img/icons/weather/24.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-25 {\n    background-image: url(\"../img/icons/weather/24@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-26 {\n  background-image: url(\"../img/icons/weather/26.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-26 {\n    background-image: url(\"../img/icons/weather/26@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-27 {\n  background-image: url(\"../img/icons/weather/27.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-27 {\n    background-image: url(\"../img/icons/weather/27@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-28 {\n  background-image: url(\"../img/icons/weather/28.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-28 {\n    background-image: url(\"../img/icons/weather/28@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-29 {\n  background-image: url(\"../img/icons/weather/27.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-29 {\n    background-image: url(\"../img/icons/weather/27@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-30 {\n  background-image: url(\"../img/icons/weather/28.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-30 {\n    background-image: url(\"../img/icons/weather/28@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-31 {\n  background-image: url(\"../img/icons/weather/31.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-31 {\n    background-image: url(\"../img/icons/weather/31@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-32 {\n  background-image: url(\"../img/icons/weather/32.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-32 {\n    background-image: url(\"../img/icons/weather/32@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-33 {\n  background-image: url(\"../img/icons/weather/31.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-33 {\n    background-image: url(\"../img/icons/weather/31@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-34 {\n  background-image: url(\"../img/icons/weather/32.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-34 {\n    background-image: url(\"../img/icons/weather/32@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-35 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-35 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-36 {\n  background-image: url(\"../img/icons/weather/32.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-36 {\n    background-image: url(\"../img/icons/weather/32@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-37 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-37 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-38 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-38 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-39 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-39 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-40 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-40 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-41 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-41 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-42 {\n  background-image: url(\"../img/icons/weather/9.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-42 {\n    background-image: url(\"../img/icons/weather/9@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-43 {\n  background-image: url(\"../img/icons/weather/5.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-43 {\n    background-image: url(\"../img/icons/weather/5@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-44 {\n  background-image: url(\"../img/icons/weather/27.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-44 {\n    background-image: url(\"../img/icons/weather/27@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-45 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-45 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-46 {\n  background-image: url(\"../img/icons/weather/18.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-46 {\n    background-image: url(\"../img/icons/weather/18@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-icon.wi-47 {\n  background-image: url(\"../img/icons/weather/2.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  #weather-widget .weather-icon.wi-47 {\n    background-image: url(\"../img/icons/weather/2@2x.png\");\n    background-size: 125px 125px;\n  }\n}\n\n#weather-widget .weather-info {\n  list-style: none;\n  padding: 0;\n  margin: 3px 0 0 0;\n}\n\n#weather-widget .weather-info > li {\n  display: inline-block;\n  border: 1px solid rgba(255, 255, 255, 0.39);\n  padding: 2px 10px 3px;\n  margin-right: 5px;\n}\n\n#weather-widget .weather-list {\n  background: rgba(0, 0, 0, 0.08);\n  padding: 5px 12px;\n  font-size: 16px;\n  height: 51px;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n\n#weather-widget .weather-list > span {\n  margin-right: 7px;\n  font-weight: 300;\n  display: inline-block;\n  line-height: 40px;\n  vertical-align: top;\n}\n\n#weather-widget .weather-list > span.weather-list-icon {\n  width: 35px;\n  height: 35px;\n  background-repeat: no-repeat;\n  background-position: center;\n  background-size: 30px 30px;\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-0 {\n  background-image: url('../img/icons/weather/0.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-1 {\n  background-image: url('../img/icons/weather/1.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-2 {\n  background-image: url('../img/icons/weather/2.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-3 {\n  background-image: url('../img/icons/weather/3.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-4 {\n  background-image: url('../img/icons/weather/2.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-5 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-6 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-7 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-8 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-9 {\n  background-image: url('../img/icons/weather/9.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-10 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-11 {\n  background-image: url('../img/icons/weather/9.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-12 {\n  background-image: url('../img/icons/weather/9.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-13 {\n  background-image: url('../img/icons/weather/9.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-14 {\n  background-image: url('../img/icons/weather/9.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-15 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-16 {\n  background-image: url('../img/icons/weather/9.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-17 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-18 {\n  background-image: url('../img/icons/weather/18.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-19 {\n  background-image: url('../img/icons/weather/19.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-20 {\n  background-image: url('../img/icons/weather/19.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-21 {\n  background-image: url('../img/icons/weather/19.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-22 {\n  background-image: url('../img/icons/weather/19.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-23 {\n  background-image: url('../img/icons/weather/19.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-24 {\n  background-image: url('../img/icons/weather/24.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-25 {\n  background-image: url('../img/icons/weather/24.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-26 {\n  background-image: url('../img/icons/weather/26.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-27 {\n  background-image: url('../img/icons/weather/27.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-28 {\n  background-image: url('../img/icons/weather/28.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-29 {\n  background-image: url('../img/icons/weather/27.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-30 {\n  background-image: url('../img/icons/weather/28.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-31 {\n  background-image: url('../img/icons/weather/31.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-32 {\n  background-image: url('../img/icons/weather/32.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-33 {\n  background-image: url('../img/icons/weather/31.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-34 {\n  background-image: url('../img/icons/weather/32.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-35 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-36 {\n  background-image: url('../img/icons/weather/32.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-37 {\n  background-image: url('../img/icons/weather/2.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-38 {\n  background-image: url('../img/icons/weather/2.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-39 {\n  background-image: url('../img/icons/weather/2.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-40 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-41 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-42 {\n  background-image: url('../img/icons/weather/9.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-43 {\n  background-image: url('../img/icons/weather/5.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-44 {\n  background-image: url('../img/icons/weather/27.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-45 {\n  background-image: url('../img/icons/weather/2.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-46 {\n  background-image: url('../img/icons/weather/18.png');\n}\n\n#weather-widget .weather-list > span.weather-list-icon.wi-47 {\n  background-image: url('../img/icons/weather/2.png');\n}\n\n#weather-widget .weather-list > span > i {\n  line-height: 100%;\n  font-size: 39px;\n}\n\n/*\n * Pie Charts\n */\n\n#pie-charts {\n  background: #fff;\n}\n\n#pie-charts .dash-widget-header {\n  color: rgba(255, 255, 255, 0.9);\n}\n\n/*\n * Blog Post\n */\n\n.blog-post .bp-header {\n  position: relative;\n}\n\n.blog-post .bp-header > img {\n  width: 100%;\n}\n\n.blog-post .bp-header .bp-title {\n  background: #3f51b5;\n  width: 100%;\n  padding: 20px;\n  color: #FFF;\n  display: block;\n}\n\n.blog-post .bp-header .bp-title > h2 {\n  color: #FFF;\n  font-weight: 400;\n  margin: 0 0 2px;\n  line-height: 100%;\n  font-size: 21px;\n}\n\n/*\n * Profile View\n */\n\n.profile-view {\n  text-align: center;\n}\n\n.profile-view .pv-header {\n  position: relative;\n  height: 145px;\n  width: 100%;\n  background-image: url('../img/headers/sm/4.png');\n  background-repeat: no-repeat;\n  -webkit-background-size: cover;\n  -moz-background-size: cover;\n  -o-background-size: cover;\n  background-size: cover;\n  background-position: center;\n}\n\n.profile-view .pv-header > .pv-main {\n  border-radius: 50%;\n  width: 130px;\n  position: absolute;\n  height: 130px;\n  bottom: -50px;\n  left: 50%;\n  margin-left: -65px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.profile-view .pv-body {\n  margin-top: 70px;\n  padding: 0 20px 20px;\n}\n\n.profile-view .pv-body > h2 {\n  margin: 0;\n  line-height: 100%;\n  font-size: 20px;\n  font-weight: 400;\n}\n\n.profile-view .pv-body > small {\n  display: block;\n  color: #8E8E8E;\n  margin: 10px 0 15px;\n}\n\n.profile-view .pv-body .pv-contact,\n.profile-view .pv-body .pv-follow {\n  padding: 0;\n  list-style: none;\n}\n\n.profile-view .pv-body .pv-contact > li,\n.profile-view .pv-body .pv-follow > li {\n  display: inline-block;\n}\n\n.profile-view .pv-body .pv-follow {\n  margin: 20px -20px;\n  padding: 10px;\n  background-color: #F7F7F7;\n  border-top: 1px solid #EEE;\n  border-bottom: 1px solid #EEE;\n}\n\n.profile-view .pv-body .pv-follow > li {\n  padding: 0 10px;\n}\n\n.profile-view .pv-body .pv-contact > li {\n  margin: 0 5px;\n}\n\n.profile-view .pv-body .pv-contact > li > .zmdi {\n  line-height: 100%;\n  vertical-align: text-bottom;\n  font-size: 22px;\n}\n\n.profile-view .pv-body .pv-follow-btn {\n  padding: 7px 20px;\n  background: #00bcd4;\n  color: #FFF;\n  border-radius: 3px;\n  text-transform: uppercase;\n  display: block;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.profile-view .pv-body .pv-follow-btn:hover {\n  background: #00a5bb;\n}\n\n.profile-view:hover .pv-main {\n  -webkit-transform: scale(1.2);\n  -ms-transform: scale(1.2);\n  -o-transform: scale(1.2);\n  transform: scale(1.2);\n}\n\n/*\n * Picture List\n */\n\n.picture-list .pl-body {\n  padding: 2px;\n}\n\n.picture-list .pl-body [class*=\"col-\"] {\n  padding: 0;\n  padding: 2px;\n}\n\n.picture-list .pl-body [class*=\"col-\"] > a {\n  display: block;\n}\n\n@media (min-width: 768px) {\n  .picture-list .pl-body [class*=\"col-\"] > a {\n    position: relative;\n  }\n\n  .picture-list .pl-body [class*=\"col-\"] > a:before {\n    left: 0;\n    top: 0;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    -webkit-transform: scale3d(0, 0, 0);\n    -moz-transform: scale3d(0, 0, 0);\n    -ms-transform: scale3d(0, 0, 0);\n    -o-transform: scale3d(0, 0, 0);\n    transform: scale3d(0, 0, 0);\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 250ms;\n    transition-duration: 250ms;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    background-color: rgba(0, 0, 0, 0.3);\n    z-index: 0;\n    border-radius: 0;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n\n  .picture-list .pl-body [class*=\"col-\"] > a:hover:before,\n  .picture-list .pl-body [class*=\"col-\"] > a.open:before {\n    -webkit-transform: scale3d(1, 1, 1);\n    -moz-transform: scale3d(1, 1, 1);\n    -ms-transform: scale3d(1, 1, 1);\n    -o-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n\n.picture-list .pl-body [class*=\"col-\"] > a img {\n  width: 100%;\n}\n\n.picture-list .pl-body:before,\n.picture-list .pl-body:after {\n  content: \" \";\n  display: table;\n}\n\n.picture-list .pl-body:after {\n  clear: both;\n}\n\n.picture-list .pl-body:before,\n.picture-list .pl-body:after {\n  content: \" \";\n  display: table;\n}\n\n.picture-list .pl-body:after {\n  clear: both;\n}\n\n/*\n * Social\n */\n\n.go-social .card-body {\n  padding: 0 15px 20px;\n}\n\n.go-social .card-body [class*=\"col-\"] {\n  padding: 12px;\n}\n\n.go-social .card-body [class*=\"col-\"] img {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n}\n\n.go-social .card-body [class*=\"col-\"]:hover img {\n  -webkit-transform: scale(1.2);\n  -ms-transform: scale(1.2);\n  -o-transform: scale(1.2);\n  transform: scale(1.2);\n}\n\n/*\n * Rating\n */\n\n.rating-list {\n  padding: 0 0 10px;\n}\n\n.rating-list .rl-star {\n  margin-top: 10px;\n  margin-bottom: 4px;\n}\n\n.rating-list .rl-star .zmdi {\n  font-size: 20px;\n}\n\n.rating-list .rl-star .zmdi:not(.active) {\n  color: #ccc;\n}\n\n.rating-list .rl-star .zmdi.active {\n  color: #ff9800;\n}\n\n.rating-list .lv-item .media .zmdi-star {\n  line-height: 100%;\n  font-size: 22px;\n  color: #FF9800;\n  vertical-align: middle;\n  position: relative;\n  top: -2px;\n  left: 6px;\n}\n\n.rating-list .lv-item .media .media-body {\n  padding: 7px 10px 0 5px;\n}\n\n.table {\n  background-color: #ffffff;\n  margin-bottom: 0;\n}\n\n.table > thead > tr > th {\n  background-color: #fff;\n  vertical-align: middle;\n  font-weight: 500;\n  color: #333;\n  border-width: 1px;\n  text-transform: uppercase;\n}\n\n.table [class*=\"bg-\"] > tr > th {\n  color: #fff;\n  border-bottom: 0;\n}\n\n.table [class*=\"bg-\"] + tbody > tr > td {\n  border-top: 0;\n}\n\n.table.table-inner {\n  border: 0;\n}\n\n.table > thead > tr > th:first-child,\n.table > tbody > tr > th:first-child,\n.table > tfoot > tr > th:first-child,\n.table > thead > tr > td:first-child,\n.table > tbody > tr > td:first-child,\n.table > tfoot > tr > td:first-child {\n  padding-left: 30px;\n}\n\n.table > thead > tr > th:last-child,\n.table > tbody > tr > th:last-child,\n.table > tfoot > tr > th:last-child,\n.table > thead > tr > td:last-child,\n.table > tbody > tr > td:last-child,\n.table > tfoot > tr > td:last-child {\n  padding-right: 30px;\n}\n\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > tbody > tr.succes > td,\n.table > tfoot > tr.succes > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td {\n  border: 0;\n}\n\n.table > tbody > tr:last-child > td,\n.table > tfoot > tr:last-child > td {\n  padding-bottom: 20px;\n}\n\n.table-striped td,\n.table-striped th {\n  border: 0 !important;\n}\n\n.table-bordered {\n  border-bottom: 0;\n  border-left: 0;\n  border-right: 0;\n}\n\n.table-bordered > tbody > tr > td,\n.table-bordered > tbody > tr > th {\n  border-bottom: 0;\n  border-left: 0;\n}\n\n.table-bordered > tbody > tr > td:last-child,\n.table-bordered > tbody > tr > th:last-child {\n  border-right: 0;\n}\n\n.table-bordered > thead > tr > th {\n  border-left: 0;\n}\n\n.table-bordered > thead > tr > th:last-child {\n  border-right: 0;\n}\n\n.table-vmiddle td {\n  vertical-align: middle !important;\n}\n\n.table-responsive {\n  border: 0;\n}\n\n#todo-lists {\n  background: #ffc107;\n  color: #fff;\n  margin-bottom: 30px;\n  font-family: 'shadowsintolight', cursive;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n}\n\n.tl-header {\n  position: relative;\n  padding: 25px;\n}\n\n.tl-header > h2 {\n  margin: 0;\n  color: #fff;\n  line-height: 100%;\n}\n\n.tl-header > small {\n  font-size: 17px;\n  display: block;\n  margin-top: 3px;\n}\n\n.tl-header .actions {\n  position: absolute;\n  right: 10px;\n  padding: 0;\n  list-style: none;\n  top: 15px;\n}\n\n.tl-header .actions > li {\n  display: inline-block;\n  vertical-align: baseline;\n}\n\n.tl-body {\n  min-height: 300px;\n  position: relative;\n  padding: 20px 10px 20px 25px;\n  background: rgba(0, 0, 0, 0.03);\n}\n\n.tl-body .media-body {\n  padding-top: 3px;\n  font-size: 18px;\n}\n\n.tl-body .checkbox {\n  margin-bottom: 15px;\n}\n\n.tl-body .checkbox span {\n  display: inline-block;\n  margin-top: -3px;\n}\n\n.tl-body .checkbox input:checked + i + span {\n  text-decoration: line-through;\n}\n\n.tl-body .checkbox .input-helper:before {\n  border-color: rgba(255, 255, 255, 0.8);\n  border-width: 2px;\n}\n\n.tl-body .checkbox .input-helper:after {\n  border-color: #fff;\n}\n\n#add-tl-item {\n  width: 50px;\n  height: 50px;\n  border-radius: 50%;\n  position: absolute;\n  background: #fff;\n  top: -25px;\n  right: 23px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n}\n\n#add-tl-item .add-new-item {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n#add-tl-item .add-tl-body {\n  overflow: hidden;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n#add-tl-item .add-tl-body textarea {\n  padding: 25px 25px 45px;\n  resize: none;\n  width: 100%;\n  font-size: 24px;\n  color: #ffc107;\n  position: absolute;\n  height: 100%;\n  border: 0;\n  outline: none;\n}\n\n#add-tl-item:not(.toggled) {\n  overflow: hidden;\n}\n\n#add-tl-item:not(.toggled) .add-new-item {\n  position: relative;\n  z-index: 1;\n  display: inline-block;\n  width: 50px;\n  height: 50px;\n  background-repeat: no-repeat;\n  background-position: center;\n  cursor: pointer;\n  text-align: center;\n  font-size: 23px;\n  color: #ff9800;\n  line-height: 50px;\n}\n\n#add-tl-item.toggled {\n  width: calc(100% - 47px);\n  height: calc(100% - 25px);\n  border-radius: 2px;\n  top: 0;\n  z-index: 1;\n  box-shadow: 0 5px 8px rgba(0, 0, 0, 0.2);\n  max-height: 300px;\n  overflow: visible;\n}\n\n#add-tl-item.toggled .add-new-item {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  height: 0;\n  overflow: hidden;\n  float: left;\n}\n\n#add-tl-item.toggled .add-tl-body {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n#add-tl-item.toggled .add-tl-body .add-tl-actions {\n  position: absolute;\n  bottom: 0;\n  width: 100%;\n  padding: 5px 10px;\n  border-top: 1px solid #EEE;\n  z-index: 1;\n}\n\n#add-tl-item.toggled .add-tl-body .add-tl-actions > a {\n  font-size: 25px;\n  padding: 0 6px;\n  text-align: center;\n  height: 40px;\n  width: 40px;\n  display: inline-block;\n  line-height: 41px;\n  border-radius: 50%;\n  -webkit-transition: background-color;\n  -o-transition: background-color;\n  transition: background-color;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n#add-tl-item.toggled .add-tl-body .add-tl-actions > a:hover {\n  background-color: #eee;\n}\n\n#add-tl-item.toggled .add-tl-body .add-tl-actions [data-tl-action=\"dismiss\"] {\n  color: #f44336;\n}\n\n#add-tl-item.toggled .add-tl-body .add-tl-actions [data-tl-action=\"save\"] {\n  color: #4caf50;\n}\n\n.btn {\n  border: 0;\n  text-transform: uppercase;\n}\n\n.btn[class*=\"bgm-\"]:not(.bgm-white) {\n  color: #fff;\n}\n\n.btn .caret {\n  margin-top: -3px;\n}\n\n.btn:not(.btn-link) {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n\n.btn-group:not(.bootstrap-select),\n.btn-group-vertical:not(.bootstrap-select) {\n  box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.3);\n}\n\n.btn-group .btn,\n.btn-group-vertical .btn,\n.btn-group .btn:active,\n.btn-group-vertical .btn:active,\n.btn-group .btn:focus,\n.btn-group-vertical .btn:focus,\n.btn-group .btn-group,\n.btn-group-vertical .btn-group {\n  box-shadow: none !important;\n}\n\n.btn-group .btn,\n.btn-group-vertical .btn {\n  margin: 0;\n}\n\n.btn-xs,\n.btn-group-xs > .btn {\n  padding: 2px 5px;\n  font-size: 11px;\n  line-height: 1.5;\n  border-radius: 2px;\n}\n\n.btn-link {\n  color: #797979;\n  text-decoration: none;\n  border-radius: 2px;\n}\n\n.btn-link:hover {\n  color: #0a0a0a;\n}\n\n.btn-link:hover,\n.btn-link:active,\n.btn-link:focus {\n  text-decoration: none;\n}\n\n.btn-inverse {\n  color: #ffffff;\n  background-color: #454545;\n  border-color: transparent;\n}\n\n.btn-inverse:focus,\n.btn-inverse.focus {\n  color: #ffffff;\n  background-color: #2b2b2b;\n  border-color: rgba(0, 0, 0, 0);\n}\n\n.btn-inverse:hover {\n  color: #ffffff;\n  background-color: #2b2b2b;\n  border-color: rgba(0, 0, 0, 0);\n}\n\n.btn-inverse:active,\n.btn-inverse.active,\n.open > .dropdown-toggle.btn-inverse {\n  color: #ffffff;\n  background-color: #2b2b2b;\n  border-color: rgba(0, 0, 0, 0);\n}\n\n.btn-inverse:active:hover,\n.btn-inverse.active:hover,\n.open > .dropdown-toggle.btn-inverse:hover,\n.btn-inverse:active:focus,\n.btn-inverse.active:focus,\n.open > .dropdown-toggle.btn-inverse:focus,\n.btn-inverse:active.focus,\n.btn-inverse.active.focus,\n.open > .dropdown-toggle.btn-inverse.focus {\n  color: #ffffff;\n  background-color: #1a1a1a;\n  border-color: rgba(0, 0, 0, 0);\n}\n\n.btn-inverse:active,\n.btn-inverse.active,\n.open > .dropdown-toggle.btn-inverse {\n  background-image: none;\n}\n\n.btn-inverse.disabled:hover,\n.btn-inverse[disabled]:hover,\nfieldset[disabled] .btn-inverse:hover,\n.btn-inverse.disabled:focus,\n.btn-inverse[disabled]:focus,\nfieldset[disabled] .btn-inverse:focus,\n.btn-inverse.disabled.focus,\n.btn-inverse[disabled].focus,\nfieldset[disabled] .btn-inverse.focus {\n  background-color: #454545;\n  border-color: transparent;\n}\n\n.btn-inverse .badge {\n  color: #454545;\n  background-color: #ffffff;\n}\n\n.btn-inverse:hover,\n.btn-inverse:focus,\n.btn-inverse.focus,\n.btn-inverse:active,\n.open > .dropdown-toggle.btn-inverse {\n  color: #ffffff;\n  background-color: #454545;\n  border-color: transparent;\n}\n\n.btn-inverse:hover:hover,\n.btn-inverse:focus:hover,\n.btn-inverse.focus:hover,\n.btn-inverse:active:hover,\n.open > .dropdown-toggle.btn-inverse:hover,\n.btn-inverse:hover:focus,\n.btn-inverse:focus:focus,\n.btn-inverse.focus:focus,\n.btn-inverse:active:focus,\n.open > .dropdown-toggle.btn-inverse:focus,\n.btn-inverse:hover.focus,\n.btn-inverse:focus.focus,\n.btn-inverse.focus.focus,\n.btn-inverse:active.focus,\n.open > .dropdown-toggle.btn-inverse.focus {\n  color: #ffffff;\n  background-color: #454545;\n  border-color: transparent;\n}\n\n.btn-inverse:active,\n.btn-inverse.active,\n.open > .dropdown-toggle.btn-inverse {\n  background-image: none;\n}\n\n.btn-inverse.disabled,\n.btn-inverse[disabled],\nfieldset[disabled] .btn-inverse,\n.btn-inverse.disabled:hover,\n.btn-inverse[disabled]:hover,\nfieldset[disabled] .btn-inverse:hover,\n.btn-inverse.disabled:focus,\n.btn-inverse[disabled]:focus,\nfieldset[disabled] .btn-inverse:focus,\n.btn-inverse.disabled.focus,\n.btn-inverse[disabled].focus,\nfieldset[disabled] .btn-inverse.focus,\n.btn-inverse.disabled:active,\n.btn-inverse[disabled]:active,\nfieldset[disabled] .btn-inverse:active {\n  background-color: #454545;\n  border-color: transparent;\n}\n\n.btn-inverse .badge {\n  color: #454545;\n  background-color: #ffffff;\n}\n\n.btn-icon {\n  border-radius: 50%;\n  width: 40px;\n  line-height: 42px;\n  height: 40px;\n  padding: 0;\n  text-align: center;\n}\n\n.btn-icon .zmdi {\n  font-size: 17px;\n}\n\n.btn-icon-text > .zmdi {\n  font-size: 15px;\n  vertical-align: top;\n  display: inline-block;\n  margin-top: 2px;\n  line-height: 100%;\n  margin-right: 5px;\n}\n\n.btn-float {\n  width: 50px;\n  height: 50px;\n  border-radius: 50%;\n  line-height: 45px !important;\n}\n\n.btn-float:not(.m-btn) {\n  position: absolute !important;\n}\n\n.btn-float i {\n  font-size: 23px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 500ms;\n  transition-duration: 500ms;\n}\n\n.btn-float:hover i {\n  -webkit-transform: rotate(360deg);\n  -ms-transform: rotate(360deg);\n  -o-transform: rotate(360deg);\n  transform: rotate(360deg);\n}\n\n.btn-float:not(.bgm-white):not(.bgm-gray) > i {\n  color: #fff;\n}\n\n.btn-float:not(.bgm-white):not(.bgm-gray) > i {\n  color: #fff;\n}\n\n.btn-float.bgm-white > i,\n.btn-float.bgm-gray > i {\n  color: #333;\n}\n\n.open .btn {\n  outline: none !important;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n}\n\n.open .btn:focus,\n.open .btn:active {\n  outline: none !important;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n}\n\n/*\n * Material Design Add button\n */\n\n.m-btn {\n  z-index: 1;\n  bottom: 40px;\n  right: 40px;\n  position: fixed !important;\n}\n\nlabel {\n  font-weight: 500;\n}\n\n/*\n * Reset Focus and Active shadows\n */\n\ninput:active,\ninput:focus {\n  outline: 0;\n  box-shadow: none !important;\n}\n\n.form-control {\n  box-shadow: none !important;\n  resize: none;\n}\n\n.form-control:active,\n.form-control:focus {\n  box-shadow: none;\n}\n\n.form-control:not(.fc-alt) {\n  border-left: 0;\n  border-right: 0;\n  border-top: 0;\n  -webkit-appearance: none;\n  -moz-appearance: none;\n  appearance: none;\n  padding: 0;\n}\n\n.form-control:not(.fc-alt).auto-size {\n  padding-top: 6px;\n}\n\n/*\n * Checkbox and Radio\n */\n\n.checkbox label,\n.radio label {\n  padding-left: 30px;\n  position: relative;\n}\n\n.checkbox input,\n.radio input {\n  top: 0;\n  left: 0;\n  margin-left: 0 !important;\n  z-index: 1;\n  cursor: pointer;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  margin-top: 0;\n}\n\n.checkbox .input-helper:before,\n.radio .input-helper:before,\n.checkbox .input-helper:after,\n.radio .input-helper:after {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  position: absolute;\n  content: \"\";\n}\n\n.checkbox .input-helper:before,\n.radio .input-helper:before {\n  left: 0;\n  border: 1px solid #ccc;\n}\n\n.checkbox.disabled,\n.radio.disabled {\n  opacity: 0.6;\n  filter: alpha(opacity=60);\n}\n\n.checkbox input {\n  width: 17px;\n  height: 17px;\n}\n\n.checkbox input:checked + .input-helper:before {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n\n.checkbox input:checked + .input-helper:after {\n  -webkit-transform: scale(1) rotate(-50deg);\n  -ms-transform: scale(1) rotate(-50deg);\n  -o-transform: scale(1) rotate(-50deg);\n  transform: scale(1) rotate(-50deg);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.checkbox .input-helper:before {\n  top: 0;\n  width: 17px;\n  height: 17px;\n}\n\n.checkbox .input-helper:after {\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transform: scale(0) rotate(80deg);\n  -ms-transform: scale(0) rotate(80deg);\n  -o-transform: scale(0) rotate(80deg);\n  transform: scale(0) rotate(80deg);\n  width: 22px;\n  height: 9px;\n  border-bottom: 2px solid #009688;\n  border-left: 2px solid #009688;\n  border-bottom-left-radius: 2px;\n  left: -1px;\n  top: 1px;\n}\n\n.radio input {\n  width: 19px;\n  height: 19px;\n}\n\n.radio input:checked + .input-helper:after {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.radio .input-helper:before {\n  top: -1px;\n  width: 19px;\n  height: 19px;\n  border-radius: 50%;\n}\n\n.radio .input-helper:after {\n  width: 11px;\n  height: 11px;\n  background: #009688;\n  border-radius: 50%;\n  top: 3px;\n  left: 4px;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n\n.checkbox-inline,\n.radio-inline {\n  vertical-align: top;\n  margin-top: 0;\n  padding-left: 25px;\n}\n\n/*\n * Select\n */\n\nhtml:not(.ie9) .select {\n  position: relative;\n}\n\nhtml:not(.ie9) .select:before {\n  position: absolute;\n  top: -1px;\n  content: \"\";\n  height: calc(100% - 1px);\n  width: 30px;\n  background-color: #FFF;\n  background-position: right calc(100% - 7px);\n  background-repeat: no-repeat;\n  background-image: url(\"../img/select.png\");\n  pointer-events: none;\n  z-index: 5;\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  html:not(.ie9) .select:before {\n    background-image: url(\"../img/select@2x.png\");\n    background-size: 12px 12px;\n  }\n}\n\nhtml:not(.ie9) .select:not(.fg-line):before {\n  right: 0;\n}\n\nhtml:not(.ie9) .select.fg-line:before {\n  right: 10px;\n}\n\n/*\n * Input Group Addon\n */\n\n.input-group:not(.input-group-lg):not(.input-group-sm) .input-group-addon {\n  font-size: 15px;\n}\n\n.input-group-addon {\n  border-width: 0px 0px 1px 0px;\n  min-width: 42px;\n}\n\n.input-group-addon > .zmdi {\n  position: relative;\n  top: 3px;\n}\n\n/*\n * Input Feilds\n */\n\n.fg-line {\n  position: relative;\n  vertical-align: top;\n}\n\n.fg-line:not(.form-group) {\n  display: inline-block;\n  width: 100%;\n}\n\n.fg-line .form-control:disabled {\n  color: #9d9d9d;\n  background: transparent;\n}\n\n.fg-line:not(.disabled):after,\n.fg-line:not(.readonly):after {\n  position: absolute;\n  z-index: 3;\n  bottom: 0;\n  left: 0;\n  height: 2px;\n  width: 0;\n  content: \"\";\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.fg-line:not([class*=has-]):after {\n  background: #2196f3;\n}\n\n.fg-line.readonly .form-control {\n  color: #9d9d9d;\n  background: transparent;\n}\n\n.fg-line.fg-toggled:after {\n  width: 100%;\n}\n\n.fg-float {\n  margin-top: 2px;\n  position: relative;\n}\n\n.fg-float .form-control {\n  position: relative;\n  background: transparent;\n  z-index: 1;\n}\n\n.fg-float .form-control::-moz-placeholder {\n  color: #ffffff;\n  opacity: 1;\n}\n\n.fg-float .form-control:-ms-input-placeholder {\n  color: #ffffff;\n}\n\n.fg-float .form-control::-webkit-input-placeholder {\n  color: #ffffff;\n}\n\n.fg-float .fg-label {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  position: absolute;\n  top: 5px;\n  font-weight: 400;\n  color: #959595;\n  pointer-events: none;\n  z-index: 0;\n  left: 0;\n  white-space: nowrap;\n}\n\n.fg-float .fg-toggled .fg-label {\n  top: -20px;\n  font-size: 11px;\n}\n\n.control-label {\n  font-weight: normal;\n}\n\n/*\n * Toggle Switch\n */\n\n.toggle-switch {\n  display: inline-block;\n  vertical-align: top;\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n}\n\n.toggle-switch .ts-label {\n  display: inline-block;\n  margin: 0 20px 0 0;\n  vertical-align: top;\n  -webkit-transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1);\n  transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.toggle-switch .ts-helper {\n  display: inline-block;\n  position: relative;\n  width: 40px;\n  height: 16px;\n  border-radius: 8px;\n  background: rgba(0, 0, 0, 0.26);\n  -webkit-transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n  transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n  vertical-align: middle;\n  cursor: pointer;\n}\n\n.toggle-switch .ts-helper:before {\n  content: '';\n  position: absolute;\n  top: -4px;\n  left: -4px;\n  width: 24px;\n  height: 24px;\n  background: #fafafa;\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);\n  border-radius: 50%;\n  webkit-transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n  transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.toggle-switch:not(.disabled) .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(128, 128, 128, 0.1);\n}\n\n.toggle-switch input {\n  position: absolute;\n  z-index: 1;\n  width: 46px;\n  margin: 0 0 0 -4px;\n  height: 24px;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  cursor: pointer;\n}\n\n.toggle-switch input:checked + .ts-helper:before {\n  left: 20px;\n}\n\n.toggle-switch:not([data-ts-color]) input:not(:disabled):checked + .ts-helper {\n  background: rgba(0, 150, 136, 0.5);\n}\n\n.toggle-switch:not([data-ts-color]) input:not(:disabled):checked + .ts-helper:before {\n  background: #009688;\n}\n\n.toggle-switch:not([data-ts-color]) input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(0, 150, 136, 0.2);\n}\n\n.toggle-switch.disabled {\n  opacity: 0.6;\n  filter: alpha(opacity=60);\n}\n\n.toggle-switch[data-ts-color=\"red\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(244, 67, 54, 0.5);\n}\n\n.toggle-switch[data-ts-color=\"red\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #f44336;\n}\n\n.toggle-switch[data-ts-color=\"red\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(244, 67, 54, 0.2);\n}\n\n.toggle-switch[data-ts-color=\"blue\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(33, 150, 243, 0.5);\n}\n\n.toggle-switch[data-ts-color=\"blue\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #2196f3;\n}\n\n.toggle-switch[data-ts-color=\"blue\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(33, 150, 243, 0.2);\n}\n\n.toggle-switch[data-ts-color=\"amber\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(255, 193, 7, 0.5);\n}\n\n.toggle-switch[data-ts-color=\"amber\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #ffc107;\n}\n\n.toggle-switch[data-ts-color=\"amber\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(255, 193, 7, 0.2);\n}\n\n.toggle-switch[data-ts-color=\"purple\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(156, 39, 176, 0.5);\n}\n\n.toggle-switch[data-ts-color=\"purple\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #9c27b0;\n}\n\n.toggle-switch[data-ts-color=\"purple\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(156, 39, 176, 0.2);\n}\n\n.toggle-switch[data-ts-color=\"pink\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(233, 30, 99, 0.5);\n}\n\n.toggle-switch[data-ts-color=\"pink\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #e91e63;\n}\n\n.toggle-switch[data-ts-color=\"pink\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(233, 30, 99, 0.2);\n}\n\n.toggle-switch[data-ts-color=\"lime\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(205, 220, 57, 0.5);\n}\n\n.toggle-switch[data-ts-color=\"lime\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #cddc39;\n}\n\n.toggle-switch[data-ts-color=\"lime\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(205, 220, 57, 0.2);\n}\n\n.toggle-switch[data-ts-color=\"cyan\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(0, 188, 212, 0.5);\n}\n\n.toggle-switch[data-ts-color=\"cyan\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #00bcd4;\n}\n\n.toggle-switch[data-ts-color=\"cyan\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(0, 188, 212, 0.2);\n}\n\n.toggle-switch[data-ts-color=\"green\"] input:not(:disabled):checked + .ts-helper {\n  background: rgba(76, 175, 80, 0.5);\n}\n\n.toggle-switch[data-ts-color=\"green\"] input:not(:disabled):checked + .ts-helper:before {\n  background: #4caf50;\n}\n\n.toggle-switch[data-ts-color=\"green\"] input:not(:disabled):checked + .ts-helper:active:before {\n  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28), 0 0 0 20px rgba(76, 175, 80, 0.2);\n}\n\n/*\n * IE 9 Placeholder\n */\n\n.ie9-placeholder {\n  color: #888 !important;\n  font-weight: normal;\n}\n\n/*\n * Validation\n */\n\n.has-error .checkbox .input-helper:before {\n  border-color: #f99d97;\n}\n\n.has-error .checkbox .input-helper:after {\n  border-bottom-color: #f77066;\n  border-left-color: #f77066;\n}\n\n.has-error .fg-line:after {\n  background: #f44336;\n}\n\n.has-success .checkbox .input-helper:before {\n  border-color: #92cf94;\n}\n\n.has-success .checkbox .input-helper:after {\n  border-bottom-color: #6ec071;\n  border-left-color: #6ec071;\n}\n\n.has-success .fg-line:after {\n  background: #4caf50;\n}\n\n.has-warning .checkbox .input-helper:before {\n  border-color: #ffc166;\n}\n\n.has-warning .checkbox .input-helper:after {\n  border-bottom-color: #ffad33;\n  border-left-color: #ffad33;\n}\n\n.has-warning .fg-line:after {\n  background: #ff9800;\n}\n\n.pagination {\n  border-radius: 0;\n}\n\n.pagination > li {\n  margin: 0 2px;\n  display: inline-block;\n  vertical-align: top;\n}\n\n.pagination > li > a,\n.pagination > li > span {\n  border-radius: 50% !important;\n  padding: 0;\n  width: 40px;\n  height: 40px;\n  line-height: 38px;\n  text-align: center;\n  font-size: 14px;\n  z-index: 1;\n  position: relative;\n  cursor: pointer;\n}\n\n.pagination > li > a > .zmdi,\n.pagination > li > span > .zmdi {\n  font-size: 22px;\n  line-height: 39px;\n}\n\n.pagination > li.disabled {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n\n/*\n * Listview Pagination\n */\n\n.lv-pagination {\n  width: 100%;\n  text-align: center;\n  padding: 40px 0;\n  border-top: 1px solid #F0F0F0;\n  margin-top: 0;\n  margin-bottom: 0;\n}\n\n/*\n * Pager\n */\n\n.pager li > a,\n.pager li > span {\n  padding: 5px 10px 6px;\n  color: #7e7e7e;\n}\n\n.popover {\n  box-shadow: 0 2px 30px rgba(0, 0, 0, 0.2);\n}\n\n.popover-title {\n  border-bottom: 0;\n  padding: 15px;\n  font-size: 12px;\n  text-transform: uppercase;\n}\n\n.popover-title + .popover-content {\n  padding-top: 0;\n}\n\n.popover-content {\n  padding: 15px;\n}\n\n.popover-content p {\n  margin-bottom: 0;\n}\n\n.fw-container .tab-content {\n  padding: 25px 0;\n}\n\n.fw-container .fw-footer {\n  text-align: center;\n  margin: 30px 0 0;\n  width: 100%;\n  border-top: 2px solid #eee;\n  padding: 15px 0;\n}\n\n.alert {\n  padding-left: 30px;\n  font-size: 13px;\n}\n\n.alert span {\n  cursor: pointer;\n}\n\n.alert:not(.alert-dismissible) {\n  padding-right: 30px;\n}\n\n.alert.alert-dismissable {\n  padding-right: 44px;\n}\n\n.alert-inverse {\n  background-color: #333333;\n  border-color: transparent;\n  color: #ffffff;\n}\n\n.alert-inverse hr {\n  border-top-color: rgba(0, 0, 0, 0);\n}\n\n.alert-inverse .alert-link {\n  color: #e6e6e6;\n}\n\n.growl-animated.alert-inverse {\n  box-shadow: 0 0 5px rgba(51, 51, 51, 0.5);\n}\n\n.growl-animated.alert-info {\n  box-shadow: 0 0 5px rgba(33, 150, 243, 0.5);\n}\n\n.growl-animated.alert-success {\n  box-shadow: 0 0 5px rgba(76, 175, 80, 0.5);\n}\n\n.growl-animated.alert-warning {\n  box-shadow: 0 0 5px rgba(255, 193, 7, 0.5);\n}\n\n.growl-animated.alert-danger {\n  box-shadow: 0 0 5px rgba(244, 67, 54, 0.5);\n}\n\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n  border-color: #e0e0e0;\n  box-shadow: 0 0 6px #EAEAEA;\n}\n\n/*\n * Lightbox  \n */\n\n.lightbox .lightbox-item > img {\n  width: 100%;\n  border-radius: 2px;\n}\n\n@media (min-width: 768px) {\n  .lightbox .lightbox-item {\n    position: relative;\n  }\n\n  .lightbox .lightbox-item:before {\n    left: 0;\n    top: 0;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    -webkit-transform: scale3d(0, 0, 0);\n    -moz-transform: scale3d(0, 0, 0);\n    -ms-transform: scale3d(0, 0, 0);\n    -o-transform: scale3d(0, 0, 0);\n    transform: scale3d(0, 0, 0);\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 250ms;\n    transition-duration: 250ms;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    background-color: rgba(0, 0, 0, 0.1);\n    z-index: 0;\n    border-radius: 0;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n\n  .lightbox .lightbox-item:hover:before,\n  .lightbox .lightbox-item.open:before {\n    -webkit-transform: scale3d(1, 1, 1);\n    -moz-transform: scale3d(1, 1, 1);\n    -ms-transform: scale3d(1, 1, 1);\n    -o-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n\n.lightbox .lightbox-item:hover {\n  cursor: pointer;\n}\n\n.lightbox [data-src]:before,\n.lightbox [data-src]:after {\n  content: \" \";\n  display: table;\n}\n\n.lightbox [data-src]:after {\n  clear: both;\n}\n\n.lightbox [data-src]:before,\n.lightbox [data-src]:after {\n  content: \" \";\n  display: table;\n}\n\n.lightbox [data-src]:after {\n  clear: both;\n}\n\n.lightbox .lightbox-item:not(.p-item) {\n  position: relative;\n}\n\n/*\n * Carousel\n */\n\n.carousel .carousel-control {\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n\n.carousel .carousel-control .zmdi {\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  line-height: 100%;\n}\n\n@media screen and (min-width: 768px) {\n  .carousel .carousel-control .zmdi {\n    font-size: 60px;\n    width: 60px;\n    height: 60px;\n    margin-top: -30px;\n    margin-left: -30px;\n  }\n}\n\n@media screen and (max-width: 991px) {\n  .carousel .carousel-control .zmdi {\n    width: 24px;\n    height: 24px;\n    margin-top: -12px;\n    margin-left: -12px;\n  }\n}\n\n.carousel:hover .carousel-control {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.carousel .carousel-caption {\n  background: rgba(0, 0, 0, 0.6);\n  left: 0;\n  right: 0;\n  bottom: 0;\n  width: 100%;\n  padding-bottom: 50px;\n}\n\n.carousel .carousel-caption > h3 {\n  color: #fff;\n  margin: 0 0 5px;\n  font-weight: 300;\n}\n\n.carousel .carousel-caption > p {\n  margin: 0;\n}\n\n@media screen and (max-width: 991px) {\n  .carousel .carousel-caption {\n    display: none;\n  }\n}\n\n.carousel .carousel-indicators {\n  bottom: 10px;\n  margin: 0;\n  left: 0;\n  bottom: 0;\n  width: 100%;\n  padding: 0 0 6px;\n  background: rgba(0, 0, 0, 0.6);\n}\n\n.carousel .carousel-indicators li {\n  border-radius: 0;\n  width: 15px;\n  border: 0;\n  background: #fff;\n  height: 3px;\n  margin: 0;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n\n.carousel .carousel-indicators li.active {\n  width: 25px;\n  height: 3px;\n  background: #ff9800;\n}\n\n.modal .modal-content {\n  box-shadow: 0 5px 20px rgba(0, 0, 0, 0.31);\n  border-radius: 3px;\n  border: 0;\n}\n\n.modal .modal-header {\n  padding: 23px 26px;\n}\n\n.modal .modal-body {\n  padding: 0 26px 10px;\n}\n\n.modal .modal-footer .btn-link {\n  font-size: 14px;\n  color: #000;\n  font-weight: 500;\n}\n\n.modal .modal-footer .btn-link:hover {\n  background-color: #eee;\n}\n\n.modal:not([data-modal-color]) .modal-footer .btn-link {\n  font-weight: 500;\n}\n\n.modal:not([data-modal-color]) .modal-footer .btn-link:hover {\n  background-color: #eee;\n}\n\n.modal[data-modal-color] {\n  color: #fff;\n}\n\n.modal[data-modal-color] .modal-title,\n.modal[data-modal-color] .modal-footer .btn-link {\n  color: #fff;\n}\n\n.modal[data-modal-color] .modal-footer {\n  background: rgba(0, 0, 0, 0.1);\n}\n\n.modal[data-modal-color] .modal-backdrop {\n  background: #fff;\n}\n\n.modal[data-modal-color] .modal-footer .btn-link {\n  font-weight: 400;\n}\n\n.modal[data-modal-color] .modal-footer .btn-link:hover {\n  background-color: rgba(0, 0, 0, 0.1);\n}\n\n.modal[data-modal-color=\"blue\"] .modal-content {\n  background: #2196f3;\n}\n\n.modal[data-modal-color=\"cyan\"] .modal-content {\n  background: #00bcd4;\n}\n\n.modal[data-modal-color=\"green\"] .modal-content {\n  background: #4caf50;\n}\n\n.modal[data-modal-color=\"lightgreen\"] .modal-content {\n  background: #8bc34a;\n}\n\n.modal[data-modal-color=\"lightblue\"] .modal-content {\n  background: #03a9f4;\n}\n\n.modal[data-modal-color=\"amber\"] .modal-content {\n  background: #ffc107;\n}\n\n.modal[data-modal-color=\"teal\"] .modal-content {\n  background: #009688;\n}\n\n.modal[data-modal-color=\"orange\"] .modal-content {\n  background: #ff9800;\n}\n\n.modal[data-modal-color=\"bluegray\"] .modal-content {\n  background: #607d8b;\n}\n\n.modal[data-modal-color=\"red\"] .modal-content {\n  background: #f44336;\n}\n\n.panel {\n  box-shadow: none;\n  border: 0;\n}\n\n.panel-heading {\n  padding: 0;\n}\n\n.panel-title > a {\n  padding: 10px 15px;\n  display: block;\n  font-size: 13px;\n}\n\n.panel-collapse .panel-heading {\n  position: relative;\n}\n\n.panel-collapse .panel-heading .panel-title > a {\n  padding: 8px 5px 16px 30px;\n  color: #000;\n  position: relative;\n}\n\n.panel-collapse .panel-heading .panel-title > a:after,\n.panel-collapse .panel-heading .panel-title > a:before {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  height: 2px;\n  width: 100%;\n  content: \"\";\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n}\n\n.panel-collapse .panel-heading .panel-title > a:after {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n\n.panel-collapse .panel-heading:not(.active) .panel-title > a:before {\n  background: #eee;\n}\n\n.panel-collapse .panel-heading:before,\n.panel-collapse .panel-heading:after {\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 17px;\n  position: absolute;\n  left: 0;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  top: 4px;\n}\n\n.panel-collapse .panel-heading:before {\n  content: \"\\f278\";\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.panel-collapse .panel-heading:after {\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  content: \"\\f273\";\n}\n\n.panel-collapse .panel-heading.active .panel-title > a:after {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.panel-collapse .panel-heading.active:before {\n  -webkit-transform: scale(0) rotate(-90deg);\n  -ms-transform: scale(0) rotate(-90deg);\n  -o-transform: scale(0) rotate(-90deg);\n  transform: scale(0) rotate(-90deg);\n}\n\n.panel-collapse .panel-heading.active:after {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.panel-collapse .panel-body {\n  border-top: 0 !important;\n  padding-left: 5px;\n  padding-right: 5px;\n}\n\n.panel-group:not([data-collapse-color]) .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #2196f3;\n}\n\n.panel-group[data-collapse-color=\"red\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #f44336;\n}\n\n.panel-group[data-collapse-color=\"green\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #4caf50;\n}\n\n.panel-group[data-collapse-color=\"amber\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #ffc107;\n}\n\n.panel-group[data-collapse-color=\"teal\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #009688;\n}\n\n.panel-group[data-collapse-color=\"black\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #000000;\n}\n\n.panel-group[data-collapse-color=\"cyan\"] .panel-collapse .panel-heading.active .panel-title > a:after {\n  background: #00bcd4;\n}\n\n.tooltip-inner {\n  border-radius: 1px;\n  padding: 3px 10px 5px;\n}\n\n.breadcrumb {\n  border-bottom: 1px solid #E5E5E5;\n  border-radius: 0;\n}\n\n.breadcrumb > li > a {\n  color: #A9A9A9;\n}\n\n.breadcrumb > li > a:hover {\n  color: #7c7c7c;\n}\n\n@media (min-width: 768px) {\n  body:not(.sw-toggled) .breadcrumb {\n    padding: 10px 33px 11px;\n  }\n}\n\n@media (min-width: 1199px) {\n  body.sw-toggled .breadcrumb {\n    padding: 10px 33px 11px 280px;\n  }\n}\n\n#messages-main {\n  position: relative;\n}\n\n#messages-main:before,\n#messages-main:after {\n  content: \" \";\n  display: table;\n}\n\n#messages-main:after {\n  clear: both;\n}\n\n#messages-main:before,\n#messages-main:after {\n  content: \" \";\n  display: table;\n}\n\n#messages-main:after {\n  clear: both;\n}\n\n#messages-main .ms-block {\n  padding: 23px 20px 0;\n}\n\n#messages-main .ms-menu {\n  position: absolute;\n  left: 0;\n  top: 0;\n  background: #F8F8F8;\n  border-right: 1px solid #EEE;\n  padding-bottom: 50px;\n  height: 100%;\n  width: 240px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n\n@media (max-width: 767px) {\n  #messages-main .ms-menu {\n    height: calc(100% - 58px);\n    -webkit-transform: translate3d(-240px, 58px, 0);\n    transform: translate3d(-240px, 58px, 0);\n    opacity: 0;\n    filter: alpha(opacity=0);\n    z-index: 1;\n  }\n\n  #messages-main .ms-menu.toggled {\n    -webkit-transform: translate3d(0, 58px, 0);\n    transform: translate3d(0, 58px, 0);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n\n#messages-main .ms-menu .lv-item {\n  padding-left: 20px;\n  padding-right: 20px;\n}\n\n#messages-main .ms-menu .lv-item.active {\n  background: #fff;\n}\n\n#messages-main .ms-menu .lv-item:not(.active):hover {\n  background: #F2F2F2;\n  cursor: pointer;\n}\n\n@media (min-width: 768px) {\n  #messages-main .ms-body {\n    padding-left: 240px;\n  }\n}\n\n@media (max-width: 767px) {\n  #messages-main .ms-body {\n    overflow: hidden;\n  }\n}\n\n#messages-main .ms-user:before,\n#messages-main .ms-user:after {\n  content: \" \";\n  display: table;\n}\n\n#messages-main .ms-user:after {\n  clear: both;\n}\n\n#messages-main .ms-user:before,\n#messages-main .ms-user:after {\n  content: \" \";\n  display: table;\n}\n\n#messages-main .ms-user:after {\n  clear: both;\n}\n\n#messages-main .ms-user > img {\n  border-radius: 50%;\n  width: 40px;\n  float: left;\n}\n\n#messages-main .ms-user > div {\n  overflow: hidden;\n  padding: 7px 5px 7px 15px;\n  font-size: 11px;\n}\n\n#ms-menu-trigger {\n  -webkit-touch-callout: none;\n  -webkit-user-select: none;\n  -khtml-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  float: left;\n  margin: 1px 0 0 -7px;\n}\n\n@media (min-width: 768px) {\n  #ms-menu-trigger {\n    display: none;\n  }\n}\n\n#ms-menu-trigger .line-wrap .line {\n  background-color: #717171;\n}\n\n/*\n * For Message\n */\n\n.lv-message .lv-item {\n  padding: 20px;\n}\n\n.lv-message .lv-item.right {\n  text-align: right;\n}\n\n.lv-message .lv-item.right .lv-avatar {\n  margin-right: 0;\n  margin-left: 15px;\n}\n\n.lv-message .lv-item:not(.right) .ms-item {\n  background: #ffc107;\n  color: #fff;\n}\n\n.lv-message .lv-item.right .ms-item {\n  background: #eee;\n}\n\n.lv-avatar {\n  width: 35px;\n  height: 35px;\n  border-radius: 50%;\n  color: #FFF;\n  text-align: center;\n  line-height: 34px;\n  font-size: 15px;\n  margin-right: 15px;\n  padding: 0 !important;\n  text-transform: uppercase;\n}\n\n.lv-avatar > img {\n  width: 35px;\n  height: 35px;\n  border-radius: 50%;\n  vertical-align: top;\n}\n\n.ms-item {\n  padding: 13px 19px 15px;\n  border-radius: 2px;\n  display: inline-block;\n}\n\n@media (min-width: 768px) {\n  .ms-item {\n    max-width: 70%;\n  }\n}\n\n.ms-date {\n  display: block;\n  color: #B3B3B3;\n  margin-top: 7px;\n}\n\n.ms-date > i {\n  font-size: 14px;\n  vertical-align: bottom;\n  line-height: 100%;\n}\n\n.ms-reply {\n  box-shadow: 0 -20px 20px -5px #ffffff;\n  position: relative;\n  margin: 0 !important;\n}\n\n.ms-reply textarea {\n  width: 100%;\n  font-size: 13px;\n  border: 0;\n  padding: 10px 8px;\n  resize: none;\n  height: 60px;\n}\n\n.ms-reply button {\n  position: absolute;\n  top: 0;\n  right: 0;\n  border: 0;\n  height: 100%;\n  width: 60px;\n  font-size: 25px;\n  background: #F5F5F5;\n  color: #2196f3;\n}\n\n.ms-reply button:hover {\n  background: #f2f2f2;\n}\n\n.four-zero-content {\n  background: #fff;\n  padding: 20px;\n}\n\n.four-zero-content:before {\n  height: 50%;\n  width: 100%;\n  position: absolute;\n  top: 0;\n  left: 0;\n  background: #EDECEC;\n  content: \"\";\n}\n\n.four-zero {\n  background: #00bcd4;\n  box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);\n  border-radius: 2px;\n  position: absolute;\n  top: 50%;\n  margin-top: -150px;\n  color: #fff;\n  text-align: center;\n  padding: 15px;\n  height: 300px;\n  width: 500px;\n  left: 50%;\n  margin-left: -250px;\n}\n\n.four-zero h2 {\n  font-size: 130px;\n}\n\n@media (max-width: 767px) {\n  .four-zero {\n    width: calc(100% - 40px);\n    left: 20px;\n    margin-left: 0;\n    height: 260px;\n    margin-top: -130px;\n  }\n\n  .four-zero h2 {\n    font-size: 90px;\n  }\n}\n\n.four-zero h2 {\n  line-height: 100%;\n  color: #fff;\n  font-weight: 100;\n}\n\n.four-zero small {\n  display: block;\n  font-size: 26px;\n  margin-top: -10px;\n}\n\n.four-zero footer {\n  background: rgba(0, 0, 0, 0.13);\n  position: absolute;\n  left: 0;\n  bottom: 0;\n  width: 100%;\n  padding: 10px;\n}\n\n.four-zero footer > a {\n  font-size: 21px;\n  display: inline-block;\n  color: #FFF;\n  margin: 0 1px;\n  line-height: 40px;\n  width: 40px;\n  height: 40px;\n  background: rgba(0, 0, 0, 0.09);\n  border-radius: 50%;\n  text-align: center;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.four-zero footer > a:hover {\n  background: rgba(0, 0, 0, 0.2);\n}\n\n.login-content {\n  overflow: hidden;\n  height: 100%;\n}\n\n.lc-block {\n  background: #fff;\n  box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);\n  border-radius: 2px;\n  width: 500px;\n  display: inline-block;\n  margin-top: 42px;\n  vertical-align: middle;\n  position: relative;\n}\n\n.lc-block:not(.toggled) {\n  display: none;\n}\n\n.lc-block.toggled {\n  -webkit-animation-name: fadeInUp;\n  animation-name: fadeInUp;\n  -webkit-animation-duration: 300ms;\n  animation-duration: 300ms;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n  z-index: 10;\n}\n\n.lc-block:not(.lcb-alt) {\n  padding: 35px 55px 35px;\n}\n\n@media (max-width: 767px) {\n  .lc-block {\n    padding: 15px 35px 25px 20px;\n    width: calc(100% - 60px);\n  }\n}\n\n.lc-block .checkbox {\n  margin: 5px 0 0 42px;\n  text-align: left;\n}\n\n.lc-block:not(.lcb-alt) .btn-login {\n  top: 50%;\n  margin-top: -25px;\n  right: -25px;\n}\n\n.login-navigation {\n  list-style: none;\n  padding: 0;\n  margin: 0;\n  position: absolute;\n  width: 100%;\n  text-align: center;\n  left: 0%;\n  bottom: -45px;\n}\n\n.login-navigation > li {\n  display: inline-block;\n  margin: 0 2px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 150ms;\n  transition-duration: 150ms;\n  cursor: pointer;\n  vertical-align: top;\n  color: #fff;\n  line-height: 16px;\n  min-width: 16px;\n  min-height: 16px;\n  text-transform: uppercase;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n}\n\n.login-navigation > li > span {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n\n.login-navigation > li:not(:hover) {\n  font-size: 0px;\n  border-radius: 100%;\n}\n\n.login-navigation > li:hover {\n  border-radius: 10px;\n  padding: 0 5px;\n  font-size: 8px;\n}\n\n.login-navigation > li:hover > span {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.lcb-alt {\n  padding: 70px 55px 60px;\n}\n\n.lcb-alt .btn-login {\n  bottom: -25px;\n  left: 50%;\n  margin-left: -25px;\n}\n\n.lcb-alt .login-navigation {\n  bottom: -75px;\n}\n\n.lcb-user {\n  width: 100px;\n  height: 100px;\n  border-radius: 50%;\n  border: 5px solid #fff;\n  position: absolute;\n  top: -50px;\n  left: 50%;\n  margin-left: -50px;\n  box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.18);\n}\n\nbody.login-content {\n  text-align: center;\n}\n\nbody.login-content:after {\n  content: \"\";\n  vertical-align: middle;\n  display: inline-block;\n  width: 1px;\n  height: 100%;\n}\n\nbody.login-content:before {\n  height: 50%;\n  width: 100%;\n  position: absolute;\n  top: 0;\n  left: 0;\n  background: #00bcd4;\n  content: \"\";\n  z-index: 0;\n}\n\n#profile-main {\n  min-height: 500px;\n  position: relative;\n}\n\n#profile-main .pm-overview {\n  overflow-y: auto;\n}\n\n@media (min-width: 1200px) {\n  #profile-main .pm-overview {\n    width: 300px;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 1200px) {\n  #profile-main .pm-overview {\n    width: 250px;\n  }\n}\n\n@media (min-width: 768px) {\n  #profile-main .pm-overview {\n    position: absolute;\n    left: 0;\n    top: 0;\n    height: 100%;\n    background: #f8f8f8;\n    border-right: 1px solid #eee;\n  }\n}\n\n@media (max-width: 767px) {\n  #profile-main .pm-overview {\n    width: 100%;\n    background: #333;\n    text-align: center;\n  }\n}\n\n@media (min-width: 1200px) {\n  #profile-main .pm-body {\n    padding-left: 300px;\n  }\n}\n\n@media (min-width: 768px) and (max-width: 1200px) {\n  #profile-main .pm-body {\n    padding-left: 250px;\n  }\n}\n\n@media (max-width: 767px) {\n  #profile-main .pm-body {\n    padding-left: 0;\n  }\n}\n\n#profile-main .pmo-pic {\n  position: relative;\n  margin: 20px;\n}\n\n@media (min-width: 768px) {\n  #profile-main .pmo-pic img {\n    width: 100%;\n    border-radius: 2px 2px 0 0;\n  }\n}\n\n@media (max-width: 767px) {\n  #profile-main .pmo-pic img {\n    width: 180px;\n    display: inline-block;\n    height: 180px;\n    border-radius: 50%;\n    border: 4px solid #fff;\n    box-shadow: 0 8px 17px rgba(0, 0, 0, 0.2), 0 6px 20px rgba(0, 0, 0, 0.19);\n  }\n}\n\n#profile-main .pmo-pic .pmo-stat {\n  border-radius: 0 0 2px 2px;\n  color: #fff;\n  text-align: center;\n  padding: 30px 5px 0;\n}\n\n@media (min-width: 768px) {\n  #profile-main .pmo-pic .pmo-stat {\n    background: #ffc107;\n    padding-bottom: 15px;\n  }\n}\n\n#profile-main .pmo-pic .pmop-edit {\n  position: absolute;\n  top: 0;\n  left: 0;\n  color: #fff;\n  background: rgba(0, 0, 0, 0.38);\n  text-align: center;\n  padding: 10px 10px 11px;\n  -webkit-transition: opacity;\n  -o-transition: opacity;\n  transition: opacity;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n\n#profile-main .pmo-pic .pmop-edit:hover {\n  background: rgba(0, 0, 0, 0.8);\n}\n\n#profile-main .pmo-pic .pmop-edit i {\n  font-size: 18px;\n  vertical-align: middle;\n  margin-top: -3px;\n}\n\n@media (min-width: 768px) {\n  #profile-main .pmo-pic .pmop-edit {\n    width: 100%;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n\n  #profile-main .pmo-pic .pmop-edit i {\n    margin-right: 4px;\n  }\n}\n\n#profile-main .pmo-pic:hover .pmop-edit {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n#profile-main .pmo-pic .pmop-message {\n  position: absolute;\n  bottom: 27px;\n  left: 50%;\n  margin-left: -25px;\n}\n\n#profile-main .pmo-pic .pmop-message .dropdown-menu {\n  padding: 5px 0 55px;\n  left: -90px;\n  width: 228px;\n  height: 150px;\n  top: -74px;\n  -webkit-transform-origin: center;\n  -moz-transform-origin: center;\n  -ms-transform-origin: center;\n  transform-origin: center;\n}\n\n#profile-main .pmo-pic .pmop-message .dropdown-menu textarea {\n  width: 100%;\n  height: 95px;\n  border: 0;\n  resize: none;\n  padding: 10px 19px;\n}\n\n#profile-main .pmo-pic .pmop-message .dropdown-menu button {\n  bottom: 5px;\n  left: 88px;\n}\n\n#profile-main .pmb-block {\n  margin-bottom: 20px;\n}\n\n@media (min-width: 1200px) {\n  #profile-main .pmb-block {\n    padding: 40px 42px 0;\n  }\n}\n\n@media (max-width: 1199px) {\n  #profile-main .pmb-block {\n    padding: 30px 20px 0;\n  }\n}\n\n#profile-main .pmb-block:last-child {\n  margin-bottom: 50px;\n}\n\n#profile-main .pmb-block .pmbb-header {\n  margin-bottom: 25px;\n  position: relative;\n}\n\n#profile-main .pmb-block .pmbb-header .actions {\n  position: absolute;\n  top: -2px;\n  right: 0;\n}\n\n#profile-main .pmb-block .pmbb-header h2 {\n  margin: 0;\n  font-weight: 100;\n  font-size: 20px;\n}\n\n#profile-main .pmb-block .pmbb-edit {\n  position: relative;\n  z-index: 1;\n  display: none;\n}\n\n#profile-main .pmb-block .pmbb-edit,\n#profile-main .pmb-block .pmbb-view {\n  -webkit-animation-name: fadeIn;\n  animation-name: fadeIn;\n  -webkit-animation-duration: 1000ms;\n  animation-duration: 1000ms;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n\n#profile-main .pmb-block.toggled .pmbb-edit {\n  display: block;\n}\n\n#profile-main .pmb-block.toggled .pmbb-view {\n  display: none;\n}\n\n#profile-main .pmo-block {\n  padding: 25px;\n}\n\n#profile-main .pmo-block > h2 {\n  font-size: 16px;\n  margin: 0 0 15px;\n}\n\n#profile-main .pmo-items .pmob-body {\n  padding: 0 10px;\n}\n\n#profile-main .pmo-items a {\n  display: block;\n  padding: 4px;\n}\n\n#profile-main .pmo-items a img {\n  width: 100%;\n}\n\n.pmo-contact ul {\n  list-style: none;\n  margin: 0;\n  padding: 0;\n}\n\n.pmo-contact ul li {\n  position: relative;\n  padding: 8px 0 8px 35px;\n}\n\n.pmo-contact ul li i {\n  font-size: 18px;\n  vertical-align: top;\n  line-height: 100%;\n  position: absolute;\n  left: 0;\n  width: 18px;\n  text-align: center;\n}\n\n.pmo-map {\n  margin: 20px -21px -18px;\n  display: block;\n}\n\n.pmo-map img {\n  width: 100%;\n}\n\n@media (max-width: 767px) {\n  .c-timeline {\n    background: #edecec;\n    box-shadow: none;\n  }\n\n  .c-timeline .tab-nav {\n    background: #fff;\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  }\n}\n\n.timeline {\n  position: relative;\n}\n\n@media (min-width: 768px) {\n  .timeline {\n    padding: 50px;\n    padding-left: 100px;\n  }\n}\n\n@media (max-width: 767px) {\n  .timeline {\n    margin-top: 30px;\n  }\n}\n\n.t-view {\n  border: 1px solid #eee;\n  position: relative;\n  margin-bottom: 35px;\n}\n\n@media (max-width: 767px) {\n  .t-view {\n    background: #fff;\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  }\n}\n\n.t-view .tv-header {\n  padding: 16px 18px;\n  border-bottom: 1px solid #eee;\n  background: #F9F9F9;\n}\n\n.t-view .tv-header .actions {\n  position: absolute;\n  top: 5px;\n  right: 10px;\n}\n\n.t-view .tv-body {\n  padding: 23px 25px;\n}\n\n.t-view .tv-body .tvb-lightbox {\n  margin: 0 -8px 15px;\n}\n\n.t-view .tv-body .tvb-lightbox [data-src] {\n  padding: 0 5px;\n  margin-bottom: 5px;\n}\n\n.t-view .tvh-user {\n  display: block;\n}\n\n.t-view .tvh-user img {\n  width: 46px;\n  height: 46px;\n  border-radius: 50%;\n}\n\n.t-view:before {\n  position: absolute;\n  width: 40px;\n  height: 40px;\n  border-radius: 50%;\n  left: -70px;\n  top: 0;\n  border: 3px solid #FFF;\n  text-align: center;\n  font-size: 16px;\n  line-height: 34px;\n  color: #FFF;\n  font-family: 'Material-Design-Iconic-Font';\n  z-index: 1;\n}\n\n.t-view:after {\n  content: \"\";\n  position: absolute;\n  top: 0;\n  left: -50px;\n  width: 1px;\n  height: calc(100% + 37px);\n}\n\n.t-view[data-tv-type=\"text\"]:before {\n  content: \"\\f24f\";\n  background: #00bcd4;\n  box-shadow: 0 0 0 1px #00bcd4;\n}\n\n.t-view[data-tv-type=\"text\"]:after {\n  background: #00bcd4;\n}\n\n.t-view[data-tv-type=\"image\"]:before {\n  content: \"\\f17f\";\n  background: #4caf50;\n  box-shadow: 0 0 0 1px #4caf50;\n}\n\n.t-view[data-tv-type=\"image\"]:after {\n  background: #4caf50;\n}\n\n.t-view[data-tv-type=\"video\"]:before {\n  content: \"\\f3a9\";\n  background: #ffc107;\n  box-shadow: 0 0 0 1px #ffc107;\n}\n\n.t-view[data-tv-type=\"video\"]:after {\n  background: #ffc107;\n}\n\n.t-view .tvb-stats {\n  list-style: none;\n  padding: 0;\n  margin: 10px 0 20px;\n}\n\n.t-view .tvb-stats > li {\n  display: inline-block;\n  padding: 5px 10px 6px;\n  border: 1px solid #ccc;\n  margin-right: 2px;\n}\n\n.t-view .tvb-stats > li i {\n  font-size: 15px;\n  line-height: 100%;\n  vertical-align: top;\n  margin-top: 2px;\n}\n\n.t-view .tvb-stats > li.tvbs-comments {\n  border-color: #4caf50;\n  color: #4caf50;\n}\n\n.t-view .tvb-stats > li.tvbs-likes {\n  border-color: #03a9f4;\n  color: #03a9f4;\n}\n\n.t-view .tvb-stats > li.tvbs-views {\n  border-color: #ff9800;\n  color: #ff9800;\n}\n\n.tv-comments .tvc-lists {\n  padding: 0;\n  list-style: none;\n  margin: 0;\n}\n\n.tv-comments .tvc-lists > li {\n  padding: 15px 20px;\n  margin: 0;\n  border-top: 1px solid #eee;\n}\n\n.tvc-more {\n  color: #333;\n  display: block;\n  margin-bottom: -10px;\n}\n\n.tvc-more:hover {\n  color: #000;\n}\n\n.tvc-more i {\n  vertical-align: middle;\n  margin-right: 5px;\n}\n\n.p-header {\n  position: relative;\n  margin: 0 -7px;\n}\n\n.p-header .actions {\n  position: absolute;\n  top: -18px;\n  right: 0;\n}\n\n.p-menu {\n  list-style: none;\n  padding: 0 5px;\n  margin: 0 0 30px;\n}\n\n.p-menu > li {\n  display: inline-block;\n  vertical-align: top;\n}\n\n.p-menu > li > a {\n  display: block;\n  padding: 5px 20px 5px 0;\n  font-weight: 500;\n  text-transform: uppercase;\n  font-size: 15px;\n}\n\n.p-menu > li > a > i {\n  margin-right: 4px;\n  font-size: 20px;\n  vertical-align: middle;\n  margin-top: -5px;\n}\n\n.p-menu > li:not(.active) > a {\n  color: #4285F4;\n}\n\n.p-menu > li:not(.active) > a:hover {\n  color: #333;\n}\n\n.p-menu > li.active > a {\n  color: #000;\n}\n\n@media (max-width: 991px) {\n  .p-menu .pm-search {\n    margin: 20px 2px 30px;\n    display: block;\n  }\n\n  .p-menu .pm-search input[type=\"text\"] {\n    width: 100%;\n    border: 1px solid #ccc;\n  }\n}\n\n.p-menu .pms-inner {\n  margin: -2px 0 0;\n  position: relative;\n  top: -2px;\n  overflow: hidden;\n  white-space: nowrap;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/app.min.2.css",
    "content": ".p-menu .pms-inner i {\n  vertical-align: top;\n  font-size: 20px;\n  line-height: 100%;\n  position: absolute;\n  left: 9px;\n  top: 8px;\n  color: #333;\n}\n\n.p-menu .pms-inner input[type=\"text\"] {\n  height: 35px;\n  border-radius: 2px;\n  padding: 0 10px 0 40px;\n}\n\n@media (min-width: 768px) {\n  .p-menu .pms-inner input[type=\"text\"] {\n    border: 1px solid #fff;\n    width: 50px;\n    background: transparent;\n    position: relative;\n    z-index: 1;\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 300ms;\n    transition-duration: 300ms;\n  }\n\n  .p-menu .pms-inner input[type=\"text\"]:focus {\n    border-color: #DFDFDF;\n    width: 200px;\n  }\n}\n\n.photos {\n  margin: 2px 0 0;\n}\n\n.photos .lightbox {\n  margin: 0 -8px;\n}\n\n.photos:not(.p-timeline) [data-src] {\n  padding: 3px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 150ms;\n  transition-duration: 150ms;\n}\n\n.p-timeline {\n  position: relative;\n  padding-left: 80px;\n  margin-bottom: 75px;\n}\n\n.p-timeline [data-src] {\n  float: left;\n  width: 70px;\n  height: 70px;\n  margin: 0 3px 3px 0;\n}\n\n.p-timeline:last-child .pt-line:before {\n  height: 100%;\n}\n\n.ptb-title {\n  font-size: 15px;\n  font-weight: 400;\n  margin-bottom: 20px;\n}\n\n.pt-line {\n  position: absolute;\n  left: 0;\n  top: 0;\n  height: 100%;\n  line-height: 14px;\n}\n\n.pt-line:before,\n.pt-line:after {\n  content: \"\";\n  position: absolute;\n}\n\n.pt-line:before {\n  width: 1px;\n  height: calc(100% + 63px);\n  background: #E2E2E2;\n  top: 14px;\n  right: -20px;\n}\n\n.pt-line:after {\n  top: 2px;\n  right: -26px;\n  width: 13px;\n  height: 13px;\n  border: 1px solid #C1C1C1;\n  border-radius: 50%;\n}\n\n.contacts:not(.c-profile) {\n  padding: 0 8px;\n}\n\n.contacts > [class*=\"col-\"] {\n  padding: 0 10px;\n}\n\n.contacts .c-item {\n  border: 1px solid #e2e2e2;\n  border-radius: 2px;\n  margin-bottom: 24px;\n}\n\n.contacts .c-item .ci-avatar {\n  display: block;\n}\n\n.contacts .c-item .ci-avatar img {\n  width: 100%;\n  border-radius: 2px 2px 0 0;\n}\n\n.contacts .ci-avatar {\n  margin: -1px -1px 0;\n}\n\n.contacts .c-info {\n  text-align: center;\n  margin-top: 15px;\n  padding: 0 5px;\n}\n\n.contacts .c-info strong {\n  color: #000;\n  font-size: 14px;\n  font-weight: 500;\n}\n\n.contacts .c-info small {\n  color: #999;\n  margin-top: 3px;\n}\n\n.contacts .c-info strong,\n.contacts .c-info small {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n  display: block;\n}\n\n.contacts .c-footer {\n  border-top: 1px solid #e2e2e2;\n  margin-top: 18px;\n}\n\n.contacts .c-footer > button {\n  padding: 4px 10px 3px;\n  display: block;\n  width: 100%;\n  text-align: center;\n  color: #333;\n  font-weight: 500;\n  border-radius: 2px;\n  background: #fff;\n  border: 0;\n}\n\n.contacts .c-footer > button > i {\n  font-size: 16px;\n  vertical-align: middle;\n  margin-top: -3px;\n}\n\n.z-depth-1 {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n\n.z-depth-1-top {\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n\n.z-depth-1-bottom {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16);\n}\n\n.z-depth-2 {\n  box-shadow: 0 8px 17px rgba(0, 0, 0, 0.2), 0 6px 20px rgba(0, 0, 0, 0.19);\n}\n\n.z-depth-2-top {\n  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.19);\n}\n\n.z-depth-2-bottom {\n  box-shadow: 0 8px 17px rgba(0, 0, 0, 0.2);\n}\n\n.z-depth-3 {\n  box-shadow: 0 12px 15px rgba(0, 0, 0, 0.24), 0 17px 50px rgba(0, 0, 0, 0.19);\n}\n\n.z-depth-3-top {\n  box-shadow: 0 17px 50px rgba(0, 0, 0, 0.19);\n}\n\n.z-depth-3-bottom {\n  box-shadow: 0 12px 15px rgba(0, 0, 0, 0.24);\n}\n\n.z-depth-4 {\n  box-shadow: 0 16px 28px rgba(0, 0, 0, 0.22), 0 25px 55px rgba(0, 0, 0, 0.21);\n}\n\n.z-depth-4-top {\n  box-shadow: 0 25px 55px rgba(0, 0, 0, 0.21);\n}\n\n.z-depth-4-bottom {\n  box-shadow: 0 16px 28px rgba(0, 0, 0, 0.22);\n}\n\n.z-depth-5 {\n  box-shadow: 0 27px 24px rgba(0, 0, 0, 0.2), 0 40px 77px rgba(0, 0, 0, 0.22);\n}\n\n.z-depth-5-top {\n  box-shadow: 0 40px 77px rgba(0, 0, 0, 0.22);\n}\n\n.z-depth-5-bottom {\n  box-shadow: 0 27px 24px rgba(0, 0, 0, 0.2);\n}\n\n.z-depth-animation .z-depth-1,\n.z-depth-animation .z-depth-2,\n.z-depth-animation .z-depth-3,\n.z-depth-animation .z-depth-4,\n.z-depth-animation .z-depth-5 {\n  transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n/*\n * Block Header\n * Used for Heading outside the Cards.\n */\n\n.block-header {\n  margin-bottom: 0;\n  position: relative;\n}\n\n@media screen and (min-width: 768px) {\n  .block-header {\n    padding: 15px;\n    background-color:#ffffff;\n  }\n}\n\n@media screen and (max-width: 991px) {\n  .block-header {\n    padding: 0 18px;\n  }\n}\n\n.block-header > h2 {\n  font-size: 15px;\n  color: #777;\n  margin: 0;\n  font-weight: 600;\n  text-transform: uppercase;\n}\n\n.block-header > h2 > small {\n  display: block;\n  text-transform: none;\n  margin-top: 8px;\n  margin-bottom: 20px;\n  color: #9E9E9E;\n  line-height: 140%;\n}\n\n.block-header .actions {\n  position: absolute;\n  right: 10px;\n  top: -5px;\n  z-index: 4;\n}\n\n/*\n * Header Actions\n */\n\n.actions {\n  list-style: none;\n  padding: 0;\n  z-index: 3;\n  margin: 0;\n}\n\n.actions > li {\n  display: inline-block;\n  vertical-align: baseline;\n}\n\n.actions > li > a,\n.actions > a {\n  width: 30px;\n  height: 30px;\n  display: inline-block;\n  text-align: center;\n  padding-top: 5px;\n}\n\n.actions > li > a > i,\n.actions > a > i {\n  color: #adadad;\n  font-size: 20px;\n}\n\n.actions > li > a:hover > i,\n.actions > a:hover > i {\n  color: #000;\n}\n\n@media (min-width: 768px) {\n  .actions > li > a,\n  .actions > a {\n    position: relative;\n  }\n\n  .actions > li > a:before,\n  .actions > a:before {\n    left: 0;\n    top: 0;\n    content: \"\";\n    position: absolute;\n    width: 100%;\n    height: 100%;\n    -webkit-transform: scale3d(0, 0, 0);\n    -moz-transform: scale3d(0, 0, 0);\n    -ms-transform: scale3d(0, 0, 0);\n    -o-transform: scale3d(0, 0, 0);\n    transform: scale3d(0, 0, 0);\n    -webkit-transition: all;\n    -o-transition: all;\n    transition: all;\n    -webkit-transition-duration: 250ms;\n    transition-duration: 250ms;\n    -webkit-backface-visibility: hidden;\n    -moz-backface-visibility: hidden;\n    backface-visibility: hidden;\n    background-color: rgba(0, 0, 0, 0.1);\n    z-index: 0;\n    border-radius: 50%;\n    opacity: 0;\n    filter: alpha(opacity=0);\n  }\n\n  .actions > li > a:hover:before,\n  .actions > a:hover:before,\n  .actions > li > a.open:before,\n  .actions > a.open:before {\n    -webkit-transform: scale3d(1, 1, 1);\n    -moz-transform: scale3d(1, 1, 1);\n    -ms-transform: scale3d(1, 1, 1);\n    -o-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n    opacity: 1;\n    filter: alpha(opacity=100);\n  }\n}\n\n.actions > li.open > a > i,\n.actions.open > a > i {\n  color: #000;\n}\n\n.actions > li.open > a:before,\n.actions.open > a:before {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.actions.actions-alt > li > a > i {\n  color: #fff;\n}\n\n.actions.actions-alt > li > a > i:hover {\n  color: #fff;\n}\n\n.actions.actions-alt > li.open > a > i {\n  color: #fff;\n}\n\n.actions.open {\n  z-index: 3;\n}\n\n/*\n * Collapse Menu Icons\n */\n\n.line-wrap {\n  width: 18px;\n  height: 12px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  margin: 12px 20px;\n}\n\n.line-wrap .line {\n  width: 18px;\n  height: 2px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.line-wrap .line.center {\n  margin: 3px 0;\n}\n\n.open .line-wrap {\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  -o-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n\n.open .line-wrap .line.top {\n  width: 12px;\n  transform: translateX(8px) translateY(1px) rotate(45deg);\n  -webkit-transform: translateX(8px) translateY(1px) rotate(45deg);\n}\n\n.open .line-wrap .line.bottom {\n  width: 12px;\n  transform: translateX(8px) translateY(-1px) rotate(-45deg);\n  -webkit-transform: translateX(8px) translateY(-1px) rotate(-45deg);\n}\n\n/*\n * Load More\n */\n\n.load-more {\n  text-align: center;\n  margin-top: 30px;\n}\n\n.load-more a {\n  padding: 5px 10px 3px;\n  display: inline-block;\n  background-color: #f44336;\n  color: #FFF;\n  border-radius: 2px;\n  white-space: nowrap;\n}\n\n.load-more a i {\n  font-size: 20px;\n  vertical-align: middle;\n  position: relative;\n  margin-top: -2px;\n}\n\n.load-more a:hover {\n  background-color: #ea1c0d;\n}\n\n/*\n * Page Loader\n */\n\nhtml:not(.ismobile) .page-loader {\n  background: #fff;\n  position: fixed;\n  width: 100%;\n  height: 100%;\n  top: 0;\n  left: 0;\n  z-index: 1000;\n}\n\nhtml:not(.ismobile) .page-loader .preloader {\n  width: 50px;\n  position: absolute;\n  left: 50%;\n  margin-left: -25px;\n  top: 50%;\n  margin-top: -55px;\n  -webkit-animation-name: fadeIn;\n  animation-name: fadeIn;\n  -webkit-animation-duration: 3000ms;\n  animation-duration: 3000ms;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n\nhtml:not(.ismobile) .page-loader .preloader p {\n  white-space: nowrap;\n  position: relative;\n  left: -9px;\n  top: 22px;\n  color: #CCC;\n}\n\nhtml.ismobile .page-loader {\n  display: none;\n}\n\n.ie-warning {\n  position: fixed;\n  top: 0;\n  left: 0;\n  z-index: 9999;\n  background: #000000;\n  width: 100%;\n  height: 100%;\n  text-align: center;\n  color: #fff;\n  font-family: \"Courier New\", Courier, monospace;\n  padding: 50px 0;\n}\n\n.ie-warning p {\n  font-size: 17px;\n}\n\n.ie-warning .iew-container {\n  min-width: 1024px;\n  width: 100%;\n  height: 200px;\n  background: #fff;\n  margin: 50px 0;\n}\n\n.ie-warning .iew-download {\n  list-style: none;\n  padding: 30px 0;\n  margin: 0 auto;\n  width: 720px;\n}\n\n.ie-warning .iew-download > li {\n  float: left;\n  vertical-align: top;\n}\n\n.ie-warning .iew-download > li > a {\n  display: block;\n  color: #000;\n  width: 140px;\n  font-size: 15px;\n  padding: 15px 0;\n}\n\n.ie-warning .iew-download > li > a > div {\n  margin-top: 10px;\n}\n\n.ie-warning .iew-download > li > a:hover {\n  background-color: #eee;\n}\n\n#footer {\n  position: absolute;\n  bottom: 0;\n  text-align: center;\n  width: 100%;\n  height: 110px;\n  color: #a2a2a2;\n  padding-top: 35px;\n  padding-bottom: 15px;\n}\n\n#footer .f-menu {\n  display: block;\n  width: 100%;\n  padding-left: 0;\n  list-style: none;\n  margin-left: -5px;\n  margin-top: 8px;\n}\n\n#footer .f-menu > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\n\n#footer .f-menu > li > a {\n  color: #a2a2a2;\n}\n\n#footer .f-menu > li > a:hover {\n  color: #777;\n}\n\n@media (min-width: 1199px) {\n  body.sw-toggled #footer {\n    padding-left: 268px;\n  }\n}\n\n.pt-inner {\n  text-align: center;\n}\n\n.pt-inner .pti-header {\n  padding: 45px 10px 70px;\n  color: #fff;\n  position: relative;\n  margin-bottom: 15px;\n}\n\n.pt-inner .pti-header > h2 {\n  margin: 0;\n  line-height: 100%;\n  color: #fff;\n  font-weight: 100;\n  font-size: 50px;\n}\n\n.pt-inner .pti-header > h2 small {\n  color: #fff;\n  letter-spacing: 0;\n  vertical-align: top;\n  font-size: 16px;\n  font-weight: 100;\n}\n\n.pt-inner .pti-header .ptih-title {\n  background-color: rgba(0, 0, 0, 0.1);\n  padding: 8px 10px 9px;\n  text-transform: uppercase;\n  margin: 0 -10px;\n  position: absolute;\n  width: 100%;\n  bottom: 0;\n}\n\n.pt-inner .pti-body {\n  padding: 0 23px;\n}\n\n.pt-inner .pti-body .ptib-item {\n  padding: 15px 0;\n  font-weight: 400;\n}\n\n.pt-inner .pti-body .ptib-item:not(:last-child) {\n  border-bottom: 1px solid #eee;\n}\n\n.pt-inner .pti-footer {\n  padding: 10px 20px 30px;\n}\n\n.pt-inner .pti-footer > a {\n  width: 60px;\n  height: 60px;\n  border-radius: 50%;\n  text-align: center;\n  color: #fff;\n  display: inline-block;\n  line-height: 60px;\n  font-size: 30px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.pt-inner .pti-footer > a:hover {\n  opacity: 0.85;\n  filter: alpha(opacity=85);\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n\n.invoice {\n  min-width: 1100px;\n  max-width: 1170px;\n}\n\n.i-logo {\n  width: 150px;\n}\n\n.i-table .highlight {\n  background-color: #eee;\n  border-bottom: 1px solid #e6e6e6;\n}\n\n.i-table td.highlight {\n  font-size: 14px;\n  font-weight: 500;\n}\n\n.wall-attrs {\n  margin-bottom: 0;\n}\n\n.wa-stats {\n  float: left;\n}\n\n.wa-stats > span {\n  margin-right: -1px;\n  padding: 7px 12px;\n  border: 1px solid #E0E0E0;\n  float: left;\n  font-weight: 500;\n}\n\n.wa-stats > span.active {\n  color: #4caf50;\n}\n\n.wa-stats > span:first-child {\n  border-radius: 2px 0 0 2px;\n}\n\n.wa-stats > span:last-child {\n  border-radius: 0 2px 2px 0;\n}\n\n.wa-stats > span > i {\n  line-height: 100%;\n  vertical-align: top;\n  position: relative;\n  top: 2px;\n  font-size: 15px;\n  margin-right: 2px;\n}\n\n.wa-users {\n  float: right;\n  padding: 0 !important;\n  margin-right: -5px;\n}\n\n.wa-users > a {\n  display: inline-block;\n  margin-left: 2px;\n}\n\n.wa-users > a > img {\n  width: 33px;\n  height: 33px;\n  border-radius: 50%;\n}\n\n.wa-users > a > img:hover {\n  opacity: 0.85;\n  filter: alpha(opacity=85);\n}\n\n.wcc-inner {\n  border: 1px solid #E4E4E4;\n  padding: 10px 15px;\n  resize: none;\n  border-radius: 2px;\n  background: #fff;\n  color: #9A9A9A;\n  cursor: pointer;\n}\n\n.wcci-text {\n  border: 0;\n  display: block;\n  width: 100%;\n  resize: none;\n  padding: 0;\n}\n\n.wall-comment-list {\n  padding: 20px;\n  background: #f7f7f7;\n}\n\n.wall-comment-list .media {\n  position: relative;\n}\n\n.wall-comment-list .media:hover .actions {\n  display: block;\n}\n\n.wall-comment-list .actions {\n  display: none;\n  position: absolute;\n  right: -20px;\n  top: -1px;\n}\n\n.wcl-list + .wcl-form {\n  margin-top: 25px;\n}\n\n.wp-text {\n  border: 0;\n  padding: 0;\n  display: block;\n  width: 100%;\n  resize: none;\n}\n\n.wp-media {\n  background: #f7f7f7;\n  border: 1px solid #E4E4E4;\n  padding: 12px 15px;\n  margin-top: 25px;\n  text-align: center;\n}\n\n.wpb-actions {\n  background: #f7f7f7;\n  margin: 0;\n  padding: 10px 20px;\n}\n\n.wpb-actions > li:not(.pull-right) {\n  float: left;\n}\n\n[data-wpba=\"image\"] {\n  color: #4caf50;\n}\n\n[data-wpba=\"image\"]:hover {\n  color: #449d48;\n}\n\n[data-wpba=\"video\"] {\n  color: #ff9800;\n}\n\n[data-wpba=\"video\"]:hover {\n  color: #e68900;\n}\n\n[data-wpba=\"link\"] {\n  color: #00bcd4;\n}\n\n[data-wpba=\"link\"]:hover {\n  color: #00a5bb;\n}\n\n.wpba-attrs > ul > li {\n  padding: 0;\n  margin-right: 5px;\n}\n\n.wpba-attrs > ul > li > a {\n  display: block;\n  width: 22px;\n}\n\n.wpba-attrs > ul > li > a > i {\n  font-size: 20px;\n}\n\n.wpba-attrs > ul > li.active i {\n  color: #333;\n}\n\n.wall-img-preview {\n  text-align: center;\n}\n\n@media screen and (min-width: 768px) {\n  .wall-img-preview {\n    margin: 0 -23px 20px;\n  }\n}\n\n@media screen and (max-width: 991px) {\n  .wall-img-preview {\n    margin: 0 -16px 20px;\n  }\n}\n\n.wall-img-preview .wip-item {\n  display: block;\n  float: left;\n  position: relative;\n  overflow: hidden;\n  border: 2px solid #fff;\n  background-repeat: no-repeat;\n  -webkit-background-size: cover;\n  -moz-background-size: cover;\n  -o-background-size: cover;\n  background-size: cover;\n  background-position: center;\n}\n\n.wall-img-preview .wip-item > img {\n  display: none;\n}\n\n.wall-img-preview .wip-item:first-child:nth-last-child(2),\n.wall-img-preview .wip-item:first-child:nth-last-child(2) ~ div {\n  width: 50%;\n  padding-bottom: 40%;\n}\n\n.wall-img-preview .wip-item:first-child:nth-last-child(3),\n.wall-img-preview .wip-item:first-child:nth-last-child(3) ~ div,\n.wall-img-preview .wip-item:first-child:nth-last-child(4),\n.wall-img-preview .wip-item:first-child:nth-last-child(4) ~ div:not(:last-child),\n.wall-img-preview .wip-item:first-child:nth-last-child(5),\n.wall-img-preview .wip-item:first-child:nth-last-child(5) ~ div:not( :nth-last-of-type(-n+2)),\n.wall-img-preview .wip-item:first-child:nth-last-child(6),\n.wall-img-preview .wip-item:first-child:nth-last-child(6) ~ div,\n.wall-img-preview .wip-item:first-child:nth-last-child(7) ~ div:nth-last-of-type(-n+3) {\n  width: 33.333333%;\n  padding-bottom: 30%;\n}\n\n.wall-img-preview .wip-item:first-child:nth-last-child(5) ~ div:nth-last-of-type(-n+2) {\n  width: 50%;\n  padding-bottom: 40%;\n}\n\n.wall-img-preview .wip-item:first-child:nth-last-child(7),\n.wall-img-preview .wip-item:first-child:nth-last-child(7) ~ div:not( :nth-last-of-type(-n+3)),\n.wall-img-preview .wip-item:first-child:nth-last-child(n+8),\n.wall-img-preview .wip-item:first-child:nth-last-child(n+8) ~ div {\n  width: 25%;\n  padding-bottom: 22%;\n}\n\n.wall-img-preview .wip-item:only-child,\n.wall-img-preview .wip-item:first-child:nth-last-child(4) ~ div:nth-child(4) {\n  width: 100%;\n  padding-bottom: 50%;\n}\n\n/*\n * For header type 1 only\n * You may remove these if you opt header 2\n */\n\n#header .skin-switch {\n  padding: 10px 0 2px;\n  text-align: center;\n}\n\n#header .ss-skin {\n  width: 16px;\n  height: 16px;\n  border-radius: 50%;\n  cursor: pointer;\n  display: inline-block;\n  margin: 2px 3px;\n}\n\n/* ----------------------------- End header type 1 ------------------------------------- */\n\n/*\n * For header type 2 only\n * You may remove these if you opt header 1\n */\n\n#header-2 .skin-switch {\n  position: absolute;\n  right: 50px;\n  bottom: 23px;\n  z-index: 1;\n}\n\n#header-2 .skin-switch .btn {\n  background: #fff;\n  width: 50px;\n  height: 50px;\n  border-radius: 50%;\n  font-size: 25px;\n  z-index: 2;\n}\n\n#header-2 .skin-switch .dropdown-menu {\n  min-width: 130px;\n  height: 130px;\n  border-radius: 50%;\n  width: 130px;\n  top: -42px;\n  left: -40px;\n  z-index: 1;\n  -webkit-transform-origin: center;\n  -moz-transform-origin: center;\n  -ms-transform-origin: center;\n  transform-origin: center;\n  -webkit-transform: scale(0) rotate(-360deg);\n  -ms-transform: scale(0) rotate(-360deg);\n  -o-transform: scale(0) rotate(-360deg);\n  transform: scale(0) rotate(-360deg);\n  -webkit-transition-duration: 500ms;\n  transition-duration: 500ms;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin {\n  position: absolute;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-1 {\n  margin-left: -8px;\n  top: 12px;\n  left: 50%;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-2 {\n  right: 24px;\n  top: 26px;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-3 {\n  top: 50%;\n  margin-top: -8px;\n  right: 12px;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-4 {\n  right: 24px;\n  bottom: 26px;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-5 {\n  margin-left: -8px;\n  bottom: 12px;\n  left: 50%;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-6 {\n  left: 24px;\n  bottom: 26px;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-7 {\n  top: 50%;\n  margin-top: -8px;\n  left: 12px;\n}\n\n#header-2 .skin-switch .dropdown-menu .ss-skin.ss-8 {\n  left: 24px;\n  top: 26px;\n}\n\n#header-2 .skin-switch.open .dropdown-menu {\n  -webkit-transform: scale(1) rotate(0deg);\n  -ms-transform: scale(1) rotate(0deg);\n  -o-transform: scale(1) rotate(0deg);\n  transform: scale(1) rotate(0deg);\n}\n\n/* ----------------------------- End header type 2 ------------------------------------- */\n\n/*\n * Do not remove these\n * This is common for both\n */\n\n.ss-skin {\n  width: 16px;\n  height: 16px;\n  border-radius: 50%;\n  cursor: pointer;\n}\n\n.ss-skin:hover {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n[data-current-skin=\"lightblue\"] {\n  background-color: #03a9f4;\n}\n\n[data-current-skin=\"lightblue\"] .ss-icon {\n  color: #03a9f4;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"lightblue\"] .ha-menu {\n    background: #03a9f4;\n  }\n}\n\n[data-current-skin=\"bluegray\"] {\n  background-color: #607d8b;\n}\n\n[data-current-skin=\"bluegray\"] .ss-icon {\n  color: #607d8b;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"bluegray\"] .ha-menu {\n    background: #607d8b;\n  }\n}\n\n[data-current-skin=\"blue\"] {\n  background-color: #2196f3;\n}\n\n[data-current-skin=\"blue\"] .ss-icon {\n  color: #2196f3;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"blue\"] .ha-menu {\n    background: #2196f3;\n  }\n}\n\n[data-current-skin=\"purple\"] {\n  background-color: #9c27b0;\n}\n\n[data-current-skin=\"purple\"] .ss-icon {\n  color: #9c27b0;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"purple\"] .ha-menu {\n    background: #9c27b0;\n  }\n}\n\n[data-current-skin=\"orange\"] {\n  background-color: #ff9800;\n}\n\n[data-current-skin=\"orange\"] .ss-icon {\n  color: #ff9800;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"orange\"] .ha-menu {\n    background: #ff9800;\n  }\n}\n\n[data-current-skin=\"cyan\"] {\n  background-color: #00bcd4;\n}\n\n[data-current-skin=\"cyan\"] .ss-icon {\n  color: #00bcd4;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"cyan\"] .ha-menu {\n    background: #00bcd4;\n  }\n}\n\n[data-current-skin=\"green\"] {\n  background-color: #4caf50;\n}\n\n[data-current-skin=\"green\"] .ss-icon {\n  color: #4caf50;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"green\"] .ha-menu {\n    background: #4caf50;\n  }\n}\n\n[data-current-skin=\"teal\"] {\n  background-color: #009688;\n}\n\n[data-current-skin=\"teal\"] .ss-icon {\n  color: #009688;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"teal\"] .ha-menu {\n    background: #009688;\n  }\n}\n\n[data-current-skin=\"pink\"] {\n  background-color: #e91e63;\n}\n\n[data-current-skin=\"pink\"] .ss-icon {\n  color: #e91e63;\n}\n\n@media (max-width: 767px) {\n  [data-current-skin=\"pink\"] .ha-menu {\n    background: #e91e63;\n  }\n}\n\n.preloader {\n  position: relative;\n  margin: 0px auto;\n  display: inline-block;\n}\n\n.preloader:not([class*=\"pl-\"]) {\n  width: 40px;\n}\n\n.preloader:before {\n  content: '';\n  display: block;\n  padding-top: 100%;\n}\n\n.preloader.pl-xs {\n  width: 20px;\n}\n\n.preloader.pl-sm {\n  width: 30px;\n}\n\n.preloader.pl-lg {\n  width: 50px;\n}\n\n.preloader.pl-xl {\n  width: 80px;\n}\n\n.preloader.pl-xxl {\n  width: 100px;\n}\n\n.preloader:not([class*=\"pls-\"]) .plc-path {\n  animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;\n}\n\n.preloader[class*=\"pls-\"] .plc-path {\n  animation: dash 1.5s ease-in-out infinite;\n}\n\n.preloader.pls-red .plc-path {\n  stroke: #f44336;\n}\n\n.preloader.pls-blue .plc-path {\n  stroke: #2196f3;\n}\n\n.preloader.pls-green .plc-path {\n  stroke: #4caf50;\n}\n\n.preloader.pls-yellow .plc-path {\n  stroke: #ffeb3b;\n}\n\n.preloader.pls-bluegray .plc-path {\n  stroke: #607d8b;\n}\n\n.preloader.pls-amber .plc-path {\n  stroke: #ffc107;\n}\n\n.preloader.pls-teal .plc-path {\n  stroke: #009688;\n}\n\n.preloader.pls-gray .plc-path {\n  stroke: #9e9e9e;\n}\n\n.preloader.pls-pink .plc-path {\n  stroke: #e91e63;\n}\n\n.preloader.pls-purple .plc-path {\n  stroke: #9c27b0;\n}\n\n.preloader.pls-white .plc-path {\n  stroke: #fff;\n}\n\n.pl-circular {\n  animation: rotate 2s linear infinite;\n  height: 100%;\n  transform-origin: center center;\n  width: 100%;\n  position: absolute;\n  top: 0;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  margin: auto;\n}\n\n.plc-path {\n  stroke-dasharray: 1,200;\n  stroke-dashoffset: 0;\n  stroke-linecap: round;\n  stroke-width: 2;\n  stroke-miterlimit: 10;\n  fill: none;\n}\n\n@keyframes rotate {\n  100% {\n    transform: rotate(360deg);\n  }\n}\n\n@keyframes dash {\n  0% {\n    stroke-dasharray: 1,200;\n    stroke-dashoffset: 0;\n  }\n\n  50% {\n    stroke-dasharray: 89,200;\n    stroke-dashoffset: -35px;\n  }\n\n  100% {\n    stroke-dasharray: 89,200;\n    stroke-dashoffset: -124px;\n  }\n}\n\n@keyframes color {\n  100%, 0% {\n    stroke: #f44336;\n  }\n\n  40% {\n    stroke: #2196f3;\n  }\n\n  66% {\n    stroke: #4caf50;\n  }\n\n  80%, 90% {\n    stroke: #ffc107;\n  }\n}\n\n@media print {\n@page {\n    margin: 0;\n    size: auto;\n}\n\n  body {\n    margin: 0mm 0mm 0mm 0mm !important;\n    padding: 0mm !important;\n  }\n\n  #header,\n  #footer,\n  #sidebar,\n  #chat,\n  .growl-animated,\n  .m-btn {\n    display: none !important;\n  }\n\n  /*\n     * INVOICE\n     */\n\n  .invoice {\n    padding: 30px !important;\n    -webkit-print-color-adjust: exact !important;\n  }\n\n  .invoice .card-header {\n    background: #eee !important;\n    padding: 20px;\n    margin-bottom: 20px;\n    margin: -60px -30px 25px -30px;\n  }\n\n  .invoice .block-header {\n    display: none;\n  }\n\n  .invoice .highlight {\n    background: #eee !important;\n  }\n}\n\n/*\n * Vendor Overrides\n */\n\n.mejs-container {\n  outline: none;\n}\n\n.mejs-container .mejs-controls {\n  background: #ec592f;\n  height: 50px;\n  padding: 10px 5px 0;\n}\n\n.mejs-container .mejs-controls div {\n  height: 5px;\n}\n\n.mejs-container .mejs-controls div.mejs-time-rail {\n  position: absolute;\n  left: 0;\n  top: 0;\n  padding: 0;\n  width: 100% !important;\n}\n\n.mejs-container .mejs-controls div.mejs-time-rail .mejs-time-total {\n  margin: 0;\n  width: 100% !important;\n  background: #ec592f;\n}\n\n.mejs-container .mejs-controls div.mejs-time-rail .mejs-time-loaded {\n  background: #D04B25;\n}\n\n.mejs-container .mejs-controls div.mejs-time-rail .mejs-time-current {\n  background: #ffea00;\n}\n\n.mejs-container .mejs-controls div.mejs-time-rail .mejs-time-buffering {\n  background: #ec592f;\n}\n\n.mejs-container .mejs-controls div.mejs-time-rail span:not(.mejs-time-float),\n.mejs-container .mejs-controls div.mejs-time-rail a {\n  border-radius: 0;\n  height: 3px;\n}\n\n.mejs-container .mejs-controls .mejs-button button {\n  background-color: #ec592f;\n  width: 15px;\n  height: 15px;\n  background-position: center;\n}\n\n.mejs-container .mejs-controls .mejs-button button:focus {\n  outline: none !important;\n}\n\n.mejs-container .mejs-controls .mejs-volume-button {\n  position: absolute;\n  right: 35px;\n}\n\n.mejs-container .mejs-controls .mejs-play button {\n  background-image: url(\"../img/icons/play.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-play button {\n    background-image: url(\"../img/icons/play@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n\n.mejs-container .mejs-controls .mejs-pause button {\n  background-image: url(\"../img/icons/pause.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-pause button {\n    background-image: url(\"../img/icons/pause@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n\n.mejs-container .mejs-controls .mejs-mute button {\n  background-image: url(\"../img/icons/speaker.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-mute button {\n    background-image: url(\"../img/icons/speaker@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n\n.mejs-container .mejs-controls .mejs-unmute button {\n  background-image: url(\"../img/icons/speaker-2.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-unmute button {\n    background-image: url(\"../img/icons/speaker-2@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n\n.mejs-container .mejs-controls .mejs-fullscreen-button {\n  position: absolute;\n  right: 5px;\n}\n\n.mejs-container .mejs-controls .mejs-fullscreen-button button {\n  background-image: url(\"../img/icons/fullscreen.png\");\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .mejs-container .mejs-controls .mejs-fullscreen-button button {\n    background-image: url(\"../img/icons/fullscreen@2x.png\");\n    background-size: 15px 15px;\n  }\n}\n\n/** CALENDAR WIDGET **/\n\n#calendar-widget {\n  margin-bottom: 30px;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n}\n\n#fc-actions {\n  position: absolute;\n  bottom: 10px;\n  right: 12px;\n}\n\n.fc {\n  background-color: #fff;\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n  margin-bottom: 30px;\n}\n\n.fc td,\n.fc th {\n  border-color: #f0f0f0;\n}\n\n.fc th {\n  font-weight: 400;\n}\n\n.fc table {\n  background: transparent;\n}\n\n.fc table tr > td:first-child {\n  border-left-width: 0;\n}\n\n#calendar-widget .fc-toolbar {\n  background: #009688;\n}\n\n#calendar-widget .fc-day-header {\n  color: #fff;\n  background: #007d71;\n  padding: 5px 0;\n  border-width: 0;\n}\n\n#calendar-widget .fc-day-number {\n  text-align: center;\n  color: #ADADAD;\n  padding: 5px 0;\n}\n\n#calendar-widget .fc-day-grid-event {\n  margin: 1px 3px 1px;\n}\n\n#calendar-widget .ui-widget-header th,\n#calendar-widget .ui-widget-header {\n  border-width: 0;\n}\n\n#calendar .fc-toolbar {\n  height: 300px;\n  background-image: url('../img/cal-header.jpg');\n  background-repeat: no-repeat;\n  -webkit-background-size: cover;\n  -moz-background-size: cover;\n  -o-background-size: cover;\n  background-size: cover;\n  background-position: center;\n  background-position: inherit;\n}\n\n#calendar .fc-toolbar:before {\n  content: \"\";\n  height: 50px;\n  width: 100%;\n  background: rgba(0, 0, 0, 0.36);\n  position: absolute;\n  bottom: 0;\n  left: 0;\n}\n\n#calendar .fc-toolbar .fc-center {\n  margin-top: 238px;\n  position: relative;\n}\n\n@media screen and (max-width: 991px) {\n  #calendar .fc-toolbar {\n    height: 200px;\n  }\n\n  #calendar .fc-toolbar .fc-center {\n    margin-top: 138px;\n  }\n}\n\n#calendar .fc-day-header {\n  color: #ADADAD;\n  text-align: left;\n  font-size: 14px;\n  border-bottom-width: 0;\n  border-right-color: #eee;\n  padding: 10px 12px;\n}\n\n#calendar .fc-day-number {\n  padding-left: 10px !important;\n  color: #CCC;\n  text-align: left !important;\n}\n\n@media screen and (min-width: 991px) {\n  #calendar .fc-day-number {\n    font-size: 25px;\n    letter-spacing: -2px;\n  }\n}\n\n#calendar .fc-day-grid-event {\n  margin: 1px 9px 0;\n}\n\n.fc-today {\n  color: #ffc107;\n}\n\n.fc-toolbar {\n  margin-bottom: 0;\n  padding: 20px 7px 19px;\n  position: relative;\n}\n\n.fc-toolbar h2 {\n  margin-top: 7px;\n  font-size: 20px;\n  font-weight: 400;\n  text-transform: uppercase;\n  color: #fff;\n}\n\n.fc-toolbar .ui-button {\n  border: 0;\n  background: 0 0;\n  padding: 0;\n  outline: none !important;\n  text-align: center;\n  width: 30px;\n  height: 30px;\n  border-radius: 50%;\n  margin-top: 2px;\n  color: #fff;\n}\n\n.fc-toolbar .ui-button:hover {\n  background: #fff;\n  color: #009688;\n}\n\n.fc-toolbar .ui-button > span {\n  position: relative;\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 20px;\n  line-height: 100%;\n  width: 30px;\n  display: block;\n  margin-top: 2px;\n}\n\n.fc-toolbar .ui-button > span:before {\n  position: relative;\n  z-index: 1;\n}\n\n.fc-toolbar .ui-button > span.ui-icon-circle-triangle-w:before {\n  content: \"\\f2fa\";\n}\n\n.fc-toolbar .ui-button > span.ui-icon-circle-triangle-e:before {\n  content: \"\\f2fb\";\n}\n\n.fc-event {\n  padding: 0;\n  font-size: 11px;\n  border-radius: 0;\n  border: 0;\n}\n\n.fc-event .fc-title {\n  padding: 2px 8px;\n  display: block;\n}\n\n.fc-event .fc-time {\n  float: left;\n  background: rgba(0, 0, 0, 0.2);\n  padding: 2px 6px;\n  margin: 0 0 0 -1px;\n}\n\n.fc-view,\n.fc-view > table {\n  border: 0;\n  overflow: hidden;\n}\n\n.fc-view > table > tbody > tr > .ui-widget-content {\n  border-top: 0;\n}\n\ndiv.fc-row {\n  margin-right: 0 !important;\n  border: 0 !important;\n}\n\n.fc-today {\n  color: #ffc107 !important;\n}\n\n/* Even Tag Color */\n\n.event-tag {\n  margin-top: 5px;\n}\n\n.event-tag > span {\n  border-radius: 50%;\n  width: 30px;\n  height: 30px;\n  margin-right: 3px;\n  position: relative;\n  display: inline-block;\n  cursor: pointer;\n}\n\n.event-tag > span:hover {\n  opacity: 0.8;\n  filter: alpha(opacity=80);\n}\n\n.event-tag > span.selected:before {\n  font-family: 'Material-Design-Iconic-Font';\n  content: \"\\f26b\";\n  position: absolute;\n  text-align: center;\n  top: 3px;\n  width: 100%;\n  font-size: 17px;\n  color: #FFF;\n}\n\nhr.fc-divider {\n  border-width: 1px;\n  border-color: #eee;\n}\n\n.fc-day-grid-container.fc-scroller {\n  height: auto !important;\n  overflow: hidden !important;\n}\n\n.bootgrid-footer .infoBar,\n.bootgrid-header .actionBar {\n  text-align: left;\n}\n\n.bootgrid-footer .search,\n.bootgrid-header .search {\n  vertical-align: top;\n}\n\n.bootgrid-header {\n  padding: 0 25px 10px;\n}\n\n.bootgrid-header .search {\n  border: 1px solid #e0e0e0;\n}\n\n.bootgrid-header .search .form-control,\n.bootgrid-header .search .input-group-addon {\n  border: 0;\n}\n\n.bootgrid-header .search .glyphicon-search {\n  vertical-align: top;\n  padding: 9px 10px 0;\n}\n\n.bootgrid-header .search .glyphicon-search:before {\n  content: \"\\f1c3\";\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 17px;\n  vertical-align: top;\n  line-height: 100%;\n}\n\n@media (min-width: 480px) {\n  .bootgrid-header .search {\n    width: 300px;\n  }\n}\n\n@media (max-width: 480px) {\n  .bootgrid-header .search {\n    width: 100%;\n    padding-right: 90px;\n  }\n}\n\n.bootgrid-header .actions {\n  box-shadow: none;\n}\n\n.bootgrid-header .actions .btn-group {\n  border: 1px solid #e0e0e0;\n}\n\n.bootgrid-header .actions .btn-group .btn {\n  height: 35px;\n  box-shadow: none !important;\n  background: transparent;\n}\n\n.bootgrid-header .actions .btn-group .dropdown-menu {\n  padding: 10px 20px;\n}\n\n.bootgrid-header .actions .btn-group .dropdown-menu .dropdown-item {\n  padding: 0 0 0 27px !important;\n}\n\n.bootgrid-header .actions .btn-group .dropdown-menu .dropdown-item:hover {\n  background-color: #fff !important;\n}\n\n@media (min-width: 768px) {\n  .bootgrid-header .actions .btn-group .dropdown-menu {\n    left: 0;\n    -webkit-transform-origin: top left;\n    -moz-transform-origin: top left;\n    -ms-transform-origin: top left;\n    transform-origin: top left;\n    margin-top: 1px;\n  }\n}\n\n.bootgrid-header .actions .btn-group .caret {\n  display: none;\n}\n\n.bootgrid-header .actions .btn-group .zmdi {\n  line-height: 100%;\n  font-size: 18px;\n  vertical-align: top;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n\n.bootgrid-header .actions .btn-group.open .zmdi {\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  -o-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n\n@media (max-width: 480px) {\n  .bootgrid-header .actions {\n    position: absolute;\n    top: 0;\n    right: 15px;\n  }\n}\n\n.bootgrid-table th > .column-header-anchor > .icon {\n  top: 0px;\n  font-size: 20px;\n  line-height: 100%;\n}\n\n.bootgrid-footer .col-sm-6 {\n  padding: 10px 30px 20px;\n}\n\n@media (max-width: 768px) {\n  .bootgrid-footer .col-sm-6 {\n    text-align: center;\n  }\n}\n\n@media (max-width: 768px) {\n  .bootgrid-footer .infoBar {\n    display: none;\n  }\n}\n\n.bootgrid-footer .infoBar .infos {\n  border: 1px solid #EEE;\n  display: inline-block;\n  float: right;\n  padding: 7px 30px;\n  font-size: 12px;\n  margin-top: 5px;\n}\n\n.select-cell .checkbox {\n  margin: 0;\n}\n\n.command-edit,\n.command-delete {\n  background: #fff;\n}\n\n.bootstrap-select .dropdown-menu {\n  padding: 0;\n}\n\n.bootstrap-select .dropdown-toggle:focus {\n  outline: none !important;\n}\n\n.bootstrap-select > .btn-default {\n  background: none !important;\n  border-bottom: 1px solid #e0e0e0 !important;\n  border-radius: 0;\n  padding-left: 0;\n  padding-right: 0;\n}\n\n.bootstrap-select > .btn-default:before {\n  position: absolute;\n  top: 0;\n  right: 0;\n  content: \"\";\n  height: calc(100% - 2px);\n  width: 30px;\n  background-color: #FFF;\n  background-position: right calc(100% - 7px);\n  background-repeat: no-repeat;\n  background-image: url(\"../img/select.png\");\n  pointer-events: none;\n  z-index: 5;\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .bootstrap-select > .btn-default:before {\n    background-image: url(\"../img/select@2x.png\");\n    background-size: 12px 12px;\n  }\n}\n\n.bootstrap-select > .btn-default:after {\n  position: absolute;\n  z-index: 3;\n  bottom: -1px;\n  left: 0;\n  height: 2px;\n  width: 0;\n  content: \"\";\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.bootstrap-select > .btn-default:not(.disabled):after,\n.bootstrap-select > .btn-default:not(.readonly):after {\n  background: #2196f3;\n}\n\n.bootstrap-select > .btn-default.disabled:after,\n.bootstrap-select > .btn-default.readonly:after {\n  background: #ccc;\n}\n\n.bootstrap-select.open > .btn-default:after {\n  width: 100%;\n}\n\n.bootstrap-select .bs-searchbox {\n  padding: 5px 5px 5px 40px;\n  position: relative;\n  background: #f7f7f7;\n}\n\n.bootstrap-select .bs-searchbox:before {\n  position: absolute;\n  left: 0;\n  top: 0;\n  width: 40px;\n  height: 100%;\n  content: \"\\f1c3\";\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 25px;\n  padding: 4px 0 0 15px;\n}\n\n.bootstrap-select .bs-searchbox input {\n  border: 0;\n  background: transparent;\n}\n\n.bootstrap-select.btn-group .dropdown-menu li a.opt {\n  padding-left: 17px;\n}\n\n.bootstrap-select .check-mark {\n  margin-top: -5px !important;\n  font-size: 19px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  display: block !important;\n  position: absolute;\n  top: 11px;\n  right: 15px;\n}\n\n.bootstrap-select .check-mark:before {\n  content: \"\\f26b\";\n  font-family: 'Material-Design-Iconic-Font';\n}\n\n.bootstrap-select .selected .check-mark {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n}\n\n.bootstrap-select .notify {\n  bottom: 0 !important;\n  margin: 0 !important;\n  width: 100% !important;\n  border: 0 !important;\n  background: #f44336 !important;\n  color: #fff !important;\n  text-align: center;\n}\n\n.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {\n  width: 100%;\n}\n\n.chosen-container .chosen-drop {\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  margin-top: 1px;\n  border: 0;\n  left: 0;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transform-origin: top left;\n  -moz-transform-origin: top left;\n  -ms-transform-origin: top left;\n  transform-origin: top left;\n  -webkit-transition: transform opacity;\n  -o-transition: transform opacity;\n  transition: transform opacity;\n  -webkit-transition-duration: 250ms;\n  transition-duration: 250ms;\n}\n\n.chosen-container.chosen-with-drop .chosen-drop {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.chosen-container.chosen-with-drop .chosen-single:after {\n  width: 100%;\n}\n\n.chosen-container .chosen-results {\n  margin: 0;\n  padding: 0;\n  max-height: 300px;\n}\n\n.chosen-container .chosen-results li {\n  padding: 10px 17px;\n  width: 100%;\n}\n\n.chosen-container .chosen-results li.highlighted {\n  background: rgba(0, 0, 0, 0.075);\n  color: #333333;\n}\n\n.chosen-container .chosen-results li.result-selected {\n  background: transparent;\n  color: #5e5e5e;\n  position: relative;\n}\n\n.chosen-container .chosen-results li.result-selected:before {\n  content: \"\\f26b\";\n  font-family: 'Material-Design-Iconic-Font';\n  position: absolute;\n  right: 15px;\n  top: 10px;\n  font-size: 19px;\n}\n\n.chosen-container .chosen-results li.group-result {\n  color: #B2B2B2;\n  font-weight: normal;\n  padding: 16px 15px 6px;\n  margin-top: 9px;\n}\n\n.chosen-container .chosen-results li.group-result:not(:first-child) {\n  border-top: 1px solid #eee;\n}\n\n.chosen-container-single .chosen-single {\n  border-radius: 0;\n  overflow: visible;\n  height: 34px;\n  padding: 6px 0 6px;\n  text-transform: uppercase;\n  border: 0;\n  border-bottom: 1px solid #e0e0e0;\n  background: none;\n  box-shadow: none;\n}\n\n.chosen-container-single .chosen-single:after {\n  content: \"\";\n  width: 0;\n  background: #2196f3;\n  height: 2px;\n  position: absolute;\n  left: 0;\n  bottom: -1px;\n  -webkit-transition: width;\n  -o-transition: width;\n  transition: width;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n}\n\n.chosen-container-single .chosen-single div b {\n  background-image: url(\"../img/select.png\");\n  background-repeat: no-repeat;\n  background-position: right 12px;\n}\n\n@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {\n  .chosen-container-single .chosen-single div b {\n    background-image: url(\"../img/select@2x.png\");\n    background-size: 12px 12px;\n  }\n}\n\n.chosen-container-single .chosen-search {\n  padding: 5px 5px 5px 40px;\n  background: #f7f7f7;\n}\n\n.chosen-container-single .chosen-search:before {\n  content: \"\\f1c3\";\n  font-family: 'Material-Design-Iconic-Font';\n  position: absolute;\n  left: 0;\n  top: 0;\n  width: 40px;\n  height: 100%;\n  font-size: 25px;\n  padding: 5px 0 0 15px;\n}\n\n.chosen-container-single .chosen-search input[type=text] {\n  border: 0;\n  height: 35px;\n  line-height: 1.42857143;\n  background: none;\n}\n\n.chosen-container-active.chosen-with-drop .chosen-single {\n  border: 0;\n  background: none;\n}\n\n.chosen-container-multi .chosen-choices {\n  padding: 0;\n  border: 0;\n  border-bottom: 1px solid #e0e0e0;\n  background: none;\n  box-shadow: none;\n}\n\n.chosen-container-multi .chosen-choices li.search-choice {\n  border-radius: 2px;\n  margin: 4px 4px 0 0;\n  background: #eaeaea;\n  padding: 5px 23px 5px 8px;\n  border: 0;\n  box-shadow: none;\n}\n\n.chosen-container-multi .chosen-choices li.search-choice .search-choice-close {\n  background-image: none;\n}\n\n.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:before {\n  display: inline-block;\n  font-family: 'Material-Design-Iconic-Font';\n  content: \"\\f135\";\n  position: relative;\n  top: 1px;\n  color: #9C9C9C;\n  z-index: 2;\n  font-size: 12px;\n}\n\n.chosen-container-multi .chosen-choices li.search-field input[type=text] {\n  padding: 0;\n  height: 31px;\n}\n\nselect.chosen {\n  display: none;\n}\n\n.noUi-target {\n  border-radius: 0;\n  box-shadow: none;\n  border: 0;\n}\n\n.noUi-background {\n  background: #d4d4d4;\n  box-shadow: none;\n}\n\n.noUi-horizontal {\n  height: 3px;\n}\n\n.noUi-horizontal .noUi-handle {\n  top: -8px;\n}\n\n.noUi-vertical {\n  width: 3px;\n}\n\n.noUi-horizontal .noUi-handle,\n.noUi-vertical .noUi-handle {\n  width: 19px;\n  height: 19px;\n  border: 0;\n  border-radius: 100%;\n  box-shadow: none;\n  -webkit-transition: box-shadow;\n  -o-transition: box-shadow;\n  transition: box-shadow;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  cursor: pointer;\n  position: relative;\n}\n\n.noUi-horizontal .noUi-handle:before,\n.noUi-vertical .noUi-handle:before,\n.noUi-horizontal .noUi-handle:after,\n.noUi-vertical .noUi-handle:after {\n  display: none;\n}\n\n.noUi-horizontal .noUi-handle:active,\n.noUi-vertical .noUi-handle:active {\n  background: #ccc !important;\n}\n\n.noUi-horizontal .noUi-handle .is-tooltip,\n.noUi-vertical .noUi-handle .is-tooltip {\n  position: absolute;\n  bottom: 32px;\n  height: 35px;\n  border-radius: 2px;\n  color: #fff;\n  text-align: center;\n  line-height: 33px;\n  width: 50px;\n  left: 50%;\n  margin-left: -25px;\n  padding: 0 10px;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 200ms;\n  transition-duration: 200ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n}\n\n.noUi-horizontal .noUi-handle .is-tooltip:after,\n.noUi-vertical .noUi-handle .is-tooltip:after {\n  width: 0;\n  height: 0;\n  border-style: solid;\n  border-width: 15px 10px 0 10px;\n  position: absolute;\n  bottom: -8px;\n  left: 50%;\n  margin-left: -9px;\n  content: \"\";\n}\n\n.noUi-horizontal .noUi-active,\n.noUi-vertical .noUi-active {\n  box-shadow: 0 0 0 13px rgba(0, 0, 0, 0.1);\n}\n\n.noUi-horizontal .noUi-active .is-tooltip,\n.noUi-vertical .noUi-active .is-tooltip {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  bottom: 40px;\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.input-slider:not([data-is-color]) .noUi-handle,\n.input-slider-range:not([data-is-color]) .noUi-handle,\n.input-slider-values:not([data-is-color]) .noUi-handle,\n.input-slider:not([data-is-color]) .noUi-connect,\n.input-slider-range:not([data-is-color]) .noUi-connect,\n.input-slider-values:not([data-is-color]) .noUi-connect {\n  background: #009688 !important;\n}\n\n.input-slider:not([data-is-color]) .is-tooltip,\n.input-slider-range:not([data-is-color]) .is-tooltip,\n.input-slider-values:not([data-is-color]) .is-tooltip {\n  background: #009688;\n}\n\n.input-slider:not([data-is-color]) .is-tooltip:after,\n.input-slider-range:not([data-is-color]) .is-tooltip:after,\n.input-slider-values:not([data-is-color]) .is-tooltip:after {\n  border-color: #009688 transparent transparent transparent;\n}\n\n.input-slider[data-is-color=red] .noUi-handle,\n.input-slider-range[data-is-color=red] .noUi-handle,\n.input-slider-values[data-is-color=red] .noUi-handle,\n.input-slider[data-is-color=red] .noUi-connect,\n.input-slider-range[data-is-color=red] .noUi-connect,\n.input-slider-values[data-is-color=red] .noUi-connect {\n  background: #f44336 !important;\n}\n\n.input-slider[data-is-color=blue] .noUi-handle,\n.input-slider-range[data-is-color=blue] .noUi-handle,\n.input-slider-values[data-is-color=blue] .noUi-handle,\n.input-slider[data-is-color=blue] .noUi-connect,\n.input-slider-range[data-is-color=blue] .noUi-connect,\n.input-slider-values[data-is-color=blue] .noUi-connect {\n  background: #2196f3 !important;\n}\n\n.input-slider[data-is-color=cyan] .noUi-handle,\n.input-slider-range[data-is-color=cyan] .noUi-handle,\n.input-slider-values[data-is-color=cyan] .noUi-handle,\n.input-slider[data-is-color=cyan] .noUi-connect,\n.input-slider-range[data-is-color=cyan] .noUi-connect,\n.input-slider-values[data-is-color=cyan] .noUi-connect {\n  background: #00bcd4 !important;\n}\n\n.input-slider[data-is-color=amber] .noUi-handle,\n.input-slider-range[data-is-color=amber] .noUi-handle,\n.input-slider-values[data-is-color=amber] .noUi-handle,\n.input-slider[data-is-color=amber] .noUi-connect,\n.input-slider-range[data-is-color=amber] .noUi-connect,\n.input-slider-values[data-is-color=amber] .noUi-connect {\n  background: #ffc107 !important;\n}\n\n.input-slider[data-is-color=green] .noUi-handle,\n.input-slider-range[data-is-color=green] .noUi-handle,\n.input-slider-values[data-is-color=green] .noUi-handle,\n.input-slider[data-is-color=green] .noUi-connect,\n.input-slider-range[data-is-color=green] .noUi-connect,\n.input-slider-values[data-is-color=green] .noUi-connect {\n  background: #4caf50 !important;\n}\n\n.input-slider .noUi-origin {\n  background: #d4d4d4;\n}\n\n.input-slider:not([data-is-color]) .noUi-base {\n  background: #009688 !important;\n}\n\n.input-slider[data-is-color=red] .noUi-base {\n  background: #f44336 !important;\n}\n\n.input-slider[data-is-color=blue] .noUi-base {\n  background: #2196f3 !important;\n}\n\n.input-slider[data-is-color=cyan] .noUi-base {\n  background: #00bcd4 !important;\n}\n\n.input-slider[data-is-color=amber] .noUi-base {\n  background: #ffc107 !important;\n}\n\n.input-slider[data-is-color=green] .noUi-base {\n  background: #4caf50 !important;\n}\n\n.cp-container {\n  position: relative;\n}\n\n.cp-container > .input-group input.cp-value {\n  color: #000 !important;\n  background: transparent !important;\n}\n\n.cp-container > .input-group .dropdown-menu {\n  padding: 20px;\n  margin-left: 10px;\n}\n\n.cp-container i.cp-value {\n  width: 25px;\n  height: 25px;\n  border-radius: 2px;\n  position: absolute;\n  top: 0;\n  right: 15px;\n}\n\n.note-editor .note-toolbar,\n.note-popover .note-toolbar,\n.note-editor .popover-content,\n.note-popover .popover-content {\n  background: #fff;\n  border-color: #e4e4e4;\n  margin: 0;\n  padding: 10px 0 15px;\n  text-align: center;\n}\n\n.note-editor .note-toolbar > .btn-group,\n.note-popover .note-toolbar > .btn-group,\n.note-editor .popover-content > .btn-group,\n.note-popover .popover-content > .btn-group {\n  display: inline-block;\n  float: none;\n  box-shadow: none;\n}\n\n.note-editor .note-toolbar > .btn-group .btn,\n.note-popover .note-toolbar > .btn-group .btn,\n.note-editor .popover-content > .btn-group .btn,\n.note-popover .popover-content > .btn-group .btn {\n  margin: 0 1px;\n}\n\n.note-editor .note-toolbar > .btn-group > .active,\n.note-popover .note-toolbar > .btn-group > .active,\n.note-editor .popover-content > .btn-group > .active,\n.note-popover .popover-content > .btn-group > .active {\n  background: #00bcd4;\n  color: #fff;\n}\n\n.note-editor .note-toolbar .btn,\n.note-popover .note-toolbar .btn,\n.note-editor .popover-content .btn,\n.note-popover .popover-content .btn {\n  height: 40px;\n  border-radius: 2px !important;\n  box-shadow: none !important;\n}\n\n.note-editor .note-toolbar .btn:active,\n.note-popover .note-toolbar .btn:active,\n.note-editor .popover-content .btn:active,\n.note-popover .popover-content .btn:active {\n  box-shadow: none;\n}\n\n.note-editor .note-toolbar .note-palette-title,\n.note-popover .note-toolbar .note-palette-title,\n.note-editor .popover-content .note-palette-title,\n.note-popover .popover-content .note-palette-title {\n  margin: 0 !important;\n  padding: 10px 0 !important;\n  font-size: 13px !important;\n  text-align: center !important;\n  border: 0 !important;\n}\n\n.note-editor .note-toolbar .note-color-reset,\n.note-popover .note-toolbar .note-color-reset,\n.note-editor .popover-content .note-color-reset,\n.note-popover .popover-content .note-color-reset {\n  padding: 0 0 10px !important;\n  margin: 0 !important;\n  background: none;\n  text-align: center;\n}\n\n.note-editor .note-toolbar .note-color .dropdown-menu,\n.note-popover .note-toolbar .note-color .dropdown-menu,\n.note-editor .popover-content .note-color .dropdown-menu,\n.note-popover .popover-content .note-color .dropdown-menu {\n  min-width: 335px;\n}\n\n.note-editor .note-statusbar .note-resizebar,\n.note-popover .note-statusbar .note-resizebar {\n  border-color: #E8E8E8;\n}\n\n.note-editor .note-statusbar .note-resizebar .note-icon-bar,\n.note-popover .note-statusbar .note-resizebar .note-icon-bar {\n  border-color: #BCBCBC;\n}\n\n.note-editor .fa,\n.note-popover .fa {\n  font-style: normal;\n  font-size: 20px;\n  vertical-align: middle;\n}\n\n.note-editor .fa:before,\n.note-popover .fa:before {\n  font-family: 'Material-Design-Iconic-Font';\n}\n\n.note-editor .fa.fa-magic:before,\n.note-popover .fa.fa-magic:before {\n  content: \"\\f16a\";\n}\n\n.note-editor .fa.fa-bold:before,\n.note-popover .fa.fa-bold:before {\n  content: \"\\f23d\";\n}\n\n.note-editor .fa.fa-italic:before,\n.note-popover .fa.fa-italic:before {\n  content: \"\\f245\";\n}\n\n.note-editor .fa.fa-underline:before,\n.note-popover .fa.fa-underline:before {\n  content: \"\\f24f\";\n}\n\n.note-editor .fa.fa-font:before,\n.note-popover .fa.fa-font:before {\n  content: \"\\f242\";\n}\n\n.note-editor .fa.fa-list-ul:before,\n.note-popover .fa.fa-list-ul:before {\n  content: \"\\f247\";\n}\n\n.note-editor .fa.fa-list-ol:before,\n.note-popover .fa.fa-list-ol:before {\n  content: \"\\f248\";\n}\n\n.note-editor .fa.fa-align-left:before,\n.note-popover .fa.fa-align-left:before {\n  content: \"\\f23b\";\n}\n\n.note-editor .fa.fa-align-right:before,\n.note-popover .fa.fa-align-right:before {\n  content: \"\\f23c\";\n}\n\n.note-editor .fa.fa-align-center:before,\n.note-popover .fa.fa-align-center:before {\n  content: \"\\f239\";\n}\n\n.note-editor .fa.fa-align-justify:before,\n.note-popover .fa.fa-align-justify:before {\n  content: \"\\f23a\";\n}\n\n.note-editor .fa.fa-indent:before,\n.note-popover .fa.fa-indent:before {\n  content: \"\\f244\";\n}\n\n.note-editor .fa.fa-outdent:before,\n.note-popover .fa.fa-outdent:before {\n  content: \"\\f243\";\n}\n\n.note-editor .fa.fa-text-height:before,\n.note-popover .fa.fa-text-height:before {\n  content: \"\\f246\";\n}\n\n.note-editor .fa.fa-table:before,\n.note-popover .fa.fa-table:before {\n  content: \"\\f320\";\n}\n\n.note-editor .fa.fa-link:before,\n.note-popover .fa.fa-link:before {\n  content: \"\\f18e\";\n}\n\n.note-editor .fa.fa-picture-o:before,\n.note-popover .fa.fa-picture-o:before {\n  content: \"\\f17f\";\n}\n\n.note-editor .fa.fa-minus:before,\n.note-popover .fa.fa-minus:before {\n  content: \"\\f22f\";\n}\n\n.note-editor .fa.fa-arrows-alt:before,\n.note-popover .fa.fa-arrows-alt:before {\n  content: \"\\f16d\";\n}\n\n.note-editor .fa.fa-code:before,\n.note-popover .fa.fa-code:before {\n  content: \"\\f13a\";\n}\n\n.note-editor .fa.fa-question:before,\n.note-popover .fa.fa-question:before {\n  content: \"\\f1f5\";\n}\n\n.note-editor .fa.fa-eraser:before,\n.note-popover .fa.fa-eraser:before {\n  content: \"\\f23f\";\n}\n\n.note-editor .fa.fa-square:before,\n.note-popover .fa.fa-square:before {\n  content: \"\\f279\";\n}\n\n.note-editor .fa.fa-circle-o:before,\n.note-popover .fa.fa-circle-o:before {\n  content: \"\\f26c\";\n}\n\n.note-editor .fa.fa-times:before,\n.note-popover .fa.fa-times:before {\n  content: \"\\f136\";\n}\n\n.note-editor .note-air-popover .arrow,\n.note-popover .note-air-popover .arrow {\n  left: 20px;\n}\n\n.note-editor {\n  overflow: visible;\n  border: 1px solid #e4e4e4;\n}\n\n.note-editor .note-editable {\n  padding: 20px 23px;\n}\n\n.bootstrap-datetimepicker-widget {\n  padding: 0 !important;\n  margin: 0 !important;\n  width: auto !important;\n}\n\n.bootstrap-datetimepicker-widget:after,\n.bootstrap-datetimepicker-widget:before {\n  display: none !important;\n}\n\n.bootstrap-datetimepicker-widget table td {\n  text-shadow: none;\n}\n\n.bootstrap-datetimepicker-widget table td span {\n  margin: 0;\n}\n\n.bootstrap-datetimepicker-widget table td span:hover {\n  background: transparent;\n}\n\n.bootstrap-datetimepicker-widget .glyphicon {\n  font-family: 'Material-Design-Iconic-Font';\n  font-size: 18px;\n}\n\n.bootstrap-datetimepicker-widget .glyphicon-chevron-left:before {\n  content: \"\\f2ff\";\n}\n\n.bootstrap-datetimepicker-widget .glyphicon-chevron-right:before {\n  content: \"\\f301\";\n}\n\n.bootstrap-datetimepicker-widget .glyphicon-time:before {\n  content: \"\\f337\";\n}\n\n.bootstrap-datetimepicker-widget .glyphicon-calendar:before {\n  content: \"\\f32e\";\n}\n\n.bootstrap-datetimepicker-widget .glyphicon-chevron-up:before {\n  content: \"\\f1e5\";\n}\n\n.bootstrap-datetimepicker-widget .glyphicon-chevron-down:before {\n  content: \"\\f1e4\";\n}\n\n.bootstrap-datetimepicker-widget [data-action=\"togglePicker\"] span {\n  font-size: 25px;\n  color: #ccc;\n}\n\n.bootstrap-datetimepicker-widget [data-action=\"togglePicker\"] span:hover {\n  color: #333;\n}\n\n.bootstrap-datetimepicker-widget a[data-action] {\n  color: #009688;\n}\n\n.timepicker-picker .btn {\n  box-shadow: none !important;\n}\n\n.timepicker-picker table tbody tr + tr:not(:last-child) {\n  background: #009688;\n  color: #fff;\n}\n\n.timepicker-picker table tbody tr + tr:not(:last-child) td {\n  border-radius: 0;\n}\n\n.timepicker-picker .btn,\n.timepicker-picker .btn:hover {\n  background: #fff;\n  color: #333;\n}\n\n.datepicker.top {\n  -webkit-transform-origin: 0 100% !important;\n  -moz-transform-origin: 0 100% !important;\n  -ms-transform-origin: 0 100% !important;\n  transform-origin: 0 100% !important;\n}\n\n.datepicker table thead tr th {\n  border-radius: 0;\n  color: #fff;\n}\n\n.datepicker table thead tr th .glyphicon {\n  width: 30px;\n  height: 30px;\n  border-radius: 50%;\n  line-height: 29px;\n}\n\n.datepicker table thead tr th:hover .glyphicon {\n  background: rgba(0, 0, 0, 0.2);\n}\n\n.datepicker table thead tr:first-child th {\n  background: #009688;\n  padding: 20px 0;\n}\n\n.datepicker table thead tr:first-child th:hover {\n  background: #009688;\n}\n\n.datepicker table thead tr:first-child th.picker-switch {\n  font-size: 16px;\n  font-weight: 400;\n  text-transform: uppercase;\n}\n\n.datepicker table thead tr:last-child th {\n  text-transform: uppercase;\n  font-weight: normal;\n  font-size: 11px;\n}\n\n.datepicker table thead tr:last-child th:first-child {\n  padding-left: 20px;\n}\n\n.datepicker table thead tr:last-child th:last-child {\n  padding-right: 20px;\n}\n\n.datepicker table thead tr:last-child:not(:only-child) {\n  background: #00877a;\n}\n\n.datepicker table tbody tr:last-child td {\n  padding-bottom: 25px;\n}\n\n.datepicker table tbody tr td:first-child {\n  padding-left: 13px;\n}\n\n.datepicker table tbody tr td:last-child {\n  padding-right: 13px;\n}\n\n.datepicker table td.day {\n  width: 35px;\n  height: 35px;\n  line-height: 20px;\n  color: #333;\n  position: relative;\n  padding: 0;\n  background: transparent;\n}\n\n.datepicker table td.day:hover {\n  background: none;\n}\n\n.datepicker table td.day:before {\n  content: \"\";\n  width: 35px;\n  height: 35px;\n  border-radius: 50%;\n  margin-bottom: -33px;\n  display: inline-block;\n  background: transparent;\n  position: static;\n  text-shadow: none;\n}\n\n.datepicker table td.day.old,\n.datepicker table td.day.new {\n  color: #CDCDCD;\n}\n\n.datepicker table td:not(.today):not(.active):hover:before {\n  background: #F0F0F0;\n}\n\n.datepicker table td.today {\n  color: #333;\n}\n\n.datepicker table td.today:before {\n  background-color: #E2E2E2;\n}\n\n.datepicker table td.active {\n  color: #fff;\n}\n\n.datepicker table td.active:before {\n  background-color: #009688;\n}\n\n.datepicker-months .month,\n.datepicker-years .year,\n.timepicker-minutes .minute,\n.timepicker-hours .hour {\n  border-radius: 50%;\n}\n\n.datepicker-months .month:not(.active):hover,\n.datepicker-years .year:not(.active):hover,\n.timepicker-minutes .minute:not(.active):hover,\n.timepicker-hours .hour:not(.active):hover {\n  background: #F0F0F0;\n}\n\n.datepicker-months .month.active,\n.datepicker-years .year.active,\n.timepicker-minutes .minute.active,\n.timepicker-hours .hour.active {\n  background: #009688;\n}\n\n.timepicker-minutes .minute,\n.timepicker-hours .hour {\n  padding: 0;\n}\n\n.fileinput {\n  position: relative;\n  padding-right: 35px;\n}\n\n.fileinput .close {\n  position: absolute;\n  top: 5px;\n  font-size: 12px;\n  float: none;\n  opacity: 1;\n  font-weight: 500;\n  border: 1px solid #ccc;\n  width: 19px;\n  text-align: center;\n  height: 19px;\n  line-height: 15px;\n  border-radius: 50%;\n  right: 0;\n}\n\n.fileinput .close:hover {\n  background: #eee;\n}\n\n.fileinput .input-group-addon {\n  padding: 0 10px;\n  vertical-align: middle;\n}\n\n.fileinput .fileinput-preview {\n  width: 200px;\n  height: 150px;\n  position: relative;\n}\n\n.fileinput .fileinput-preview img {\n  display: inline-block;\n  vertical-align: middle;\n  margin-top: -13px;\n}\n\n.fileinput .fileinput-preview:after {\n  content: \"\";\n  display: inline-block;\n  vertical-align: middle;\n}\n\n#lg-slider:after {\n  content: \"\";\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n  height: 50px;\n  width: 50px;\n  border-radius: 100%;\n  border: 2px solid #2196f3;\n  -webkit-animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);\n  animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);\n  position: absolute;\n  left: 50%;\n  margin-left: -25px;\n  top: 50%;\n  margin-top: -25px;\n  z-index: -1;\n}\n\n#lg-outer {\n  background: rgba(255, 255, 255, 0.95);\n}\n\n#lg-outer .object {\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n  border-radius: 2px;\n}\n\n#lg-close {\n  display: none;\n}\n\n#lg-action {\n  top: 0;\n  width: 100%;\n  left: 0;\n  margin-left: 0 !important;\n  height: 40px;\n  text-align: center;\n}\n\n#lg-action > a {\n  background: transparent;\n  color: #9D9D9D;\n  font-size: 18px;\n  width: 28px;\n  height: 37px;\n}\n\n#lg-action > a:hover {\n  background: transparent;\n  color: #000;\n}\n\n#lg-action .cl-thumb {\n  position: fixed;\n  right: 20px;\n  bottom: 20px;\n  width: 50px;\n  height: 50px;\n  border-radius: 50%;\n  line-height: 38px;\n  background: #f44336;\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.16), 0 2px 10px rgba(0, 0, 0, 0.12);\n}\n\n#lg-action .cl-thumb:after {\n  text-align: center;\n  left: 16px !important;\n  bottom: 6px !important;\n  color: #fff;\n}\n\n#lg-action .cl-thumb:hover {\n  background: #f32c1e;\n}\n\n#lg-gallery .thumb-cont {\n  background: #f44336;\n  text-align: center;\n}\n\n#lg-gallery .thumb-cont .thumb-info {\n  background: #f44336;\n}\n\n#lg-gallery .thumb-cont .thumb-info .count {\n  display: none;\n}\n\n#lg-gallery .thumb-cont .thumb-info .close {\n  width: 14px;\n  margin-top: 0;\n  background: none;\n}\n\n#lg-gallery .thumb-cont .thumb-info .close:hover {\n  background: none;\n}\n\n#lg-gallery .thumb-cont .thumb {\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n#lg-gallery .thumb-cont .thumb-inner {\n  display: inline-block;\n  padding: 12px 12px 15px;\n}\n\n.lg-slide {\n  background: none !important;\n}\n\n.lg-slide em {\n  font-style: normal;\n}\n\n.lg-slide em h3 {\n  margin-bottom: 5px;\n}\n\n.lg-slide .video-cont {\n  box-shadow: 0 8px 17px rgba(0, 0, 0, 0.2), 0 6px 20px rgba(0, 0, 0, 0.19);\n}\n\n@-webkit-keyframes ball-scale-ripple {\n  0% {\n    -webkit-transform: scale(0.1);\n    transform: scale(0.1);\n    opacity: 1;\n  }\n\n  70% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n    opacity: 0.7;\n  }\n\n  100% {\n    opacity: 0.0;\n  }\n}\n\n@keyframes ball-scale-ripple {\n  0% {\n    -webkit-transform: scale(0.1);\n    transform: scale(0.1);\n    opacity: 1;\n  }\n\n  70% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n    opacity: 0.7;\n  }\n\n  100% {\n    opacity: 0.0;\n  }\n}\n\n.sweet-alert {\n  border-radius: 2px;\n  padding: 10px 30px;\n}\n\n.sweet-alert h2 {\n  font-size: 16px;\n  font-weight: 400;\n  position: relative;\n  z-index: 1;\n}\n\n.sweet-alert .lead {\n  font-size: 13px;\n}\n\n.sweet-alert .btn {\n  padding: 6px 12px;\n  font-size: 13px;\n  margin: 20px 2px 0;\n}\n\n.twitter-typeahead {\n  width: 100%;\n}\n\n.twitter-typeahead .tt-menu {\n  min-width: 200px;\n  background: #fff;\n  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n  display: block !important;\n  z-index: 2 !important;\n  -webkit-transform: scale(0);\n  -ms-transform: scale(0);\n  -o-transform: scale(0);\n  transform: scale(0);\n  opacity: 0;\n  filter: alpha(opacity=0);\n  -webkit-transition: all;\n  -o-transition: all;\n  transition: all;\n  -webkit-transition-duration: 300ms;\n  transition-duration: 300ms;\n  -webkit-backface-visibility: hidden;\n  -moz-backface-visibility: hidden;\n  backface-visibility: hidden;\n  -webkit-transform-origin: top left;\n  -moz-transform-origin: top left;\n  -ms-transform-origin: top left;\n  transform-origin: top left;\n}\n\n.twitter-typeahead .tt-menu.tt-open:not(.tt-empty) {\n  -webkit-transform: scale(1);\n  -ms-transform: scale(1);\n  -o-transform: scale(1);\n  transform: scale(1);\n  opacity: 1;\n  filter: alpha(opacity=100);\n}\n\n.twitter-typeahead .tt-suggestion {\n  padding: 8px 17px;\n  color: #333;\n  cursor: pointer;\n}\n\n.twitter-typeahead .tt-suggestion:hover,\n.twitter-typeahead .tt-cursor {\n  background-color: rgba(0, 0, 0, 0.075);\n}\n\n.twitter-typeahead .tt-hint {\n  color: #818181 !important;\n}\n\n.mCSB_scrollTools {\n  width: 5px;\n}\n\n.mCSB_scrollTools .mCSB_dragger_bar {\n  border-radius: 0 !important;\n}\n\n.mCSB_scrollTools.mCSB_scrollTools_horizontal,\n.mCSB_scrollTools.mCSB_scrollTools_vertical {\n  margin: 0 !important;\n}\n\n.mCSB_scrollTools.mCSB_scrollTools_horizontal {\n  height: 10px;\n}\n\n.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {\n  background: rgba(0, 0, 0, 0.4);\n}\n\n.mCS-minimal-dark.mCSB_scrollTools_onDrag .mCSB_dragger .mCSB_dragger_bar {\n  background: rgba(0, 0, 0, 0.5) !important;\n}\n\n.mCSB_inside > .mCSB_container {\n  margin-right: 0;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/font-awesome.css",
    "content": "/*!\n *  Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome\n *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\n */\n/* FONT PATH\n * -------------------------- */\n@font-face {\n  font-family: 'FontAwesome';\n  src: url('../fonts/fontawesome-webfont.eot?v=4.4.0');\n  src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.4.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.4.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.4.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.4.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.4.0#fontawesomeregular') format('svg');\n  font-weight: normal;\n  font-style: normal;\n}\n.fa {\n  display: inline-block;\n  font: normal normal normal 14px/1 FontAwesome;\n  font-size: inherit;\n  text-rendering: auto;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n/* makes the font 33% larger relative to the icon container */\n.fa-lg {\n  font-size: 1.33333333em;\n  line-height: 0.75em;\n  vertical-align: -15%;\n}\n.fa-2x {\n  font-size: 2em;\n}\n.fa-3x {\n  font-size: 3em;\n}\n.fa-4x {\n  font-size: 4em;\n}\n.fa-5x {\n  font-size: 5em;\n}\n.fa-fw {\n  width: 1.28571429em;\n  text-align: center;\n}\n.fa-ul {\n  padding-left: 0;\n  margin-left: 2.14285714em;\n  list-style-type: none;\n}\n.fa-ul > li {\n  position: relative;\n}\n.fa-li {\n  position: absolute;\n  left: -2.14285714em;\n  width: 2.14285714em;\n  top: 0.14285714em;\n  text-align: center;\n}\n.fa-li.fa-lg {\n  left: -1.85714286em;\n}\n.fa-border {\n  padding: .2em .25em .15em;\n  border: solid 0.08em #eeeeee;\n  border-radius: .1em;\n}\n.fa-pull-left {\n  float: left;\n}\n.fa-pull-right {\n  float: right;\n}\n.fa.fa-pull-left {\n  margin-right: .3em;\n}\n.fa.fa-pull-right {\n  margin-left: .3em;\n}\n/* Deprecated as of 4.4.0 */\n.pull-right {\n  float: right;\n}\n.pull-left {\n  float: left;\n}\n.fa.pull-left {\n  margin-right: .3em;\n}\n.fa.pull-right {\n  margin-left: .3em;\n}\n.fa-spin {\n  -webkit-animation: fa-spin 2s infinite linear;\n  animation: fa-spin 2s infinite linear;\n}\n.fa-pulse {\n  -webkit-animation: fa-spin 1s infinite steps(8);\n  animation: fa-spin 1s infinite steps(8);\n}\n@-webkit-keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n@keyframes fa-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n    transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n    transform: rotate(359deg);\n  }\n}\n.fa-rotate-90 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1);\n  -webkit-transform: rotate(90deg);\n  -ms-transform: rotate(90deg);\n  transform: rotate(90deg);\n}\n.fa-rotate-180 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2);\n  -webkit-transform: rotate(180deg);\n  -ms-transform: rotate(180deg);\n  transform: rotate(180deg);\n}\n.fa-rotate-270 {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);\n  -webkit-transform: rotate(270deg);\n  -ms-transform: rotate(270deg);\n  transform: rotate(270deg);\n}\n.fa-flip-horizontal {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);\n  -webkit-transform: scale(-1, 1);\n  -ms-transform: scale(-1, 1);\n  transform: scale(-1, 1);\n}\n.fa-flip-vertical {\n  filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);\n  -webkit-transform: scale(1, -1);\n  -ms-transform: scale(1, -1);\n  transform: scale(1, -1);\n}\n:root .fa-rotate-90,\n:root .fa-rotate-180,\n:root .fa-rotate-270,\n:root .fa-flip-horizontal,\n:root .fa-flip-vertical {\n  filter: none;\n}\n.fa-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n.fa-stack-1x,\n.fa-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n.fa-stack-1x {\n  line-height: inherit;\n}\n.fa-stack-2x {\n  font-size: 2em;\n}\n.fa-inverse {\n  color: #ffffff;\n}\n/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n.fa-glass:before {\n  content: \"\\f000\";\n}\n.fa-music:before {\n  content: \"\\f001\";\n}\n.fa-search:before {\n  content: \"\\f002\";\n}\n.fa-envelope-o:before {\n  content: \"\\f003\";\n}\n.fa-heart:before {\n  content: \"\\f004\";\n}\n.fa-star:before {\n  content: \"\\f005\";\n}\n.fa-star-o:before {\n  content: \"\\f006\";\n}\n.fa-user:before {\n  content: \"\\f007\";\n}\n.fa-film:before {\n  content: \"\\f008\";\n}\n.fa-th-large:before {\n  content: \"\\f009\";\n}\n.fa-th:before {\n  content: \"\\f00a\";\n}\n.fa-th-list:before {\n  content: \"\\f00b\";\n}\n.fa-check:before {\n  content: \"\\f00c\";\n}\n.fa-remove:before,\n.fa-close:before,\n.fa-times:before {\n  content: \"\\f00d\";\n}\n.fa-search-plus:before {\n  content: \"\\f00e\";\n}\n.fa-search-minus:before {\n  content: \"\\f010\";\n}\n.fa-power-off:before {\n  content: \"\\f011\";\n}\n.fa-signal:before {\n  content: \"\\f012\";\n}\n.fa-gear:before,\n.fa-cog:before {\n  content: \"\\f013\";\n}\n.fa-trash-o:before {\n  content: \"\\f014\";\n}\n.fa-home:before {\n  content: \"\\f015\";\n}\n.fa-file-o:before {\n  content: \"\\f016\";\n}\n.fa-clock-o:before {\n  content: \"\\f017\";\n}\n.fa-road:before {\n  content: \"\\f018\";\n}\n.fa-download:before {\n  content: \"\\f019\";\n}\n.fa-arrow-circle-o-down:before {\n  content: \"\\f01a\";\n}\n.fa-arrow-circle-o-up:before {\n  content: \"\\f01b\";\n}\n.fa-inbox:before {\n  content: \"\\f01c\";\n}\n.fa-play-circle-o:before {\n  content: \"\\f01d\";\n}\n.fa-rotate-right:before,\n.fa-repeat:before {\n  content: \"\\f01e\";\n}\n.fa-refresh:before {\n  content: \"\\f021\";\n}\n.fa-list-alt:before {\n  content: \"\\f022\";\n}\n.fa-lock:before {\n  content: \"\\f023\";\n}\n.fa-flag:before {\n  content: \"\\f024\";\n}\n.fa-headphones:before {\n  content: \"\\f025\";\n}\n.fa-volume-off:before {\n  content: \"\\f026\";\n}\n.fa-volume-down:before {\n  content: \"\\f027\";\n}\n.fa-volume-up:before {\n  content: \"\\f028\";\n}\n.fa-qrcode:before {\n  content: \"\\f029\";\n}\n.fa-barcode:before {\n  content: \"\\f02a\";\n}\n.fa-tag:before {\n  content: \"\\f02b\";\n}\n.fa-tags:before {\n  content: \"\\f02c\";\n}\n.fa-book:before {\n  content: \"\\f02d\";\n}\n.fa-bookmark:before {\n  content: \"\\f02e\";\n}\n.fa-print:before {\n  content: \"\\f02f\";\n}\n.fa-camera:before {\n  content: \"\\f030\";\n}\n.fa-font:before {\n  content: \"\\f031\";\n}\n.fa-bold:before {\n  content: \"\\f032\";\n}\n.fa-italic:before {\n  content: \"\\f033\";\n}\n.fa-text-height:before {\n  content: \"\\f034\";\n}\n.fa-text-width:before {\n  content: \"\\f035\";\n}\n.fa-align-left:before {\n  content: \"\\f036\";\n}\n.fa-align-center:before {\n  content: \"\\f037\";\n}\n.fa-align-right:before {\n  content: \"\\f038\";\n}\n.fa-align-justify:before {\n  content: \"\\f039\";\n}\n.fa-list:before {\n  content: \"\\f03a\";\n}\n.fa-dedent:before,\n.fa-outdent:before {\n  content: \"\\f03b\";\n}\n.fa-indent:before {\n  content: \"\\f03c\";\n}\n.fa-video-camera:before {\n  content: \"\\f03d\";\n}\n.fa-photo:before,\n.fa-image:before,\n.fa-picture-o:before {\n  content: \"\\f03e\";\n}\n.fa-pencil:before {\n  content: \"\\f040\";\n}\n.fa-map-marker:before {\n  content: \"\\f041\";\n}\n.fa-adjust:before {\n  content: \"\\f042\";\n}\n.fa-tint:before {\n  content: \"\\f043\";\n}\n.fa-edit:before,\n.fa-pencil-square-o:before {\n  content: \"\\f044\";\n}\n.fa-share-square-o:before {\n  content: \"\\f045\";\n}\n.fa-check-square-o:before {\n  content: \"\\f046\";\n}\n.fa-arrows:before {\n  content: \"\\f047\";\n}\n.fa-step-backward:before {\n  content: \"\\f048\";\n}\n.fa-fast-backward:before {\n  content: \"\\f049\";\n}\n.fa-backward:before {\n  content: \"\\f04a\";\n}\n.fa-play:before {\n  content: \"\\f04b\";\n}\n.fa-pause:before {\n  content: \"\\f04c\";\n}\n.fa-stop:before {\n  content: \"\\f04d\";\n}\n.fa-forward:before {\n  content: \"\\f04e\";\n}\n.fa-fast-forward:before {\n  content: \"\\f050\";\n}\n.fa-step-forward:before {\n  content: \"\\f051\";\n}\n.fa-eject:before {\n  content: \"\\f052\";\n}\n.fa-chevron-left:before {\n  content: \"\\f053\";\n}\n.fa-chevron-right:before {\n  content: \"\\f054\";\n}\n.fa-plus-circle:before {\n  content: \"\\f055\";\n}\n.fa-minus-circle:before {\n  content: \"\\f056\";\n}\n.fa-times-circle:before {\n  content: \"\\f057\";\n}\n.fa-check-circle:before {\n  content: \"\\f058\";\n}\n.fa-question-circle:before {\n  content: \"\\f059\";\n}\n.fa-info-circle:before {\n  content: \"\\f05a\";\n}\n.fa-crosshairs:before {\n  content: \"\\f05b\";\n}\n.fa-times-circle-o:before {\n  content: \"\\f05c\";\n}\n.fa-check-circle-o:before {\n  content: \"\\f05d\";\n}\n.fa-ban:before {\n  content: \"\\f05e\";\n}\n.fa-arrow-left:before {\n  content: \"\\f060\";\n}\n.fa-arrow-right:before {\n  content: \"\\f061\";\n}\n.fa-arrow-up:before {\n  content: \"\\f062\";\n}\n.fa-arrow-down:before {\n  content: \"\\f063\";\n}\n.fa-mail-forward:before,\n.fa-share:before {\n  content: \"\\f064\";\n}\n.fa-expand:before {\n  content: \"\\f065\";\n}\n.fa-compress:before {\n  content: \"\\f066\";\n}\n.fa-plus:before {\n  content: \"\\f067\";\n}\n.fa-minus:before {\n  content: \"\\f068\";\n}\n.fa-asterisk:before {\n  content: \"\\f069\";\n}\n.fa-exclamation-circle:before {\n  content: \"\\f06a\";\n}\n.fa-gift:before {\n  content: \"\\f06b\";\n}\n.fa-leaf:before {\n  content: \"\\f06c\";\n}\n.fa-fire:before {\n  content: \"\\f06d\";\n}\n.fa-eye:before {\n  content: \"\\f06e\";\n}\n.fa-eye-slash:before {\n  content: \"\\f070\";\n}\n.fa-warning:before,\n.fa-exclamation-triangle:before {\n  content: \"\\f071\";\n}\n.fa-plane:before {\n  content: \"\\f072\";\n}\n.fa-calendar:before {\n  content: \"\\f073\";\n}\n.fa-random:before {\n  content: \"\\f074\";\n}\n.fa-comment:before {\n  content: \"\\f075\";\n}\n.fa-magnet:before {\n  content: \"\\f076\";\n}\n.fa-chevron-up:before {\n  content: \"\\f077\";\n}\n.fa-chevron-down:before {\n  content: \"\\f078\";\n}\n.fa-retweet:before {\n  content: \"\\f079\";\n}\n.fa-shopping-cart:before {\n  content: \"\\f07a\";\n}\n.fa-folder:before {\n  content: \"\\f07b\";\n}\n.fa-folder-open:before {\n  content: \"\\f07c\";\n}\n.fa-arrows-v:before {\n  content: \"\\f07d\";\n}\n.fa-arrows-h:before {\n  content: \"\\f07e\";\n}\n.fa-bar-chart-o:before,\n.fa-bar-chart:before {\n  content: \"\\f080\";\n}\n.fa-twitter-square:before {\n  content: \"\\f081\";\n}\n.fa-facebook-square:before {\n  content: \"\\f082\";\n}\n.fa-camera-retro:before {\n  content: \"\\f083\";\n}\n.fa-key:before {\n  content: \"\\f084\";\n}\n.fa-gears:before,\n.fa-cogs:before {\n  content: \"\\f085\";\n}\n.fa-comments:before {\n  content: \"\\f086\";\n}\n.fa-thumbs-o-up:before {\n  content: \"\\f087\";\n}\n.fa-thumbs-o-down:before {\n  content: \"\\f088\";\n}\n.fa-star-half:before {\n  content: \"\\f089\";\n}\n.fa-heart-o:before {\n  content: \"\\f08a\";\n}\n.fa-sign-out:before {\n  content: \"\\f08b\";\n}\n.fa-linkedin-square:before {\n  content: \"\\f08c\";\n}\n.fa-thumb-tack:before {\n  content: \"\\f08d\";\n}\n.fa-external-link:before {\n  content: \"\\f08e\";\n}\n.fa-sign-in:before {\n  content: \"\\f090\";\n}\n.fa-trophy:before {\n  content: \"\\f091\";\n}\n.fa-github-square:before {\n  content: \"\\f092\";\n}\n.fa-upload:before {\n  content: \"\\f093\";\n}\n.fa-lemon-o:before {\n  content: \"\\f094\";\n}\n.fa-phone:before {\n  content: \"\\f095\";\n}\n.fa-square-o:before {\n  content: \"\\f096\";\n}\n.fa-bookmark-o:before {\n  content: \"\\f097\";\n}\n.fa-phone-square:before {\n  content: \"\\f098\";\n}\n.fa-twitter:before {\n  content: \"\\f099\";\n}\n.fa-facebook-f:before,\n.fa-facebook:before {\n  content: \"\\f09a\";\n}\n.fa-github:before {\n  content: \"\\f09b\";\n}\n.fa-unlock:before {\n  content: \"\\f09c\";\n}\n.fa-credit-card:before {\n  content: \"\\f09d\";\n}\n.fa-feed:before,\n.fa-rss:before {\n  content: \"\\f09e\";\n}\n.fa-hdd-o:before {\n  content: \"\\f0a0\";\n}\n.fa-bullhorn:before {\n  content: \"\\f0a1\";\n}\n.fa-bell:before {\n  content: \"\\f0f3\";\n}\n.fa-certificate:before {\n  content: \"\\f0a3\";\n}\n.fa-hand-o-right:before {\n  content: \"\\f0a4\";\n}\n.fa-hand-o-left:before {\n  content: \"\\f0a5\";\n}\n.fa-hand-o-up:before {\n  content: \"\\f0a6\";\n}\n.fa-hand-o-down:before {\n  content: \"\\f0a7\";\n}\n.fa-arrow-circle-left:before {\n  content: \"\\f0a8\";\n}\n.fa-arrow-circle-right:before {\n  content: \"\\f0a9\";\n}\n.fa-arrow-circle-up:before {\n  content: \"\\f0aa\";\n}\n.fa-arrow-circle-down:before {\n  content: \"\\f0ab\";\n}\n.fa-globe:before {\n  content: \"\\f0ac\";\n}\n.fa-wrench:before {\n  content: \"\\f0ad\";\n}\n.fa-tasks:before {\n  content: \"\\f0ae\";\n}\n.fa-filter:before {\n  content: \"\\f0b0\";\n}\n.fa-briefcase:before {\n  content: \"\\f0b1\";\n}\n.fa-arrows-alt:before {\n  content: \"\\f0b2\";\n}\n.fa-group:before,\n.fa-users:before {\n  content: \"\\f0c0\";\n}\n.fa-chain:before,\n.fa-link:before {\n  content: \"\\f0c1\";\n}\n.fa-cloud:before {\n  content: \"\\f0c2\";\n}\n.fa-flask:before {\n  content: \"\\f0c3\";\n}\n.fa-cut:before,\n.fa-scissors:before {\n  content: \"\\f0c4\";\n}\n.fa-copy:before,\n.fa-files-o:before {\n  content: \"\\f0c5\";\n}\n.fa-paperclip:before {\n  content: \"\\f0c6\";\n}\n.fa-save:before,\n.fa-floppy-o:before {\n  content: \"\\f0c7\";\n}\n.fa-square:before {\n  content: \"\\f0c8\";\n}\n.fa-navicon:before,\n.fa-reorder:before,\n.fa-bars:before {\n  content: \"\\f0c9\";\n}\n.fa-list-ul:before {\n  content: \"\\f0ca\";\n}\n.fa-list-ol:before {\n  content: \"\\f0cb\";\n}\n.fa-strikethrough:before {\n  content: \"\\f0cc\";\n}\n.fa-underline:before {\n  content: \"\\f0cd\";\n}\n.fa-table:before {\n  content: \"\\f0ce\";\n}\n.fa-magic:before {\n  content: \"\\f0d0\";\n}\n.fa-truck:before {\n  content: \"\\f0d1\";\n}\n.fa-pinterest:before {\n  content: \"\\f0d2\";\n}\n.fa-pinterest-square:before {\n  content: \"\\f0d3\";\n}\n.fa-google-plus-square:before {\n  content: \"\\f0d4\";\n}\n.fa-google-plus:before {\n  content: \"\\f0d5\";\n}\n.fa-money:before {\n  content: \"\\f0d6\";\n}\n.fa-caret-down:before {\n  content: \"\\f0d7\";\n}\n.fa-caret-up:before {\n  content: \"\\f0d8\";\n}\n.fa-caret-left:before {\n  content: \"\\f0d9\";\n}\n.fa-caret-right:before {\n  content: \"\\f0da\";\n}\n.fa-columns:before {\n  content: \"\\f0db\";\n}\n.fa-unsorted:before,\n.fa-sort:before {\n  content: \"\\f0dc\";\n}\n.fa-sort-down:before,\n.fa-sort-desc:before {\n  content: \"\\f0dd\";\n}\n.fa-sort-up:before,\n.fa-sort-asc:before {\n  content: \"\\f0de\";\n}\n.fa-envelope:before {\n  content: \"\\f0e0\";\n}\n.fa-linkedin:before {\n  content: \"\\f0e1\";\n}\n.fa-rotate-left:before,\n.fa-undo:before {\n  content: \"\\f0e2\";\n}\n.fa-legal:before,\n.fa-gavel:before {\n  content: \"\\f0e3\";\n}\n.fa-dashboard:before,\n.fa-tachometer:before {\n  content: \"\\f0e4\";\n}\n.fa-comment-o:before {\n  content: \"\\f0e5\";\n}\n.fa-comments-o:before {\n  content: \"\\f0e6\";\n}\n.fa-flash:before,\n.fa-bolt:before {\n  content: \"\\f0e7\";\n}\n.fa-sitemap:before {\n  content: \"\\f0e8\";\n}\n.fa-umbrella:before {\n  content: \"\\f0e9\";\n}\n.fa-paste:before,\n.fa-clipboard:before {\n  content: \"\\f0ea\";\n}\n.fa-lightbulb-o:before {\n  content: \"\\f0eb\";\n}\n.fa-exchange:before {\n  content: \"\\f0ec\";\n}\n.fa-cloud-download:before {\n  content: \"\\f0ed\";\n}\n.fa-cloud-upload:before {\n  content: \"\\f0ee\";\n}\n.fa-user-md:before {\n  content: \"\\f0f0\";\n}\n.fa-stethoscope:before {\n  content: \"\\f0f1\";\n}\n.fa-suitcase:before {\n  content: \"\\f0f2\";\n}\n.fa-bell-o:before {\n  content: \"\\f0a2\";\n}\n.fa-coffee:before {\n  content: \"\\f0f4\";\n}\n.fa-cutlery:before {\n  content: \"\\f0f5\";\n}\n.fa-file-text-o:before {\n  content: \"\\f0f6\";\n}\n.fa-building-o:before {\n  content: \"\\f0f7\";\n}\n.fa-hospital-o:before {\n  content: \"\\f0f8\";\n}\n.fa-ambulance:before {\n  content: \"\\f0f9\";\n}\n.fa-medkit:before {\n  content: \"\\f0fa\";\n}\n.fa-fighter-jet:before {\n  content: \"\\f0fb\";\n}\n.fa-beer:before {\n  content: \"\\f0fc\";\n}\n.fa-h-square:before {\n  content: \"\\f0fd\";\n}\n.fa-plus-square:before {\n  content: \"\\f0fe\";\n}\n.fa-angle-double-left:before {\n  content: \"\\f100\";\n}\n.fa-angle-double-right:before {\n  content: \"\\f101\";\n}\n.fa-angle-double-up:before {\n  content: \"\\f102\";\n}\n.fa-angle-double-down:before {\n  content: \"\\f103\";\n}\n.fa-angle-left:before {\n  content: \"\\f104\";\n}\n.fa-angle-right:before {\n  content: \"\\f105\";\n}\n.fa-angle-up:before {\n  content: \"\\f106\";\n}\n.fa-angle-down:before {\n  content: \"\\f107\";\n}\n.fa-desktop:before {\n  content: \"\\f108\";\n}\n.fa-laptop:before {\n  content: \"\\f109\";\n}\n.fa-tablet:before {\n  content: \"\\f10a\";\n}\n.fa-mobile-phone:before,\n.fa-mobile:before {\n  content: \"\\f10b\";\n}\n.fa-circle-o:before {\n  content: \"\\f10c\";\n}\n.fa-quote-left:before {\n  content: \"\\f10d\";\n}\n.fa-quote-right:before {\n  content: \"\\f10e\";\n}\n.fa-spinner:before {\n  content: \"\\f110\";\n}\n.fa-circle:before {\n  content: \"\\f111\";\n}\n.fa-mail-reply:before,\n.fa-reply:before {\n  content: \"\\f112\";\n}\n.fa-github-alt:before {\n  content: \"\\f113\";\n}\n.fa-folder-o:before {\n  content: \"\\f114\";\n}\n.fa-folder-open-o:before {\n  content: \"\\f115\";\n}\n.fa-smile-o:before {\n  content: \"\\f118\";\n}\n.fa-frown-o:before {\n  content: \"\\f119\";\n}\n.fa-meh-o:before {\n  content: \"\\f11a\";\n}\n.fa-gamepad:before {\n  content: \"\\f11b\";\n}\n.fa-keyboard-o:before {\n  content: \"\\f11c\";\n}\n.fa-flag-o:before {\n  content: \"\\f11d\";\n}\n.fa-flag-checkered:before {\n  content: \"\\f11e\";\n}\n.fa-terminal:before {\n  content: \"\\f120\";\n}\n.fa-code:before {\n  content: \"\\f121\";\n}\n.fa-mail-reply-all:before,\n.fa-reply-all:before {\n  content: \"\\f122\";\n}\n.fa-star-half-empty:before,\n.fa-star-half-full:before,\n.fa-star-half-o:before {\n  content: \"\\f123\";\n}\n.fa-location-arrow:before {\n  content: \"\\f124\";\n}\n.fa-crop:before {\n  content: \"\\f125\";\n}\n.fa-code-fork:before {\n  content: \"\\f126\";\n}\n.fa-unlink:before,\n.fa-chain-broken:before {\n  content: \"\\f127\";\n}\n.fa-question:before {\n  content: \"\\f128\";\n}\n.fa-info:before {\n  content: \"\\f129\";\n}\n.fa-exclamation:before {\n  content: \"\\f12a\";\n}\n.fa-superscript:before {\n  content: \"\\f12b\";\n}\n.fa-subscript:before {\n  content: \"\\f12c\";\n}\n.fa-eraser:before {\n  content: \"\\f12d\";\n}\n.fa-puzzle-piece:before {\n  content: \"\\f12e\";\n}\n.fa-microphone:before {\n  content: \"\\f130\";\n}\n.fa-microphone-slash:before {\n  content: \"\\f131\";\n}\n.fa-shield:before {\n  content: \"\\f132\";\n}\n.fa-calendar-o:before {\n  content: \"\\f133\";\n}\n.fa-fire-extinguisher:before {\n  content: \"\\f134\";\n}\n.fa-rocket:before {\n  content: \"\\f135\";\n}\n.fa-maxcdn:before {\n  content: \"\\f136\";\n}\n.fa-chevron-circle-left:before {\n  content: \"\\f137\";\n}\n.fa-chevron-circle-right:before {\n  content: \"\\f138\";\n}\n.fa-chevron-circle-up:before {\n  content: \"\\f139\";\n}\n.fa-chevron-circle-down:before {\n  content: \"\\f13a\";\n}\n.fa-html5:before {\n  content: \"\\f13b\";\n}\n.fa-css3:before {\n  content: \"\\f13c\";\n}\n.fa-anchor:before {\n  content: \"\\f13d\";\n}\n.fa-unlock-alt:before {\n  content: \"\\f13e\";\n}\n.fa-bullseye:before {\n  content: \"\\f140\";\n}\n.fa-ellipsis-h:before {\n  content: \"\\f141\";\n}\n.fa-ellipsis-v:before {\n  content: \"\\f142\";\n}\n.fa-rss-square:before {\n  content: \"\\f143\";\n}\n.fa-play-circle:before {\n  content: \"\\f144\";\n}\n.fa-ticket:before {\n  content: \"\\f145\";\n}\n.fa-minus-square:before {\n  content: \"\\f146\";\n}\n.fa-minus-square-o:before {\n  content: \"\\f147\";\n}\n.fa-level-up:before {\n  content: \"\\f148\";\n}\n.fa-level-down:before {\n  content: \"\\f149\";\n}\n.fa-check-square:before {\n  content: \"\\f14a\";\n}\n.fa-pencil-square:before {\n  content: \"\\f14b\";\n}\n.fa-external-link-square:before {\n  content: \"\\f14c\";\n}\n.fa-share-square:before {\n  content: \"\\f14d\";\n}\n.fa-compass:before {\n  content: \"\\f14e\";\n}\n.fa-toggle-down:before,\n.fa-caret-square-o-down:before {\n  content: \"\\f150\";\n}\n.fa-toggle-up:before,\n.fa-caret-square-o-up:before {\n  content: \"\\f151\";\n}\n.fa-toggle-right:before,\n.fa-caret-square-o-right:before {\n  content: \"\\f152\";\n}\n.fa-euro:before,\n.fa-eur:before {\n  content: \"\\f153\";\n}\n.fa-gbp:before {\n  content: \"\\f154\";\n}\n.fa-dollar:before,\n.fa-usd:before {\n  content: \"\\f155\";\n}\n.fa-rupee:before,\n.fa-inr:before {\n  content: \"\\f156\";\n}\n.fa-cny:before,\n.fa-rmb:before,\n.fa-yen:before,\n.fa-jpy:before {\n  content: \"\\f157\";\n}\n.fa-ruble:before,\n.fa-rouble:before,\n.fa-rub:before {\n  content: \"\\f158\";\n}\n.fa-won:before,\n.fa-krw:before {\n  content: \"\\f159\";\n}\n.fa-bitcoin:before,\n.fa-btc:before {\n  content: \"\\f15a\";\n}\n.fa-file:before {\n  content: \"\\f15b\";\n}\n.fa-file-text:before {\n  content: \"\\f15c\";\n}\n.fa-sort-alpha-asc:before {\n  content: \"\\f15d\";\n}\n.fa-sort-alpha-desc:before {\n  content: \"\\f15e\";\n}\n.fa-sort-amount-asc:before {\n  content: \"\\f160\";\n}\n.fa-sort-amount-desc:before {\n  content: \"\\f161\";\n}\n.fa-sort-numeric-asc:before {\n  content: \"\\f162\";\n}\n.fa-sort-numeric-desc:before {\n  content: \"\\f163\";\n}\n.fa-thumbs-up:before {\n  content: \"\\f164\";\n}\n.fa-thumbs-down:before {\n  content: \"\\f165\";\n}\n.fa-youtube-square:before {\n  content: \"\\f166\";\n}\n.fa-youtube:before {\n  content: \"\\f167\";\n}\n.fa-xing:before {\n  content: \"\\f168\";\n}\n.fa-xing-square:before {\n  content: \"\\f169\";\n}\n.fa-youtube-play:before {\n  content: \"\\f16a\";\n}\n.fa-dropbox:before {\n  content: \"\\f16b\";\n}\n.fa-stack-overflow:before {\n  content: \"\\f16c\";\n}\n.fa-instagram:before {\n  content: \"\\f16d\";\n}\n.fa-flickr:before {\n  content: \"\\f16e\";\n}\n.fa-adn:before {\n  content: \"\\f170\";\n}\n.fa-bitbucket:before {\n  content: \"\\f171\";\n}\n.fa-bitbucket-square:before {\n  content: \"\\f172\";\n}\n.fa-tumblr:before {\n  content: \"\\f173\";\n}\n.fa-tumblr-square:before {\n  content: \"\\f174\";\n}\n.fa-long-arrow-down:before {\n  content: \"\\f175\";\n}\n.fa-long-arrow-up:before {\n  content: \"\\f176\";\n}\n.fa-long-arrow-left:before {\n  content: \"\\f177\";\n}\n.fa-long-arrow-right:before {\n  content: \"\\f178\";\n}\n.fa-apple:before {\n  content: \"\\f179\";\n}\n.fa-windows:before {\n  content: \"\\f17a\";\n}\n.fa-android:before {\n  content: \"\\f17b\";\n}\n.fa-linux:before {\n  content: \"\\f17c\";\n}\n.fa-dribbble:before {\n  content: \"\\f17d\";\n}\n.fa-skype:before {\n  content: \"\\f17e\";\n}\n.fa-foursquare:before {\n  content: \"\\f180\";\n}\n.fa-trello:before {\n  content: \"\\f181\";\n}\n.fa-female:before {\n  content: \"\\f182\";\n}\n.fa-male:before {\n  content: \"\\f183\";\n}\n.fa-gittip:before,\n.fa-gratipay:before {\n  content: \"\\f184\";\n}\n.fa-sun-o:before {\n  content: \"\\f185\";\n}\n.fa-moon-o:before {\n  content: \"\\f186\";\n}\n.fa-archive:before {\n  content: \"\\f187\";\n}\n.fa-bug:before {\n  content: \"\\f188\";\n}\n.fa-vk:before {\n  content: \"\\f189\";\n}\n.fa-weibo:before {\n  content: \"\\f18a\";\n}\n.fa-renren:before {\n  content: \"\\f18b\";\n}\n.fa-pagelines:before {\n  content: \"\\f18c\";\n}\n.fa-stack-exchange:before {\n  content: \"\\f18d\";\n}\n.fa-arrow-circle-o-right:before {\n  content: \"\\f18e\";\n}\n.fa-arrow-circle-o-left:before {\n  content: \"\\f190\";\n}\n.fa-toggle-left:before,\n.fa-caret-square-o-left:before {\n  content: \"\\f191\";\n}\n.fa-dot-circle-o:before {\n  content: \"\\f192\";\n}\n.fa-wheelchair:before {\n  content: \"\\f193\";\n}\n.fa-vimeo-square:before {\n  content: \"\\f194\";\n}\n.fa-turkish-lira:before,\n.fa-try:before {\n  content: \"\\f195\";\n}\n.fa-plus-square-o:before {\n  content: \"\\f196\";\n}\n.fa-space-shuttle:before {\n  content: \"\\f197\";\n}\n.fa-slack:before {\n  content: \"\\f198\";\n}\n.fa-envelope-square:before {\n  content: \"\\f199\";\n}\n.fa-wordpress:before {\n  content: \"\\f19a\";\n}\n.fa-openid:before {\n  content: \"\\f19b\";\n}\n.fa-institution:before,\n.fa-bank:before,\n.fa-university:before {\n  content: \"\\f19c\";\n}\n.fa-mortar-board:before,\n.fa-graduation-cap:before {\n  content: \"\\f19d\";\n}\n.fa-yahoo:before {\n  content: \"\\f19e\";\n}\n.fa-google:before {\n  content: \"\\f1a0\";\n}\n.fa-reddit:before {\n  content: \"\\f1a1\";\n}\n.fa-reddit-square:before {\n  content: \"\\f1a2\";\n}\n.fa-stumbleupon-circle:before {\n  content: \"\\f1a3\";\n}\n.fa-stumbleupon:before {\n  content: \"\\f1a4\";\n}\n.fa-delicious:before {\n  content: \"\\f1a5\";\n}\n.fa-digg:before {\n  content: \"\\f1a6\";\n}\n.fa-pied-piper:before {\n  content: \"\\f1a7\";\n}\n.fa-pied-piper-alt:before {\n  content: \"\\f1a8\";\n}\n.fa-drupal:before {\n  content: \"\\f1a9\";\n}\n.fa-joomla:before {\n  content: \"\\f1aa\";\n}\n.fa-language:before {\n  content: \"\\f1ab\";\n}\n.fa-fax:before {\n  content: \"\\f1ac\";\n}\n.fa-building:before {\n  content: \"\\f1ad\";\n}\n.fa-child:before {\n  content: \"\\f1ae\";\n}\n.fa-paw:before {\n  content: \"\\f1b0\";\n}\n.fa-spoon:before {\n  content: \"\\f1b1\";\n}\n.fa-cube:before {\n  content: \"\\f1b2\";\n}\n.fa-cubes:before {\n  content: \"\\f1b3\";\n}\n.fa-behance:before {\n  content: \"\\f1b4\";\n}\n.fa-behance-square:before {\n  content: \"\\f1b5\";\n}\n.fa-steam:before {\n  content: \"\\f1b6\";\n}\n.fa-steam-square:before {\n  content: \"\\f1b7\";\n}\n.fa-recycle:before {\n  content: \"\\f1b8\";\n}\n.fa-automobile:before,\n.fa-car:before {\n  content: \"\\f1b9\";\n}\n.fa-cab:before,\n.fa-taxi:before {\n  content: \"\\f1ba\";\n}\n.fa-tree:before {\n  content: \"\\f1bb\";\n}\n.fa-spotify:before {\n  content: \"\\f1bc\";\n}\n.fa-deviantart:before {\n  content: \"\\f1bd\";\n}\n.fa-soundcloud:before {\n  content: \"\\f1be\";\n}\n.fa-database:before {\n  content: \"\\f1c0\";\n}\n.fa-file-pdf-o:before {\n  content: \"\\f1c1\";\n}\n.fa-file-word-o:before {\n  content: \"\\f1c2\";\n}\n.fa-file-excel-o:before {\n  content: \"\\f1c3\";\n}\n.fa-file-powerpoint-o:before {\n  content: \"\\f1c4\";\n}\n.fa-file-photo-o:before,\n.fa-file-picture-o:before,\n.fa-file-image-o:before {\n  content: \"\\f1c5\";\n}\n.fa-file-zip-o:before,\n.fa-file-archive-o:before {\n  content: \"\\f1c6\";\n}\n.fa-file-sound-o:before,\n.fa-file-audio-o:before {\n  content: \"\\f1c7\";\n}\n.fa-file-movie-o:before,\n.fa-file-video-o:before {\n  content: \"\\f1c8\";\n}\n.fa-file-code-o:before {\n  content: \"\\f1c9\";\n}\n.fa-vine:before {\n  content: \"\\f1ca\";\n}\n.fa-codepen:before {\n  content: \"\\f1cb\";\n}\n.fa-jsfiddle:before {\n  content: \"\\f1cc\";\n}\n.fa-life-bouy:before,\n.fa-life-buoy:before,\n.fa-life-saver:before,\n.fa-support:before,\n.fa-life-ring:before {\n  content: \"\\f1cd\";\n}\n.fa-circle-o-notch:before {\n  content: \"\\f1ce\";\n}\n.fa-ra:before,\n.fa-rebel:before {\n  content: \"\\f1d0\";\n}\n.fa-ge:before,\n.fa-empire:before {\n  content: \"\\f1d1\";\n}\n.fa-git-square:before {\n  content: \"\\f1d2\";\n}\n.fa-git:before {\n  content: \"\\f1d3\";\n}\n.fa-y-combinator-square:before,\n.fa-yc-square:before,\n.fa-hacker-news:before {\n  content: \"\\f1d4\";\n}\n.fa-tencent-weibo:before {\n  content: \"\\f1d5\";\n}\n.fa-qq:before {\n  content: \"\\f1d6\";\n}\n.fa-wechat:before,\n.fa-weixin:before {\n  content: \"\\f1d7\";\n}\n.fa-send:before,\n.fa-paper-plane:before {\n  content: \"\\f1d8\";\n}\n.fa-send-o:before,\n.fa-paper-plane-o:before {\n  content: \"\\f1d9\";\n}\n.fa-history:before {\n  content: \"\\f1da\";\n}\n.fa-circle-thin:before {\n  content: \"\\f1db\";\n}\n.fa-header:before {\n  content: \"\\f1dc\";\n}\n.fa-paragraph:before {\n  content: \"\\f1dd\";\n}\n.fa-sliders:before {\n  content: \"\\f1de\";\n}\n.fa-share-alt:before {\n  content: \"\\f1e0\";\n}\n.fa-share-alt-square:before {\n  content: \"\\f1e1\";\n}\n.fa-bomb:before {\n  content: \"\\f1e2\";\n}\n.fa-soccer-ball-o:before,\n.fa-futbol-o:before {\n  content: \"\\f1e3\";\n}\n.fa-tty:before {\n  content: \"\\f1e4\";\n}\n.fa-binoculars:before {\n  content: \"\\f1e5\";\n}\n.fa-plug:before {\n  content: \"\\f1e6\";\n}\n.fa-slideshare:before {\n  content: \"\\f1e7\";\n}\n.fa-twitch:before {\n  content: \"\\f1e8\";\n}\n.fa-yelp:before {\n  content: \"\\f1e9\";\n}\n.fa-newspaper-o:before {\n  content: \"\\f1ea\";\n}\n.fa-wifi:before {\n  content: \"\\f1eb\";\n}\n.fa-calculator:before {\n  content: \"\\f1ec\";\n}\n.fa-paypal:before {\n  content: \"\\f1ed\";\n}\n.fa-google-wallet:before {\n  content: \"\\f1ee\";\n}\n.fa-cc-visa:before {\n  content: \"\\f1f0\";\n}\n.fa-cc-mastercard:before {\n  content: \"\\f1f1\";\n}\n.fa-cc-discover:before {\n  content: \"\\f1f2\";\n}\n.fa-cc-amex:before {\n  content: \"\\f1f3\";\n}\n.fa-cc-paypal:before {\n  content: \"\\f1f4\";\n}\n.fa-cc-stripe:before {\n  content: \"\\f1f5\";\n}\n.fa-bell-slash:before {\n  content: \"\\f1f6\";\n}\n.fa-bell-slash-o:before {\n  content: \"\\f1f7\";\n}\n.fa-trash:before {\n  content: \"\\f1f8\";\n}\n.fa-copyright:before {\n  content: \"\\f1f9\";\n}\n.fa-at:before {\n  content: \"\\f1fa\";\n}\n.fa-eyedropper:before {\n  content: \"\\f1fb\";\n}\n.fa-paint-brush:before {\n  content: \"\\f1fc\";\n}\n.fa-birthday-cake:before {\n  content: \"\\f1fd\";\n}\n.fa-area-chart:before {\n  content: \"\\f1fe\";\n}\n.fa-pie-chart:before {\n  content: \"\\f200\";\n}\n.fa-line-chart:before {\n  content: \"\\f201\";\n}\n.fa-lastfm:before {\n  content: \"\\f202\";\n}\n.fa-lastfm-square:before {\n  content: \"\\f203\";\n}\n.fa-toggle-off:before {\n  content: \"\\f204\";\n}\n.fa-toggle-on:before {\n  content: \"\\f205\";\n}\n.fa-bicycle:before {\n  content: \"\\f206\";\n}\n.fa-bus:before {\n  content: \"\\f207\";\n}\n.fa-ioxhost:before {\n  content: \"\\f208\";\n}\n.fa-angellist:before {\n  content: \"\\f209\";\n}\n.fa-cc:before {\n  content: \"\\f20a\";\n}\n.fa-shekel:before,\n.fa-sheqel:before,\n.fa-ils:before {\n  content: \"\\f20b\";\n}\n.fa-meanpath:before {\n  content: \"\\f20c\";\n}\n.fa-buysellads:before {\n  content: \"\\f20d\";\n}\n.fa-connectdevelop:before {\n  content: \"\\f20e\";\n}\n.fa-dashcube:before {\n  content: \"\\f210\";\n}\n.fa-forumbee:before {\n  content: \"\\f211\";\n}\n.fa-leanpub:before {\n  content: \"\\f212\";\n}\n.fa-sellsy:before {\n  content: \"\\f213\";\n}\n.fa-shirtsinbulk:before {\n  content: \"\\f214\";\n}\n.fa-simplybuilt:before {\n  content: \"\\f215\";\n}\n.fa-skyatlas:before {\n  content: \"\\f216\";\n}\n.fa-cart-plus:before {\n  content: \"\\f217\";\n}\n.fa-cart-arrow-down:before {\n  content: \"\\f218\";\n}\n.fa-diamond:before {\n  content: \"\\f219\";\n}\n.fa-ship:before {\n  content: \"\\f21a\";\n}\n.fa-user-secret:before {\n  content: \"\\f21b\";\n}\n.fa-motorcycle:before {\n  content: \"\\f21c\";\n}\n.fa-street-view:before {\n  content: \"\\f21d\";\n}\n.fa-heartbeat:before {\n  content: \"\\f21e\";\n}\n.fa-venus:before {\n  content: \"\\f221\";\n}\n.fa-mars:before {\n  content: \"\\f222\";\n}\n.fa-mercury:before {\n  content: \"\\f223\";\n}\n.fa-intersex:before,\n.fa-transgender:before {\n  content: \"\\f224\";\n}\n.fa-transgender-alt:before {\n  content: \"\\f225\";\n}\n.fa-venus-double:before {\n  content: \"\\f226\";\n}\n.fa-mars-double:before {\n  content: \"\\f227\";\n}\n.fa-venus-mars:before {\n  content: \"\\f228\";\n}\n.fa-mars-stroke:before {\n  content: \"\\f229\";\n}\n.fa-mars-stroke-v:before {\n  content: \"\\f22a\";\n}\n.fa-mars-stroke-h:before {\n  content: \"\\f22b\";\n}\n.fa-neuter:before {\n  content: \"\\f22c\";\n}\n.fa-genderless:before {\n  content: \"\\f22d\";\n}\n.fa-facebook-official:before {\n  content: \"\\f230\";\n}\n.fa-pinterest-p:before {\n  content: \"\\f231\";\n}\n.fa-whatsapp:before {\n  content: \"\\f232\";\n}\n.fa-server:before {\n  content: \"\\f233\";\n}\n.fa-user-plus:before {\n  content: \"\\f234\";\n}\n.fa-user-times:before {\n  content: \"\\f235\";\n}\n.fa-hotel:before,\n.fa-bed:before {\n  content: \"\\f236\";\n}\n.fa-viacoin:before {\n  content: \"\\f237\";\n}\n.fa-train:before {\n  content: \"\\f238\";\n}\n.fa-subway:before {\n  content: \"\\f239\";\n}\n.fa-medium:before {\n  content: \"\\f23a\";\n}\n.fa-yc:before,\n.fa-y-combinator:before {\n  content: \"\\f23b\";\n}\n.fa-optin-monster:before {\n  content: \"\\f23c\";\n}\n.fa-opencart:before {\n  content: \"\\f23d\";\n}\n.fa-expeditedssl:before {\n  content: \"\\f23e\";\n}\n.fa-battery-4:before,\n.fa-battery-full:before {\n  content: \"\\f240\";\n}\n.fa-battery-3:before,\n.fa-battery-three-quarters:before {\n  content: \"\\f241\";\n}\n.fa-battery-2:before,\n.fa-battery-half:before {\n  content: \"\\f242\";\n}\n.fa-battery-1:before,\n.fa-battery-quarter:before {\n  content: \"\\f243\";\n}\n.fa-battery-0:before,\n.fa-battery-empty:before {\n  content: \"\\f244\";\n}\n.fa-mouse-pointer:before {\n  content: \"\\f245\";\n}\n.fa-i-cursor:before {\n  content: \"\\f246\";\n}\n.fa-object-group:before {\n  content: \"\\f247\";\n}\n.fa-object-ungroup:before {\n  content: \"\\f248\";\n}\n.fa-sticky-note:before {\n  content: \"\\f249\";\n}\n.fa-sticky-note-o:before {\n  content: \"\\f24a\";\n}\n.fa-cc-jcb:before {\n  content: \"\\f24b\";\n}\n.fa-cc-diners-club:before {\n  content: \"\\f24c\";\n}\n.fa-clone:before {\n  content: \"\\f24d\";\n}\n.fa-balance-scale:before {\n  content: \"\\f24e\";\n}\n.fa-hourglass-o:before {\n  content: \"\\f250\";\n}\n.fa-hourglass-1:before,\n.fa-hourglass-start:before {\n  content: \"\\f251\";\n}\n.fa-hourglass-2:before,\n.fa-hourglass-half:before {\n  content: \"\\f252\";\n}\n.fa-hourglass-3:before,\n.fa-hourglass-end:before {\n  content: \"\\f253\";\n}\n.fa-hourglass:before {\n  content: \"\\f254\";\n}\n.fa-hand-grab-o:before,\n.fa-hand-rock-o:before {\n  content: \"\\f255\";\n}\n.fa-hand-stop-o:before,\n.fa-hand-paper-o:before {\n  content: \"\\f256\";\n}\n.fa-hand-scissors-o:before {\n  content: \"\\f257\";\n}\n.fa-hand-lizard-o:before {\n  content: \"\\f258\";\n}\n.fa-hand-spock-o:before {\n  content: \"\\f259\";\n}\n.fa-hand-pointer-o:before {\n  content: \"\\f25a\";\n}\n.fa-hand-peace-o:before {\n  content: \"\\f25b\";\n}\n.fa-trademark:before {\n  content: \"\\f25c\";\n}\n.fa-registered:before {\n  content: \"\\f25d\";\n}\n.fa-creative-commons:before {\n  content: \"\\f25e\";\n}\n.fa-gg:before {\n  content: \"\\f260\";\n}\n.fa-gg-circle:before {\n  content: \"\\f261\";\n}\n.fa-tripadvisor:before {\n  content: \"\\f262\";\n}\n.fa-odnoklassniki:before {\n  content: \"\\f263\";\n}\n.fa-odnoklassniki-square:before {\n  content: \"\\f264\";\n}\n.fa-get-pocket:before {\n  content: \"\\f265\";\n}\n.fa-wikipedia-w:before {\n  content: \"\\f266\";\n}\n.fa-safari:before {\n  content: \"\\f267\";\n}\n.fa-chrome:before {\n  content: \"\\f268\";\n}\n.fa-firefox:before {\n  content: \"\\f269\";\n}\n.fa-opera:before {\n  content: \"\\f26a\";\n}\n.fa-internet-explorer:before {\n  content: \"\\f26b\";\n}\n.fa-tv:before,\n.fa-television:before {\n  content: \"\\f26c\";\n}\n.fa-contao:before {\n  content: \"\\f26d\";\n}\n.fa-500px:before {\n  content: \"\\f26e\";\n}\n.fa-amazon:before {\n  content: \"\\f270\";\n}\n.fa-calendar-plus-o:before {\n  content: \"\\f271\";\n}\n.fa-calendar-minus-o:before {\n  content: \"\\f272\";\n}\n.fa-calendar-times-o:before {\n  content: \"\\f273\";\n}\n.fa-calendar-check-o:before {\n  content: \"\\f274\";\n}\n.fa-industry:before {\n  content: \"\\f275\";\n}\n.fa-map-pin:before {\n  content: \"\\f276\";\n}\n.fa-map-signs:before {\n  content: \"\\f277\";\n}\n.fa-map-o:before {\n  content: \"\\f278\";\n}\n.fa-map:before {\n  content: \"\\f279\";\n}\n.fa-commenting:before {\n  content: \"\\f27a\";\n}\n.fa-commenting-o:before {\n  content: \"\\f27b\";\n}\n.fa-houzz:before {\n  content: \"\\f27c\";\n}\n.fa-vimeo:before {\n  content: \"\\f27d\";\n}\n.fa-black-tie:before {\n  content: \"\\f27e\";\n}\n.fa-fonticons:before {\n  content: \"\\f280\";\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/material.css",
    "content": ".input-group .form-control{\n    float:none;\n}\n\n.ibox-title h5 {\n    display: inline-block;\n    font-size: 14px;\n    margin: 0 0 7px;\n    padding: 0;\n    text-overflow: ellipsis;\n    float: left;\n    font-weight:600;\n    margin-bottom:15px;\n}\n.dept-tree{\n    padding:10px 0px 0px 0px;\n}\n.ztree{\n    padding: 0px;margin: 5px;\n}\n.panel-ztree {\n    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.15);\n    min-height: 644px;\n}\n.fixed-table-toolbar>div>div>.col-sm-6:first-child{\n    padding-left:0px;\n}\n\n.fixed-table-toolbar>div>div>div:first-child{\n    padding-left:0px;\n}\n.bs-checkbox {\n    text-align: center !important;\n    vertical-align: middle !important;\n}\n.fixed-table-pagination .pagination a {\n    padding: 9px 12px !important;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/plugins/dataTables/dataTables.bootstrap.css",
    "content": "div.dataTables_length label {\n    float: left;\n    text-align: left;\n    font-weight: normal;\n}\n\ndiv.dataTables_length select {\n    width: 75px;\n}\n\ndiv.dataTables_filter label {\n    float: right;\n    font-weight: normal;\n}\n\ndiv.dataTables_filter input {\n    width: 16em;\n}\n\ndiv.dataTables_info {\n    padding-top: 8px;\n}\n\ndiv.dataTables_paginate {\n    float: right;\n    margin: 0;\n}\n\ndiv.dataTables_paginate ul.pagination {\n    margin: 2px 0;\n    white-space: nowrap;\n}\n\ntable.dataTable,\ntable.dataTable td,\ntable.dataTable th {\n    -webkit-box-sizing: content-box;\n    -moz-box-sizing: content-box;\n    box-sizing: content-box;\n}\n\ntable.dataTable {\n    clear: both;\n    margin-top: 6px !important;\n    margin-bottom: 6px !important;\n    max-width: none !important;\n}\n\ntable.dataTable thead .sorting,\ntable.dataTable thead .sorting_asc,\ntable.dataTable thead .sorting_desc,\ntable.dataTable thead .sorting_asc_disabled,\ntable.dataTable thead .sorting_desc_disabled {\n    cursor: pointer;\n}\n\ntable.dataTable thead .sorting {\n\n}\n\ntable.dataTable thead .sorting_asc {\n    background: url('../images/sort_asc.png') no-repeat center right;\n}\n\ntable.dataTable thead .sorting_desc {\n    background: url('../images/sort_desc.png') no-repeat center right;\n}\n\ntable.dataTable thead .sorting_asc_disabled {\n}\n\ntable.dataTable thead .sorting_desc_disabled {\n}\n\ntable.dataTable th:active {\n    outline: none;\n}\n\n/* Scrolling */\n\ndiv.dataTables_scrollHead table {\n    margin-bottom: 0 !important;\n    border-bottom-left-radius: 0;\n    border-bottom-right-radius: 0;\n}\n\ndiv.dataTables_scrollHead table thead tr:last-child th:first-child,\ndiv.dataTables_scrollHead table thead tr:last-child td:first-child {\n    border-bottom-left-radius: 0 !important;\n    border-bottom-right-radius: 0 !important;\n}\n\ndiv.dataTables_scrollBody table {\n    margin-top: 0 !important;\n    margin-bottom: 0 !important;\n    border-top: none;\n}\n\ndiv.dataTables_scrollBody tbody tr:first-child th,\ndiv.dataTables_scrollBody tbody tr:first-child td {\n    border-top: none;\n}\n\ndiv.dataTables_scrollFoot table {\n    margin-top: 0 !important;\n    border-top: none;\n}\n\n/*\n * TableTools styles\n */\n\n.table tbody tr.active td,\n.table tbody tr.active th {\n    color: white;\n    background-color: #08C;\n}\n\n.table tbody tr.active:hover td,\n.table tbody tr.active:hover th {\n    background-color: #0075b0 !important;\n}\n\n.table tbody tr.active a {\n    color: white;\n}\n\n.table-striped tbody tr.active:nth-child(odd) td,\n.table-striped tbody tr.active:nth-child(odd) th {\n    background-color: #017ebc;\n}\n\ntable.DTTT_selectable tbody tr {\n    cursor: pointer;\n}\n\ndiv.DTTT .btn {\n    font-size: 12px;\n    color: #333 !important;\n}\n\ndiv.DTTT .btn:hover {\n    text-decoration: none !important;\n}\n\nul.DTTT_dropdown.dropdown-menu {\n    z-index: 2003;\n}\n\nul.DTTT_dropdown.dropdown-menu a {\n    color: #333 !important; /* needed only when demo_page.css is included */\n}\n\nul.DTTT_dropdown.dropdown-menu li {\n    position: relative;\n}\n\nul.DTTT_dropdown.dropdown-menu li:hover a {\n    color: white !important;\n    background-color: #0088cc;\n}\n\ndiv.DTTT_collection_background {\n    z-index: 2002;\n}\n\n/* TableTools information display */\n\ndiv.DTTT_print_info.modal {\n    height: 150px;\n    margin-top: -75px;\n    text-align: center;\n}\n\ndiv.DTTT_print_info h6 {\n    margin: 1em;\n    font-size: 28px;\n    font-weight: normal;\n    line-height: 28px;\n}\n\ndiv.DTTT_print_info p {\n    font-size: 14px;\n    line-height: 20px;\n}\n\n/*\n * FixedColumns styles\n */\n\ndiv.DTFC_LeftHeadWrapper table,\ndiv.DTFC_LeftFootWrapper table,\ndiv.DTFC_RightHeadWrapper table,\ndiv.DTFC_RightFootWrapper table,\ntable.DTFC_Cloned tr.even {\n    background-color: white;\n}\n\ndiv.DTFC_RightHeadWrapper table,\ndiv.DTFC_LeftHeadWrapper table {\n    margin-bottom: 0 !important;\n    border-top-right-radius: 0 !important;\n    border-bottom-left-radius: 0 !important;\n    border-bottom-right-radius: 0 !important;\n}\n\ndiv.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,\ndiv.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,\ndiv.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,\ndiv.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {\n    border-bottom-left-radius: 0 !important;\n    border-bottom-right-radius: 0 !important;\n}\n\ndiv.DTFC_RightBodyWrapper table,\ndiv.DTFC_LeftBodyWrapper table {\n    margin-bottom: 0 !important;\n    border-top: none;\n}\n\ndiv.DTFC_RightBodyWrapper tbody tr:first-child th,\ndiv.DTFC_RightBodyWrapper tbody tr:first-child td,\ndiv.DTFC_LeftBodyWrapper tbody tr:first-child th,\ndiv.DTFC_LeftBodyWrapper tbody tr:first-child td {\n    border-top: none;\n}\n\ndiv.DTFC_RightFootWrapper table,\ndiv.DTFC_LeftFootWrapper table {\n    border-top: none;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/plugins/jquery-treegrid/css/jquery.treegrid.css",
    "content": ".treegrid-indent {width:16px; height: 16px; display: inline-block; position: relative;}\n\n.treegrid-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;}\n\n.treegrid-expander-expanded{background-image: url(../img/collapse.png); }\n.treegrid-expander-collapsed{background-image: url(../img/expand.png);}\n.treegrid-selected{background: #f5f5f5 !important;}\n.treegrid-table{border:0 !important;margin-bottom:0}\n.treegrid-table tbody {display:block;height:auto;overflow-y:auto;}\n.treegrid-table thead, .treegrid-table tbody tr {display:table;width:100%;table-layout:fixed;}\n.treegrid-thead th{line-height:40px;border: 0 !important;background:#fff !important;border-radius: 4px;border-left:1px solid #e7eaec !important;border-bottom:2px solid #e7eaec !important;text-align: center;}\n.treegrid-thead tr :first-child{border-left:0 !important}\n.treegrid-tbody td{border: 0 !important;border-left:1px solid #e7eaec !important;border-bottom:1px solid #e7eaec !important;}\n.treegrid-tbody tr :first-child{border-left:0 !important}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/plugins/webuploader/webuploader.css",
    "content": ".webuploader-container {\n\tposition: relative;\n}\n.webuploader-element-invisible {\n\tposition: absolute !important;\n\tclip: rect(1px 1px 1px 1px); /* IE6, IE7 */\n    clip: rect(1px,1px,1px,1px);\n}\n.webuploader-pick {\n\tposition: relative;\n\tdisplay: inline-block;\n\tcursor: pointer;\n\tbackground: #1ab394;\n\tpadding: 6px 12px;\n\tcolor: #fff;\n\ttext-align: center;\n\tborder-radius: 3px;\n\toverflow: hidden;\n\tfont-size: 14px;\n    font-weight: 400;\n}\n.webuploader-pick-hover {\n\tbackground: #18ab8d;\n}\n\n.webuploader-pick-disable {\n\topacity: 0.6;\n\tpointer-events:none;\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/plugins/ztree/demo.css",
    "content": "html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {\n\tmargin: 0;padding: 0;border: 0;outline: 0;font-weight: inherit;font-style: inherit;font-size: 100%;font-family: inherit;vertical-align: baseline;}\nbody {color: #2f332a;font: 15px/21px Arial, Helvetica, simsun, sans-serif;background: #f0f6e4 \\9;}\nh1, h2, h3, h4, h5, h6 {color: #2f332a;font-weight: bold;font-family: Helvetica, Arial, sans-serif;padding-bottom: 5px;}\nh1 {font-size: 24px;line-height: 34px;text-align: center;}\nh2 {font-size: 14px;line-height: 24px;padding-top: 5px;}\nh6 {font-weight: normal;font-size: 12px;letter-spacing: 1px;line-height: 24px;text-align: center;}\na {color:#3C6E31;text-decoration: underline;}\na:hover {background-color:#3C6E31;color:white;}\ninput.radio {margin: 0 2px 0 8px;}\ninput.radio.first {margin-left:0;}\ninput.empty {color: lightgray;}\ncode {color: #2f332a;}\n.highlight_red {color:#A60000;}\n.highlight_green {color:#A7F43D;}\nli {list-style: circle;font-size: 12px;}\nli.title {list-style: none;}\nul.list {margin-left: 17px;}\n\ndiv.content_wrap {width: 600px;height:380px;}\ndiv.content_wrap div.left{float: left;width: 250px;}\ndiv.content_wrap div.right{float: right;width: 340px;}\ndiv.zTreeDemoBackground {width:250px;height:362px;text-align:left;}\n\nul.ztree {margin-top: 10px;border: 1px solid #617775;background: #f0f6e4;width:220px;height:360px;overflow-y:scroll;overflow-x:auto;}\nul.log {border: 1px solid #617775;background: #f0f6e4;width:300px;height:170px;overflow: hidden;}\nul.log.small {height:45px;}\nul.log li {color: #666666;list-style: none;padding-left: 10px;}\nul.log li.dark {background-color: #E3E3E3;}\n\n/* ruler */\ndiv.ruler {height:20px; width:220px; background-color:#f0f6e4;border: 1px solid #333; margin-bottom: 5px; cursor: pointer}\ndiv.ruler div.cursor {height:20px; width:30px; background-color:#3C6E31; color:white; text-align: right; padding-right: 5px; cursor: pointer}"
  },
  {
    "path": "material-manage/src/main/webapp/static/css/plugins/ztree/zTreeStyle.css",
    "content": "/*-------------------------------------\nzTree Style\n\nversion:\t3.5.19\nauthor:\t\tHunter.z\nemail:\t\thunter.z@263.net\nwebsite:\thttp://code.google.com/p/jquerytree/\n\n-------------------------------------*/\n\n.ztree * {padding:0; margin:0; font-size:12px; font-family: Verdana, Arial, Helvetica, AppleGothic, sans-serif}\n.ztree {margin:0; padding:5px; color:#333}\n.ztree li{padding:0; margin:0; list-style:none; line-height:14px; text-align:left; white-space:nowrap; outline:0}\n.ztree li ul{ margin:0; padding:0 0 0 18px}\n.ztree li ul.line{ background:url(./img/line_conn.gif) 0 0 repeat-y;}\n\n.ztree li a {padding:1px 3px 0 0; margin:0; cursor:pointer; height:17px; color:#333; background-color: transparent;\n\ttext-decoration:none; vertical-align:top; display: inline-block}\n.ztree li a:hover {text-decoration:underline}\n.ztree li a.curSelectedNode {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}\n.ztree li a.curSelectedNode_Edit {padding-top:0px; background-color:#FFE6B0; color:black; height:16px; border:1px #FFB951 solid; opacity:0.8;}\n.ztree li a.tmpTargetNode_inner {padding-top:0px; background-color:#316AC5; color:white; height:16px; border:1px #316AC5 solid;\n\topacity:0.8; filter:alpha(opacity=80)}\n.ztree li a.tmpTargetNode_prev {}\n.ztree li a.tmpTargetNode_next {}\n.ztree li a input.rename {height:14px; width:80px; padding:0; margin:0;\n\tfont-size:12px; border:1px #7EC4CC solid; *border:0px}\n.ztree li span {line-height:16px; margin-right:2px}\n.ztree li span.button {line-height:0; margin:0; width:16px; height:16px; display: inline-block; vertical-align:middle;\n\tborder:0 none; cursor: pointer;outline:none;\n\tbackground-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\n\tbackground-image:url(\"./img/zTreeStandard.png\"); *background-image:url(\"./img/zTreeStandard.gif\")}\n\n.ztree li span.button.chk {width:13px; height:13px; margin:0 3px 0 0; cursor: auto}\n.ztree li span.button.chk.checkbox_false_full {background-position:0 0}\n.ztree li span.button.chk.checkbox_false_full_focus {background-position:0 -14px}\n.ztree li span.button.chk.checkbox_false_part {background-position:0 -28px}\n.ztree li span.button.chk.checkbox_false_part_focus {background-position:0 -42px}\n.ztree li span.button.chk.checkbox_false_disable {background-position:0 -56px}\n.ztree li span.button.chk.checkbox_true_full {background-position:-14px 0}\n.ztree li span.button.chk.checkbox_true_full_focus {background-position:-14px -14px}\n.ztree li span.button.chk.checkbox_true_part {background-position:-14px -28px}\n.ztree li span.button.chk.checkbox_true_part_focus {background-position:-14px -42px}\n.ztree li span.button.chk.checkbox_true_disable {background-position:-14px -56px}\n.ztree li span.button.chk.radio_false_full {background-position:-28px 0}\n.ztree li span.button.chk.radio_false_full_focus {background-position:-28px -14px}\n.ztree li span.button.chk.radio_false_part {background-position:-28px -28px}\n.ztree li span.button.chk.radio_false_part_focus {background-position:-28px -42px}\n.ztree li span.button.chk.radio_false_disable {background-position:-28px -56px}\n.ztree li span.button.chk.radio_true_full {background-position:-42px 0}\n.ztree li span.button.chk.radio_true_full_focus {background-position:-42px -14px}\n.ztree li span.button.chk.radio_true_part {background-position:-42px -28px}\n.ztree li span.button.chk.radio_true_part_focus {background-position:-42px -42px}\n.ztree li span.button.chk.radio_true_disable {background-position:-42px -56px}\n\n.ztree li span.button.switch {width:18px; height:18px}\n.ztree li span.button.root_open{background-position:-92px -54px}\n.ztree li span.button.root_close{background-position:-74px -54px}\n.ztree li span.button.roots_open{background-position:-92px 0}\n.ztree li span.button.roots_close{background-position:-74px 0}\n.ztree li span.button.center_open{background-position:-92px -18px}\n.ztree li span.button.center_close{background-position:-74px -18px}\n.ztree li span.button.bottom_open{background-position:-92px -36px}\n.ztree li span.button.bottom_close{background-position:-74px -36px}\n.ztree li span.button.noline_open{background-position:-92px -72px}\n.ztree li span.button.noline_close{background-position:-74px -72px}\n.ztree li span.button.root_docu{ background:none;}\n.ztree li span.button.roots_docu{background-position:-56px 0}\n.ztree li span.button.center_docu{background-position:-56px -18px}\n.ztree li span.button.bottom_docu{background-position:-56px -36px}\n.ztree li span.button.noline_docu{ background:none;}\n\n.ztree li span.button.ico_open{margin-right:2px; background-position:-110px -16px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.ico_close{margin-right:2px; background-position:-110px 0; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.ico_docu{margin-right:2px; background-position:-110px -32px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.edit {margin-right:2px; background-position:-110px -48px; vertical-align:top; *vertical-align:middle}\n.ztree li span.button.remove {margin-right:2px; background-position:-110px -64px; vertical-align:top; *vertical-align:middle}\n\n.ztree li span.button.ico_loading{margin-right:2px; background:url(./img/loading.gif) no-repeat scroll 0 0 transparent; vertical-align:top; *vertical-align:middle}\n\nul.tmpTargetzTree {background-color:#FFE6B0; opacity:0.8; filter:alpha(opacity=80)}\n\nspan.tmpzTreeMove_arrow {width:16px; height:16px; display: inline-block; padding:0; margin:2px 0 0 1px; border:0 none; position:absolute;\n\tbackground-color:transparent; background-repeat:no-repeat; background-attachment: scroll;\n\tbackground-position:-110px -80px; background-image:url(\"./img/zTreeStandard.png\"); *background-image:url(\"./img/zTreeStandard.gif\")}\n\nul.ztree.zTreeDragUL {margin:0; padding:0; position:absolute; width:auto; height:auto;overflow:hidden; background-color:#cfcfcf; border:1px #00B83F dotted; opacity:0.8; filter:alpha(opacity=80)}\n.zTreeMask {z-index:10000; background-color:#cfcfcf; opacity:0.0; filter:alpha(opacity=0); position:absolute}\n\n/* level style*/\n/*.ztree li span.button.level0 {\n\tdisplay:none;\n}\n.ztree li ul.level0 {\n\tpadding:0;\n\tbackground:none;\n}*/"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/charts.js",
    "content": "$(document).ready(function () {\n    /*\n    * SPARKLINE\n    */\n    function sparklineBar(id, values, height, barWidth, barColor, barSpacing) {\n        $('.'+id).sparkline(values, {\n            type: 'bar',\n            height: height,\n            barWidth: barWidth,\n            barColor: barColor,\n            barSpacing: barSpacing\n        })\n    }\n    \n    function sparklineLine(id, values, width, height, lineColor, fillColor, lineWidth, maxSpotColor, minSpotColor, spotColor, spotRadius, hSpotColor, hLineColor) {\n        $('.'+id).sparkline(values, {\n            type: 'line',\n            width: width,\n            height: height,\n            lineColor: lineColor,\n            fillColor: fillColor,\n            lineWidth: lineWidth,\n            maxSpotColor: maxSpotColor,\n            minSpotColor: minSpotColor,\n            spotColor: spotColor,\n            spotRadius: spotRadius,\n            highlightSpotColor: hSpotColor,\n            highlightLineColor: hLineColor\n        });\n    }\n    \n    function sparklinePie(id, values, width, height, sliceColors) {\n        $('.'+id).sparkline(values, {\n            type: 'pie',\n            width: width,\n            height: height,\n            sliceColors: sliceColors,\n            offset: 0,\n            borderWidth: 0\n        });\n    }    \n    \n    /* Mini Chart - Bar Chart 1 */\n    if ($('.stats-bar')[0]) {\n        sparklineBar('stats-bar', [6,4,8,6,5,6,7,8,3,5,9,5,8,4,3,6,8], '45px', 3, '#fff', 2);\n    }\n    \n    /* Mini Chart - Bar Chart 2 */\n    if ($('.stats-bar-2')[0]) {\n        sparklineBar('stats-bar-2', [4,7,6,2,5,3,8,6,6,4,8,6,5,8,2,4,6], '45px', 3, '#fff', 2);\n    }\n    \n    /* Mini Chart - Line Chart 1 */\n    if ($('.stats-line')[0]) {\n        sparklineLine('stats-line', [9,4,6,5,6,4,5,7,9,3,6,5], 85, 45, '#fff', 'rgba(0,0,0,0)', 1.25, 'rgba(255,255,255,0.4)', 'rgba(255,255,255,0.4)', 'rgba(255,255,255,0.4)', 3, '#fff', 'rgba(255,255,255,0.4)');\n    }\n    \n    /* Mini Chart - Line Chart 2 */\n    if ($('.stats-line-2')[0]) {\n        sparklineLine('stats-line-2', [5,6,3,9,7,5,4,6,5,6,4,9], 85, 45, '#fff', 'rgba(0,0,0,0)', 1.25, 'rgba(255,255,255,0.4)', 'rgba(255,255,255,0.4)', 'rgba(255,255,255,0.4)', 3, '#fff', 'rgba(255,255,255,0.4)');\n    }\n    \n    /* Mini Chart - Pie Chart 1 */\n    if ($('.stats-pie')[0]) {\n        sparklinePie('stats-pie', [20, 35, 30, 5], 45, 45, ['#fff', 'rgba(255,255,255,0.7)', 'rgba(255,255,255,0.4)', 'rgba(255,255,255,0.2)']);\n    }\n    \n    /* Dash Widget Line Chart */\n    if ($('.dash-widget-visits')[0]) {\n        sparklineLine('dash-widget-visits', [9,4,6,5,6,4,5,7,9,3,6,5], '100%', '95px', 'rgba(255,255,255,0.7)', 'rgba(0,0,0,0)', 2, 'rgba(255,255,255,0.4)', 'rgba(255,255,255,0.4)', 'rgba(255,255,255,0.4)', 5, 'rgba(255,255,255,0.4)', '#fff');\n    }\n    \n    \n    \n    /*\n     * Easy Pie Charts - Used in widgets\n     */\n    function easyPieChart(id, trackColor, scaleColor, barColor, lineWidth, lineCap, size) {\n        $('.'+id).easyPieChart({\n            trackColor: trackColor,\n            scaleColor: scaleColor,\n            barColor: barColor,\n            lineWidth: lineWidth,\n            lineCap: lineCap,\n            size: size\n        });\n    }\n    \n    /* Main Pie Chart */\n    if ($('.main-pie')[0]) {\n        easyPieChart('main-pie', 'rgba(255,255,255,0.2)', 'rgba(255,255,255,0.5)', 'rgba(255,255,255,0.7)', 7, 'butt', 148);\n    }\n    \n    /* Others */\n    if ($('.sub-pie-1')[0]) {\n        easyPieChart('sub-pie-1', '#eee', '#ccc', '#2196F3', 4, 'butt', 95);\n    }\n    \n    if ($('.sub-pie-2')[0]) {\n        easyPieChart('sub-pie-2', '#eee', '#ccc', '#FFC107', 4, 'butt', 95);\n    }\n});\n\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/common/Feng.js",
    "content": "var Feng = {\n    ctxPath: \"\",\n    addCtx: function (ctx) {\n        if (this.ctxPath == \"\") {\n            this.ctxPath = ctx;\n        }\n    },\n    notify:function(message,type){\n        $.growl({\n            message: message\n        },{\n            type: type,\n            allow_dismiss: false,\n            label: 'Cancel',\n            className: 'btn-xs btn-inverse',\n            placement: {\n                from: 'top',\n                align: 'center'\n            },\n            delay: 3500,\n            animate: {\n                enter: 'animated fadeIn',\n                exit: 'animated fadeOut'\n            },\n            offset: {\n                x: 20,\n                y: 85\n            }\n        });\n    },\n    info: function (info) {\n        Feng.notify(info, 'info');\n    },\n    success: function (info) {\n        Feng.notify(info, 'success');\n    },\n    warning: function (info) {\n        Feng.notify(info, 'warning');\n    },\n    error: function (info) {\n        Feng.notify(info, 'danger');\n    },\n    /**\n     * 确认框\n     * @param tip 确认提示\n     * @param ensure 确认操作\n     * @param subTip 更详细的确认询问信息，可以不传改参数\n     */\n    confirm: function (tip, ensure,subTip) {\n        swal({\n            title: tip,\n            text: subTip?subTip:\"\",\n            type: \"warning\",\n            showCancelButton: true,\n            confirmButtonColor: \"#DD6B55\",\n            confirmButtonText: \"确定\",\n            cancelButtonText:'取消',\n            closeOnConfirm: true\n        }, function(){\n            // swal(\"Deleted!\", \"Your imaginary file has been deleted.\", \"success\");\n            ensure();\n        });\n    },\n    log: function (info) {\n        console.log(info);\n    },\n    alert: function (info, iconIndex) {\n        parent.layer.msg(info, {\n            icon: iconIndex\n        });\n    },\n\n    infoDetail: function (title, info) {\n        var display = \"\";\n        if (typeof info == \"string\") {\n            display = info;\n        } else {\n            if (info instanceof Array) {\n                for (var x in info) {\n                    display = display + info[x] + \"<br/>\";\n                }\n            } else {\n                display = info;\n            }\n        }\n        parent.layer.open({\n            title: title,\n            type: 1,\n            skin: 'layui-layer-rim', //加上边框\n            area: ['950px', '600px'], //宽高\n            content: '<div style=\"padding: 20px;\">' + display + '</div>'\n        });\n    },\n    writeObj: function (obj) {\n        var description = \"\";\n        for (var i in obj) {\n            var property = obj[i];\n            description += i + \" = \" + property + \",\";\n        }\n        layer.alert(description, {\n            skin: 'layui-layer-molv',\n            closeBtn: 0\n        });\n    },\n    showInputTree: function (inputId, inputTreeContentId, leftOffset, rightOffset) {\n        var onBodyDown = function (event) {\n            if (!(event.target.id == \"menuBtn\" || event.target.id == inputTreeContentId || $(event.target).parents(\"#\" + inputTreeContentId).length > 0)) {\n                $(\"#\" + inputTreeContentId).fadeOut(\"fast\");\n                $(\"body\").unbind(\"mousedown\", onBodyDown);// mousedown当鼠标按下就可以触发，不用弹起\n            }\n        };\n\n        if(leftOffset == undefined && rightOffset == undefined){\n            var inputDiv = $(\"#\" + inputId);\n            var inputDivOffset = $(\"#\" + inputId).offset();\n            $(\"#\" + inputTreeContentId).css({\n                left: inputDivOffset.left + \"px\",\n                top: inputDivOffset.top + inputDiv.outerHeight() + \"px\"\n            }).slideDown(\"fast\");\n        }else{\n            $(\"#\" + inputTreeContentId).css({\n                left: leftOffset + \"px\",\n                top: rightOffset + \"px\"\n            }).slideDown(\"fast\");\n        }\n\n        $(\"body\").bind(\"mousedown\", onBodyDown);\n    },\n    baseAjax: function (url, tip) {\n        var ajax = new $ax(Feng.ctxPath + url, function (data) {\n            Feng.success(tip + \"成功!\");\n        }, function (data) {\n            Feng.error(tip + \"失败!\" + data.responseJSON.message + \"!\");\n        });\n        return ajax;\n    },\n    changeAjax: function (url) {\n        return Feng.baseAjax(url, \"修改\");\n    },\n    zTreeCheckedNodes: function (zTreeId) {\n        var zTree = $.fn.zTree.getZTreeObj(zTreeId);\n        var nodes = zTree.getCheckedNodes();\n        var ids = \"\";\n        for (var i = 0, l = nodes.length; i < l; i++) {\n            ids += \",\" + nodes[i].id;\n        }\n        return ids.substring(1);\n    },\n    eventParseObject: function (event) {//获取点击事件的源对象\n        event = event ? event : window.event;\n        var obj = event.srcElement ? event.srcElement : event.target;\n        return $(obj);\n    },\n    sessionTimeoutRegistry: function () {\n        $.ajaxSetup({\n            contentType: \"application/x-www-form-urlencoded;charset=utf-8\",\n            complete: function (XMLHttpRequest, textStatus) {\n                //通过XMLHttpRequest取得响应头，sessionstatus，\n                var sessionstatus = XMLHttpRequest.getResponseHeader(\"sessionstatus\");\n                if (sessionstatus == \"timeout\") {\n                    //如果超时就处理 ，指定要跳转的页面\n                    window.location = Feng.ctxPath + \"/global/sessionError\";\n                }\n            }\n        });\n    },\n    initValidator: function(formId,fields){\n        $('#' + formId).bootstrapValidator({\n            feedbackIcons: {\n                valid: 'glyphicon glyphicon-ok',\n                invalid: 'glyphicon glyphicon-remove',\n                validating: 'glyphicon glyphicon-refresh'\n            },\n            fields: fields,\n            live: 'enabled',\n            message: '该字段不能为空'\n        });\n    },\n    underLineToCamel: function (str) {\n        var strArr = str.split('_');\n        for (var i = 1; i < strArr.length; i++) {\n            strArr[i] = strArr[i].charAt(0).toUpperCase() + strArr[i].substring(1);\n        }\n        var result = strArr.join('');\n        return result.charAt(0).toUpperCase() + result.substring(1);\n    }\n};\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/common/ajax-object.js",
    "content": "(function () {\n\tvar $ax = function (url, success, error) {\n\t\tthis.url = url;\n\t\tthis.type = \"post\";\n\t\tthis.data = {};\n\t\tthis.dataType = \"json\";\n\t\tthis.async = false;\n\t\tthis.success = success;\n\t\tthis.error = error;\n\t};\n\t\n\t$ax.prototype = {\n\t\tstart : function () {\t\n\t\t\tvar me = this;\n\t\t\t\n\t\t\tif (this.url.indexOf(\"?\") == -1) {\n\t\t\t\tthis.url = this.url + \"?jstime=\" + new Date().getTime();\n\t\t\t} else {\n\t\t\t\tthis.url = this.url + \"&jstime=\" + new Date().getTime();\n\t\t\t}\n\t\t\t\n\t\t\t$.ajax({\n\t\t        type: this.type,\n\t\t        url: this.url,\n\t\t        dataType: this.dataType,\n\t\t        async: this.async,\n\t\t        data: this.data,\n\t\t\t\tbeforeSend: function(data) {\n\t\t\t\t\t\n\t\t\t\t},\n\t\t        success: function(data) {\n\t\t        \tif(data.code && data.code != 200){\n\t\t\t\t\t\tFeng.error(data.message);\n\t\t\t\t\t}else {\n\t\t\t\t\t\tme.success(data);\n\t\t\t\t\t}\n\t\t        },\n\t\t        error: function(data) {\n\t\t        \t//如果后台通过spring validator返回错误信息，则取第一条错误信息并显示\n\t\t        \tif(data.responseJSON.errors && data.responseJSON.errors.length>0){\n\t\t\t\t\t\tdata.responseJSON.message = data.responseJSON.errors[0].defaultMessage;\n\t\t\t\t\t}\n\t\t        \tme.error(data);\n\t\t        }\n\t\t    });\n\t\t}, \n\t\t\n\t\tset : function (key, value) {\n\t\t\tif (typeof key == \"object\") {\n\t\t\t\tfor (var i in key) {\n\t\t\t\t\tif (typeof i == \"function\")\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tthis.data[i] = key[i];\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.data[key] = (typeof value == \"undefined\") ? $(\"#\" + key).val() : value;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\t\n\t\tsetData : function(data){\n\t\t\tthis.data = data;\n\t\t\treturn this;\n\t\t},\n\t\t\n\t\tclear : function () {\n\t\t\tthis.data = {};\n\t\t\treturn this;\n\t\t},\n\t\tsetType: function(type){\n\t\t\tthis.type = type;\n\t\t}\n\t};\n\t\n\twindow.$ax = $ax;\n\t\n} ());"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/common/bootstrap-table-object.js",
    "content": "/**\n * 初始化 BootStrap Table 的封装\n *\n * 约定：toolbar的id为 (bstableId + \"Toolbar\")\n *\n * @author fengshuonan\n */\n(function () {\n    var BSTable = function (bstableId, url, columns) {\n        this.btInstance = null;\t\t\t\t\t//jquery和BootStrapTable绑定的对象\n        this.bstableId = bstableId;\n        this.url = Feng.ctxPath + url;\n        this.method = \"post\";\n        this.paginationType = \"server\";\t\t\t//默认分页方式是服务器分页,可选项\"client\"\n        this.toolbarId = bstableId + \"Toolbar\";\n        this.columns = columns;\n        this.height = 665;\t\t\t\t\t\t//默认表格高度665\n        this.data = {};\n        this.queryParams = {}; // 向后台传递的自定义参数\n    };\n\n    BSTable.prototype = {\n        /**\n         * 初始化bootstrap table\n         */\n        init: function () {\n            var tableId = this.bstableId;\n            var me = this;\n            this.btInstance =\n                $('#' + tableId).bootstrapTable({\n                    contentType: \"application/x-www-form-urlencoded\",\n                    url: this.url,\t\t\t\t//请求地址\n                    method: this.method,\t\t//ajax方式,post还是get\n                    ajaxOptions: {\t\t\t\t//ajax请求的附带参数\n                        data: this.data\n                    },\n                    toolbar: \"#\" + this.toolbarId,//顶部工具条\n                    striped: true,     \t\t\t//是否显示行间隔色\n                    cache: false,      \t\t\t//是否使用缓存,默认为true\n                    pagination: true,     \t\t//是否显示分页（*）\n                    sortable: true,      \t\t//是否启用排序\n                    sortOrder: \"desc\",     \t\t//排序方式\n                    pageNumber: 1,      \t\t\t//初始化加载第一页，默认第一页\n                    pageSize: 14,      \t\t\t//每页的记录行数（*）\n                    pageList: [14, 50, 100],  \t//可供选择的每页的行数（*）\n                    queryParamsType: 'limit', \t//默认值为 'limit' ,在默认情况下 传给服务端的参数为：offset,limit,sort\n                    queryParams: function (param) {\n                        return $.extend(me.queryParams, param);\n                    }, // 向后台传递的自定义参数\n                    sidePagination: this.paginationType,   //分页方式：client客户端分页，server服务端分页（*）\n                    search: false,      \t\t//是否显示表格搜索，此搜索是客户端搜索，不会进服务端\n                    strictSearch: true,\t\t\t//设置为 true启用 全匹配搜索，否则为模糊搜索\n                    // showColumns: true,     \t\t//是否显示所有的列\n                    showRefresh: true,     \t\t//是否显示刷新按钮\n                    // minimumCountColumns: 2,    \t//最少允许的列数\n                    clickToSelect: false,    \t//是否启用点击选中行\n                    searchOnEnterKey: true,\t\t//设置为 true时，按回车触发搜索方法，否则自动触发搜索方法\n                    columns: this.columns,\t\t//列数组\n                    pagination: true,\t\t\t//是否显示分页条\n                    height: this.height,\n                    icons: {\n                        refresh: 'glyphicon-repeat',\n                        toggle: 'glyphicon-list-alt',\n                        columns: 'glyphicon-list'\n                    },\n                    iconSize: 'outline'\n                });\n            return this;\n        },\n        /**\n         * 向后台传递的自定义参数\n         * @param param\n         */\n        setQueryParams: function (param) {\n            this.queryParams = param;\n        },\n        /**\n         * 设置分页方式：server 或者 client\n         */\n        setPaginationType: function (type) {\n            this.paginationType = type;\n        },\n\n        /**\n         * 设置ajax post请求时候附带的参数\n         */\n        set: function (key, value) {\n            if (typeof key == \"object\") {\n                for (var i in key) {\n                    if (typeof i == \"function\")\n                        continue;\n                    this.data[i] = key[i];\n                }\n            } else {\n                this.data[key] = (typeof value == \"undefined\") ? $(\"#\" + key).val() : value;\n            }\n            return this;\n        },\n\n        /**\n         * 设置ajax post请求时候附带的参数\n         */\n        setData: function (data) {\n            this.data = data;\n            return this;\n        },\n\n        /**\n         * 清空ajax post请求参数\n         */\n        clear: function () {\n            this.data = {};\n            return this;\n        },\n\n        /**\n         * 刷新 bootstrap 表格\n         * Refresh the remote server data,\n         * you can set {silent: true} to refresh the data silently,\n         * and set {url: newUrl} to change the url.\n         * To supply query params specific to this request, set {query: {foo: 'bar'}}\n         */\n        refresh: function (parms) {\n            if (typeof parms != \"undefined\") {\n                this.btInstance.bootstrapTable('refresh', parms);\n            } else {\n                this.btInstance.bootstrapTable('refresh');\n            }\n        }\n    };\n\n    window.BSTable = BSTable;\n\n}());"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/common/tree-table-object.js",
    "content": "/**\n * 初始化 Tree Table 的封装\n *\n * @author cyf\n */\n(function () {\n    var BSTreeTable = function (bstableId, url, columns) {\n        this.btInstance = null;\t\t\t\t\t//jquery和bootstrapTreeTable绑定的对象\n        this.bstableId = bstableId;\n        this.url = Feng.ctxPath + url;\n        this.method = \"post\";\n        this.columns = columns;\n        this.data = {};// ajax的参数\n        this.expandColumn = null;// 展开显示的列 \n        this.id = 'id';// 选取记录返回的值\n        this.code = 'code';// 用于设置父子关系\n        this.parentCode = 'pcode';// 用于设置父子关系\n        this.expandAll = false;// 是否默认全部展开\n        this.toolbarId = bstableId + \"Toolbar\";\n        this.height = 665;\t\t\t\t\t\t//默认表格高度665\n    };\n\n    BSTreeTable.prototype = {\n        /**\n         * 初始化bootstrap table\n         */\n        init: function () {\n            var tableId = this.bstableId;\n            this.btInstance =\n                $('#'+tableId).bootstrapTreeTable({\n                    id: this.id,// 选取记录返回的值\n                    code: this.code,// 用于设置父子关系\n                    parentCode: this.parentCode,// 用于设置父子关系\n                    rootCodeValue: this.rootCodeValue,//设置根节点code值----可指定根节点，默认为null,\"\",0,\"0\"\n                    type: this.method, //请求数据的ajax类型\n                    url: this.url,   //请求数据的ajax的url\n                    ajaxParams: this.data, //请求数据的ajax的data属性\n                    expandColumn: this.expandColumn,//在哪一列上面显示展开按钮,从0开始\n                    striped: true,   //是否各行渐变色\n                    expandAll: this.expandAll,  //是否全部展开\n                    columns: this.columns,\t\t//列数组\n                    toolbar: \"#\" + this.toolbarId,//顶部工具条\n                    height: this.height,\n                });\n            return this;\n        },\n\n        /**\n         * 设置在哪一列上面显示展开按钮,从0开始\n         */\n        setExpandColumn: function (expandColumn) {\n            this.expandColumn = expandColumn;\n        },\n        /**\n         * 设置记录返回的id值\n         */\n        setIdField: function (id) {\n            this.id = id;\n        },\n        /**\n         * 设置记录分级的字段\n         */\n        setCodeField: function (code) {\n            this.code = code;\n        },\n        /**\n         * 设置记录分级的父级字段\n         */\n        setParentCodeField: function (parentCode) {\n            this.parentCode = parentCode;\n        },\n        /**\n         * 设置根节点code值----可指定根节点，默认为null,\"\",0,\"0\"\n         */\n        setRootCodeValue: function (rootCodeValue) {\n            this.rootCodeValue = rootCodeValue;\n        },\n        /**\n         * 设置是否默认全部展开\n         */\n        setExpandAll: function (expandAll) {\n        \tthis.expandAll = expandAll;\n        },\n        /**\n         * 设置表格高度\n         */\n        setHeight: function (height) {\n        \tthis.height = height;\n        },\n        /**\n         * 设置ajax post请求时候附带的参数\n         */\n        set: function (key, value) {\n            if (typeof key == \"object\") {\n                for (var i in key) {\n                    if (typeof i == \"function\")\n                        continue;\n                    this.data[i] = key[i];\n                }\n            } else {\n                this.data[key] = (typeof value == \"undefined\") ? $(\"#\" + key).val() : value;\n            }\n            return this;\n        },\n\n        /**\n         * 设置ajax post请求时候附带的参数\n         */\n        setData: function (data) {\n            this.data = data;\n            return this;\n        },\n\n        /**\n         * 清空ajax post请求参数\n         */\n        clear: function () {\n            this.data = {};\n            return this;\n        },\n\n        /**\n         * 刷新表格\n         */\n        refresh: function (parms) {\n            if (typeof parms != \"undefined\") {\n                this.btInstance.bootstrapTreeTable('refresh', parms.query);// 为了兼容bootstrap-table的写法\n            } else {\n                this.btInstance.bootstrapTreeTable('refresh');\n            }\n        }\n    };\n\n    window.BSTreeTable = BSTreeTable;\n\n}());"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/common/web-upload-object.js",
    "content": "/**\n * web-upload 工具类\n * \n * 约定：\n * 上传按钮的id = 图片隐藏域id + 'BtnId'\n * 图片预览框的id = 图片隐藏域id + 'PreId'\n * \n * @author fengshuonan\n */\n(function() {\n\t\n\tvar $WebUpload = function(pictureId) {\n\t\tthis.pictureId = pictureId;\n\t\tthis.uploadBtnId = pictureId + \"BtnId\";\n\t\tthis.uploadPreId = pictureId + \"PreId\";\n\t\tthis.uploadUrl = Feng.ctxPath + '/mgr/upload';\n\t\tthis.fileSizeLimit = 100 * 1024 * 1024;\n\t\tthis.picWidth = 800;\n\t\tthis.picHeight = 800;\n        this.uploadBarId = null;\n\t};\n\n\t$WebUpload.prototype = {\n\t\t/**\n\t\t * 初始化webUploader\n\t\t */\n\t\tinit : function() {\n\t\t\tvar uploader = this.create();\n\t\t\tthis.bindEvent(uploader);\n\t\t\treturn uploader;\n\t\t},\n\t\t\n\t\t/**\n\t\t * 创建webuploader对象\n\t\t */\n\t\tcreate : function() {\n\t\t\tvar webUploader = WebUploader.create({\n\t\t\t\tauto : true,\n\t\t\t\tpick : {\n\t\t\t\t\tid : '#' + this.uploadBtnId,\n\t\t\t\t\tmultiple : false,// 只上传一个\n\t\t\t\t},\n\t\t\t\taccept : {\n\t\t\t\t\ttitle : 'Images',\n\t\t\t\t\textensions : 'gif,jpg,jpeg,bmp,png',\n                    mimeTypes : 'image/gif,image/jpg,image/jpeg,image/bmp,image/png'\n\t\t\t\t},\n\t\t\t\tswf : Feng.ctxPath\n\t\t\t\t\t\t+ '/static/js/plugins/webuploader/Uploader.swf',\n\t\t\t\tdisableGlobalDnd : true,\n\t\t\t\tduplicate : true,\n\t\t\t\tserver : this.uploadUrl,\n\t\t\t\tfileSingleSizeLimit : this.fileSizeLimit\n\t\t\t});\n\t\t\t\n\t\t\treturn webUploader;\n\t\t},\n\n\t\t/**\n\t\t * 绑定事件\n\t\t */\n\t\tbindEvent : function(bindedObj) {\n\t\t\tvar me =  this;\n\t\t\tbindedObj.on('fileQueued', function(file) {\n\t\t\t\tvar $li = $('<div><img width=\"100px\" height=\"100px\"></div>');\n\t\t\t\tvar $img = $li.find('img');\n\n\t\t\t\t$(\"#\" + me.uploadPreId).html($li);\n\n\t\t\t\t// 生成缩略图\n\t\t\t\tbindedObj.makeThumb(file, function(error, src) {\n\t\t\t\t\tif (error) {\n\t\t\t\t\t\t$img.replaceWith('<span>不能预览</span>');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t$img.attr('src', src);\n\t\t\t\t}, me.picWidth, me.picHeight);\n\t\t\t});\n\n\t\t\t// 文件上传过程中创建进度条实时显示。\n\t\t\tbindedObj.on('uploadProgress', function(file, percentage) {\n                $(\"#\"+me.uploadBarId).css(\"width\",percentage * 100 + \"%\");\n\t\t\t});\n\n\t\t\t// 文件上传成功，给item添加成功class, 用样式标记上传成功。\n\t\t\tbindedObj.on('uploadSuccess', function(file,response) {\n\t\t\t\tFeng.success(\"上传成功\");\n\t\t\t\t$(\"#\" + me.pictureId).val(response);\n\t\t\t});\n\n\t\t\t// 文件上传失败，显示上传出错。\n\t\t\tbindedObj.on('uploadError', function(file) {\n\t\t\t\tFeng.error(\"上传失败\");\n\t\t\t});\n\n\t\t\t// 其他错误\n\t\t\tbindedObj.on('error', function(type) {\n\t\t\t\tif (\"Q_EXCEED_SIZE_LIMIT\" == type) {\n\t\t\t\t\tFeng.error(\"文件大小超出了限制\");\n\t\t\t\t} else if (\"Q_TYPE_DENIED\" == type) {\n\t\t\t\t\tFeng.error(\"文件类型不满足\");\n\t\t\t\t} else if (\"Q_EXCEED_NUM_LIMIT\" == type) {\n\t\t\t\t\tFeng.error(\"上传数量超过限制\");\n\t\t\t\t} else if (\"F_DUPLICATE\" == type) {\n\t\t\t\t\tFeng.error(\"图片选择重复\");\n\t\t\t\t} else {\n\t\t\t\t\tFeng.error(\"上传过程中出错\");\n\t\t\t\t}\n\t\t\t});\n\n\t\t\t// 完成上传完了，成功或者失败\n\t\t\tbindedObj.on('uploadComplete', function(file) {\n\t\t\t});\n\t\t},\n\n        /**\n         * 设置图片上传的进度条的id\n         */\n        setUploadBarId: function (id) {\n            this.uploadBarId = id;\n        }\n\t};\n\n\twindow.$WebUpload = $WebUpload;\n\n}());"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/common/ztree-object.js",
    "content": "/**\n * ztree插件的封装\n */\n(function() {\n\n\tvar $ZTree = function(id, url) {\n\t\tthis.id = id;\n\t\tthis.url = url;\n\t\tthis.onClick = null;\n\t\tthis.settings = null;\n\t\tthis.ondblclick=null;\n\t};\n\n\t$ZTree.prototype = {\n\t\t/**\n\t\t * 初始化ztree的设置\n\t\t */\n\t\tinitSetting : function() {\n\t\t\tvar settings = {\n\t\t\t\tview : {\n\t\t\t\t\tdblClickExpand : true,\n\t\t\t\t\tselectedMulti : false,\n\t\t\t\t\tshowIcon:false\n\t\t\t\t},\n\t\t\t\tdata : {simpleData : {enable : true}},\n\t\t\t\tcallback : {\n\t\t\t\t\tonClick : this.onClick,\n\t\t\t\t\tonDblClick:this.ondblclick\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn settings;\n\t\t},\n\n\t\t/**\n\t\t * 手动设置ztree的设置\n\t\t */\n\t\tsetSettings : function(val) {\n\t\t\tthis.settings = val;\n\t\t},\n\n\t\t/**\n\t\t * 初始化ztree\n\t\t */\n\t\tinit : function() {\n\t\t\tvar zNodeSeting = null;\n\t\t\tif(this.settings != null){\n\t\t\t\tzNodeSeting = this.settings;\n\t\t\t}else{\n\t\t\t\tzNodeSeting = this.initSetting();\n\t\t\t}\n\t\t\tvar zNodes = this.loadNodes();\n\t\t\t$.fn.zTree.init($(\"#\" + this.id), zNodeSeting, zNodes);\n\t\t},\n\n\t\t/**\n\t\t * 绑定onclick事件\n\t\t */\n\t\tbindOnClick : function(func) {\n\t\t\tthis.onClick = func;\n\t\t},\n\t\t/**\n\t\t * 绑定双击事件\n\t\t */\n\t\tbindOnDblClick : function(func) {\n\t\t\tthis.ondblclick=func;\n\t\t},\n\n\n\t\t/**\n\t\t * 加载节点\n\t\t */\n\t\tloadNodes : function() {\n\t\t\tvar zNodes = null;\n\t\t\tvar ajax = new $ax(Feng.ctxPath + this.url, function(data) {\n\t\t\t\tzNodes = data;\n\t\t\t}, function(data) {\n\t\t\t\tFeng.error(\"加载ztree信息失败!\");\n\t\t\t});\n\t\t\tajax.start();\n\t\t\treturn zNodes;\n\t\t},\n\n\t\t/**\n\t\t * 获取选中的值\n\t\t */\n\t\tgetSelectedVal : function(){\n\t\t\tvar zTree = $.fn.zTree.getZTreeObj(this.id);\n\t\t\tvar nodes = zTree.getSelectedNodes();\n\t\t\treturn nodes[0].name;\n\t\t}\n\t};\n\n\twindow.$ZTree = $ZTree;\n\n}());"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/demo.js",
    "content": "$(window).load(function(){\n    //Welcome Message (not for login page)\n    function notify(message, type){\n        $.growl({\n            message: message\n        },{\n            type: type,\n            allow_dismiss: false,\n            label: 'Cancel',\n            className: 'btn-xs btn-inverse',\n            placement: {\n                from: 'top',\n                align: 'right'\n            },\n            delay: 11500,\n            animate: {\n                    enter: 'animated fadeIn',\n                    exit: 'animated fadeOut'\n            },\n            offset: {\n                x: 20,\n                y: 85\n            }\n        });\n    };\n    \n    if (!$('.login-content')[0]) {\n        notify('欢迎光临 Flash Material', 'inverse');\n    } \n});"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/flot-charts/bar-chart.js",
    "content": "$(document).ready(function(){\n    \n    /* Make some random data for Flot Line Chart*/\n    \n    var data1 = [[1,60], [2,30], [3,50], [4,100], [5,10], [6,90], [7,85]];\n    var data2 = [[1,20], [2,90], [3,60], [4,40], [5,100], [6,25], [7,65]];\n    var data3 = [[1,100], [2,20], [3,60], [4,90], [5,80], [6,10], [7,5]];\n    \n    /* Create an Array push the data + Draw the bars*/\n    \n    var barData = new Array();\n\n    barData.push({\n            data : data1,\n            label: 'Tokyo',\n            bars : {\n                    show : true,\n                    barWidth : 0.08,\n                    order : 1,\n                    lineWidth: 0,\n                    fillColor: '#8BC34A'\n            }\n    });\n    \n    barData.push({\n            data : data2,\n            label: 'Seoul',\n            bars : {\n                    show : true,\n                    barWidth : 0.08,\n                    order : 2,\n                    lineWidth: 0,\n                    fillColor: '#00BCD4'\n            }\n    });\n    \n    barData.push({\n            data : data3,\n            label: 'Beijing',\n            bars : {\n                    show : true,\n                    barWidth : 0.08,\n                    order : 3,\n                    lineWidth: 0,\n                    fillColor: '#FF9800'\n            }\n    });\n    \n    /* Let's create the chart */\n    if ($('#bar-chart')[0]) {\n        $.plot($(\"#bar-chart\"), barData, {\n            grid : {\n                    borderWidth: 1,\n                    borderColor: '#eee',\n                    show : true,\n                    hoverable : true,\n                    clickable : true\n            },\n            \n            yaxis: {\n                tickColor: '#eee',\n                tickDecimals: 0,\n                font :{\n                    lineHeight: 13,\n                    style: \"normal\",\n                    color: \"#9f9f9f\",\n                },\n                shadowSize: 0\n            },\n            \n            xaxis: {\n                tickColor: '#fff',\n                tickDecimals: 0,\n                font :{\n                    lineHeight: 13,\n                    style: \"normal\",\n                    color: \"#9f9f9f\"\n                },\n                shadowSize: 0,\n            },\n    \n            legend:{\n                container: '.flc-bar',\n                backgroundOpacity: 0.5,\n                noColumns: 0,\n                backgroundColor: \"white\",\n                lineWidth: 0\n            }\n        });\n    }\n    \n    /* Tooltips for Flot Charts */\n    \n    if ($(\".flot-chart\")[0]) {\n        $(\".flot-chart\").bind(\"plothover\", function (event, pos, item) {\n            if (item) {\n                var x = item.datapoint[0].toFixed(2),\n                    y = item.datapoint[1].toFixed(2);\n                $(\".flot-tooltip\").html(item.series.label + \" of \" + x + \" = \" + y).css({top: item.pageY+5, left: item.pageX+5}).show();\n            }\n            else {\n                $(\".flot-tooltip\").hide();\n            }\n        });\n        \n        $(\"<div class='flot-tooltip' class='chart-tooltip'></div>\").appendTo(\"body\");\n    }\n});"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/flot-charts/curved-line-chart.js",
    "content": "$(document).ready(function(){\n    \n    /* Make some random data for the Chart*/\n    \n    var d1 = [];\n    for (var i = 0; i <= 10; i += 1) {\n        d1.push([i, parseInt(Math.random() * 30)]);\n    }\n    var d2 = [];\n    for (var i = 0; i <= 20; i += 1) {\n        d2.push([i, parseInt(Math.random() * 30)]);\n    }    \n    var d3 = [];\n    for (var i = 0; i <= 10; i += 1) {\n        d3.push([i, parseInt(Math.random() * 30)]);\n    }\n    \n    /* Chart Options */\n    \n    var options = {\n        series: {\n            shadowSize: 0,\n            curvedLines: { //This is a third party plugin to make curved lines\n                apply: true,\n                active: true,\n                monotonicFit: true\n            },\n            lines: {\n                show: false,\n                lineWidth: 0,\n            },\n        },\n        grid: {\n            borderWidth: 0,\n            labelMargin:10,\n            hoverable: true,\n            clickable: true,\n            mouseActiveRadius:6,\n            \n        },\n        xaxis: {\n            tickDecimals: 0,\n            ticks: false\n        },\n        \n        yaxis: {\n            tickDecimals: 0,\n            ticks: false\n        },\n        \n        legend: {\n            show: false\n        }\n    };\n    \n    /* Let's create the chart */\n    \n    if ($(\"#curved-line-chart\")[0]) {\n        $.plot($(\"#curved-line-chart\"), [\n            {data: d1, lines: { show: true, fill: 0.98 }, label: 'Product 1', stack: true, color: '#e3e3e3' },\n            {data: d3, lines: { show: true, fill: 0.98 }, label: 'Product 2', stack: true, color: '#f1dd2c' }\n        ], options);\n    }\n    \n    /* Tooltips for Flot Charts */\n    \n    if ($(\".flot-chart\")[0]) {\n        $(\".flot-chart\").bind(\"plothover\", function (event, pos, item) {\n            if (item) {\n                var x = item.datapoint[0].toFixed(2),\n                    y = item.datapoint[1].toFixed(2);\n                $(\".flot-tooltip\").html(item.series.label + \" of \" + x + \" = \" + y).css({top: item.pageY+5, left: item.pageX+5}).show();\n            }\n            else {\n                $(\".flot-tooltip\").hide();\n            }\n        });\n        \n        $(\"<div class='flot-tooltip' class='chart-tooltip'></div>\").appendTo(\"body\");\n    }\n});"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/flot-charts/dynamic-chart.js",
    "content": "$(document).ready(function(){\n    \n    /* Make some random data*/\n    \n    var data = [];\n    var totalPoints = 300;\n    var updateInterval = 30;\n    \n    function getRandomData() {\n        if (data.length > 0)\n            data = data.slice(1);\n\n        while (data.length < totalPoints) {\n    \n            var prev = data.length > 0 ? data[data.length - 1] : 50,\n                y = prev + Math.random() * 10 - 5;\n            if (y < 0) {\n                y = 0;\n            } else if (y > 90) {\n                y = 90;\n            }\n\n            data.push(y);\n        }\n\n        var res = [];\n        for (var i = 0; i < data.length; ++i) {\n            res.push([i, data[i]])\n        }\n\n        return res;\n    }\n\n    /* Create Chart */\n    \n    if ($('#dynamic-chart')[0]) {\n        var plot = $.plot(\"#dynamic-chart\", [ getRandomData() ], {\n            series: {\n                label: \"Server Process Data\",\n                lines: {\n                    show: true,\n                    lineWidth: 0.2,\n                    fill: 0.6\n                },\n    \n                color: '#00BCD4',\n                shadowSize: 0,\n            },\n            yaxis: {\n                min: 0,\n                max: 100,\n                tickColor: '#eee',\n                font :{\n                    lineHeight: 13,\n                    style: \"normal\",\n                    color: \"#9f9f9f\",\n                },\n                shadowSize: 0,\n    \n            },\n            xaxis: {\n                tickColor: '#eee',\n                show: true,\n                font :{\n                    lineHeight: 13,\n                    style: \"normal\",\n                    color: \"#9f9f9f\",\n                },\n                shadowSize: 0,\n                min: 0,\n                max: 250\n            },\n            grid: {\n                borderWidth: 1,\n                borderColor: '#eee',\n                labelMargin:10,\n                hoverable: true,\n                clickable: true,\n                mouseActiveRadius:6,\n            },\n            legend:{\n                container: '.flc-dynamic',\n                backgroundOpacity: 0.5,\n                noColumns: 0,\n                backgroundColor: \"white\",\n                lineWidth: 0\n            }\n        });\n    }\n        \n    /* Update */    \n    function update() {\n        plot.setData([getRandomData()]);\n        // Since the axes don't change, we don't need to call plot.setupGrid()\n\n        plot.draw();\n        setTimeout(update, updateInterval);\n    }\n    update();\n});"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/flot-charts/line-chart.js",
    "content": "$(document).ready(function(){\n    \n    /* Make some random data for Recent Items chart */\n    \n    var data = [];\n    var totalPoints = 100;\n    var updateInterval = 30;\n    \n    function getRandomData() {\n        if (data.length > 0)\n            data = data.slice(1);\n\n        while (data.length < totalPoints) {\n    \n            var prev = data.length > 0 ? data[data.length - 1] : 50,\n                y = prev + Math.random() * 10 - 5;\n            if (y < 0) {\n                y = 0;\n            } else if (y > 90) {\n                y = 90;\n            }\n\n            data.push(y);\n        }\n\n        var res = [];\n        for (var i = 0; i < data.length; ++i) {\n            res.push([i, data[i]])\n        }\n\n        return res;\n    }\n    \n    /* Make some random data for Flot Line Chart */\n    \n    var d1 = [];\n    for (var i = 0; i <= 10; i += 1) {\n        d1.push([i, parseInt(Math.random() * 30)]);\n    }\n    var d2 = [];\n    for (var i = 0; i <= 20; i += 1) {\n        d2.push([i, parseInt(Math.random() * 30)]);\n    }    \n    var d3 = [];\n    for (var i = 0; i <= 10; i += 1) {\n        d3.push([i, parseInt(Math.random() * 30)]);\n    }\n    \n    /* Chart Options */\n    \n    var options = {\n        series: {\n            shadowSize: 0,\n            lines: {\n                show: false,\n                lineWidth: 0,\n            },\n        },\n        grid: {\n            borderWidth: 0,\n            labelMargin:10,\n            hoverable: true,\n            clickable: true,\n            mouseActiveRadius:6,\n            \n        },\n        xaxis: {\n            tickDecimals: 0,\n            ticks: false\n        },\n        \n        yaxis: {\n            tickDecimals: 0,\n            ticks: false\n        },\n        \n        legend: {\n            show: false\n        }\n    };\n    \n    /* Regular Line Chart */\n    if ($(\"#line-chart\")[0]) {\n        $.plot($(\"#line-chart\"), [\n            {data: d1, lines: { show: true, fill: 0.98 }, label: 'Product 1', stack: true, color: '#e3e3e3' },\n            {data: d3, lines: { show: true, fill: 0.98 }, label: 'Product 2', stack: true, color: '#FFC107' }\n        ], options);\n    }\n    \n    /* Recent Items Table Chart */\n    if ($(\"#recent-items-chart\")[0]) {\n        $.plot($(\"#recent-items-chart\"), [\n            {data: getRandomData(), lines: { show: true, fill: 0.8 }, label: 'Items', stack: true, color: '#00BCD4' },\n        ], options);\n    }\n    \n    /* Tooltips for Flot Charts */\n    \n    if ($(\".flot-chart\")[0]) {\n        $(\".flot-chart\").bind(\"plothover\", function (event, pos, item) {\n            if (item) {\n                var x = item.datapoint[0].toFixed(2),\n                    y = item.datapoint[1].toFixed(2);\n                $(\".flot-tooltip\").html(item.series.label + \" of \" + x + \" = \" + y).css({top: item.pageY+5, left: item.pageX+5}).show();\n            }\n            else {\n                $(\".flot-tooltip\").hide();\n            }\n        });\n        \n        $(\"<div class='flot-tooltip' class='chart-tooltip'></div>\").appendTo(\"body\");\n    }\n});"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/flot-charts/pie-chart.js",
    "content": "$(document).ready(function(){\n    var pieData = [\n        {data: 1, color: '#F44336', label: 'Toyota'},\n        {data: 2, color: '#03A9F4', label: 'Nissan'},\n        {data: 3, color: '#8BC34A', label: 'Hyundai'},\n        {data: 4, color: '#FFEB3B', label: 'Scion'},\n        {data: 4, color: '#009688', label: 'Daihatsu'},\n    ];\n    \n    /* Pie Chart */\n    \n    if($('#pie-chart')[0]){\n        $.plot('#pie-chart', pieData, {\n            series: {\n                pie: {\n                    show: true,\n                    stroke: { \n                        width: 2,\n                    },\n                },\n            },\n            legend: {\n                container: '.flc-pie',\n                backgroundOpacity: 0.5,\n                noColumns: 0,\n                backgroundColor: \"white\",\n                lineWidth: 0\n            },\n            grid: {\n                hoverable: true,\n                clickable: true\n            },\n            tooltip: true,\n            tooltipOpts: {\n                content: \"%p.0%, %s\", // show percentages, rounding to 2 decimal places\n                shifts: {\n                    x: 20,\n                    y: 0\n                },\n                defaultTheme: false,\n                cssClass: 'flot-tooltip'\n            }\n            \n        });\n    }\n    \n    /* Donut Chart */\n\n    if($('#donut-chart')[0]){\n        $.plot('#donut-chart', pieData, {\n            series: {\n                pie: {\n                    innerRadius: 0.5,\n                    show: true,\n                    stroke: { \n                        width: 2,\n                    },\n                },\n            },\n            legend: {\n                container: '.flc-donut',\n                backgroundOpacity: 0.5,\n                noColumns: 0,\n                backgroundColor: \"white\",\n                lineWidth: 0\n            },\n            grid: {\n                hoverable: true,\n                clickable: true\n            },\n            tooltip: true,\n            tooltipOpts: {\n                content: \"%p.0%, %s\", // show percentages, rounding to 2 decimal places\n                shifts: {\n                    x: 20,\n                    y: 0\n                },\n                defaultTheme: false,\n                cssClass: 'flot-tooltip'\n            }\n            \n        });\n    }\n});"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/functions.js",
    "content": "/*\n * Detact Mobile Browser\n */\nif( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {\n   $('html').addClass('ismobile');\n}\n\n$(document).ready(function(){\n    /* --------------------------------------------------------\n        Layout\n    -----------------------------------------------------------*/\n    (function () {\n\n        //Get saved layout type from LocalStorage\n        var layoutStatus = localStorage.getItem('ma-layout-status');\n\n        if(!$('#header-2')[0]) {  //Make it work only on normal headers\n            if (layoutStatus == 1) {\n                $('body').addClass('sw-toggled');\n                $('#tw-switch').prop('checked', true);\n            }\n        }\n\n        $('body').on('change', '#toggle-width input:checkbox', function () {\n            if ($(this).is(':checked')) {\n                setTimeout(function () {\n                    $('body').addClass('toggled sw-toggled');\n                    localStorage.setItem('ma-layout-status', 1);\n                }, 250);\n            }\n            else {\n                setTimeout(function () {\n                    $('body').removeClass('toggled sw-toggled');\n                    localStorage.setItem('ma-layout-status', 0);\n                }, 250);\n            }\n        });\n    })();\n\n    /* --------------------------------------------------------\n        Scrollbar\n    -----------------------------------------------------------*/\n    function scrollBar(selector, theme, mousewheelaxis) {\n        $(selector).mCustomScrollbar({\n            theme: theme,\n            scrollInertia: 100,\n            axis:'yx',\n            mouseWheel: {\n                enable: true,\n                axis: mousewheelaxis,\n                preventDefault: true\n            }\n        });\n    }\n\n    if (!$('html').hasClass('ismobile')) {\n        //On Custom Class\n        if ($('.c-overflow')[0]) {\n            scrollBar('.c-overflow', 'minimal-dark', 'y');\n        }\n    }\n\n    /*\n     * Top Search\n     */\n    (function(){\n        $('body').on('click', '#top-search > a', function(e){\n            e.preventDefault();\n\n            $('#header').addClass('search-toggled');\n            $('#top-search-wrap input').focus();\n        });\n\n        $('body').on('click', '#top-search-close', function(e){\n            e.preventDefault();\n\n            $('#header').removeClass('search-toggled');\n        });\n    })();\n\n    /*\n     * Sidebar\n     */\n    (function(){\n        //Toggle\n        $('body').on('click', '#menu-trigger, #chat-trigger', function(e){\n            e.preventDefault();\n            var x = $(this).data('trigger');\n\n            $(x).toggleClass('toggled');\n            $(this).toggleClass('open');\n\n    \t    //Close opened sub-menus\n    \t    $('.sub-menu.toggled').not('.active').each(function(){\n        \t\t$(this).removeClass('toggled');\n        \t\t$(this).find('ul').hide();\n    \t    });\n\n\n\n\t    $('.profile-menu .main-menu').hide();\n\n            if (x == '#sidebar') {\n\n                $elem = '#sidebar';\n                $elem2 = '#menu-trigger';\n\n                $('#chat-trigger').removeClass('open');\n\n                if (!$('#chat').hasClass('toggled')) {\n                    $('#header').toggleClass('sidebar-toggled');\n                }\n                else {\n                    $('#chat').removeClass('toggled');\n                }\n            }\n\n            if (x == '#chat') {\n                $elem = '#chat';\n                $elem2 = '#chat-trigger';\n\n                $('#menu-trigger').removeClass('open');\n\n                if (!$('#sidebar').hasClass('toggled')) {\n                    $('#header').toggleClass('sidebar-toggled');\n                }\n                else {\n                    $('#sidebar').removeClass('toggled');\n                }\n            }\n\n            //When clicking outside\n            if ($('#header').hasClass('sidebar-toggled')) {\n                $(document).on('click', function (e) {\n                    if (($(e.target).closest($elem).length === 0) && ($(e.target).closest($elem2).length === 0)) {\n                        setTimeout(function(){\n                            $($elem).removeClass('toggled');\n                            $('#header').removeClass('sidebar-toggled');\n                            $($elem2).removeClass('open');\n                        });\n                    }\n                });\n            }\n        })\n\n        //Submenu\n        $('body').on('click', '.sub-menu > a', function(e){\n            e.preventDefault();\n            $(this).next().slideToggle(200);\n            $(this).parent().toggleClass('toggled');\n        });\n    })();\n\n    /*\n     * Clear Notification\n     */\n    $('body').on('click', '[data-clear=\"notification\"]', function(e){\n      e.preventDefault();\n\n      var x = $(this).closest('.listview');\n      var y = x.find('.lv-item');\n      var z = y.size();\n\n      $(this).parent().fadeOut();\n\n      x.find('.list-group').prepend('<i class=\"grid-loading hide-it\"></i>');\n      x.find('.grid-loading').fadeIn(1500);\n\n\n      var w = 0;\n      y.each(function(){\n          var z = $(this);\n          setTimeout(function(){\n          z.addClass('animated fadeOutRightBig').delay(1000).queue(function(){\n              z.remove();\n          });\n          }, w+=150);\n      })\n\n\t//Popup empty message\n\tsetTimeout(function(){\n\t    $('#notifications').addClass('empty');\n\t}, (z*150)+200);\n    });\n\n    /*\n     * Dropdown Menu\n     */\n    if($('.dropdown')[0]) {\n\t//Propagate\n\t$('body').on('click', '.dropdown.open .dropdown-menu', function(e){\n\t    e.stopPropagation();\n\t});\n\n\t$('.dropdown').on('shown.bs.dropdown', function (e) {\n\t    if($(this).attr('data-animation')) {\n\t\t$animArray = [];\n\t\t$animation = $(this).data('animation');\n\t\t$animArray = $animation.split(',');\n\t\t$animationIn = 'animated '+$animArray[0];\n\t\t$animationOut = 'animated '+ $animArray[1];\n\t\t$animationDuration = ''\n\t\tif(!$animArray[2]) {\n\t\t    $animationDuration = 500; //if duration is not defined, default is set to 500ms\n\t\t}\n\t\telse {\n\t\t    $animationDuration = $animArray[2];\n\t\t}\n\n\t\t$(this).find('.dropdown-menu').removeClass($animationOut)\n\t\t$(this).find('.dropdown-menu').addClass($animationIn);\n\t    }\n\t});\n\n\t$('.dropdown').on('hide.bs.dropdown', function (e) {\n\t    if($(this).attr('data-animation')) {\n    \t\te.preventDefault();\n    \t\t$this = $(this);\n    \t\t$dropdownMenu = $this.find('.dropdown-menu');\n\n    \t\t$dropdownMenu.addClass($animationOut);\n    \t\tsetTimeout(function(){\n    \t\t    $this.removeClass('open')\n\n    \t\t}, $animationDuration);\n    \t    }\n    \t});\n    }\n\n\n    /*\n     * Todo Add new item\n     */\n    if ($('#todo-lists')[0]) {\n    \t//Add Todo Item\n    \t$('body').on('click', '#add-tl-item .add-new-item', function(){\n    \t    $(this).parent().addClass('toggled');\n    \t});\n\n            //Dismiss\n            $('body').on('click', '.add-tl-actions > a', function(e){\n                e.preventDefault();\n                var x = $(this).closest('#add-tl-item');\n                var y = $(this).data('tl-action');\n\n                if (y == \"dismiss\") {\n                    x.find('textarea').val('');\n                    x.removeClass('toggled');\n                }\n\n                if (y == \"save\") {\n                    x.find('textarea').val('');\n                    x.removeClass('toggled');\n                }\n    \t});\n    }\n\n    /*\n     * Auto Hight Textarea\n     */\n    if ($('.auto-size')[0]) {\n\t   autosize($('.auto-size'));\n    }\n\n    /*\n    * Profile Menu\n    */\n    $('body').on('click', '.profile-menu > a', function(e){\n        e.preventDefault();\n        $(this).parent().toggleClass('toggled');\n\t    $(this).next().slideToggle(200);\n    });\n\n    /*\n     * Text Feild\n     */\n\n    //Add blue animated border and remove with condition when focus and blur\n    if($('.fg-line')[0]) {\n        $('body').on('focus', '.fg-line .form-control', function(){\n            $(this).closest('.fg-line').addClass('fg-toggled');\n        })\n\n        $('body').on('blur', '.form-control', function(){\n            var p = $(this).closest('.form-group, .input-group');\n            var i = p.find('.form-control').val();\n\n            if (p.hasClass('fg-float')) {\n                if (i.length == 0) {\n                    $(this).closest('.fg-line').removeClass('fg-toggled');\n                }\n            }\n            else {\n                $(this).closest('.fg-line').removeClass('fg-toggled');\n            }\n        });\n    }\n\n    //Add blue border for pre-valued fg-flot text feilds\n    if($('.fg-float')[0]) {\n        $('.fg-float .form-control').each(function(){\n            var i = $(this).val();\n\n            if (!i.length == 0) {\n                $(this).closest('.fg-line').addClass('fg-toggled');\n            }\n\n        });\n    }\n\n    /*\n     * Audio and Video\n     */\n    if($('audio, video')[0]) {\n        $('video,audio').mediaelementplayer();\n    }\n\n    /*\n     * Tag Select\n     */\n    if($('.chosen')[0]) {\n        $('.chosen').chosen({\n            width: '100%',\n            allow_single_deselect: true\n        });\n    }\n\n    /*\n     * Input Slider\n     */\n    //Basic\n    if($('.input-slider')[0]) {\n        $('.input-slider').each(function(){\n            var isStart = $(this).data('is-start');\n\n            $(this).noUiSlider({\n                start: isStart,\n                range: {\n                    'min': 0,\n                    'max': 100,\n                }\n            });\n        });\n    }\n\n    //Range slider\n    if($('.input-slider-range')[0]) {\n\t$('.input-slider-range').noUiSlider({\n\t    start: [30, 60],\n\t    range: {\n\t\t    'min': 0,\n\t\t    'max': 100\n\t    },\n\t    connect: true\n\t});\n    }\n\n    //Range slider with value\n    if($('.input-slider-values')[0]) {\n\t$('.input-slider-values').noUiSlider({\n\t    start: [ 45, 80 ],\n\t    connect: true,\n\t    direction: 'rtl',\n\t    behaviour: 'tap-drag',\n\t    range: {\n\t\t    'min': 0,\n\t\t    'max': 100\n\t    }\n\t});\n\n\t$('.input-slider-values').Link('lower').to($('#value-lower'));\n        $('.input-slider-values').Link('upper').to($('#value-upper'), 'html');\n    }\n\n    /*\n     * Input Mask\n     */\n    if ($('input-mask')[0]) {\n        $('.input-mask').mask();\n    }\n\n    /*\n     * Color Picker\n     */\n    if ($('.color-picker')[0]) {\n\t    $('.color-picker').each(function(){\n            var colorOutput = $(this).closest('.cp-container').find('.cp-value');\n            $(this).farbtastic(colorOutput);\n        });\n    }\n\n    /*\n     * HTML Editor\n     */\n    if ($('.html-editor')[0]) {\n\t   $('.html-editor').summernote({\n            height: 150\n        });\n    }\n\n    if($('.html-editor-click')[0]) {\n        //Edit\n        $('body').on('click', '.hec-button', function(){\n            $('.html-editor-click').summernote({\n                focus: true\n            });\n            $('.hec-save').show();\n        })\n\n        //Save\n        $('body').on('click', '.hec-save', function(){\n            $('.html-editor-click').code();\n            $('.html-editor-click').destroy();\n            $('.hec-save').hide();\n            notify('Content Saved Successfully!', 'success');\n        });\n    }\n\n    //Air Mode\n    if($('.html-editor-airmod')[0]) {\n        $('.html-editor-airmod').summernote({\n            airMode: true\n        });\n    }\n\n    /*\n     * Date Time Picker\n     */\n\n    //Date Time Picker\n    if ($('.date-time-picker')[0]) {\n\t   $('.date-time-picker').datetimepicker(\n           {\n               locale : 'zh-cn'\n           }\n       );\n    }\n\n    //Time\n    if ($('.time-picker')[0]) {\n    \t$('.time-picker').datetimepicker({\n            locale : 'zh-cn',\n    \t    format: 'LT'\n\n    \t});\n    }\n\n    //Date\n    if ($('.date-picker')[0]) {\n    \t$('.date-picker').datetimepicker({\n            locale : 'zh-cn',\n    \t    format: 'YYYY-MM-DD'\n    \t});\n    }\n\n    /*\n     * Form Wizard\n     */\n\n    if ($('.form-wizard-basic')[0]) {\n    \t$('.form-wizard-basic').bootstrapWizard({\n    \t    tabClass: 'fw-nav',\n            'nextSelector': '.next',\n            'previousSelector': '.previous'\n    \t});\n    }\n\n    /*\n     * Bootstrap Growl - Notifications popups\n     */\n    function notify(message, type){\n        $.growl({\n            message: message\n        },{\n            type: type,\n            allow_dismiss: false,\n            label: 'Cancel',\n            className: 'btn-xs btn-inverse',\n            placement: {\n                from: 'top',\n                align: 'right'\n            },\n            delay: 2500,\n            animate: {\n                    enter: 'animated bounceIn',\n                    exit: 'animated bounceOut'\n            },\n            offset: {\n                x: 20,\n                y: 85\n            }\n        });\n    };\n\n    /*\n     * Waves Animation\n     */\n    (function(){\n         Waves.attach('.btn:not(.btn-icon):not(.btn-float)');\n         Waves.attach('.btn-icon, .btn-float', ['waves-circle', 'waves-float']);\n        Waves.init();\n    })();\n\n    /*\n     * Lightbox\n     */\n    if ($('.lightbox')[0]) {\n        $('.lightbox').lightGallery({\n            enableTouch: true\n        });\n    }\n\n    /*\n     * Link prevent\n     */\n    $('body').on('click', '.a-prevent', function(e){\n        e.preventDefault();\n    });\n\n    /*\n     * Collaspe Fix\n     */\n    if ($('.collapse')[0]) {\n\n        //Add active class for opened items\n        $('.collapse').on('show.bs.collapse', function (e) {\n            $(this).closest('.panel').find('.panel-heading').addClass('active');\n        });\n\n        $('.collapse').on('hide.bs.collapse', function (e) {\n            $(this).closest('.panel').find('.panel-heading').removeClass('active');\n        });\n\n        //Add active class for pre opened items\n        $('.collapse.in').each(function(){\n            $(this).closest('.panel').find('.panel-heading').addClass('active');\n        });\n    }\n\n    /*\n     * Tooltips\n     */\n    if ($('[data-toggle=\"tooltip\"]')[0]) {\n        $('[data-toggle=\"tooltip\"]').tooltip();\n    }\n\n    /*\n     * Popover\n     */\n    if ($('[data-toggle=\"popover\"]')[0]) {\n        $('[data-toggle=\"popover\"]').popover();\n    }\n\n    /*\n     * Message\n     */\n\n    //Actions\n    if ($('.on-select')[0]) {\n        var checkboxes = '.lv-avatar-content input:checkbox';\n        var actions = $('.on-select').closest('.lv-actions');\n\n        $('body').on('click', checkboxes, function() {\n            if ($(checkboxes+':checked')[0]) {\n                actions.addClass('toggled');\n            }\n            else {\n                actions.removeClass('toggled');\n            }\n        });\n    }\n\n    if($('#ms-menu-trigger')[0]) {\n        $('body').on('click', '#ms-menu-trigger', function(e){\n            e.preventDefault();\n            $(this).toggleClass('open');\n            $('.ms-menu').toggleClass('toggled');\n        });\n    }\n\n    /*\n     * Login\n     */\n    if ($('.login-content')[0]) {\n        //Add class to HTML. This is used to center align the logn box\n        $('html').addClass('login-content');\n\n        $('body').on('click', '.login-navigation > li', function(){\n            var z = $(this).data('block');\n            var t = $(this).closest('.lc-block');\n\n            t.removeClass('toggled');\n\n            setTimeout(function(){\n                $(z).addClass('toggled');\n            });\n\n        })\n    }\n\n    /*\n     * Fullscreen Browsing\n     */\n    if ($('[data-action=\"fullscreen\"]')[0]) {\n\tvar fs = $(\"[data-action='fullscreen']\");\n\tfs.on('click', function(e) {\n\t    e.preventDefault();\n\n\t    //Launch\n\t    function launchIntoFullscreen(element) {\n\n\t\tif(element.requestFullscreen) {\n\t\t    element.requestFullscreen();\n\t\t} else if(element.mozRequestFullScreen) {\n\t\t    element.mozRequestFullScreen();\n\t\t} else if(element.webkitRequestFullscreen) {\n\t\t    element.webkitRequestFullscreen();\n\t\t} else if(element.msRequestFullscreen) {\n\t\t    element.msRequestFullscreen();\n\t\t}\n\t    }\n\n\t    //Exit\n\t    function exitFullscreen() {\n\n\t\tif(document.exitFullscreen) {\n\t\t    document.exitFullscreen();\n\t\t} else if(document.mozCancelFullScreen) {\n\t\t    document.mozCancelFullScreen();\n\t\t} else if(document.webkitExitFullscreen) {\n\t\t    document.webkitExitFullscreen();\n\t\t}\n\t    }\n\n\t    launchIntoFullscreen(document.documentElement);\n\t    fs.closest('.dropdown').removeClass('open');\n\t});\n    }\n\n    /*\n     * Clear Local Storage\n     */\n    if ($('[data-action=\"clear-localstorage\"]')[0]) {\n        var cls = $('[data-action=\"clear-localstorage\"]');\n\n        cls.on('click', function(e) {\n            e.preventDefault();\n\n            swal({\n                title: \"Are you sure?\",\n                text: \"All your saved localStorage values will be removed\",\n                type: \"warning\",\n                showCancelButton: true,\n                confirmButtonColor: \"#DD6B55\",\n                confirmButtonText: \"Yes, delete it!\",\n                closeOnConfirm: false\n            }, function(){\n                localStorage.clear();\n                swal(\"Done!\", \"localStorage is cleared\", \"success\");\n            });\n        });\n    }\n\n    /*\n     * Profile Edit Toggle\n     */\n    if ($('[data-pmb-action]')[0]) {\n        $('body').on('click', '[data-pmb-action]', function(e){\n            e.preventDefault();\n            var d = $(this).data('pmb-action');\n\n            if (d === \"edit\") {\n                $(this).closest('.pmb-block').toggleClass('toggled');\n            }\n\n            if (d === \"reset\") {\n                $(this).closest('.pmb-block').removeClass('toggled');\n            }\n\n\n        });\n    }\n\n    /*\n     * IE 9 Placeholder\n     */\n    if($('html').hasClass('ie9')) {\n        $('input, textarea').placeholder({\n            customClass: 'ie9-placeholder'\n        });\n    }\n\n\n    /*\n     * Listview Search\n     */\n    if ($('.lvh-search-trigger')[0]) {\n\n\n        $('body').on('click', '.lvh-search-trigger', function(e){\n            e.preventDefault();\n            x = $(this).closest('.lv-header-alt').find('.lvh-search');\n\n            x.fadeIn(300);\n            x.find('.lvhs-input').focus();\n        });\n\n        //Close Search\n        $('body').on('click', '.lvh-search-close', function(){\n            x.fadeOut(300);\n            setTimeout(function(){\n                x.find('.lvhs-input').val('');\n            }, 350);\n        })\n    }\n\n\n    /*\n     * Print\n     */\n    if ($('[data-action=\"print\"]')[0]) {\n        $('body').on('click', '[data-action=\"print\"]', function(e){\n            e.preventDefault();\n\n            window.print();\n        })\n    }\n\n    /*\n     * Typeahead Auto Complete\n     */\n     if($('.typeahead')[0]) {\n\n          var statesArray = ['Alabama', 'Alaska', 'Arizona', 'Arkansas', 'California',\n            'Colorado', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii',\n            'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana',\n            'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota',\n            'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire',\n            'New Jersey', 'New Mexico', 'New York', 'North Carolina', 'North Dakota',\n            'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island',\n            'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont',\n            'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'\n          ];\n        var states = new Bloodhound({\n            datumTokenizer: Bloodhound.tokenizers.whitespace,\n            queryTokenizer: Bloodhound.tokenizers.whitespace,\n            local: statesArray\n        });\n\n        $('.typeahead').typeahead({\n            hint: true,\n            highlight: true,\n            minLength: 1\n        },\n        {\n          name: 'states',\n          source: states\n        });\n    }\n\n\n    /*\n     * Wall\n     */\n    if ($('.wcc-toggle')[0]) {\n        var z = '<div class=\"wcc-inner\">' +\n                    '<textarea class=\"wcci-text auto-size\" placeholder=\"Write Something...\"></textarea>' +\n                '</div>' +\n                '<div class=\"m-t-15\">' +\n                    '<button class=\"btn btn-sm btn-primary\">Post</button>' +\n                    '<button class=\"btn btn-sm btn-link wcc-cencel\">Cancel</button>' +\n                '</div>'\n\n\n        $('body').on('click', '.wcc-toggle', function() {\n            $(this).parent().html(z);\n            autosize($('.auto-size')); //Reload Auto size textarea\n        });\n\n        //Cancel\n        $('body').on('click', '.wcc-cencel', function(e) {\n            e.preventDefault();\n\n            $(this).closest('.wc-comment').find('.wcc-inner').addClass('wcc-toggle').html('Write Something...')\n        });\n\n    }\n\n    /*\n     * Skin Change\n     */\n    $('body').on('click', '[data-skin]', function() {\n        var currentSkin = $('[data-current-skin]').data('current-skin');\n        var skin = $(this).data('skin');\n\n        $('[data-current-skin]').attr('data-current-skin', skin)\n\n    });\n\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/hplus.js",
    "content": "//自定义js\n\n//公共配置\n\n\n$(document).ready(function () {\n\n    // MetsiMenu\n    $('#side-menu').metisMenu();\n    // 打开右侧边栏\n    $('.right-sidebar-toggle').click(function () {\n        $('#right-sidebar').toggleClass('sidebar-open');\n    });\n\n    // 右侧边栏使用slimscroll\n    $('.sidebar-container').slimScroll({\n        height: '100%',\n        railOpacity: 0.4,\n        wheelStep: 10\n    });\n\n    // 打开聊天窗口\n    $('.open-small-chat').click(function () {\n        $(this).children().toggleClass('fa-comments').toggleClass('fa-remove');\n        $('.small-chat-box').toggleClass('active');\n    });\n\n    // 聊天窗口使用slimscroll\n    $('.small-chat-box .content').slimScroll({\n        height: '234px',\n        railOpacity: 0.4\n    });\n\n    // Small todo handler\n    $('.check-link').click(function () {\n        var button = $(this).find('i');\n        var label = $(this).next('span');\n        button.toggleClass('fa-check-square').toggleClass('fa-square-o');\n        label.toggleClass('todo-completed');\n        return false;\n    });\n\n    //固定菜单栏\n    $(function () {\n        $('.sidebar-collapse').slimScroll({\n            height: '100%',\n            railOpacity: 0.9,\n            alwaysVisible: false\n        });\n    });\n\n\n    // 菜单切换\n    $('.navbar-minimalize').click(function () {\n        $(\"body\").toggleClass(\"mini-navbar\");\n        SmoothlyMenu();\n    });\n\n\n    // 侧边栏高度\n    function fix_height() {\n        var heightWithoutNavbar = $(\"body > #wrapper\").height() - 61;\n        $(\".sidebard-panel\").css(\"min-height\", heightWithoutNavbar + \"px\");\n    }\n    fix_height();\n\n    $(window).bind(\"load resize click scroll\", function () {\n        if (!$(\"body\").hasClass('body-small')) {\n            fix_height();\n        }\n    });\n\n    //侧边栏滚动\n    $(window).scroll(function () {\n        if ($(window).scrollTop() > 0 && !$('body').hasClass('fixed-nav')) {\n            $('#right-sidebar').addClass('sidebar-top');\n        } else {\n            $('#right-sidebar').removeClass('sidebar-top');\n        }\n    });\n\n    $('.full-height-scroll').slimScroll({\n        height: '100%'\n    });\n\n    $('#side-menu>li').click(function () {\n        if ($('body').hasClass('mini-navbar')) {\n            NavToggle();\n        }\n    });\n    $('#side-menu>li li a').click(function () {\n        if ($(window).width() < 769) {\n            NavToggle();\n        }\n    });\n\n    //点击菜单的时候高亮显示菜单\n    $(\"a[name='tabMenuItem']\").click(function(){\n        clearTabMenuItem();\n        $(this).addClass(\"tab-menu-selected\");\n    });\n\n    $('.nav-close').click(NavToggle);\n\n    //ios浏览器兼容性处理\n    if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) {\n        $('#content-main').css('overflow-y', 'auto');\n    }\n\n});\n\n$(window).bind(\"load resize\", function () {\n    if ($(this).width() < 769) {\n        $('body').addClass('mini-navbar');\n        $('.navbar-static-side').fadeIn();\n    }\n});\n\nfunction clearTabMenuItem(){\n    $(\"a[name='tabMenuItem']\").each(function(){\n        $(this).removeClass(\"tab-menu-selected\");\n    });\n}\n\nfunction highLightMenuItem(hrefVal){\n    clearTabMenuItem();\n    $(\"a[href='\" + hrefVal + \"']\").addClass(\"tab-menu-selected\");\n}\n\nfunction NavToggle() {\n    $('.navbar-minimalize').trigger('click');\n}\n\nfunction SmoothlyMenu() {\n    if (!$('body').hasClass('mini-navbar')) {\n        $('#side-menu').hide();\n        setTimeout(\n            function () {\n                $('#side-menu').fadeIn(500);\n            }, 100);\n    } else if ($('body').hasClass('fixed-sidebar')) {\n        $('#side-menu').hide();\n        setTimeout(\n            function () {\n                $('#side-menu').fadeIn(500);\n            }, 300);\n    } else {\n        $('#side-menu').removeAttr('style');\n    }\n}\n\n\n//主题设置\n$(function () {\n\n    // 顶部菜单固定\n    $('#fixednavbar').click(function () {\n        if ($('#fixednavbar').is(':checked')) {\n            $(\".navbar-static-top\").removeClass('navbar-static-top').addClass('navbar-fixed-top');\n            $(\"body\").removeClass('boxed-layout');\n            $(\"body\").addClass('fixed-nav');\n            $('#boxedlayout').prop('checked', false);\n\n            if (localStorageSupport) {\n                localStorage.setItem(\"boxedlayout\", 'off');\n            }\n\n            if (localStorageSupport) {\n                localStorage.setItem(\"fixednavbar\", 'on');\n            }\n        } else {\n            $(\".navbar-fixed-top\").removeClass('navbar-fixed-top').addClass('navbar-static-top');\n            $(\"body\").removeClass('fixed-nav');\n\n            if (localStorageSupport) {\n                localStorage.setItem(\"fixednavbar\", 'off');\n            }\n        }\n    });\n\n\n    // 收起左侧菜单\n    $('#collapsemenu').click(function () {\n        if ($('#collapsemenu').is(':checked')) {\n            $(\"body\").addClass('mini-navbar');\n            SmoothlyMenu();\n\n            if (localStorageSupport) {\n                localStorage.setItem(\"collapse_menu\", 'on');\n            }\n\n        } else {\n            $(\"body\").removeClass('mini-navbar');\n            SmoothlyMenu();\n\n            if (localStorageSupport) {\n                localStorage.setItem(\"collapse_menu\", 'off');\n            }\n        }\n    });\n\n    // 固定宽度\n    $('#boxedlayout').click(function () {\n        if ($('#boxedlayout').is(':checked')) {\n            $(\"body\").addClass('boxed-layout');\n            $('#fixednavbar').prop('checked', false);\n            $(\".navbar-fixed-top\").removeClass('navbar-fixed-top').addClass('navbar-static-top');\n            $(\"body\").removeClass('fixed-nav');\n            if (localStorageSupport) {\n                localStorage.setItem(\"fixednavbar\", 'off');\n            }\n\n\n            if (localStorageSupport) {\n                localStorage.setItem(\"boxedlayout\", 'on');\n            }\n        } else {\n            $(\"body\").removeClass('boxed-layout');\n\n            if (localStorageSupport) {\n                localStorage.setItem(\"boxedlayout\", 'off');\n            }\n        }\n    });\n\n    // 默认主题\n    $('.s-skin-0').click(function () {\n        $(\"body\").removeClass(\"skin-1\");\n        $(\"body\").removeClass(\"skin-2\");\n        $(\"body\").removeClass(\"skin-3\");\n        return false;\n    });\n\n    // 蓝色主题\n    $('.s-skin-1').click(function () {\n        $(\"body\").removeClass(\"skin-2\");\n        $(\"body\").removeClass(\"skin-3\");\n        $(\"body\").addClass(\"skin-1\");\n        return false;\n    });\n\n    // 黄色主题\n    $('.s-skin-3').click(function () {\n        $(\"body\").removeClass(\"skin-1\");\n        $(\"body\").removeClass(\"skin-2\");\n        $(\"body\").addClass(\"skin-3\");\n        return false;\n    });\n\n    if (localStorageSupport) {\n        var collapse = localStorage.getItem(\"collapse_menu\");\n        var fixednavbar = localStorage.getItem(\"fixednavbar\");\n        var boxedlayout = localStorage.getItem(\"boxedlayout\");\n\n        if (collapse == 'on') {\n            $('#collapsemenu').prop('checked', 'checked')\n        }\n        if (fixednavbar == 'on') {\n            $('#fixednavbar').prop('checked', 'checked')\n        }\n        if (boxedlayout == 'on') {\n            $('#boxedlayout').prop('checked', 'checked')\n        }\n    }\n\n    if (localStorageSupport) {\n\n        var collapse = localStorage.getItem(\"collapse_menu\");\n        var fixednavbar = localStorage.getItem(\"fixednavbar\");\n        var boxedlayout = localStorage.getItem(\"boxedlayout\");\n\n        var body = $('body');\n\n        if (collapse == 'on') {\n            if (!body.hasClass('body-small')) {\n                body.addClass('mini-navbar');\n            }\n        }\n\n        if (fixednavbar == 'on') {\n            $(\".navbar-static-top\").removeClass('navbar-static-top').addClass('navbar-fixed-top');\n            body.addClass('fixed-nav');\n        }\n\n        if (boxedlayout == 'on') {\n            body.addClass('boxed-layout');\n        }\n    }\n});\n\n//判断浏览器是否支持html5本地存储\nfunction localStorageSupport() {\n    return (('localStorage' in window) && window['localStorage'] !== null)\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/bootstrap-table/locale/bootstrap-table-zh-CN.js",
    "content": "/**\n * Bootstrap Table Chinese translation\n * Author: Zhixin Wen<wenzhixin2010@gmail.com>\n */\n(function ($) {\n    'use strict';\n\n    $.fn.bootstrapTable.locales['zh-CN'] = {\n        formatLoadingMessage: function () {\n            return '正在努力地加载数据中，请稍候……';\n        },\n        formatRecordsPerPage: function (pageNumber) {\n            return '每页显示 ' + pageNumber + ' 条记录';\n        },\n        formatShowingRows: function (pageFrom, pageTo, totalRows) {\n            return '显示第 ' + pageFrom + ' 到第 ' + pageTo + ' 条记录，总共 ' + totalRows + ' 条记录';\n        },\n        formatSearch: function () {\n            return '搜索';\n        },\n        formatNoMatches: function () {\n            return '没有找到匹配的记录';\n        },\n        formatPaginationSwitch: function () {\n            return '隐藏/显示分页';\n        },\n        formatRefresh: function () {\n            return '刷新';\n        },\n        formatToggle: function () {\n            return '切换';\n        },\n        formatColumns: function () {\n            return '列';\n        },\n        formatExport: function () {\n            return '导出数据';\n        },\n        formatClearFilters: function () {\n            return '清空过滤';\n        }\n    };\n\n    $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['zh-CN']);\n\n})(jQuery);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/dataTables/dataTables.bootstrap.js",
    "content": "/* Set the defaults for DataTables initialisation */\n$.extend(true, $.fn.dataTable.defaults, {\n    \"sDom\": \"<'row'<'col-sm-6'l><'col-sm-6'f>r>\" + \"t\" + \"<'row'<'col-sm-6'i><'col-sm-6'p>>\",\n    \"oLanguage\": {\n        \"sLengthMenu\": \"每页 _MENU_ 条记录\"\n    }\n});\n\n\n/* Default class modification */\n$.extend($.fn.dataTableExt.oStdClasses, {\n    \"sWrapper\": \"dataTables_wrapper form-inline\",\n    \"sFilterInput\": \"form-control input-sm\",\n    \"sLengthSelect\": \"form-control input-sm\"\n});\n\n// In 1.10 we use the pagination renderers to draw the Bootstrap paging,\n// rather than  custom plug-in\nif ($.fn.dataTable.Api) {\n    $.fn.dataTable.defaults.renderer = 'bootstrap';\n    $.fn.dataTable.ext.renderer.pageButton.bootstrap = function(settings, host, idx, buttons, page, pages) {\n        var api = new $.fn.dataTable.Api(settings);\n        var classes = settings.oClasses;\n        var lang = settings.oLanguage.oPaginate;\n        var btnDisplay, btnClass;\n\n        var attach = function(container, buttons) {\n            var i, ien, node, button;\n            var clickHandler = function(e) {\n                e.preventDefault();\n                if (e.data.action !== 'ellipsis') {\n                    api.page(e.data.action).draw(false);\n                }\n            };\n\n            for (i = 0, ien = buttons.length; i < ien; i++) {\n                button = buttons[i];\n\n                if ($.isArray(button)) {\n                    attach(container, button);\n                } else {\n                    btnDisplay = '';\n                    btnClass = '';\n\n                    switch (button) {\n                        case 'ellipsis':\n                            btnDisplay = '&hellip;';\n                            btnClass = 'disabled';\n                            break;\n\n                        case 'first':\n                            btnDisplay = lang.sFirst;\n                            btnClass = button + (page > 0 ?\n                                '' : ' disabled');\n                            break;\n\n                        case 'previous':\n                            btnDisplay = lang.sPrevious;\n                            btnClass = button + (page > 0 ?\n                                '' : ' disabled');\n                            break;\n\n                        case 'next':\n                            btnDisplay = lang.sNext;\n                            btnClass = button + (page < pages - 1 ?\n                                '' : ' disabled');\n                            break;\n\n                        case 'last':\n                            btnDisplay = lang.sLast;\n                            btnClass = button + (page < pages - 1 ?\n                                '' : ' disabled');\n                            break;\n\n                        default:\n                            btnDisplay = button + 1;\n                            btnClass = page === button ?\n                                'active' : '';\n                            break;\n                    }\n\n                    if (btnDisplay) {\n                        node = $('<li>', {\n                            'class': classes.sPageButton + ' ' + btnClass,\n                            'aria-controls': settings.sTableId,\n                            'tabindex': settings.iTabIndex,\n                            'id': idx === 0 && typeof button === 'string' ? settings.sTableId + '_' + button : null\n                        })\n                            .append($('<a>', {\n                                    'href': '#'\n                                })\n                                .html(btnDisplay)\n                        )\n                            .appendTo(container);\n\n                        settings.oApi._fnBindAction(\n                            node, {\n                                action: button\n                            }, clickHandler\n                        );\n                    }\n                }\n            }\n        };\n\n        attach(\n            $(host).empty().html('<ul class=\"pagination\"/>').children('ul'),\n            buttons\n        );\n    }\n} else {\n    // Integration for 1.9-\n    $.fn.dataTable.defaults.sPaginationType = 'bootstrap';\n\n    /* API method to get paging information */\n    $.fn.dataTableExt.oApi.fnPagingInfo = function(oSettings) {\n        return {\n            \"iStart\": oSettings._iDisplayStart,\n            \"iEnd\": oSettings.fnDisplayEnd(),\n            \"iLength\": oSettings._iDisplayLength,\n            \"iTotal\": oSettings.fnRecordsTotal(),\n            \"iFilteredTotal\": oSettings.fnRecordsDisplay(),\n            \"iPage\": oSettings._iDisplayLength === -1 ? 0 : Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength),\n            \"iTotalPages\": oSettings._iDisplayLength === -1 ? 0 : Math.ceil(oSettings.fnRecordsDisplay() / oSettings._iDisplayLength)\n        };\n    };\n\n    /* Bootstrap style pagination control */\n    $.extend($.fn.dataTableExt.oPagination, {\n        \"bootstrap\": {\n            \"fnInit\": function(oSettings, nPaging, fnDraw) {\n                var oLang = oSettings.oLanguage.oPaginate;\n                var fnClickHandler = function(e) {\n                    e.preventDefault();\n                    if (oSettings.oApi._fnPageChange(oSettings, e.data.action)) {\n                        fnDraw(oSettings);\n                    }\n                };\n\n                $(nPaging).append(\n                    '<ul class=\"pagination\">' +\n                    '<li class=\"prev disabled\"><a href=\"#\">&larr; ' + oLang.sPrevious + '</a></li>' +\n                    '<li class=\"next disabled\"><a href=\"#\">' + oLang.sNext + ' &rarr; </a></li>' +\n                    '</ul>'\n                );\n                var els = $('a', nPaging);\n                $(els[0]).bind('click.DT', {\n                    action: \"previous\"\n                }, fnClickHandler);\n                $(els[1]).bind('click.DT', {\n                    action: \"next\"\n                }, fnClickHandler);\n            },\n\n            \"fnUpdate\": function(oSettings, fnDraw) {\n                var iListLength = 5;\n                var oPaging = oSettings.oInstance.fnPagingInfo();\n                var an = oSettings.aanFeatures.p;\n                var i, ien, j, sClass, iStart, iEnd, iHalf = Math.floor(iListLength / 2);\n\n                if (oPaging.iTotalPages < iListLength) {\n                    iStart = 1;\n                    iEnd = oPaging.iTotalPages;\n                } else if (oPaging.iPage <= iHalf) {\n                    iStart = 1;\n                    iEnd = iListLength;\n                } else if (oPaging.iPage >= (oPaging.iTotalPages - iHalf)) {\n                    iStart = oPaging.iTotalPages - iListLength + 1;\n                    iEnd = oPaging.iTotalPages;\n                } else {\n                    iStart = oPaging.iPage - iHalf + 1;\n                    iEnd = iStart + iListLength - 1;\n                }\n\n                for (i = 0, ien = an.length; i < ien; i++) {\n                    // Remove the middle elements\n                    $('li:gt(0)', an[i]).filter(':not(:last)').remove();\n\n                    // Add the new list items and their event handlers\n                    for (j = iStart; j <= iEnd; j++) {\n                        sClass = (j == oPaging.iPage + 1) ? 'class=\"active\"' : '';\n                        $('<li ' + sClass + '><a href=\"#\">' + j + '</a></li>')\n                            .insertBefore($('li:last', an[i])[0])\n                            .bind('click', function(e) {\n                                e.preventDefault();\n                                oSettings._iDisplayStart = (parseInt($('a', this).text(), 10) - 1) * oPaging.iLength;\n                                fnDraw(oSettings);\n                            });\n                    }\n\n                    // Add / remove disabled classes from the static elements\n                    if (oPaging.iPage === 0) {\n                        $('li:first', an[i]).addClass('disabled');\n                    } else {\n                        $('li:first', an[i]).removeClass('disabled');\n                    }\n\n                    if (oPaging.iPage === oPaging.iTotalPages - 1 || oPaging.iTotalPages === 0) {\n                        $('li:last', an[i]).addClass('disabled');\n                    } else {\n                        $('li:last', an[i]).removeClass('disabled');\n                    }\n                }\n            }\n        }\n    });\n}\n\n\n/*\n * TableTools Bootstrap compatibility\n * Required TableTools 2.1+\n */\nif ($.fn.DataTable.TableTools) {\n    // Set the classes that TableTools uses to something suitable for Bootstrap\n    $.extend(true, $.fn.DataTable.TableTools.classes, {\n        \"container\": \"DTTT btn-group\",\n        \"buttons\": {\n            \"normal\": \"btn btn-default\",\n            \"disabled\": \"disabled\"\n        },\n        \"collection\": {\n            \"container\": \"DTTT_dropdown dropdown-menu\",\n            \"buttons\": {\n                \"normal\": \"\",\n                \"disabled\": \"disabled\"\n            }\n        },\n        \"print\": {\n            \"info\": \"DTTT_print_info modal\"\n        },\n        \"select\": {\n            \"row\": \"active\"\n        }\n    });\n\n    // Have the collection use a bootstrap compatible dropdown\n    $.extend(true, $.fn.DataTable.TableTools.DEFAULTS.oTags, {\n        \"collection\": {\n            \"container\": \"ul\",\n            \"button\": \"li\",\n            \"liner\": \"a\"\n        }\n    });\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/dataTables/jquery.dataTables.js",
    "content": "/*! DataTables 1.10.0-dev\n * ©2008-2013 SpryMedia Ltd - datatables.net/license\n */\n\n/**\n * @summary     DataTables\n * @description Paginate, search and order HTML tables\n * @version     1.10.0-dev\n * @file        jquery.dataTables.js\n * @author      SpryMedia Ltd (www.sprymedia.co.uk)\n * @contact     www.sprymedia.co.uk/contact\n * @copyright   Copyright 2008-2013 SpryMedia Ltd.\n *\n * This source file is free software, available under the following license:\n *   MIT license - http://datatables.net/license\n *\n * This source file is distributed in the hope that it will be useful, but\n * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.\n *\n * For details please refer to: http://www.datatables.net\n */\n\n/*jslint evil: true, undef: true, browser: true */\n/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_empty,_intVal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidateRow,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/\n\n(/** @lends <global> */function( window, document, $, undefined ) {\n\n(function( factory ) {\n\t\"use strict\";\n\n\t// Define as an AMD module if possible\n\tif ( typeof define === 'function' && define.amd )\n\t{\n\t\tdefine( 'datatables', ['jquery'], factory );\n\t}\n\t/* Define using browser globals otherwise\n\t * Prevent multiple instantiations if the script is loaded twice\n\t */\n\telse if ( jQuery && !jQuery.fn.dataTable )\n\t{\n\t\tfactory( jQuery );\n\t}\n}\n(/** @lends <global> */function( $ ) {\n\t\"use strict\";\n\n\t/**\n\t * DataTables is a plug-in for the jQuery Javascript library. It is a highly\n\t * flexible tool, based upon the foundations of progressive enhancement,\n\t * which will add advanced interaction controls to any HTML table. For a\n\t * full list of features please refer to\n\t * [DataTables.net](href=\"http://datatables.net).\n\t *\n\t * Note that the `DataTable` object is not a global variable but is aliased\n\t * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may\n\t * be  accessed.\n\t *\n\t *  @class\n\t *  @param {object} [init={}] Configuration object for DataTables. Options\n\t *    are defined by {@link DataTable.defaults}\n\t *  @requires jQuery 1.3+\n\t *\n\t *  @example\n\t *    // Basic initialisation\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable();\n\t *    } );\n\t *\n\t *  @example\n\t *    // Initialisation with configuration options - in this case, disable\n\t *    // pagination and sorting.\n\t *    $(document).ready( function {\n\t *      $('#example').dataTable( {\n\t *        \"paginate\": false,\n\t *        \"sort\": false\n\t *      } );\n\t *    } );\n\t */\n\tvar DataTable;\n\n\n\t/*\n\t * It is useful to have variables which are scoped locally so only the\n\t * DataTables functions can access them and they don't leak into global space.\n\t * At the same time these functions are often useful over multiple files in the\n\t * core and API, so we list, or at least document, all variables which are used\n\t * by DataTables as private variables here. This also ensures that there is no\n\t * clashing of variable names and that they can easily referenced for reuse.\n\t */\n\n\n\t// Defined else where\n\t//  _selector_run\n\t//  _selector_opts\n\t//  _selector_first\n\t//  _selector_row_indexes\n\n\tvar _ext; // DataTable.ext\n\tvar _Api; // DataTable.Api\n\tvar _api_register; // DataTable.Api.register\n\tvar _api_registerPlural; // DataTable.Api.registerPlural\n\n\tvar _re_new_lines = /[\\r\\n]/g;\n\tvar _re_html = /<.*?>/g;\n\tvar _re_formatted_numeric = /[',$£€¥%]/g;\n\tvar _re_date_start = /^[\\d\\+\\-a-zA-Z]/;\n\n\n\n\n\tvar _empty = function ( d ) {\n\t\treturn !d || d === '-' ? true : false;\n\t};\n\n\n\tvar _intVal = function ( s ) {\n\t\tvar integer = parseInt( s, 10 );\n\t\treturn !isNaN(integer) && isFinite(s) ? integer : null;\n\t};\n\n\n\tvar _isNumber = function ( d, formatted ) {\n\t\tif ( formatted && typeof d === 'string' ) {\n\t\t\td = d.replace( _re_formatted_numeric, '' );\n\t\t}\n\n\t\treturn !d || d==='-' || (!isNaN( parseFloat(d) ) && isFinite( d ));\n\t};\n\n\n\t// A string without HTML in it can be considered to be HTML still\n\tvar _isHtml = function ( d ) {\n\t\treturn !d || typeof d === 'string';\n\t};\n\n\n\tvar _htmlNumeric = function ( d, formatted ) {\n\t\tif ( _empty( d ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tvar html = _isHtml( d );\n\t\treturn ! html ?\n\t\t\tnull :\n\t\t\t_isNumber( _stripHtml( d ), formatted ) ?\n\t\t\t\ttrue :\n\t\t\t\tnull;\n\t};\n\n\n\tvar _pluck = function ( a, prop, prop2 ) {\n\t\tvar out = [];\n\t\tvar i=0, ien=a.length;\n\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] && a[i][ prop ] ) {\n\t\t\t\t\tout.push( a[i][ prop ][ prop2 ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tif ( a[i] ) {\n\t\t\t\t\tout.push( a[i][ prop ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t};\n\n\n\t// Basically the same as _pluck, but rather than looping over `a` we use `order`\n\t// as the indexes to pick from `a`\n\tvar _pluck_order = function ( a, order, prop, prop2 )\n\t{\n\t\tvar out = [];\n\t\tvar i=0, ien=order.length;\n\n\t\t// Could have the test in the loop for slightly smaller code, but speed\n\t\t// is essential here\n\t\tif ( prop2 !== undefined ) {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ][ prop2 ] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor ( ; i<ien ; i++ ) {\n\t\t\t\tout.push( a[ order[i] ][ prop ] );\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t};\n\n\n\tvar _range = function ( len, start )\n\t{\n\t\tvar out = [];\n\t\tvar end;\n\n\t\tif ( start === undefined ) {\n\t\t\tstart = 0;\n\t\t\tend = len;\n\t\t}\n\t\telse {\n\t\t\tend = start;\n\t\t\tstart = len;\n\t\t}\n\n\t\tfor ( var i=start ; i<end ; i++ ) {\n\t\t\tout.push( i );\n\t\t}\n\n\t\treturn out;\n\t};\n\n\n\tvar _stripHtml = function ( d ) {\n\t\treturn d.replace( _re_html, '' );\n\t};\n\n\n\t/**\n\t * Find the unique elements in a source array.\n\t *\n\t * @param  {array} src Source array\n\t * @return {array} Array of unique items\n\t * @ignore\n\t */\n\tvar _unique = function ( src )\n\t{\n\t\t// A faster unique method is to use object keys to identify used values,\n\t\t// but this doesn't work with arrays or objects, which we must also\n\t\t// consider. See jsperf.com/compare-array-unique-versions/4 for more\n\t\t// information.\n\t\tvar\n\t\t\tout = [],\n\t\t\tval,\n\t\t\ti, ien=src.length,\n\t\t\tj, k=0;\n\n\t\tagain: for ( i=0 ; i<ien ; i++ ) {\n\t\t\tval = src[i];\n\n\t\t\tfor ( j=0 ; j<k ; j++ ) {\n\t\t\t\tif ( out[j] === val ) {\n\t\t\t\t\tcontinue again;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tout.push( val );\n\t\t\tk++;\n\t\t}\n\n\t\treturn out;\n\t};\n\n\n\n\t/**\n\t * Create a mapping object that allows camel case parameters to be looked up\n\t * for their Hungarian counterparts. The mapping is stored in a private\n\t * parameter called `_hungarianMap` which can be accessed on the source object.\n\t *  @param {object} o\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnHungarianMap ( o )\n\t{\n\t\tvar\n\t\t\thungarian = 'a aa ao as b fn i m o s ',\n\t\t\tmatch,\n\t\t\tnewKey,\n\t\t\tmap = {};\n\n\t\t$.each( o, function (key, val) {\n\t\t\tmatch = key.match(/^([^A-Z]+?)([A-Z])/);\n\n\t\t\tif ( match && hungarian.indexOf(match[1]+' ') !== -1 )\n\t\t\t{\n\t\t\t\tnewKey = key.replace( match[0], match[2].toLowerCase() );\n\t\t\t\tmap[ newKey ] = key;\n\n\t\t\t\tif ( match[1] === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnHungarianMap( o[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\to._hungarianMap = map;\n\t}\n\n\n\t/**\n\t * Convert from camel case parameters to Hungarian, based on a Hungarian map\n\t * created by _fnHungarianMap.\n\t *  @param {object} src The model object which holds all parameters that can be\n\t *    mapped.\n\t *  @param {object} user The object to convert from camel case to Hungarian.\n\t *  @param {boolean} force When set to `true`, properties which already have a\n\t *    Hungarian value in the `user` object will be overwritten. Otherwise they\n\t *    won't be.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCamelToHungarian ( src, user, force )\n\t{\n\t\tif ( ! src._hungarianMap )\n\t\t{\n\t\t\t_fnHungarianMap( src );\n\t\t}\n\n\t\tvar hungarianKey;\n\n\t\t$.each( user, function (key, val) {\n\t\t\thungarianKey = src._hungarianMap[ key ];\n\n\t\t\tif ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )\n\t\t\t{\n\t\t\t\tuser[hungarianKey] = user[ key ];\n\n\t\t\t\tif ( hungarianKey.charAt(0) === 'o' )\n\t\t\t\t{\n\t\t\t\t\t_fnCamelToHungarian( src[hungarianKey], user[key] );\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t}\n\n\n\t/**\n\t * Language compatibility - when certain options are given, and others aren't, we\n\t * need to duplicate the values over, in order to provide backwards compatibility\n\t * with older language files.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLanguageCompat( oLanguage )\n\t{\n\t\tvar oDefaults = DataTable.defaults.oLanguage;\n\t\tvar zeroRecords = oLanguage.sZeroRecords;\n\n\t\t/* Backwards compatibility - if there is no sEmptyTable given, then use the same as\n\t\t * sZeroRecords - assuming that is given.\n\t\t */\n\t\tif ( !oLanguage.sEmptyTable && zeroRecords &&\n\t\t\toDefaults.sEmptyTable === \"没有数据\" )\n\t\t{\n\t\t\t_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );\n\t\t}\n\n\t\t/* Likewise with loading records */\n\t\tif ( !oLanguage.sLoadingRecords && zeroRecords &&\n\t\t\toDefaults.sLoadingRecords === \"加载中…\" )\n\t\t{\n\t\t\t_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );\n\t\t}\n\t}\n\n\n\t/**\n\t * Map one parameter onto another\n\t *  @param {object} o Object to map\n\t *  @param {*} knew The new parameter name\n\t *  @param {*} old The old parameter name\n\t */\n\tvar _fnCompatMap = function ( o, knew, old ) {\n\t\tif ( o[ knew ] !== undefined ) {\n\t\t\to[ old ] = o[ knew ];\n\t\t}\n\t};\n\n\n\t/**\n\t * Provide backwards compatibility for the main DT options. Note that the new\n\t * options are mapped onto the old parameters, so this is an external interface\n\t * change only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatOpts ( init )\n\t{\n\t\t_fnCompatMap( init, 'ordering',      'bSort' );\n\t\t_fnCompatMap( init, 'orderMulti',    'bSortMulti' );\n\t\t_fnCompatMap( init, 'orderClasses',  'bSortClasses' );\n\t\t_fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );\n\t\t_fnCompatMap( init, 'order',         'aaSorting' );\n\t\t_fnCompatMap( init, 'orderFixed',    'aaSortingFixed' );\n\t\t_fnCompatMap( init, 'paging',        'bPaginate' );\n\t\t_fnCompatMap( init, 'pagingType',    'sPaginationType' );\n\t\t_fnCompatMap( init, 'pageLength',    'iDisplayLength' );\n\t\t_fnCompatMap( init, 'searching',     'bFilter' );\n\t}\n\n\n\t/**\n\t * Provide backwards compatibility for column options. Note that the new options\n\t * are mapped onto the old parameters, so this is an external interface change\n\t * only.\n\t *  @param {object} init Object to map\n\t */\n\tfunction _fnCompatCols ( init )\n\t{\n\t\t_fnCompatMap( init, 'orderable',     'bSortable' );\n\t\t_fnCompatMap( init, 'orderData',     'aDataSort' );\n\t\t_fnCompatMap( init, 'orderSequence', 'asSorting' );\n\t\t_fnCompatMap( init, 'orderDataType', 'sortDataType' );\n\t}\n\n\n\t/**\n\t * Browser feature detection for capabilities, quirks\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBrowserDetect( settings )\n\t{\n\t\tvar browser = settings.oBrowser;\n\n\t\t// Scrolling feature / quirks detection\n\t\tvar n = $('<div/>')\n\t\t\t.css( {\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\theight: 1,\n\t\t\t\twidth: 1,\n\t\t\t\toverflow: 'hidden'\n\t\t\t} )\n\t\t\t.append(\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.css( {\n\t\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\t\ttop: 1,\n\t\t\t\t\t\tleft: 1,\n\t\t\t\t\t\twidth: 100,\n\t\t\t\t\t\toverflow: 'scroll'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$('<div class=\"test\"/>')\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\twidth: '100%',\n\t\t\t\t\t\t\t\theight: 10\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t)\n\t\t\t)\n\t\t\t.appendTo( 'body' );\n\n\t\tvar test = n.find('.test');\n\n\t\t// IE6/7 will oversize a width 100% element inside a scrolling element, to\n\t\t// include the width of the scrollbar, while other browsers ensure the inner\n\t\t// element is contained without forcing scrolling\n\t\tbrowser.bScrollOversize = test[0].offsetWidth === 100;\n\n\t\t// In rtl text layout, some browsers (most, but not all) will place the\n\t\t// scrollbar on the left, rather than the right.\n\t\tbrowser.bScrollbarLeft = test.offset().left !== 1;\n\n\t\tn.remove();\n\t}\n\n\t/**\n\t * Add a column to the list used for the table with default values\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nTh The th element for this column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddColumn( oSettings, nTh )\n\t{\n\t\tvar oDefaults = DataTable.defaults.column;\n\t\tvar iCol = oSettings.aoColumns.length;\n\t\tvar oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {\n\t\t\t\"sSortingClass\": oSettings.oClasses.sSortable,\n\t\t\t\"sSortingClassJUI\": oSettings.oClasses.sSortJUI,\n\t\t\t\"nTh\": nTh ? nTh : document.createElement('th'),\n\t\t\t\"sTitle\":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',\n\t\t\t\"aDataSort\": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],\n\t\t\t\"mData\": oDefaults.mData ? oDefaults.mData : iCol\n\t\t} );\n\t\toSettings.aoColumns.push( oCol );\n\n\t\t/* Add a column specific filter */\n\t\tif ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )\n\t\t{\n\t\t\toSettings.aoPreSearchCols[ iCol ] = $.extend( true, {}, DataTable.models.oSearch );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tvar oPre = oSettings.aoPreSearchCols[ iCol ];\n\n\t\t\t/* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */\n\t\t\tif ( oPre.bRegex === undefined )\n\t\t\t{\n\t\t\t\toPre.bRegex = true;\n\t\t\t}\n\n\t\t\tif ( oPre.bSmart === undefined )\n\t\t\t{\n\t\t\t\toPre.bSmart = true;\n\t\t\t}\n\n\t\t\tif ( oPre.bCaseInsensitive === undefined )\n\t\t\t{\n\t\t\t\toPre.bCaseInsensitive = true;\n\t\t\t}\n\t\t}\n\n\t\t/* Use the column options function to initialise classes etc */\n\t\t_fnColumnOptions( oSettings, iCol, null );\n\t}\n\n\n\t/**\n\t * Apply options for a column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iCol column index to consider\n\t *  @param {object} oOptions object with sType, bVisible and bSearchable etc\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnOptions( oSettings, iCol, oOptions )\n\t{\n\t\tvar oCol = oSettings.aoColumns[ iCol ];\n\t\tvar oClasses = oSettings.oClasses;\n\n\t\t/* User specified column options */\n\t\tif ( oOptions !== undefined && oOptions !== null )\n\t\t{\n\t\t\t// Backwards compatibility\n\t\t\t_fnCompatCols( oOptions );\n\n\t\t\t// Map camel case parameters to their Hungarian counterparts\n\t\t\t_fnCamelToHungarian( DataTable.defaults.column, oOptions );\n\n\t\t\t/* Backwards compatibility for mDataProp */\n\t\t\tif ( oOptions.mDataProp !== undefined && !oOptions.mData )\n\t\t\t{\n\t\t\t\toOptions.mData = oOptions.mDataProp;\n\t\t\t}\n\n\t\t\toCol._sManualType = oOptions.sType;\n\n\t\t\t// `class` is a reserved word in Javascript, so we need to provide\n\t\t\t// the ability to use a valid name for the camel case input\n\t\t\tif ( oOptions.className && ! oOptions.sClass )\n\t\t\t{\n\t\t\t\toOptions.sClass = oOptions.className;\n\t\t\t}\n\n\t\t\t$.extend( oCol, oOptions );\n\t\t\t_fnMap( oCol, oOptions, \"sWidth\", \"sWidthOrig\" );\n\n\t\t\t/* iDataSort to be applied (backwards compatibility), but aDataSort will take\n\t\t\t * priority if defined\n\t\t\t */\n\t\t\tif ( typeof oOptions.iDataSort === 'number' )\n\t\t\t{\n\t\t\t\toCol.aDataSort = [ oOptions.iDataSort ];\n\t\t\t}\n\t\t\t_fnMap( oCol, oOptions, \"aDataSort\" );\n\t\t}\n\n\t\t/* Cache the data get and set functions for speed */\n\t\tvar mDataSrc = oCol.mData;\n\t\tvar mData = _fnGetObjectDataFn( mDataSrc );\n\t\tvar mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;\n\n\t\tvar attrTest = function( src ) {\n\t\t\treturn typeof src === 'string' && src.indexOf('@') !== -1;\n\t\t};\n\t\toCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (\n\t\t\tattrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)\n\t\t);\n\n\t\toCol.fnGetData = function (oData, sSpecific) {\n\t\t\tvar innerData = mData( oData, sSpecific );\n\n\t\t\tif ( oCol.mRender && (sSpecific && sSpecific !== '') )\n\t\t\t{\n\t\t\t\treturn mRender( innerData, sSpecific, oData );\n\t\t\t}\n\t\t\treturn innerData;\n\t\t};\n\t\toCol.fnSetData = _fnSetObjectDataFn( mDataSrc );\n\n\t\t/* Feature sorting overrides column specific when off */\n\t\tif ( !oSettings.oFeatures.bSort )\n\t\t{\n\t\t\toCol.bSortable = false;\n\t\t}\n\n\t\t/* Check that the class assignment is correct for sorting */\n\t\tvar bAsc = $.inArray('asc', oCol.asSorting) !== -1;\n\t\tvar bDesc = $.inArray('desc', oCol.asSorting) !== -1;\n\t\tif ( !oCol.bSortable || (!bAsc && !bDesc) )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableNone;\n\t\t\toCol.sSortingClassJUI = \"\";\n\t\t}\n\t\telse if ( bAsc && !bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableAsc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;\n\t\t}\n\t\telse if ( !bAsc && bDesc )\n\t\t{\n\t\t\toCol.sSortingClass = oClasses.sSortableDesc;\n\t\t\toCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;\n\t\t}\n\t}\n\n\n\t/**\n\t * Adjust the table column widths for new data. Note: you would probably want to\n\t * do a redraw after calling this function!\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAdjustColumnSizing ( settings )\n\t{\n\t\t/* Not interested in doing column width calculation if auto-width is disabled */\n\t\tif ( settings.oFeatures.bAutoWidth !== false )\n\t\t{\n\t\t\tvar columns = settings.aoColumns;\n\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t\tfor ( var i=0 , iLen=columns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tcolumns[i].nTh.style.width = columns[i].sWidth;\n\t\t\t}\n\t\t}\n\n\t\tvar scroll = settings.oScroll;\n\t\tif ( scroll.sY !== '' || scroll.sX !== '')\n\t\t{\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\n\t\t_fnCallbackFire( settings, null, 'column-sizing', [settings] );\n\t}\n\n\n\t/**\n\t * Covert the index of a visible column to the index in the data array (take account\n\t * of hidden columns)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iMatch Visible column index to lookup\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisibleToColumnIndex( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\n\t\treturn typeof aiVis[iMatch] === 'number' ?\n\t\t\taiVis[iMatch] :\n\t\t\tnull;\n\t}\n\n\n\t/**\n\t * Covert the index of an index in the data array and convert it to the visible\n\t *   column index (take account of hidden columns)\n\t *  @param {int} iMatch Column index to lookup\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the data index\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnColumnIndexToVisible( oSettings, iMatch )\n\t{\n\t\tvar aiVis = _fnGetColumns( oSettings, 'bVisible' );\n\t\tvar iPos = $.inArray( iMatch, aiVis );\n\n\t\treturn iPos !== -1 ? iPos : null;\n\t}\n\n\n\t/**\n\t * Get the number of visible columns\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {int} i the number of visible columns\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnVisbleColumns( oSettings )\n\t{\n\t\treturn _fnGetColumns( oSettings, 'bVisible' ).length;\n\t}\n\n\n\t/**\n\t * Get an array of column indexes that match a given property\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sParam Parameter in aoColumns to look for - typically\n\t *    bVisible or bSearchable\n\t *  @returns {array} Array of indexes with matched properties\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetColumns( oSettings, sParam )\n\t{\n\t\tvar a = [];\n\n\t\t$.map( oSettings.aoColumns, function(val, i) {\n\t\t\tif ( val[sParam] ) {\n\t\t\t\ta.push( i );\n\t\t\t}\n\t\t} );\n\n\t\treturn a;\n\t}\n\n\n\tfunction _fnColumnTypes ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar data = settings.aoData;\n\t\tvar types = DataTable.ext.type.detect;\n\t\tvar i, ien, j, jen, k, ken;\n\t\tvar col, cell, detectedType, cache;\n\n\t\t// For each column, spin over the\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcol = columns[i];\n\t\t\tcache = [];\n\n\t\t\tif ( ! col.sType && col._sManualType ) {\n\t\t\t\tcol.sType = col._sManualType;\n\t\t\t}\n\t\t\telse if ( ! col.sType ) {\n\t\t\t\tfor ( j=0, jen=types.length ; j<jen ; j++ ) {\n\t\t\t\t\tfor ( k=0, ken=data.length ; k<ken ; k++ ) {\n\t\t\t\t\t\t// Use a cache array so we only need to get the type data\n\t\t\t\t\t\t// from the formatter once (when using multiple detectors)\n\t\t\t\t\t\tif ( cache[k] === undefined ) {\n\t\t\t\t\t\t\tcache[k] = _fnGetCellData( settings, k, i, 'type' );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdetectedType = types[j]( cache[k] );\n\n\t\t\t\t\t\t// Doesn't match, so break early, since this type can't\n\t\t\t\t\t\t// apply to this column. Also, HTML is a special case since\n\t\t\t\t\t\t// it is so similar to `string`. Just a single match is\n\t\t\t\t\t\t// needed for a column to be html type\n\t\t\t\t\t\tif ( ! detectedType || detectedType === 'html' ) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Type is valid for all data points in the column - use this\n\t\t\t\t\t// type\n\t\t\t\t\tif ( detectedType ) {\n\t\t\t\t\t\tcol.sType = detectedType;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Fall back - if no type was detected, always use string\n\t\t\t\tif ( ! col.sType ) {\n\t\t\t\t\tcol.sType = 'string';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Take the column definitions and static columns arrays and calculate how\n\t * they relate to column indexes. The callback function will then apply the\n\t * definition found for a column to a suitable configuration object.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aoColDefs The aoColumnDefs array that is to be applied\n\t *  @param {array} aoCols The aoColumns array that defines columns individually\n\t *  @param {function} fn Callback function - takes two parameters, the calculated\n\t *    column index and the definition for that column.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, def;\n\n\t\t// Column definitions with aTargets\n\t\tif ( aoColDefs )\n\t\t{\n\t\t\t/* Loop over the definitions array - loop in reverse so first instance has priority */\n\t\t\tfor ( i=aoColDefs.length-1 ; i>=0 ; i-- )\n\t\t\t{\n\t\t\t\tdef = aoColDefs[i];\n\n\t\t\t\t/* Each definition can target multiple columns, as it is an array */\n\t\t\t\tvar aTargets = def.targets !== undefined ?\n\t\t\t\t\tdef.targets :\n\t\t\t\t\tdef.aTargets;\n\n\t\t\t\tif ( ! $.isArray( aTargets ) )\n\t\t\t\t{\n\t\t\t\t\taTargets = [ aTargets ];\n\t\t\t\t}\n\n\t\t\t\tfor ( j=0, jLen=aTargets.length ; j<jLen ; j++ )\n\t\t\t\t{\n\t\t\t\t\tif ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Add columns that we don't yet know about */\n\t\t\t\t\t\twhile( oSettings.aoColumns.length <= aTargets[j] )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t_fnAddColumn( oSettings );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t/* Integer, basic index */\n\t\t\t\t\t\tfn( aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Negative integer, right to left column counting */\n\t\t\t\t\t\tfn( oSettings.aoColumns.length+aTargets[j], def );\n\t\t\t\t\t}\n\t\t\t\t\telse if ( typeof aTargets[j] === 'string' )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Class name matching on TH element */\n\t\t\t\t\t\tfor ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif ( aTargets[j] == \"_all\" ||\n\t\t\t\t\t\t\t     $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfn( k, def );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Statically defined columns array\n\t\tif ( aoCols )\n\t\t{\n\t\t\tfor ( i=0, iLen=aoCols.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\tfn( i, aoCols[i] );\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Add a data array to the table, creating DOM node etc. This is the parallel to\n\t * _fnGatherData, but for adding rows from a Javascript source, rather than a\n\t * DOM source.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {array} aData data array to be added\n\t *  @param {node} [nTr] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddData ( oSettings, aDataIn, nTr, anTds )\n\t{\n\t\t/* Create the object for storing information about this new row */\n\t\tvar iRow = oSettings.aoData.length;\n\t\tvar oData = $.extend( true, {}, DataTable.models.oRow, {\n\t\t\tsrc: nTr ? 'dom' : 'data'\n\t\t} );\n\n\t\toData._aData = aDataIn;\n\t\toSettings.aoData.push( oData );\n\n\t\t/* Create the cells */\n\t\tvar nTd, sThisType;\n\t\tvar columns = oSettings.aoColumns;\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\t// When working with a row, the data source object must be populated. In\n\t\t\t// all other cases, the data source object is already populated, so we\n\t\t\t// don't overwrite it, which might break bindings etc\n\t\t\tif ( nTr ) {\n\t\t\t\t_fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );\n\t\t\t}\n\t\t\tcolumns[i].sType = null;\n\t\t}\n\n\t\t/* Add to the display array */\n\t\toSettings.aiDisplayMaster.push( iRow );\n\n\t\t/* Create the DOM information */\n\t\tif ( !oSettings.oFeatures.bDeferRender )\n\t\t{\n\t\t\t_fnCreateTr( oSettings, iRow, nTr, anTds );\n\t\t}\n\n\t\treturn iRow;\n\t}\n\n\n\t/**\n\t * Add one or more TR elements to the table. Generally we'd expect to\n\t * use this for reading data from a DOM sourced table, but it could be\n\t * used for an TR element. Note that if a TR is given, it is used (i.e.\n\t * it is not cloned).\n\t *  @param {object} settings dataTables settings object\n\t *  @param {array|node|jQuery} trs The TR element(s) to add to the table\n\t *  @returns {array} Array of indexes for the added rows\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddTr( settings, trs )\n\t{\n\t\tvar row;\n\n\t\t// Allow an individual node to be passed in\n\t\tif ( ! (trs instanceof $) ) {\n\t\t\ttrs = $(trs);\n\t\t}\n\n\t\treturn trs.map( function (i, el) {\n\t\t\trow = _fnGetRowElements( settings, el );\n\t\t\treturn _fnAddData( settings, row.data, el, row.cells );\n\t\t} );\n\t}\n\n\n\t/**\n\t * Take a TR element and convert it to an index in aoData\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n the TR element to find\n\t *  @returns {int} index if the node is found, null if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToDataIndex( oSettings, n )\n\t{\n\t\treturn (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;\n\t}\n\n\n\t/**\n\t * Take a TD element and convert it into a column data index (not the visible index)\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow The row number the TD/TH can be found in\n\t *  @param {node} n The TD/TH element to find\n\t *  @returns {int} index if the node is found, -1 if not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnNodeToColumnIndex( oSettings, iRow, n )\n\t{\n\t\treturn $.inArray( n, oSettings.aoData[ iRow ].anCells );\n\t}\n\n\n\t/**\n\t * Get an array of data for a given row from the internal data cache\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow aoData row id\n\t *  @param {string} sSpecific data get type ('type' 'filter' 'sort')\n\t *  @param {array} aiColumns Array of column indexes to get data from\n\t *  @returns {array} Data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )\n\t{\n\t\tvar out = [];\n\t\tfor ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tout.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );\n\t\t}\n\t\treturn out;\n\t}\n\n\n\t/**\n\t * Get the data for a given cell from the internal cache, taking into account data mapping\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow aoData row id\n\t *  @param {int} iCol Column index\n\t *  @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')\n\t *  @returns {*} Cell data\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetCellData( oSettings, iRow, iCol, sSpecific )\n\t{\n\t\tvar oCol = oSettings.aoColumns[iCol];\n\t\tvar oData = oSettings.aoData[iRow]._aData;\n\t\tvar sData = oCol.fnGetData( oData, sSpecific );\n\n\t\tif ( sData === undefined )\n\t\t{\n\t\t\tif ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )\n\t\t\t{\n\t\t\t\t_fnLog( oSettings, 0, \"Requested unknown parameter \"+\n\t\t\t\t\t(typeof oCol.mData=='function' ? '{function}' : \"'\"+oCol.mData+\"'\")+\n\t\t\t\t\t\" for row \"+iRow, 4 );\n\t\t\t\toSettings.iDrawError = oSettings.iDraw;\n\t\t\t}\n\t\t\treturn oCol.sDefaultContent;\n\t\t}\n\n\t\t/* When the data source is null, we can use default column data */\n\t\tif ( (sData === oData || sData === null) && oCol.sDefaultContent !== null )\n\t\t{\n\t\t\tsData = oCol.sDefaultContent;\n\t\t}\n\t\telse if ( typeof sData === 'function' )\n\t\t{\n\t\t\t// If the data source is a function, then we run it and use the return\n\t\t\treturn sData();\n\t\t}\n\n\t\tif ( sData === null && sSpecific == 'display' )\n\t\t{\n\t\t\treturn '';\n\t\t}\n\t\treturn sData;\n\t}\n\n\n\t/**\n\t * Set the value for a specific cell, into the internal data cache\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow aoData row id\n\t *  @param {int} iCol Column index\n\t *  @param {*} val Value to set\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetCellData( oSettings, iRow, iCol, val )\n\t{\n\t\tvar oCol = oSettings.aoColumns[iCol];\n\t\tvar oData = oSettings.aoData[iRow]._aData;\n\n\t\toCol.fnSetData( oData, val );\n\t}\n\n\n\t// Private variable that is used to match action syntax in the data property object\n\tvar __reArray = /\\[.*?\\]$/;\n\tvar __reFn = /\\(\\)$/;\n\n\t/**\n\t * Split string on periods, taking into account escaped periods\n\t * @param  {string} str String to split\n\t * @return {array} Split string\n\t */\n\tfunction _fnSplitObjNotation( str )\n\t{\n\t\treturn $.map( str.match(/(\\\\.|[^\\.])+/g), function ( s ) {\n\t\t\treturn s.replace('\\\\.', '.');\n\t\t} );\n\t}\n\n\n\t/**\n\t * Return a function that can be used to get data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data get function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Build an object of get functions, and wrap them in a single call */\n\t\t\tvar o = {};\n\t\t\t$.each( mSource, function (key, val) {\n\t\t\t\tif ( val ) {\n\t\t\t\t\to[key] = _fnGetObjectDataFn( val );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn function (data, type, extra) {\n\t\t\t\treturn o[ o[type] !== undefined ? type : '_' ](data, type, extra);\n\t\t\t};\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Give an empty string for rendering / sorting etc */\n\t\t\treturn function (data, type) {\n\t\t\t\treturn data;\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, type, extra) {\n\t\t\t\treturn mSource( data, type, extra );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* If there is a . in the source string then the data source is in a\n\t\t\t * nested object so we loop over the data for each level to get the next\n\t\t\t * level down. On each loop we test for undefined, and if found immediately\n\t\t\t * return. This allows entire objects to be missing and sDefaultContent to\n\t\t\t * be used if defined, rather than throwing an error\n\t\t\t */\n\t\t\tvar fetchData = function (data, type, src) {\n\t\t\t\tvar arrayNotation, funcNotation, out, innerSrc;\n\n\t\t\t\tif ( src !== \"\" )\n\t\t\t\t{\n\t\t\t\t\tvar a = _fnSplitObjNotation( src );\n\n\t\t\t\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Check if we are dealing with special notation\n\t\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\n\t\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Array notation\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\n\t\t\t\t\t\t\t// Condition allows simply [] to be passed in\n\t\t\t\t\t\t\tif ( a[i] !== \"\" ) {\n\t\t\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tout = [];\n\n\t\t\t\t\t\t\t// Get the remainder of the nested object to get\n\t\t\t\t\t\t\ta.splice( 0, i+1 );\n\t\t\t\t\t\t\tinnerSrc = a.join('.');\n\n\t\t\t\t\t\t\t// Traverse each entry in the array getting the properties requested\n\t\t\t\t\t\t\tfor ( var j=0, jLen=data.length ; j<jLen ; j++ ) {\n\t\t\t\t\t\t\t\tout.push( fetchData( data[j], type, innerSrc ) );\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// If a string is given in between the array notation indicators, that\n\t\t\t\t\t\t\t// is used to join the strings together, otherwise an array is returned\n\t\t\t\t\t\t\tvar join = arrayNotation[0].substring(1, arrayNotation[0].length-1);\n\t\t\t\t\t\t\tdata = (join===\"\") ? out : out.join(join);\n\n\t\t\t\t\t\t\t// The inner call to fetchData has already traversed through the remainder\n\t\t\t\t\t\t\t// of the source requested, so we exit from the loop\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// Function call\n\t\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\t\tdata = data[ a[i] ]();\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( data === null || data[ a[i] ] === undefined )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn data;\n\t\t\t};\n\n\t\t\treturn function (data, type) {\n\t\t\t\treturn fetchData( data, type, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, type) {\n\t\t\t\treturn data[mSource];\n\t\t\t};\n\t\t}\n\t}\n\n\n\t/**\n\t * Return a function that can be used to set data from a source object, taking\n\t * into account the ability to use nested objects as a source\n\t *  @param {string|int|function} mSource The data source for the object\n\t *  @returns {function} Data set function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSetObjectDataFn( mSource )\n\t{\n\t\tif ( $.isPlainObject( mSource ) )\n\t\t{\n\t\t\t/* Unlike get, only the underscore (global) option is used for for\n\t\t\t * setting data since we don't know the type here. This is why an object\n\t\t\t * option is not documented for `mData` (which is read/write), but it is\n\t\t\t * for `mRender` which is read only.\n\t\t\t */\n\t\t\treturn _fnSetObjectDataFn( mSource._ );\n\t\t}\n\t\telse if ( mSource === null )\n\t\t{\n\t\t\t/* Nothing to do when the data source is null */\n\t\t\treturn function (data, val) {};\n\t\t}\n\t\telse if ( typeof mSource === 'function' )\n\t\t{\n\t\t\treturn function (data, val) {\n\t\t\t\tmSource( data, 'set', val );\n\t\t\t};\n\t\t}\n\t\telse if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||\n\t\t\t      mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )\n\t\t{\n\t\t\t/* Like the get, we need to get data from a nested object */\n\t\t\tvar setData = function (data, val, src) {\n\t\t\t\tvar a = _fnSplitObjNotation( src ), b;\n\t\t\t\tvar aLast = a[a.length-1];\n\t\t\t\tvar arrayNotation, funcNotation, o, innerSrc;\n\n\t\t\t\tfor ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\t// Check if we are dealing with an array notation request\n\t\t\t\t\tarrayNotation = a[i].match(__reArray);\n\t\t\t\t\tfuncNotation = a[i].match(__reFn);\n\n\t\t\t\t\tif ( arrayNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\ta[i] = a[i].replace(__reArray, '');\n\t\t\t\t\t\tdata[ a[i] ] = [];\n\n\t\t\t\t\t\t// Get the remainder of the nested object to set so we can recurse\n\t\t\t\t\t\tb = a.slice();\n\t\t\t\t\t\tb.splice( 0, i+1 );\n\t\t\t\t\t\tinnerSrc = b.join('.');\n\n\t\t\t\t\t\t// Traverse each entry in the array setting the properties requested\n\t\t\t\t\t\tfor ( var j=0, jLen=val.length ; j<jLen ; j++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\to = {};\n\t\t\t\t\t\t\tsetData( o, val[j], innerSrc );\n\t\t\t\t\t\t\tdata[ a[i] ].push( o );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// The inner call to setData has already traversed through the remainder\n\t\t\t\t\t\t// of the source and has set the data, thus we can exit here\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( funcNotation )\n\t\t\t\t\t{\n\t\t\t\t\t\t// Function call\n\t\t\t\t\t\ta[i] = a[i].replace(__reFn, '');\n\t\t\t\t\t\tdata = data[ a[i] ]( val );\n\t\t\t\t\t}\n\n\t\t\t\t\t// If the nested object doesn't currently exist - since we are\n\t\t\t\t\t// trying to set the value - create it\n\t\t\t\t\tif ( data[ a[i] ] === null || data[ a[i] ] === undefined )\n\t\t\t\t\t{\n\t\t\t\t\t\tdata[ a[i] ] = {};\n\t\t\t\t\t}\n\t\t\t\t\tdata = data[ a[i] ];\n\t\t\t\t}\n\n\t\t\t\t// Last item in the input - i.e, the actual set\n\t\t\t\tif ( aLast.match(__reFn ) )\n\t\t\t\t{\n\t\t\t\t\t// Function call\n\t\t\t\t\tdata = data[ aLast.replace(__reFn, '') ]( val );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// If array notation is used, we just want to strip it and use the property name\n\t\t\t\t\t// and assign the value. If it isn't used, then we get the result we want anyway\n\t\t\t\t\tdata[ aLast.replace(__reArray, '') ] = val;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\treturn function (data, val) {\n\t\t\t\treturn setData( data, val, mSource );\n\t\t\t};\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Array or flat object mapping */\n\t\t\treturn function (data, val) {\n\t\t\t\tdata[mSource] = val;\n\t\t\t};\n\t\t}\n\t}\n\n\n\t/**\n\t * Return an array with the full table data\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns array {array} aData Master data array\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetDataMaster ( settings )\n\t{\n\t\treturn _pluck( settings.aoData, '_aData' );\n\t}\n\n\n\t/**\n\t * Nuke the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnClearTable( settings )\n\t{\n\t\tsettings.aoData.length = 0;\n\t\tsettings.aiDisplayMaster.length = 0;\n\t\tsettings.aiDisplay.length = 0;\n\t}\n\n\n\t /**\n\t * Take an array of integers (index array) and remove a target integer (value - not\n\t * the key!)\n\t *  @param {array} a Index array to target\n\t *  @param {int} iTarget value to find\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDeleteIndex( a, iTarget, splice )\n\t{\n\t\tvar iTargetIndex = -1;\n\n\t\tfor ( var i=0, iLen=a.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tif ( a[i] == iTarget )\n\t\t\t{\n\t\t\t\tiTargetIndex = i;\n\t\t\t}\n\t\t\telse if ( a[i] > iTarget )\n\t\t\t{\n\t\t\t\ta[i]--;\n\t\t\t}\n\t\t}\n\n\t\tif ( iTargetIndex != -1 && splice === undefined )\n\t\t{\n\t\t\ta.splice( iTargetIndex, 1 );\n\t\t}\n\t}\n\n\n\t/**\n\t * Mark cached data as invalid such that a re-read of the data will occur when\n\t * the cached data is next requested. Also update from the data source object.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param  {int}    rowIdx   Row index to invalidate\n\t * @memberof DataTable#oApi\n\t *\n\t * @todo For the modularisation of v1.11 this will need to become a callback, so\n\t *   the sort and filter methods can subscribe to it. That will required\n\t *   initialisation options for sorting, which is why it is not already baked in\n\t */\n\tfunction _fnInvalidateRow( settings, rowIdx, src, column )\n\t{\n\t\tvar row = settings.aoData[ rowIdx ];\n\t\tvar i, ien;\n\n\t\t// Are we reading last data from DOM or the data object?\n\t\tif ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {\n\t\t\t// Read the data from the DOM\n\t\t\trow._aData = _fnGetRowElements( settings, row.nTr ).data;\n\t\t}\n\t\telse {\n\t\t\t// Reading from data object, update the DOM\n\t\t\tvar cells = row.anCells;\n\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcells[i].innerHTML = _fnGetCellData( settings, rowIdx, i, 'display' );\n\t\t\t}\n\t\t}\n\n\t\trow._aSortData = null;\n\t\trow._aFilterData = null;\n\n\t\t// Invalidate the type for a specific column (if given) or all columns since\n\t\t// the data might have changed\n\t\tvar cols = settings.aoColumns;\n\t\tif ( column !== undefined ) {\n\t\t\tcols[ column ].sType = null;\n\t\t}\n\t\telse {\n\t\t\tfor ( i=0, ien=cols.length ; i<ien ; i++ ) {\n\t\t\t\tcols[i].sType = null;\n\t\t\t}\n\t\t}\n\n\t\t// Update DataTables special `DT_*` attributes for the row\n\t\t_fnRowAttributes( row );\n\t}\n\n\n\t/**\n\t * Build a data source object from an HTML row, reading the contents of the\n\t * cells that are in the row.\n\t *\n\t * @param {object} settings DataTables settings object\n\t * @param {node} TR element from which to read data\n\t * @returns {object} Object with two parameters: `data` the data read, in\n\t *   document order, and `cells` and array of nodes (they can be useful to the\n\t *   caller, so rather than needing a second traversal to get them, just return\n\t *   them from here).\n\t * @memberof DataTable#oApi\n\t */\n\tfunction _fnGetRowElements( settings, row )\n\t{\n\t\tvar\n\t\t\td = [],\n\t\t\ttds = [],\n\t\t\ttd = row.firstChild,\n\t\t\tname, col, o, i=0, contents,\n\t\t\tcolumns = settings.aoColumns;\n\n\t\tvar attr = function ( str, data, td  ) {\n\t\t\tif ( typeof str === 'string' ) {\n\t\t\t\tvar idx = str.indexOf('@');\n\n\t\t\t\tif ( idx !== -1 ) {\n\t\t\t\t\tvar src = str.substring( idx+1 );\n\t\t\t\t\to[ '@'+src ] = td.getAttribute( src );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\twhile ( td ) {\n\t\t\tname = td.nodeName.toUpperCase();\n\n\t\t\tif ( name == \"TD\" || name == \"TH\" ) {\n\t\t\t\tcol = columns[i];\n\t\t\t\tcontents = $.trim(td.innerHTML);\n\n\t\t\t\tif ( col && col._bAttrSrc ) {\n\t\t\t\t\to = {\n\t\t\t\t\t\tdisplay: contents\n\t\t\t\t\t};\n\n\t\t\t\t\tattr( col.mData.sort, o, td );\n\t\t\t\t\tattr( col.mData.type, o, td );\n\t\t\t\t\tattr( col.mData.filter, o, td );\n\n\t\t\t\t\td.push( o );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\td.push( contents );\n\t\t\t\t}\n\n\t\t\t\ttds.push( td );\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\ttd = td.nextSibling;\n\t\t}\n\n\t\treturn {\n\t\t\tdata: d,\n\t\t\tcells: tds\n\t\t};\n\t}\n\t/**\n\t * Create a new TR element (and it's TD children) for a row\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {int} iRow Row to consider\n\t *  @param {node} [nTrIn] TR element to add to the table - optional. If not given,\n\t *    DataTables will create a row automatically\n\t *  @param {array} [anTds] Array of TD|TH elements for the row - must be given\n\t *    if nTr is.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCreateTr ( oSettings, iRow, nTrIn, anTds )\n\t{\n\t\tvar\n\t\t\trow = oSettings.aoData[iRow],\n\t\t\trowData = row._aData,\n\t\t\tcells = [],\n\t\t\tnTr, nTd, oCol,\n\t\t\ti, iLen;\n\n\t\tif ( row.nTr === null )\n\t\t{\n\t\t\tnTr = nTrIn || document.createElement('tr');\n\n\t\t\trow.nTr = nTr;\n\t\t\trow.anCells = cells;\n\n\t\t\t/* Use a private property on the node to allow reserve mapping from the node\n\t\t\t * to the aoData array for fast look up\n\t\t\t */\n\t\t\tnTr._DT_RowIndex = iRow;\n\n\t\t\t/* Special parameters can be given by the data source to be used on the row */\n\t\t\t_fnRowAttributes( row );\n\n\t\t\t/* Process each column */\n\t\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\toCol = oSettings.aoColumns[i];\n\n\t\t\t\tnTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );\n\t\t\t\tcells.push( nTd );\n\n\t\t\t\t// Need to create the HTML if new, or if a rendering function is defined\n\t\t\t\tif ( !nTrIn || oCol.mRender || oCol.mData !== i )\n\t\t\t\t{\n\t\t\t\t\tnTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );\n\t\t\t\t}\n\n\t\t\t\t/* Add user defined class */\n\t\t\t\tif ( oCol.sClass !== null )\n\t\t\t\t{\n\t\t\t\t\tnTd.className += ' '+oCol.sClass;\n\t\t\t\t}\n\n\t\t\t\t// Visibility - add or remove as required\n\t\t\t\tif ( oCol.bVisible && ! nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTr.appendChild( nTd );\n\t\t\t\t}\n\t\t\t\telse if ( ! oCol.bVisible && nTrIn )\n\t\t\t\t{\n\t\t\t\t\tnTd.parentNode.removeChild( nTd );\n\t\t\t\t}\n\n\t\t\t\tif ( oCol.fnCreatedCell )\n\t\t\t\t{\n\t\t\t\t\toCol.fnCreatedCell.call( oSettings.oInstance,\n\t\t\t\t\t\tnTd, _fnGetCellData( oSettings, iRow, i, 'display' ), rowData, iRow, i\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );\n\t\t}\n\t}\n\n\n\t/**\n\t * Add attributes to a row based on the special `DT_*` parameters in a data\n\t * source object.\n\t *  @param {object} DataTables row object for the row to be modified\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnRowAttributes( row )\n\t{\n\t\tvar tr = row.nTr;\n\t\tvar data = row._aData;\n\n\t\tif ( tr ) {\n\t\t\tif ( data.DT_RowId ) {\n\t\t\t\ttr.id = data.DT_RowId;\n\t\t\t}\n\n\t\t\tif ( data.DT_RowClass ) {\n\t\t\t\t// Remove any classes added by DT_RowClass before\n\t\t\t\tvar a = data.DT_RowClass.split(' ');\n\t\t\t\trow.__rowc = row.__rowc ?\n\t\t\t\t\t_unique( row.__rowc.concat( a ) ) :\n\t\t\t\t\ta;\n\n\t\t\t\t$(tr)\n\t\t\t\t\t.removeClass( row.__rowc.join(' ') )\n\t\t\t\t\t.addClass( data.DT_RowClass );\n\t\t\t}\n\n\t\t\tif ( data.DT_RowData ) {\n\t\t\t\t$(tr).data( data.DT_RowData );\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Create the HTML header for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBuildHead( oSettings )\n\t{\n\t\tvar i, ien, cell, row, column;\n\t\tvar thead = oSettings.nTHead;\n\t\tvar tfoot = oSettings.nTFoot;\n\t\tvar createHeader = $('th, td', thead).length === 0;\n\t\tvar classes = oSettings.oClasses;\n\t\tvar columns = oSettings.aoColumns;\n\n\t\tif ( createHeader ) {\n\t\t\trow = $('<tr/>').appendTo( thead );\n\t\t}\n\n\t\tfor ( i=0, ien=columns.length ; i<ien ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcell = $( column.nTh ).addClass( column.sClass );\n\n\t\t\tif ( createHeader ) {\n\t\t\t\tcell.appendTo( row );\n\t\t\t}\n\n\t\t\t// 1.11 move into sorting\n\t\t\tif ( oSettings.oFeatures.bSort ) {\n\t\t\t\tcell.addClass( column.sSortingClass );\n\n\t\t\t\tif ( column.bSortable !== false ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.attr( 'tabindex', oSettings.iTabIndex )\n\t\t\t\t\t\t.attr( 'aria-controls', oSettings.sTableId );\n\n\t\t\t\t\t_fnSortAttachListener( oSettings, column.nTh, i );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( column.sTitle != cell.html() ) {\n\t\t\t\tcell.html( column.sTitle );\n\t\t\t}\n\n\t\t\t_fnRenderer( oSettings, 'header' )(\n\t\t\t\toSettings, cell, column, i, classes\n\t\t\t);\n\t\t}\n\n\t\tif ( createHeader ) {\n\t\t\t_fnDetectHeader( oSettings.aoHeader, thead );\n\t\t}\n\n\t\t/* ARIA role for the rows */\n\t\t$(thead).find('>tr').attr('role', 'row');\n\n\t\t/* Deal with the footer - add classes if required */\n\t\t$(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );\n\t\t$(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );\n\n\t\t// Cache the footer cells. Note that we only take the cells from the first\n\t\t// row in the footer. If there is more than one row the user wants to\n\t\t// interact with, they need to use the table().foot() method. Note also this\n\t\t// allows cells to be used for multiple columns using colspan\n\t\tif ( tfoot !== null ) {\n\t\t\tvar cells = oSettings.aoFooter[0];\n\n\t\t\tfor ( i=0, ien=cells.length ; i<ien ; i++ ) {\n\t\t\t\tcolumn = columns[i];\n\t\t\t\tcolumn.nTf = cells[i].cell;\n\n\t\t\t\tif ( column.sClass ) {\n\t\t\t\t\t$(column.nTf).addClass( column.sClass );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Draw the header (or footer) element based on the column visibility states. The\n\t * methodology here is to use the layout array from _fnDetectHeader, modified for\n\t * the instantaneous column visibility, to construct the new layout. The grid is\n\t * traversed over cell at a time in a rows x columns grid fashion, although each\n\t * cell insert can cover multiple elements in the grid - which is tracks using the\n\t * aApplied array. Cell inserts in the grid will only occur where there isn't\n\t * already a cell in that position.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param array {objects} aoSource Layout array from _fnDetectHeader\n\t *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDrawHead( oSettings, aoSource, bIncludeHidden )\n\t{\n\t\tvar i, iLen, j, jLen, k, kLen, n, nLocalTr;\n\t\tvar aoLocal = [];\n\t\tvar aApplied = [];\n\t\tvar iColumns = oSettings.aoColumns.length;\n\t\tvar iRowspan, iColspan;\n\n\t\tif ( ! aoSource )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif (  bIncludeHidden === undefined )\n\t\t{\n\t\t\tbIncludeHidden = false;\n\t\t}\n\n\t\t/* Make a copy of the master layout array, but without the visible columns in it */\n\t\tfor ( i=0, iLen=aoSource.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taoLocal[i] = aoSource[i].slice();\n\t\t\taoLocal[i].nTr = aoSource[i].nTr;\n\n\t\t\t/* Remove any columns which are currently hidden */\n\t\t\tfor ( j=iColumns-1 ; j>=0 ; j-- )\n\t\t\t{\n\t\t\t\tif ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )\n\t\t\t\t{\n\t\t\t\t\taoLocal[i].splice( j, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Prep the applied array - it needs an element for each row */\n\t\t\taApplied.push( [] );\n\t\t}\n\n\t\tfor ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnLocalTr = aoLocal[i].nTr;\n\n\t\t\t/* All cells are going to be replaced, so empty out the row */\n\t\t\tif ( nLocalTr )\n\t\t\t{\n\t\t\t\twhile( (n = nLocalTr.firstChild) )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.removeChild( n );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tiRowspan = 1;\n\t\t\t\tiColspan = 1;\n\n\t\t\t\t/* Check to see if there is already a cell (row/colspan) covering our target\n\t\t\t\t * insert point. If there is, then there is nothing to do.\n\t\t\t\t */\n\t\t\t\tif ( aApplied[i][j] === undefined )\n\t\t\t\t{\n\t\t\t\t\tnLocalTr.appendChild( aoLocal[i][j].cell );\n\t\t\t\t\taApplied[i][j] = 1;\n\n\t\t\t\t\t/* Expand the cell to cover as many rows as needed */\n\t\t\t\t\twhile ( aoLocal[i+iRowspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\taApplied[i+iRowspan][j] = 1;\n\t\t\t\t\t\tiRowspan++;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* Expand the cell to cover as many columns as needed */\n\t\t\t\t\twhile ( aoLocal[i][j+iColspan] !== undefined &&\n\t\t\t\t\t        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )\n\t\t\t\t\t{\n\t\t\t\t\t\t/* Must update the applied array over the rows for the columns */\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taApplied[i+k][j+iColspan] = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tiColspan++;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* Do the actual expansion in the DOM */\n\t\t\t\t\taoLocal[i][j].cell.rowSpan = iRowspan;\n\t\t\t\t\taoLocal[i][j].cell.colSpan = iColspan;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Insert the required TR nodes into the table for display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDraw( oSettings )\n\t{\n\t\t/* Provide a pre-callback function which can be used to cancel the draw is false is returned */\n\t\tvar aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );\n\t\tif ( $.inArray( false, aPreDraw ) !== -1 )\n\t\t{\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t\treturn;\n\t\t}\n\n\t\tvar i, iLen, n;\n\t\tvar anRows = [];\n\t\tvar iRowCount = 0;\n\t\tvar asStripeClasses = oSettings.asStripeClasses;\n\t\tvar iStripes = asStripeClasses.length;\n\t\tvar iOpenRows = oSettings.aoOpenRows.length;\n\t\tvar oLang = oSettings.oLanguage;\n\t\tvar iInitDisplayStart = oSettings.iInitDisplayStart;\n\t\tvar bServerSide = _fnDataSource( oSettings ) == 'ssp';\n\t\tvar aiDisplay = oSettings.aiDisplay;\n\n\t\toSettings.bDrawing = true;\n\n\t\t/* Check and see if we have an initial draw position from state saving */\n\t\tif ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )\n\t\t{\n\t\t\toSettings._iDisplayStart = bServerSide ?\n\t\t\t\tiInitDisplayStart :\n\t\t\t\tiInitDisplayStart >= oSettings.fnRecordsDisplay() ?\n\t\t\t\t\t0 :\n\t\t\t\t\tiInitDisplayStart;\n\n\t\t\toSettings.iInitDisplayStart = -1;\n\t\t}\n\n\t\tvar iDisplayStart = oSettings._iDisplayStart;\n\t\tvar iDisplayEnd = oSettings.fnDisplayEnd();\n\n\t\t/* Server-side processing draw intercept */\n\t\tif ( oSettings.bDeferLoading )\n\t\t{\n\t\t\toSettings.bDeferLoading = false;\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, false );\n\t\t}\n\t\telse if ( !bServerSide )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t}\n\t\telse if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tif ( aiDisplay.length !== 0 )\n\t\t{\n\t\t\tvar iStart = bServerSide ? 0 : iDisplayStart;\n\t\t\tvar iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;\n\n\t\t\tfor ( var j=iStart ; j<iEnd ; j++ )\n\t\t\t{\n\t\t\t\tvar iDataIndex = aiDisplay[j];\n\t\t\t\tvar aoData = oSettings.aoData[ iDataIndex ];\n\t\t\t\tif ( aoData.nTr === null )\n\t\t\t\t{\n\t\t\t\t\t_fnCreateTr( oSettings, iDataIndex );\n\t\t\t\t}\n\n\t\t\t\tvar nRow = aoData.nTr;\n\n\t\t\t\t/* Remove the old striping classes and then add the new one */\n\t\t\t\tif ( iStripes !== 0 )\n\t\t\t\t{\n\t\t\t\t\tvar sStripe = asStripeClasses[ iRowCount % iStripes ];\n\t\t\t\t\tif ( aoData._sRowStripe != sStripe )\n\t\t\t\t\t{\n\t\t\t\t\t\t$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );\n\t\t\t\t\t\taoData._sRowStripe = sStripe;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* Row callback functions - might want to manipulate the row */\n\t\t\t\t_fnCallbackFire( oSettings, 'aoRowCallback', null,\n\t\t\t\t\t[nRow, aoData._aData, iRowCount, j] );\n\n\t\t\t\tanRows.push( nRow );\n\t\t\t\tiRowCount++;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/* Table is empty - create a row with an empty message in it */\n\t\t\tvar sZero = oLang.sZeroRecords;\n\t\t\tif ( oSettings.iDraw == 1 &&  _fnDataSource( oSettings ) == 'ajax' )\n\t\t\t{\n\t\t\t\tsZero = oLang.sLoadingRecords;\n\t\t\t}\n\t\t\telse if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )\n\t\t\t{\n\t\t\t\tsZero = oLang.sEmptyTable;\n\t\t\t}\n\n\t\t\tanRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )\n\t\t\t\t.append( $('<td />', {\n\t\t\t\t\t'valign':  'top',\n\t\t\t\t\t'colSpan': _fnVisbleColumns( oSettings ),\n\t\t\t\t\t'class':   oSettings.oClasses.sRowEmpty\n\t\t\t\t} ).html( sZero ) )[0];\n\t\t}\n\n\t\t/* Header and footer callbacks */\n\t\t_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\n\t\t_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],\n\t\t\t_fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );\n\n\t\tvar body = $(oSettings.nTBody);\n\n\t\tbody.children().detach();\n\t\tbody.append( $(anRows) );\n\n\t\t/* Call all required callback functions for the end of a draw */\n\t\t_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );\n\n\t\t/* Draw is complete, sorting and filtering must be as well */\n\t\toSettings.bSorted = false;\n\t\toSettings.bFiltered = false;\n\t\toSettings.bDrawing = false;\n\t}\n\n\n\t/**\n\t * Redraw the table - taking account of the various features which are enabled\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {boolean} [holdPosition] Keep the current paging position. By default\n\t *    the paging is reset to the first page\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnReDraw( settings, holdPosition )\n\t{\n\t\tvar\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tsort     = features.bSort,\n\t\t\tfilter   = features.bFilter;\n\n\t\tif ( sort ) {\n\t\t\t_fnSort( settings );\n\t\t}\n\n\t\tif ( filter ) {\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch );\n\t\t}\n\t\telse {\n\t\t\t// No filtering, so we want to just use the display master\n\t\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\t\t}\n\n\t\tif ( holdPosition !== true ) {\n\t\t\tsettings._iDisplayStart = 0;\n\t\t}\n\n\t\t_fnDraw( settings );\n\t}\n\n\n\t/**\n\t * Add the options to the page HTML for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAddOptionsHtml ( oSettings )\n\t{\n\t\t/*\n\t\t * Create a temporary, empty, div which we can later on replace with what we have generated\n\t\t * we do it this way to rendering the 'options' html offline - speed :-)\n\t\t */\n\t\tvar nHolding = $('<div></div>')[0];\n\t\toSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );\n\n\t\t/*\n\t\t * All DataTables are wrapped in a div\n\t\t */\n\t\toSettings.nTableWrapper = $('<div id=\"'+oSettings.sTableId+'_wrapper\" class=\"'+oSettings.oClasses.sWrapper+'\" role=\"grid\"></div>')[0];\n\t\toSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;\n\n\t\t/* Track where we want to insert the option */\n\t\tvar nInsertNode = oSettings.nTableWrapper;\n\n\t\t/* Loop over the user set positioning and place the elements as needed */\n\t\tvar aDom = oSettings.sDom.split('');\n\t\tvar nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;\n\t\tfor ( var i=0 ; i<aDom.length ; i++ )\n\t\t{\n\t\t\tiPushFeature = 0;\n\t\t\tcOption = aDom[i];\n\n\t\t\tif ( cOption == '<' )\n\t\t\t{\n\t\t\t\t/* New container div */\n\t\t\t\tnNewNode = $('<div></div>')[0];\n\n\t\t\t\t/* Check to see if we should append an id and/or a class name to the container */\n\t\t\t\tcNext = aDom[i+1];\n\t\t\t\tif ( cNext == \"'\" || cNext == '\"' )\n\t\t\t\t{\n\t\t\t\t\tsAttr = \"\";\n\t\t\t\t\tj = 2;\n\t\t\t\t\twhile ( aDom[i+j] != cNext )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr += aDom[i+j];\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* Replace jQuery UI constants @todo depreciated */\n\t\t\t\t\tif ( sAttr == \"H\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = oSettings.oClasses.sJUIHeader;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr == \"F\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tsAttr = oSettings.oClasses.sJUIFooter;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* The attribute can be in the format of \"#id.class\", \"#id\" or \"class\" This logic\n\t\t\t\t\t * breaks the string into parts and applies them as needed\n\t\t\t\t\t */\n\t\t\t\t\tif ( sAttr.indexOf('.') != -1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar aSplit = sAttr.split('.');\n\t\t\t\t\t\tnNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);\n\t\t\t\t\t\tnNewNode.className = aSplit[1];\n\t\t\t\t\t}\n\t\t\t\t\telse if ( sAttr.charAt(0) == \"#\" )\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.id = sAttr.substr(1, sAttr.length-1);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnNewNode.className = sAttr;\n\t\t\t\t\t}\n\n\t\t\t\t\ti += j; /* Move along the position array */\n\t\t\t\t}\n\n\t\t\t\tnInsertNode.appendChild( nNewNode );\n\t\t\t\tnInsertNode = nNewNode;\n\t\t\t}\n\t\t\telse if ( cOption == '>' )\n\t\t\t{\n\t\t\t\t/* End container div */\n\t\t\t\tnInsertNode = nInsertNode.parentNode;\n\t\t\t}\n\t\t\t// @todo Move options into their own plugins?\n\t\t\telse if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )\n\t\t\t{\n\t\t\t\t/* Length */\n\t\t\t\tnTmp = _fnFeatureHtmlLength( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption == 'f' && oSettings.oFeatures.bFilter )\n\t\t\t{\n\t\t\t\t/* Filter */\n\t\t\t\tnTmp = _fnFeatureHtmlFilter( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption == 'r' && oSettings.oFeatures.bProcessing )\n\t\t\t{\n\t\t\t\t/* pRocessing */\n\t\t\t\tnTmp = _fnFeatureHtmlProcessing( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption == 't' )\n\t\t\t{\n\t\t\t\t/* Table */\n\t\t\t\tnTmp = _fnFeatureHtmlTable( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption ==  'i' && oSettings.oFeatures.bInfo )\n\t\t\t{\n\t\t\t\t/* Info */\n\t\t\t\tnTmp = _fnFeatureHtmlInfo( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( cOption == 'p' && oSettings.oFeatures.bPaginate )\n\t\t\t{\n\t\t\t\t/* Pagination */\n\t\t\t\tnTmp = _fnFeatureHtmlPaginate( oSettings );\n\t\t\t\tiPushFeature = 1;\n\t\t\t}\n\t\t\telse if ( DataTable.ext.feature.length !== 0 )\n\t\t\t{\n\t\t\t\t/* Plug-in features */\n\t\t\t\tvar aoFeatures = DataTable.ext.feature;\n\t\t\t\tfor ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )\n\t\t\t\t{\n\t\t\t\t\tif ( cOption == aoFeatures[k].cFeature )\n\t\t\t\t\t{\n\t\t\t\t\t\tnTmp = aoFeatures[k].fnInit( oSettings );\n\t\t\t\t\t\tif ( nTmp )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tiPushFeature = 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Add to the 2D features array */\n\t\t\tif ( iPushFeature == 1 && nTmp !== null )\n\t\t\t{\n\t\t\t\tif ( typeof oSettings.aanFeatures[cOption] !== 'object' )\n\t\t\t\t{\n\t\t\t\t\toSettings.aanFeatures[cOption] = [];\n\t\t\t\t}\n\t\t\t\toSettings.aanFeatures[cOption].push( nTmp );\n\t\t\t\tnInsertNode.appendChild( nTmp );\n\t\t\t}\n\t\t}\n\n\t\t/* Built our DOM structure - replace the holding div with what we want */\n\t\tnHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );\n\t}\n\n\n\t/**\n\t * Use the DOM source to create up an array of header cells. The idea here is to\n\t * create a layout grid (array) of rows x columns, which contains a reference\n\t * to the cell that that point in the grid (regardless of col/rowspan), such that\n\t * any column / row could be removed and the new grid constructed\n\t *  @param array {object} aLayout Array to store the calculated layout in\n\t *  @param {node} nThead The header/footer element for the table\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDetectHeader ( aLayout, nThead )\n\t{\n\t\tvar nTrs = $(nThead).children('tr');\n\t\tvar nTr, nCell;\n\t\tvar i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;\n\t\tvar bUnique;\n\t\tvar fnShiftCol = function ( a, i, j ) {\n\t\t\tvar k = a[i];\n\t                while ( k[j] ) {\n\t\t\t\tj++;\n\t\t\t}\n\t\t\treturn j;\n\t\t};\n\n\t\taLayout.splice( 0, aLayout.length );\n\n\t\t/* We know how many rows there are in the layout - so prep it */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\taLayout.push( [] );\n\t\t}\n\n\t\t/* Calculate a layout array */\n\t\tfor ( i=0, iLen=nTrs.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tnTr = nTrs[i];\n\t\t\tiColumn = 0;\n\n\t\t\t/* For every cell in the row... */\n\t\t\tnCell = nTr.firstChild;\n\t\t\twhile ( nCell ) {\n\t\t\t\tif ( nCell.nodeName.toUpperCase() == \"TD\" ||\n\t\t\t\t     nCell.nodeName.toUpperCase() == \"TH\" )\n\t\t\t\t{\n\t\t\t\t\t/* Get the col and rowspan attributes from the DOM and sanitise them */\n\t\t\t\t\tiColspan = nCell.getAttribute('colspan') * 1;\n\t\t\t\t\tiRowspan = nCell.getAttribute('rowspan') * 1;\n\t\t\t\t\tiColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;\n\t\t\t\t\tiRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;\n\n\t\t\t\t\t/* There might be colspan cells already in this row, so shift our target\n\t\t\t\t\t * accordingly\n\t\t\t\t\t */\n\t\t\t\t\tiColShifted = fnShiftCol( aLayout, i, iColumn );\n\n\t\t\t\t\t/* Cache calculation for unique columns */\n\t\t\t\t\tbUnique = iColspan === 1 ? true : false;\n\n\t\t\t\t\t/* If there is col / rowspan, copy the information into the layout grid */\n\t\t\t\t\tfor ( l=0 ; l<iColspan ; l++ )\n\t\t\t\t\t{\n\t\t\t\t\t\tfor ( k=0 ; k<iRowspan ; k++ )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\taLayout[i+k][iColShifted+l] = {\n\t\t\t\t\t\t\t\t\"cell\": nCell,\n\t\t\t\t\t\t\t\t\"unique\": bUnique\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\taLayout[i+k].nTr = nTr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnCell = nCell.nextSibling;\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Get an array of unique th elements, one for each column\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} nHeader automatically detect the layout from this node - optional\n\t *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional\n\t *  @returns array {node} aReturn list of unique th's\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetUniqueThs ( oSettings, nHeader, aLayout )\n\t{\n\t\tvar aReturn = [];\n\t\tif ( !aLayout )\n\t\t{\n\t\t\taLayout = oSettings.aoHeader;\n\t\t\tif ( nHeader )\n\t\t\t{\n\t\t\t\taLayout = [];\n\t\t\t\t_fnDetectHeader( aLayout, nHeader );\n\t\t\t}\n\t\t}\n\n\t\tfor ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tfor ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tif ( aLayout[i][j].unique &&\n\t\t\t\t\t (!aReturn[j] || !oSettings.bSortCellsTop) )\n\t\t\t\t{\n\t\t\t\t\taReturn[j] = aLayout[i][j].cell;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn aReturn;\n\t}\n\n\n\n\t/**\n\t * Create an Ajax call based on the table's settings, taking into account that\n\t * parameters can have multiple forms, and backwards compatibility.\n\t *\n\t * @param {object} oSettings dataTables settings object\n\t * @param {array} data Data to send to the server, required by\n\t *     DataTables - may be augmented by developer callbacks\n\t * @param {function} fn Callback function to run when data is obtained\n\t */\n\tfunction _fnBuildAjax( oSettings, data, fn )\n\t{\n\t\t// Compatibility with 1.9-, allow fnServerData and event to manipulate\n\t\t_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );\n\n\t\t// Convert to object based for 1.10+ if using the old scheme\n\t\tif ( data && data.__legacy ) {\n\t\t\tvar tmp = {};\n\t\t\tvar rbracket = /(.*?)\\[\\]$/;\n\n\t\t\t$.each( data, function (key, val) {\n\t\t\t\tvar match = val.name.match(rbracket);\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\t// Support for arrays\n\t\t\t\t\tvar name = match[0];\n\n\t\t\t\t\tif ( ! tmp[ name ] ) {\n\t\t\t\t\t\ttmp[ name ] = [];\n\t\t\t\t\t}\n\t\t\t\t\ttmp[ name ].push( val.value );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ttmp[val.name] = val.value;\n\t\t\t\t}\n\t\t\t} );\n\t\t\tdata = tmp;\n\t\t}\n\n\t\tvar ajaxData;\n\t\tvar ajax = oSettings.ajax;\n\t\tvar instance = oSettings.oInstance;\n\n\t\tif ( $.isPlainObject( ajax ) && ajax.data )\n\t\t{\n\t\t\tajaxData = ajax.data;\n\n\t\t\tvar newData = $.isFunction( ajaxData ) ?\n\t\t\t\tajaxData( data ) :  // fn can manipulate data or return an object\n\t\t\t\tajaxData;           // object or array to merge\n\n\t\t\t// If the function returned an object, use that alone\n\t\t\tdata = $.isFunction( ajaxData ) && newData ?\n\t\t\t\tnewData :\n\t\t\t\t$.extend( true, data, newData );\n\n\t\t\t// Remove the data property as we've resolved it already and don't want\n\t\t\t// jQuery to do it again (it is restored at the end of the function)\n\t\t\tdelete ajax.data;\n\t\t}\n\n\t\tvar baseAjax = {\n\t\t\t\"data\": data,\n\t\t\t\"success\": function (json) {\n\t\t\t\tvar error = json.error || json.sError;\n\t\t\t\tif ( error ) {\n\t\t\t\t\toSettings.oApi._fnLog( oSettings, 0, error );\n\t\t\t\t}\n\n\t\t\t\toSettings.json = json;\n\t\t\t\t_fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );\n\t\t\t\tfn( json );\n\t\t\t},\n\t\t\t\"dataType\": \"json\",\n\t\t\t\"cache\": false,\n\t\t\t\"type\": oSettings.sServerMethod,\n\t\t\t\"error\": function (xhr, error, thrown) {\n\t\t\t\tvar log = oSettings.oApi._fnLog;\n\n\t\t\t\tif ( error == \"parsererror\" ) {\n\t\t\t\t\tlog( oSettings, 0, 'Invalid JSON response', 1 );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlog( oSettings, 0, 'Ajax error', 7 );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tif ( oSettings.fnServerData )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.fnServerData.call( instance,\n\t\t\t\toSettings.sAjaxSource, data, fn, oSettings\n\t\t\t);\n\t\t}\n\t\telse if ( oSettings.sAjaxSource || typeof ajax === 'string' )\n\t\t{\n\t\t\t// DataTables 1.9- compatibility\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, {\n\t\t\t\turl: ajax || oSettings.sAjaxSource\n\t\t\t} ) );\n\t\t}\n\t\telse if ( $.isFunction( ajax ) )\n\t\t{\n\t\t\t// Is a function - let the caller define what needs to be done\n\t\t\toSettings.jqXHR = ajax.call( instance, data, fn, oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Object to extend the base settings\n\t\t\toSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );\n\n\t\t\t// Restore for next time around\n\t\t\tajax.data = ajaxData;\n\t\t}\n\t}\n\n\n\t/**\n\t * Update the table using an Ajax call\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {boolean} Block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdate( oSettings )\n\t{\n\t\tif ( oSettings.bAjaxDataGet )\n\t\t{\n\t\t\toSettings.iDraw++;\n\t\t\t_fnProcessingDisplay( oSettings, true );\n\t\t\tvar iColumns = oSettings.aoColumns.length;\n\t\t\tvar aoData = _fnAjaxParameters( oSettings );\n\n\t\t\t_fnBuildAjax( oSettings, aoData, function(json) {\n\t\t\t\t_fnAjaxUpdateDraw( oSettings, json );\n\t\t\t}, oSettings );\n\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\n\t/**\n\t * Build up the parameters in an object needed for a server-side processing\n\t * request. Note that this is basically done twice, is different ways - a modern\n\t * method which is used by default in DataTables 1.10 which uses objects and\n\t * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if\n\t * the sAjaxSource option is used in the initialisation, or the legacyAjax\n\t * option is set.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {bool} block the table drawing or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxParameters( settings )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tcolumnCount = columns.length,\n\t\t\tfeatures = settings.oFeatures,\n\t\t\tpreSearch = settings.oPreviousSearch,\n\t\t\tpreColSearch = settings.aoPreSearchCols,\n\t\t\ti, data = [], dataProp, column, columnSearch,\n\t\t\tsort = _fnSortFlatten( settings ),\n\t\t\tdisplayStart = settings._iDisplayStart,\n\t\t\tdisplayLength = features.bPaginate !== false ?\n\t\t\t\tsettings._iDisplayLength :\n\t\t\t\t-1;\n\n\t\tvar param = function ( name, value ) {\n\t\t\tdata.push( { 'name': name, 'value': value } );\n\t\t};\n\n\t\t// DataTables 1.9- compatible method\n\t\tparam( 'sEcho',          settings.iDraw );\n\t\tparam( 'iColumns',       columnCount );\n\t\tparam( 'sColumns',       _pluck( columns, 'sName' ).join(',') );\n\t\tparam( 'iDisplayStart',  displayStart );\n\t\tparam( 'iDisplayLength', displayLength );\n\n\t\t// DataTables 1.10+ method\n\t\tvar d = {\n\t\t\tdraw:    settings.iDraw,\n\t\t\tcolumns: [],\n\t\t\torder:   [],\n\t\t\tstart:   displayStart,\n\t\t\tlength:  displayLength,\n\t\t\tsearch:  {\n\t\t\t\tvalue: preSearch.sSearch,\n\t\t\t\tregex: preSearch.bRegex\n\t\t\t}\n\t\t};\n\n\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\tcolumn = columns[i];\n\t\t\tcolumnSearch = preColSearch[i];\n\t\t\tdataProp = typeof column.mData==\"function\" ? 'function' : column.mData ;\n\n\t\t\td.columns.push( {\n\t\t\t\tdata:       dataProp,\n\t\t\t\tname:       column.sName,\n\t\t\t\tsearchable: column.bSearchable,\n\t\t\t\torderable:  column.bSortable,\n\t\t\t\tsearch:     {\n\t\t\t\t\tvalue: columnSearch.sSearch,\n\t\t\t\t\tregex: columnSearch.bRegex\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tparam( \"mDataProp_\"+i, dataProp );\n\n\t\t\tif ( features.bFilter ) {\n\t\t\t\tparam( 'sSearch_'+i,     columnSearch.sSearch );\n\t\t\t\tparam( 'bRegex_'+i,      columnSearch.bRegex );\n\t\t\t\tparam( 'bSearchable_'+i, column.bSearchable );\n\t\t\t}\n\n\t\t\tif ( features.bSort ) {\n\t\t\t\tparam( 'bSortable_'+i, column.bSortable );\n\t\t\t}\n\t\t}\n\n\t\t$.each( sort, function ( i, val ) {\n\t\t\td.order.push( { column: val.col, dir: val.dir } );\n\n\t\t\tparam( 'iSortCol_'+i, val.col );\n\t\t\tparam( 'sSortDir_'+i, val.dir );\n\t\t} );\n\n\t\tif ( features.bFilter ) {\n\t\t\tparam( 'sSearch', preSearch.sSearch );\n\t\t\tparam( 'bRegex', preSearch.bRegex );\n\t\t}\n\n\t\tif ( features.bSort ) {\n\t\t\tparam( 'iSortingCols', sort.length );\n\t\t}\n\n\t\tdata.__legacy = true;\n\t\treturn settings.sAjaxSource || DataTable.ext.legacy.ajax ?\n\t\t\tdata : d;\n\t}\n\n\n\t/**\n\t * Data the data from the server (nuking the old) and redraw the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} json json data return from the server.\n\t *  @param {string} json.sEcho Tracking flag for DataTables to match requests\n\t *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering\n\t *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering\n\t *  @param {array} json.aaData The data to display on this page\n\t *  @param {string} [json.sColumns] Column ordering (sName, comma separated)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnAjaxUpdateDraw ( settings, json )\n\t{\n\t\t// v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.\n\t\t// Support both\n\t\tvar compat = function ( old, modern ) {\n\t\t\treturn json[old] !== undefined ? json[old] : json[modern];\n\t\t};\n\n\t\tvar draw            = compat( 'sEcho',                'draw' );\n\t\tvar recordsTotal    = compat( 'iTotalRecords',        'recordsTotal' );\n\t\tvar rocordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );\n\n\t\tif ( draw ) {\n\t\t\t// Protect against out of sequence returns\n\t\t\tif ( draw*1 < settings.iDraw ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsettings.iDraw = draw * 1;\n\t\t}\n\n\t\t_fnClearTable( settings );\n\t\tsettings._iRecordsTotal   = parseInt(recordsTotal, 10);\n\t\tsettings._iRecordsDisplay = parseInt(rocordsFiltered, 10);\n\n\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t_fnAddData( settings, data[i] );\n\t\t}\n\t\tsettings.aiDisplay = settings.aiDisplayMaster.slice();\n\n\t\tsettings.bAjaxDataGet = false;\n\t\t_fnDraw( settings );\n\n\t\tif ( ! settings._bInitComplete ) {\n\t\t\t_fnInitComplete( settings, json );\n\t\t}\n\n\t\tsettings.bAjaxDataGet = true;\n\t\t_fnProcessingDisplay( settings, false );\n\t}\n\n\n\t/**\n\t * Get the data from the JSON data source to use for drawing a table. Using\n\t * `_fnGetObjectDataFn` allows the data to be sourced from a property of the\n\t * source object, or from a processing function.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param  {object} json Data source object / array from the server\n\t *  @return {array} Array of data to use\n\t */\n\tfunction _fnAjaxDataSrc ( oSettings, json )\n\t{\n\t\tvar dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?\n\t\t\toSettings.ajax.dataSrc :\n\t\t\toSettings.sAjaxDataProp; // Compatibility with 1.9-.\n\n\t\t// Compatibility with 1.9-. In order to read from aaData, check if the\n\t\t// default has been changed, if not, check for aaData\n\t\tif ( dataSrc === 'data' ) {\n\t\t\treturn json.aaData || json[dataSrc];\n\t\t}\n\n\t\treturn dataSrc !== \"\" ?\n\t\t\t_fnGetObjectDataFn( dataSrc )( json ) :\n\t\t\tjson;\n\t}\n\n\n\t/**\n\t * Generate the node required for filtering text\n\t *  @returns {node} Filter control element\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlFilter ( settings )\n\t{\n\t\tvar classes = settings.oClasses;\n\t\tvar tableId = settings.sTableId;\n\t\tvar previousSearch = settings.oPreviousSearch;\n\t\tvar features = settings.aanFeatures;\n\t\tvar input = '<input type=\"search\" class=\"'+classes.sFilterInput+'\"/>';\n\n\t\tvar str = settings.oLanguage.sSearch;\n\t\tstr = str.match(/_INPUT_/) ?\n\t\t\tstr.replace('_INPUT_', input) :\n\t\t\tstr+input;\n\n\t\tvar filter = $('<div/>', {\n\t\t\t\t'id': ! features.f ? tableId+'_filter' : null,\n\t\t\t\t'class': classes.sFilter\n\t\t\t} )\n\t\t\t.append( $('<label/>' ).append( str ) );\n\n\t\tvar jqFilter = $('input[type=\"search\"]', filter)\n\t\t\t.val( previousSearch.sSearch.replace('\"','&quot;') )\n\t\t\t.bind( 'keyup.DT search.DT input.DT paste.DT cut.DT', function(e) {\n\t\t\t\t/* Update all other filter input elements for the new display */\n\t\t\t\tvar n = features.f;\n\t\t\t\tvar val = !this.value ? \"\" : this.value; // mental IE8 fix :-(\n\n\t\t\t\t/* Now do the filter */\n\t\t\t\tif ( val != previousSearch.sSearch ) {\n\t\t\t\t\t_fnFilterComplete( settings, {\n\t\t\t\t\t\t\"sSearch\": val,\n\t\t\t\t\t\t\"bRegex\": previousSearch.bRegex,\n\t\t\t\t\t\t\"bSmart\": previousSearch.bSmart ,\n\t\t\t\t\t\t\"bCaseInsensitive\": previousSearch.bCaseInsensitive\n\t\t\t\t\t} );\n\n\t\t\t\t\t// Need to redraw, without resorting\n\t\t\t\t\tsettings._iDisplayStart = 0;\n\t\t\t\t\t_fnDraw( settings );\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.bind( 'keypress.DT', function(e) {\n\t\t\t\t/* Prevent form submission */\n\t\t\t\tif ( e.keyCode == 13 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} )\n\t\t\t.attr('aria-controls', tableId);\n\n\t\t// Update the input elements whenever the table is filtered\n\t\t$(settings.nTable).on( 'filter.DT', function () {\n\t\t\t// IE9 throws an 'unknown error' if document.activeElement is used\n\t\t\t// inside an iframe or frame...\n\t\t\ttry {\n\t\t\t\tif ( jqFilter[0] !== document.activeElement ) {\n\t\t\t\t\tjqFilter.val( previousSearch.sSearch );\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch ( e ) {}\n\t\t} );\n\n\t\treturn filter[0];\n\t}\n\n\n\t/**\n\t * Filter the table using both the global filter and column based filtering\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oSearch search information\n\t *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterComplete ( oSettings, oInput, iForce )\n\t{\n\t\tvar oPrevSearch = oSettings.oPreviousSearch;\n\t\tvar aoPrevSearch = oSettings.aoPreSearchCols;\n\t\tvar fnSaveFilter = function ( oFilter ) {\n\t\t\t/* Save the filtering values */\n\t\t\toPrevSearch.sSearch = oFilter.sSearch;\n\t\t\toPrevSearch.bRegex = oFilter.bRegex;\n\t\t\toPrevSearch.bSmart = oFilter.bSmart;\n\t\t\toPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;\n\t\t};\n\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo As per sort - can this be moved into an event handler?\n\t\t_fnColumnTypes( oSettings );\n\n\t\t/* In server-side processing all filtering is done by the server, so no point hanging around here */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' )\n\t\t{\n\t\t\t/* Global filter */\n\t\t\t_fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );\n\t\t\tfnSaveFilter( oInput );\n\n\t\t\t/* Now do the individual column filter */\n\t\t\tfor ( var i=0 ; i<aoPrevSearch.length ; i++ )\n\t\t\t{\n\t\t\t\t_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex,\n\t\t\t\t\taoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );\n\t\t\t}\n\n\t\t\t/* Custom filtering */\n\t\t\t_fnFilterCustom( oSettings );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tfnSaveFilter( oInput );\n\t\t}\n\n\t\t/* Tell the draw function we have been filtering */\n\t\toSettings.bFiltered = true;\n\t\t_fnCallbackFire( oSettings, null, 'search', [oSettings] );\n\t}\n\n\n\t/**\n\t * Apply custom filtering functions\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCustom( oSettings )\n\t{\n\t\tvar afnFilters = DataTable.ext.search;\n\t\tvar aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );\n\n\t\tfor ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar iCorrector = 0;\n\t\t\tfor ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )\n\t\t\t{\n\t\t\t\tvar iDisIndex = oSettings.aiDisplay[j-iCorrector];\n\t\t\t\tvar bTest = afnFilters[i](\n\t\t\t\t\toSettings,\n\t\t\t\t\t_fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),\n\t\t\t\t\tiDisIndex\n\t\t\t\t);\n\n\t\t\t\t/* Check if we should use this row based on the filtering function */\n\t\t\t\tif ( !bTest )\n\t\t\t\t{\n\t\t\t\t\toSettings.aiDisplay.splice( j-iCorrector, 1 );\n\t\t\t\t\tiCorrector++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Filter the table on a per-column basis\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sInput string to filter on\n\t *  @param {int} iColumn column to filter\n\t *  @param {bool} bRegex treat search string as a regular expression or not\n\t *  @param {bool} bSmart use smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )\n\t{\n\t\tif ( searchStr === '' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar data;\n\t\tvar display = settings.aiDisplay;\n\t\tvar rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );\n\n\t\tfor ( var i=display.length-1 ; i>=0 ; i-- ) {\n\t\t\tdata = settings.aoData[ display[i] ]._aFilterData[ colIdx ];\n\n\t\t\tif ( ! rpSearch.test( data ) ) {\n\t\t\t\tdisplay.splice( i, 1 );\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Filter the data table based on user input and draw the table\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} input string to filter on\n\t *  @param {int} force optional - force a research of the master array (1) or not (undefined or 0)\n\t *  @param {bool} regex treat as a regular expression or not\n\t *  @param {bool} smart perform smart filtering or not\n\t *  @param {bool} caseInsensitive Do case insenstive matching or not\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilter( settings, input, force, regex, smart, caseInsensitive )\n\t{\n\t\tvar rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );\n\t\tvar prevSearch = settings.oPreviousSearch.sSearch;\n\t\tvar displayMaster = settings.aiDisplayMaster;\n\t\tvar display, invalidated, i;\n\n\t\t// Need to take account of custom filtering functions - always filter\n\t\tif ( DataTable.ext.search.length !== 0 ) {\n\t\t\tforce = true;\n\t\t}\n\n\t\t// Check if any of the rows were invalidated\n\t\tinvalidated = _fnFilterData( settings );\n\n\t\t// If the input is blank - we just want the full data set\n\t\tif ( input.length <= 0 ) {\n\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t}\n\t\telse {\n\t\t\t// New search - start from the master array\n\t\t\tif ( invalidated ||\n\t\t\t\t force ||\n\t\t\t\t prevSearch.length > input.length ||\n\t\t\t\t input.indexOf(prevSearch) !== 0 ||\n\t\t\t\t settings.bSorted // On resort, the display master needs to be\n\t\t\t\t                  // re-filtered since indexes will have changed\n\t\t\t) {\n\t\t\t\tsettings.aiDisplay = displayMaster.slice();\n\t\t\t}\n\n\t\t\t// Search the display array\n\t\t\tdisplay = settings.aiDisplay;\n\n\t\t\tfor ( i=display.length-1 ; i>=0 ; i-- ) {\n\t\t\t\tif ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {\n\t\t\t\t\tdisplay.splice( i, 1 );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Build a regular expression object suitable for searching a table\n\t *  @param {string} sSearch string to search for\n\t *  @param {bool} bRegex treat as a regular expression or not\n\t *  @param {bool} bSmart perform smart filtering or not\n\t *  @param {bool} bCaseInsensitive Do case insensitive matching or not\n\t *  @returns {RegExp} constructed object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )\n\t{\n\t\tvar asSearch,\n\t\t\tsRegExpString = bRegex ? sSearch : _fnEscapeRegex( sSearch );\n\n\t\tif ( bSmart )\n\t\t{\n\t\t\t/* Generate the regular expression to use. Something along the lines of:\n\t\t\t * ^(?=.*?\\bone\\b)(?=.*?\\btwo\\b)(?=.*?\\bthree\\b).*$\n\t\t\t */\n\t\t\tasSearch = sRegExpString.split( ' ' );\n\t\t\tsRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';\n\t\t}\n\n\t\treturn new RegExp( sRegExpString, bCaseInsensitive ? \"i\" : \"\" );\n\t}\n\n\n\t/**\n\t * scape a string such that it can be used in a regular expression\n\t *  @param {string} sVal string to escape\n\t *  @returns {string} escaped string\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnEscapeRegex ( sVal )\n\t{\n\t\tvar acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\\\', '$', '^', '-' ];\n\t\tvar reReplace = new RegExp( '(\\\\' + acEscape.join('|\\\\') + ')', 'g' );\n\t\treturn sVal.replace(reReplace, '\\\\$1');\n\t}\n\n\n\n\tvar __filter_div = $('<div>')[0];\n\tvar __filter_div_textContent = __filter_div.textContent !== undefined;\n\n\t// Update the filtering data for each row if needed (by invalidation or first run)\n\tfunction _fnFilterData ( settings )\n\t{\n\t\tvar columns = settings.aoColumns;\n\t\tvar column;\n\t\tvar i, j, ien, jen, filterData, cellData, row;\n\t\tvar fomatters = DataTable.ext.type.search;\n\t\tvar wasInvalidated = false;\n\n\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\n\t\t\tif ( ! row._aFilterData ) {\n\t\t\t\tfilterData = [];\n\n\t\t\t\tfor ( j=0, jen=columns.length ; j<jen ; j++ ) {\n\t\t\t\t\tcolumn = columns[j];\n\n\t\t\t\t\tif ( column.bSearchable ) {\n\t\t\t\t\t\tcellData = _fnGetCellData( settings, i, j, 'filter' );\n\n\t\t\t\t\t\tcellData = fomatters[ column.sType ] ?\n\t\t\t\t\t\t\tfomatters[ column.sType ]( cellData ) :\n\t\t\t\t\t\t\tcellData !== null ?\n\t\t\t\t\t\t\t\tcellData :\n\t\t\t\t\t\t\t\t'';\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcellData = '';\n\t\t\t\t\t}\n\n\t\t\t\t\t// If it looks like there is an HTML entity in the string,\n\t\t\t\t\t// attempt to decode it so sorting works as expected. Note that\n\t\t\t\t\t// we could use a single line of jQuery to do this, but the DOM\n\t\t\t\t\t// method used here is much faster http://jsperf.com/html-decode\n\t\t\t\t\tif ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {\n\t\t\t\t\t\t__filter_div.innerHTML = cellData;\n\t\t\t\t\t\tcellData = __filter_div_textContent ?\n\t\t\t\t\t\t\t__filter_div.textContent :\n\t\t\t\t\t\t\t__filter_div.innerText;\n\t\t\t\t\t\tcellData = cellData.replace(/[\\r\\n]/g, '');\n\t\t\t\t\t}\n\n\t\t\t\t\tfilterData.push( cellData );\n\t\t\t\t}\n\n\t\t\t\trow._aFilterData = filterData;\n\t\t\t\trow._sFilterRow = filterData.join('  ');\n\t\t\t\twasInvalidated = true;\n\t\t\t}\n\t\t}\n\n\t\treturn wasInvalidated;\n\t}\n\n\t/**\n\t * Generate the node required for the info display\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Information element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlInfo ( settings )\n\t{\n\t\tvar\n\t\t\ttid = settings.sTableId,\n\t\t\tnodes = settings.aanFeatures.i,\n\t\t\tn = $('<div/>', {\n\t\t\t\t'class': settings.oClasses.sInfo,\n\t\t\t\t'id': ! nodes ? tid+'_info' : null\n\t\t\t} );\n\n\t\tif ( ! nodes ) {\n\t\t\t// Update display on each draw\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": _fnUpdateInfo,\n\t\t\t\t\"sName\": \"information\"\n\t\t\t} );\n\n\t\t\tn\n\t\t\t\t.attr( 'role', 'alert' )\n\t\t\t\t.attr( 'aria-live', 'polite' )\n\t\t\t\t.attr( 'aria-relevant', 'all' );\n\n\t\t\t// Table is described by our info div\n\t\t\t$(settings.nTable).attr( 'aria-describedby', tid+'_info' );\n\t\t}\n\n\t\treturn n[0];\n\t}\n\n\n\t/**\n\t * Update the information elements in the display\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnUpdateInfo ( settings )\n\t{\n\t\t/* Show information about the table */\n\t\tvar nodes = settings.aanFeatures.i;\n\t\tif ( nodes.length === 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar\n\t\t\tlang  = settings.oLanguage,\n\t\t\tstart = settings._iDisplayStart+1,\n\t\t\tend   = settings.fnDisplayEnd(),\n\t\t\tmax   = settings.fnRecordsTotal(),\n\t\t\ttotal = settings.fnRecordsDisplay(),\n\t\t\tout   = total ?\n\t\t\t\tlang.sInfo :\n\t\t\t\tlang.sInfoEmpty;\n\n\t\tif ( total !== max ) {\n\t\t\t/* Record set after filtering */\n\t\t\tout += ' ' + lang.sInfoFiltered;\n\t\t}\n\n\t\t// Convert the macros\n\t\tout += lang.sInfoPostFix;\n\t\tout = _fnInfoMacros( settings, out );\n\n\t\tvar callback = lang.fnInfoCallback;\n\t\tif ( callback !== null ) {\n\t\t\tout = callback.call( settings.oInstance,\n\t\t\t\tsettings, start, end, max, total, out\n\t\t\t);\n\t\t}\n\n\t\t$(nodes).html( out );\n\t}\n\n\n\tfunction _fnInfoMacros ( settings, str )\n\t{\n\t\t// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only\n\t\t// internally\n\t\tvar\n\t\t\tformatter  = settings.fnFormatNumber,\n\t\t\tstart      = settings._iDisplayStart+1,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvis        = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\n\t\treturn str.\n\t\t\treplace(/_START_/g, formatter.call( settings, start ) ).\n\t\t\treplace(/_END_/g,   formatter.call( settings, settings.fnDisplayEnd() ) ).\n\t\t\treplace(/_MAX_/g,   formatter.call( settings, settings.fnRecordsTotal() ) ).\n\t\t\treplace(/_TOTAL_/g, formatter.call( settings, vis ) ).\n\t\t\treplace(/_PAGE_/g,  formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).\n\t\t\treplace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );\n\t}\n\n\n\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitialise ( settings )\n\t{\n\t\tvar i, iLen, iAjaxStart=settings.iInitDisplayStart;\n\t\tvar columns = settings.aoColumns, column;\n\t\tvar features = settings.oFeatures;\n\n\t\t/* Ensure that the table data is fully initialised */\n\t\tif ( ! settings.bInitialised ) {\n\t\t\tsetTimeout( function(){ _fnInitialise( settings ); }, 200 );\n\t\t\treturn;\n\t\t}\n\n\t\t/* Show the display HTML options */\n\t\t_fnAddOptionsHtml( settings );\n\n\t\t/* Build and draw the header / footer for the table */\n\t\t_fnBuildHead( settings );\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\n\t\t/* Okay to show that something is going on now */\n\t\t_fnProcessingDisplay( settings, true );\n\n\t\t/* Calculate sizes for columns */\n\t\tif ( features.bAutoWidth ) {\n\t\t\t_fnCalculateColumnWidths( settings );\n\t\t}\n\n\t\tfor ( i=0, iLen=columns.length ; i<iLen ; i++ ) {\n\t\t\tcolumn = columns[i];\n\n\t\t\tif ( column.sWidth ) {\n\t\t\t\tcolumn.nTh.style.width = _fnStringToCss( column.sWidth );\n\t\t\t}\n\t\t}\n\n\t\t// If there is default sorting required - let's do it. The sort function\n\t\t// will do the drawing for us. Otherwise we draw the table regardless of the\n\t\t// Ajax source - this allows the table to look initialised for Ajax sourcing\n\t\t// data (show 'loading' message possibly)\n\t\t_fnReDraw( settings );\n\n\t\t// Server-side processing init complete is done by _fnAjaxUpdateDraw\n\t\tvar dataSrc = _fnDataSource( settings );\n\t\tif ( dataSrc != 'ssp' ) {\n\t\t\t// if there is an ajax source load the data\n\t\t\tif ( dataSrc == 'ajax' ) {\n\t\t\t\t_fnBuildAjax( settings, [], function(json) {\n\t\t\t\t\tvar aData = _fnAjaxDataSrc( settings, json );\n\n\t\t\t\t\t// Got the data - add it to the table\n\t\t\t\t\tfor ( i=0 ; i<aData.length ; i++ ) {\n\t\t\t\t\t\t_fnAddData( settings, aData[i] );\n\t\t\t\t\t}\n\n\t\t\t\t\t// Reset the init display for cookie saving. We've already done\n\t\t\t\t\t// a filter, and therefore cleared it before. So we need to make\n\t\t\t\t\t// it appear 'fresh'\n\t\t\t\t\tsettings.iInitDisplayStart = iAjaxStart;\n\n\t\t\t\t\t_fnReDraw( settings );\n\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t\t_fnInitComplete( settings, json );\n\t\t\t\t}, settings );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t_fnInitComplete( settings );\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Draw the table for the first time, adding all required features\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} [json] JSON from the server that completed the table, if using Ajax source\n\t *    with client-side processing (optional)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnInitComplete ( settings, json )\n\t{\n\t\tsettings._bInitComplete = true;\n\n\t\t// On an Ajax load we now have data and therefore want to apply the column\n\t\t// sizing\n\t\tif ( json ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t}\n\n\t\t_fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );\n\t}\n\n\n\tfunction _fnLengthChange ( settings, val )\n\t{\n\t\tvar len = parseInt( val, 10 );\n\t\tsettings._iDisplayLength = len;\n\n\t\t_fnLengthOverflow( settings );\n\n\t\t// Fire length change event\n\t\t_fnCallbackFire( settings, null, 'length', [settings, len] );\n\t}\n\n\n\t/**\n\t * Generate the node required for user display length changing\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Display length feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlLength ( settings )\n\t{\n\t\tvar\n\t\t\tclasses  = settings.oClasses,\n\t\t\ttableId  = settings.sTableId,\n\t\t\tmenu     = settings.aLengthMenu,\n\t\t\td2       = $.isArray( menu[0] ),\n\t\t\tlengths  = d2 ? menu[0] : menu,\n\t\t\tlanguage = d2 ? menu[1] : menu;\n\n\t\tvar select = $('<select/>', {\n\t\t\t'name':          tableId+'_length',\n\t\t\t'aria-controls': tableId,\n\t\t\t'class':         classes.sLengthSelect\n\t\t} );\n\n\t\tfor ( var i=0, ien=lengths.length ; i<ien ; i++ ) {\n\t\t\tselect[0][ i ] = new Option( language[i], lengths[i] );\n\t\t}\n\n\t\tvar div = $('<div><label/></div>').addClass( classes.sLength );\n\t\tif ( ! settings.aanFeatures.l ) {\n\t\t\tdiv[0].id = tableId+'_length';\n\t\t}\n\n\t\t// This split doesn't matter where _MENU_ is, we get three items back from it\n\t\tvar a = settings.oLanguage.sLengthMenu.split(/(_MENU_)/);\n\t\tdiv.children()\n\t\t\t.append( a[0] )\n\t\t\t.append( select )\n\t\t\t.append( a[2] );\n\n\t\tselect\n\t\t\t.val( settings._iDisplayLength )\n\t\t\t.bind( 'change.DT', function(e) {\n\t\t\t\t_fnLengthChange( settings, $(this).val() );\n\t\t\t\t_fnDraw( settings );\n\t\t\t} );\n\n\t\t// Update node value whenever anything changes the table's length\n\t\t$(settings.nTable).bind( 'length', function (e, s, len) {\n\t\t\tselect.val( len );\n\t\t} );\n\n\t\treturn div[0];\n\t}\n\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Note that most of the paging logic is done in\n\t * DataTable.ext.pager\n\t */\n\n\t/**\n\t * Generate the node required for default pagination\n\t *  @param {object} oSettings dataTables settings object\n\t *  @returns {node} Pagination feature node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlPaginate ( settings )\n\t{\n\t\tvar\n\t\t\ttype   = settings.sPaginationType,\n\t\t\tplugin = DataTable.ext.pager[ type ],\n\t\t\tmodern = typeof plugin === 'function',\n\t\t\tredraw = function( settings ) {\n\t\t\t\t_fnDraw( settings );\n\t\t\t},\n\t\t\tnode = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],\n\t\t\tfeatures = settings.aanFeatures;\n\n\t\tif ( ! modern ) {\n\t\t\tplugin.fnInit( settings, node, redraw );\n\t\t}\n\n\t\t/* Add a draw callback for the pagination on first instance, to update the paging display */\n\t\tif ( ! features.p )\n\t\t{\n\t\t\tnode.id = settings.sTableId+'_paginate';\n\n\t\t\tsettings.aoDrawCallback.push( {\n\t\t\t\t\"fn\": function( settings ) {\n\t\t\t\t\tif ( modern ) {\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\tstart      = settings._iDisplayStart,\n\t\t\t\t\t\t\tlen        = settings._iDisplayLength,\n\t\t\t\t\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\t\t\t\t\tall        = len === -1,\n\t\t\t\t\t\t\tpage = all ? 0 : Math.ceil( start / len ),\n\t\t\t\t\t\t\tpages = all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\t\t\t\tbuttons = plugin(page, pages),\n\t\t\t\t\t\t\ti, ien;\n\n\t\t\t\t\t\tfor ( i=0, ien=features.p.length ; i<ien ; i++ ) {\n\t\t\t\t\t\t\t_fnRenderer( settings, 'pageButton' )(\n\t\t\t\t\t\t\t\tsettings, features.p[i], i, buttons, page, pages\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tplugin.fnUpdate( settings, redraw );\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"sName\": \"pagination\"\n\t\t\t} );\n\t\t}\n\n\t\treturn node;\n\t}\n\n\n\t/**\n\t * Alter the display settings to change the page\n\t *  @param {object} settings DataTables settings object\n\t *  @param {string|int} action Paging action to take: \"first\", \"previous\",\n\t *    \"next\" or \"last\" or page number to jump to (integer)\n\t *  @param [bool] redraw Automatically draw the update or not\n\t *  @returns {bool} true page has changed, false - no change\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnPageChange ( settings, action, redraw )\n\t{\n\t\tvar\n\t\t\tstart     = settings._iDisplayStart,\n\t\t\tlen       = settings._iDisplayLength,\n\t\t\trecords   = settings.fnRecordsDisplay();\n\n\t\tif ( records === 0 || len === -1 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( typeof action === \"number\" )\n\t\t{\n\t\t\tstart = action * len;\n\n\t\t\tif ( start > records )\n\t\t\t{\n\t\t\t\tstart = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"first\" )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\t\telse if ( action == \"previous\" )\n\t\t{\n\t\t\tstart = len >= 0 ?\n\t\t\t\tstart - len :\n\t\t\t\t0;\n\n\t\t\tif ( start < 0 )\n\t\t\t{\n\t\t\t  start = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"next\" )\n\t\t{\n\t\t\tif ( start + len < records )\n\t\t\t{\n\t\t\t\tstart += len;\n\t\t\t}\n\t\t}\n\t\telse if ( action == \"last\" )\n\t\t{\n\t\t\tstart = Math.floor( (records-1) / len) * len;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t_fnLog( settings, 0, \"Unknown paging action: \"+action, 5 );\n\t\t}\n\n\t\tvar changed = settings._iDisplayStart !== start;\n\t\tsettings._iDisplayStart = start;\n\n\t\t_fnCallbackFire( settings, null, 'page', [settings] );\n\n\t\tif ( redraw ) {\n\t\t\t_fnDraw( settings );\n\t\t}\n\n\t\treturn changed;\n\t}\n\n\n\n\t/**\n\t * Generate the node required for the processing node\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Processing element\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlProcessing ( settings )\n\t{\n\t\treturn $('<div/>', {\n\t\t\t\t'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,\n\t\t\t\t'class': settings.oClasses.sProcessing\n\t\t\t} )\n\t\t\t.html( settings.oLanguage.sProcessing )\n\t\t\t.insertBefore( settings.nTable )[0];\n\t}\n\n\n\t/**\n\t * Display or hide the processing indicator\n\t *  @param {object} settings dataTables settings object\n\t *  @param {bool} show Show the processing indicator (true) or not (false)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnProcessingDisplay ( settings, show )\n\t{\n\t\tif ( settings.oFeatures.bProcessing ) {\n\t\t\t$(settings.aanFeatures.r).css( 'visibility', show ? 'visible' : 'hidden' );\n\t\t}\n\n\t\t_fnCallbackFire( settings, null, 'processing', [settings, show] );\n\t}\n\n\t/**\n\t * Add any control elements for the table - specifically scrolling\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {node} Node to add to the DOM\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnFeatureHtmlTable ( settings )\n\t{\n\t\tvar scroll = settings.oScroll;\n\n\t\tif ( scroll.sX === '' && scroll.sY === '' ) {\n\t\t\treturn settings.nTable;\n\t\t}\n\n\t\tvar scrollX = scroll.sX;\n\t\tvar scrollY = scroll.sY;\n\t\tvar classes = settings.oClasses;\n\t\tvar table = $(settings.nTable);\n\t\tvar caption = table.children('caption');\n\t\tvar captionSide = caption.length ? caption[0]._captionSide : null;\n\t\tvar headerClone = $( table[0].cloneNode(false) );\n\t\tvar footerClone = $( table[0].cloneNode(false) );\n\t\tvar footer = table.children('tfoot');\n\t\tvar _div = '<div/>';\n\t\tvar size = function ( s ) {\n\t\t\treturn !s ? null : _fnStringToCss( s );\n\t\t};\n\n\t\tif ( ! footer.length ) {\n\t\t\tfooter = null;\n\t\t}\n\n\t\t/*\n\t\t * The HTML structure that we want to generate in this function is:\n\t\t *  div - scroller\n\t\t *    div - scroll head\n\t\t *      div - scroll head inner\n\t\t *        table - scroll head table\n\t\t *          thead - thead\n\t\t *    div - scroll body\n\t\t *      table - table (master table)\n\t\t *        thead - thead clone for sizing\n\t\t *        tbody - tbody\n\t\t *    div - scroll foot\n\t\t *      div - scroll foot inner\n\t\t *        table - scroll foot table\n\t\t *          tfoot - tfoot\n\t\t */\n\t\tvar scroller = $( _div, { 'class': classes.sScrollWrapper } )\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollHead } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tposition: 'relative',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollHeadInner } )\n\t\t\t\t\t\t\t.css( {\n\t\t\t\t\t\t\t\t'box-sizing': 'content-box',\n\t\t\t\t\t\t\t\twidth: scroll.sXInner || '100%'\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\theaderClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('thead')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t.append( captionSide === 'top' ? caption : null )\n\t\t\t)\n\t\t\t.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollBody } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'auto',\n\t\t\t\t\t\theight: size( scrollY ),\n\t\t\t\t\t\twidth: size( scrollX )\n\t\t\t\t\t} )\n\t\t\t\t\t.append( table )\n\t\t\t);\n\n\t\tif ( footer ) {\n\t\t\tscroller.append(\n\t\t\t\t$(_div, { 'class': classes.sScrollFoot } )\n\t\t\t\t\t.css( {\n\t\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\t\tborder: 0,\n\t\t\t\t\t\twidth: scrollX ? size(scrollX) : '100%'\n\t\t\t\t\t} )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$(_div, { 'class': classes.sScrollFootInner } )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\tfooterClone\n\t\t\t\t\t\t\t\t\t.removeAttr('id')\n\t\t\t\t\t\t\t\t\t.css( 'margin-left', 0 )\n\t\t\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t\t\ttable.children('tfoot')\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t.append( captionSide === 'bottom' ? caption : null )\n\t\t\t);\n\t\t}\n\n\t\tvar children = scroller.children();\n\t\tvar scrollHead = children[0];\n\t\tvar scrollBody = children[1];\n\t\tvar scrollFoot = footer ? children[2] : null;\n\n\t\t// When the body is scrolled, then we also want to scroll the headers\n\t\tif ( scrollX ) {\n\t\t\t$(scrollBody).scroll( function (e) {\n\t\t\t\tvar scrollLeft = this.scrollLeft;\n\n\t\t\t\tscrollHead.scrollLeft = scrollLeft;\n\n\t\t\t\tif ( footer ) {\n\t\t\t\t\tscrollFoot.scrollLeft = scrollLeft;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tsettings.nScrollHead = scrollHead;\n\t\tsettings.nScrollBody = scrollBody;\n\t\tsettings.nScrollFoot = scrollFoot;\n\n\t\t// On redraw - align columns\n\t\tsettings.aoDrawCallback.push( {\n\t\t\t\"fn\": _fnScrollDraw,\n\t\t\t\"sName\": \"scrolling\"\n\t\t} );\n\n\t\treturn scroller[0];\n\t}\n\n\n\n\t/**\n\t * Update the header, footer and body tables for resizing - i.e. column\n\t * alignment.\n\t *\n\t * Welcome to the most horrible function DataTables. The process that this\n\t * function follows is basically:\n\t *   1. Re-create the table inside the scrolling div\n\t *   2. Take live measurements from the DOM\n\t *   3. Apply the measurements to align the columns\n\t *   4. Clean up\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollDraw ( settings )\n\t{\n\t\t// Given that this is such a monster function, a lot of variables are use\n\t\t// to try and keep the minimised size as small as possible\n\t\tvar\n\t\t\tscroll         = settings.oScroll,\n\t\t\tscrollX        = scroll.sX,\n\t\t\tscrollXInner   = scroll.sXInner,\n\t\t\tscrollY        = scroll.sY,\n\t\t\tbarWidth       = scroll.iBarWidth,\n\t\t\tdivHeader      = $(settings.nScrollHead),\n\t\t\tdivHeaderStyle = divHeader[0].style,\n\t\t\tdivHeaderInner = divHeader.children('div'),\n\t\t\tdivHeaderInnerStyle = divHeaderInner[0].style,\n\t\t\tdivHeaderTable = divHeaderInner.children('table'),\n\t\t\tdivBodyEl      = settings.nScrollBody,\n\t\t\tdivBody        = $(divBodyEl),\n\t\t\tdivBodyStyle   = divBodyEl.style,\n\t\t\tdivFooter      = $(settings.nScrollFoot),\n\t\t\tdivFooterInner = divFooter.children('div'),\n\t\t\tdivFooterTable = divFooterInner.children('table'),\n\t\t\theader         = $(settings.nTHead),\n\t\t\ttable          = $(settings.nTable),\n\t\t\ttableEl        = table[0],\n\t\t\ttableStyle     = tableEl.style,\n\t\t\tfooter         = settings.nTFoot ? $(settings.nTFoot) : null,\n\t\t\tbrowser        = settings.oBrowser,\n\t\t\tie67           = browser.bScrollOversize,\n\t\t\theaderTrgEls, footerTrgEls,\n\t\t\theaderSrcEls, footerSrcEls,\n\t\t\theaderCopy, footerCopy,\n\t\t\theaderWidths=[], footerWidths=[],\n\t\t\tidx, correction, sanityWidth,\n\t\t\tzeroOut = function(nSizer) {\n\t\t\t\tvar style = nSizer.style;\n\t\t\t\tstyle.paddingTop = \"0\";\n\t\t\t\tstyle.paddingBottom = \"0\";\n\t\t\t\tstyle.borderTopWidth = \"0\";\n\t\t\t\tstyle.borderBottomWidth = \"0\";\n\t\t\t\tstyle.height = 0;\n\t\t\t};\n\n\t\t/*\n\t\t * 1. Re-create the table inside the scrolling div\n\t\t */\n\n\t\t// Remove the old minimised thead and tfoot elements in the inner table\n\t\ttable.children('thead, tfoot').remove();\n\n\t\t// Clone the current header and footer elements and then place it into the inner table\n\t\theaderCopy = header.clone().prependTo( table );\n\t\theaderTrgEls = header.find('tr'); // original header is in its own table\n\t\theaderSrcEls = headerCopy.find('tr');\n\t\theaderCopy.find('th, td').removeAttr('tabindex');\n\n\t\tif ( footer ) {\n\t\t\tfooterCopy = footer.clone().prependTo( table );\n\t\t\tfooterTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized\n\t\t\tfooterSrcEls = footerCopy.find('tr');\n\t\t}\n\n\n\t\t/*\n\t\t * 2. Take live measurements from the DOM - do not alter the DOM itself!\n\t\t */\n\n\t\t// Remove old sizing and apply the calculated column widths\n\t\t// Get the unique column headers in the newly created (cloned) header. We want to apply the\n\t\t// calculated sizes to this header\n\t\tif ( ! scrollX )\n\t\t{\n\t\t\tdivBodyStyle.width = '100%';\n\t\t\tdivHeader[0].style.width = '100%';\n\t\t}\n\n\t\t$.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {\n\t\t\tidx = _fnVisibleToColumnIndex( settings, i );\n\t\t\tel.style.width = settings.aoColumns[idx].sWidth;\n\t\t} );\n\n\t\tif ( footer ) {\n\t\t\t_fnApplyToChildren( function(n) {\n\t\t\t\tn.style.width = \"\";\n\t\t\t}, footerSrcEls );\n\t\t}\n\n\t\t// If scroll collapse is enabled, when we put the headers back into the body for sizing, we\n\t\t// will end up forcing the scrollbar to appear, making our measurements wrong for when we\n\t\t// then hide it (end of this function), so add the header height to the body scroller.\n\t\tif ( scroll.bCollapse && scrollY !== \"\" ) {\n\t\t\tdivBodyStyle.height = (divBody.offsetHeight + header[0].offsetHeight)+\"px\";\n\t\t}\n\n\t\t// Size the table as a whole\n\t\tsanityWidth = table.outerWidth();\n\t\tif ( scrollX === \"\" ) {\n\t\t\t// No x scrolling\n\t\t\ttableStyle.width = \"100%\";\n\n\t\t\t// IE7 will make the width of the table when 100% include the scrollbar\n\t\t\t// - which is shouldn't. When there is a scrollbar we need to take this\n\t\t\t// into account.\n\t\t\tif ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// x scrolling\n\t\t\tif ( scrollXInner !== \"\" ) {\n\t\t\t\t// x scroll inner has been given - use it\n\t\t\t\ttableStyle.width = _fnStringToCss(scrollXInner);\n\t\t\t}\n\t\t\telse if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {\n\t\t\t\t// There is y-scrolling - try to take account of the y scroll bar\n\t\t\t\ttableStyle.width = _fnStringToCss( sanityWidth-barWidth );\n\t\t\t\tif ( table.outerWidth() > sanityWidth-barWidth ) {\n\t\t\t\t\t// Not possible to take account of it\n\t\t\t\t\ttableStyle.width = _fnStringToCss( sanityWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// When all else fails\n\t\t\t\ttableStyle.width = _fnStringToCss( sanityWidth );\n\t\t\t}\n\t\t}\n\n\t\t// Recalculate the sanity width - now that we've applied the required width,\n\t\t// before it was a temporary variable. This is required because the column\n\t\t// width calculation is done before this table DOM is created.\n\t\tsanityWidth = table.outerWidth();\n\n\t\t// Hidden header should have zero height, so remove padding and borders. Then\n\t\t// set the width based on the real headers\n\n\t\t// Apply all styles in one pass\n\t\t_fnApplyToChildren( zeroOut, headerSrcEls );\n\n\t\t// Read all widths in next pass\n\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\theaderWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t}, headerSrcEls );\n\n\t\t// Apply all widths in final pass\n\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\tnToSize.style.width = headerWidths[i];\n\t\t}, headerTrgEls );\n\n\t\t$(headerSrcEls).height(0);\n\n\t\t/* Same again with the footer if we have one */\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( zeroOut, footerSrcEls );\n\n\t\t\t_fnApplyToChildren( function(nSizer) {\n\t\t\t\tfooterWidths.push( _fnStringToCss( $(nSizer).css('width') ) );\n\t\t\t}, footerSrcEls );\n\n\t\t\t_fnApplyToChildren( function(nToSize, i) {\n\t\t\t\tnToSize.style.width = footerWidths[i];\n\t\t\t}, footerTrgEls );\n\n\t\t\t$(footerSrcEls).height(0);\n\t\t}\n\n\n\t\t/*\n\t\t * 3. Apply the measurements\n\t\t */\n\n\t\t// \"Hide\" the header and footer that we used for the sizing. We want to also fix their width\n\t\t// to what they currently are\n\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\tnSizer.innerHTML = \"\";\n\t\t\tnSizer.style.width = headerWidths[i];\n\t\t}, headerSrcEls );\n\n\t\tif ( footer )\n\t\t{\n\t\t\t_fnApplyToChildren( function(nSizer, i) {\n\t\t\t\tnSizer.innerHTML = \"\";\n\t\t\t\tnSizer.style.width = footerWidths[i];\n\t\t\t}, footerSrcEls );\n\t\t}\n\n\t\t// Sanity check that the table is of a sensible width. If not then we are going to get\n\t\t// misalignment - try to prevent this by not allowing the table to shrink below its min width\n\t\tif ( table.outerWidth() < sanityWidth )\n\t\t{\n\t\t\t// The min width depends upon if we have a vertical scrollbar visible or not */\n\t\t\tcorrection = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||\n\t\t\t\tdivBody.css('overflow-y') == \"scroll\")) ?\n\t\t\t\t\tsanityWidth+barWidth :\n\t\t\t\t\tsanityWidth;\n\n\t\t\t// IE6/7 are a law unto themselves...\n\t\t\tif ( ie67 && (divBodyEl.scrollHeight >\n\t\t\t\tdivBodyEl.offsetHeight || divBody.css('overflow-y') == \"scroll\")\n\t\t\t) {\n\t\t\t\ttableStyle.width = _fnStringToCss( correction-barWidth );\n\t\t\t}\n\n\t\t\t// And give the user a warning that we've stopped the table getting too small\n\t\t\tif ( scrollX === \"\" || scrollXInner !== \"\" ) {\n\t\t\t\t_fnLog( settings, 1, 'Possible column misalignment', 6 );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tcorrection = '100%';\n\t\t}\n\n\t\t// Apply to the container elements\n\t\tdivBodyStyle.width = _fnStringToCss( correction );\n\t\tdivHeaderStyle.width = _fnStringToCss( correction );\n\n\t\tif ( footer ) {\n\t\t\tsettings.nScrollFoot.style.width = _fnStringToCss( correction );\n\t\t}\n\n\n\t\t/*\n\t\t * 4. Clean up\n\t\t */\n\t\tif ( ! scrollY ) {\n\t\t\t/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting\n\t\t\t * the scrollbar height from the visible display, rather than adding it on. We need to\n\t\t\t * set the height in order to sort this. Don't want to do it in any other browsers.\n\t\t\t */\n\t\t\tif ( ie67 ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );\n\t\t\t}\n\t\t}\n\n\t\tif ( scrollY && scroll.bCollapse ) {\n\t\t\tdivBodyStyle.height = _fnStringToCss( scrollY );\n\n\t\t\tvar iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?\n\t\t\t\tbarWidth :\n\t\t\t\t0;\n\n\t\t\tif ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {\n\t\t\t\tdivBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );\n\t\t\t}\n\t\t}\n\n\t\t/* Finally set the width's of the header and footer tables */\n\t\tvar iOuterWidth = table.outerWidth();\n\t\tdivHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\tdivHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );\n\n\t\t// Figure out if there are scrollbar present - if so then we need a the header and footer to\n\t\t// provide a bit more space to allow \"overflow\" scrolling (i.e. past the scrollbar)\n\t\tvar bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == \"scroll\";\n\t\tvar padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );\n\t\tdivHeaderInnerStyle[ padding ] = bScrolling ? barWidth+\"px\" : \"0px\";\n\n\t\tif ( footer ) {\n\t\t\tdivFooterTable[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style.width = _fnStringToCss( iOuterWidth );\n\t\t\tdivFooterInner[0].style[padding] = bScrolling ? barWidth+\"px\" : \"0px\";\n\t\t}\n\n\t\t/* Adjust the position of the header in case we loose the y-scrollbar */\n\t\tdivBody.scroll();\n\n\t\t/* If sorting or filtering has occurred, jump the scrolling back to the top */\n\t\tif ( settings.bSorted || settings.bFiltered ) {\n\t\t\tdivBodyEl.scrollTop = 0;\n\t\t}\n\t}\n\n\n\n\t/**\n\t * Apply a given function to the display child nodes of an element array (typically\n\t * TD children of TR rows\n\t *  @param {function} fn Method to apply to the objects\n\t *  @param array {nodes} an1 List of elements to look through for display children\n\t *  @param array {nodes} an2 Another list (identical structure to the first) - optional\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnApplyToChildren( fn, an1, an2 )\n\t{\n\t\tvar index=0, i=0, iLen=an1.length;\n\t\tvar nNode1, nNode2;\n\n\t\twhile ( i < iLen ) {\n\t\t\tnNode1 = an1[i].firstChild;\n\t\t\tnNode2 = an2 ? an2[i].firstChild : null;\n\n\t\t\twhile ( nNode1 ) {\n\t\t\t\tif ( nNode1.nodeType === 1 ) {\n\t\t\t\t\tif ( an2 ) {\n\t\t\t\t\t\tfn( nNode1, nNode2, index );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfn( nNode1, index );\n\t\t\t\t\t}\n\n\t\t\t\t\tindex++;\n\t\t\t\t}\n\n\t\t\t\tnNode1 = nNode1.nextSibling;\n\t\t\t\tnNode2 = an2 ? nNode2.nextSibling : null;\n\t\t\t}\n\n\t\t\ti++;\n\t\t}\n\t}\n\n\n\n\tvar __re_html_remove = /<.*?>/g;\n\n\n\t/**\n\t * Calculate the width of columns for the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCalculateColumnWidths ( oSettings )\n\t{\n\t\tvar\n\t\t\ttable = oSettings.nTable,\n\t\t\tcolumns = oSettings.aoColumns,\n\t\t\tscroll = oSettings.oScroll,\n\t\t\tscrollY = scroll.sY,\n\t\t\tscrollX = scroll.sX,\n\t\t\tscrollXInner = scroll.sXInner,\n\t\t\tcolumnCount = columns.length,\n\t\t\tvisibleColumns = _fnGetColumns( oSettings, 'bVisible' ),\n\t\t\theaderCells = $('th', oSettings.nTHead),\n\t\t\ttableWidthAttr = table.getAttribute('width'),\n\t\t\ttableContainer = table.parentNode,\n\t\t\tuserInputs = false,\n\t\t\ti, column, columnIdx, width, outerWidth;\n\n\t\t/* Convert any user input sizes into pixel sizes */\n\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\tcolumn = columns[ visibleColumns[i] ];\n\n\t\t\tif ( column.sWidth !== null ) {\n\t\t\t\tcolumn.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );\n\n\t\t\t\tuserInputs = true;\n\t\t\t}\n\t\t}\n\n\t\t/* If the number of columns in the DOM equals the number that we have to\n\t\t * process in DataTables, then we can use the offsets that are created by\n\t\t * the web- browser. No custom sizes can be set in order for this to happen,\n\t\t * nor scrolling used\n\t\t */\n\t\tif ( ! userInputs && ! scrollX && ! scrollY &&\n\t\t    columnCount == _fnVisbleColumns( oSettings ) &&\n\t\t\tcolumnCount == headerCells.length\n\t\t) {\n\t\t\tfor ( i=0 ; i<columnCount ; i++ ) {\n\t\t\t\tcolumns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise construct a single row table with the widest node in the\n\t\t\t// data, assign any user defined widths, then insert it into the DOM and\n\t\t\t// allow the browser to do all the hard work of calculating table widths\n\t\t\tvar tmpTable = $( table.cloneNode( false ) )\n\t\t\t\t.css( 'visibility', 'hidden' )\n\t\t\t\t.removeAttr( 'id' )\n\t\t\t\t.append( $(oSettings.nTHead).clone( false ) )\n\t\t\t\t.append( $(oSettings.nTFoot).clone( false ) )\n\t\t\t\t.append( $('<tbody><tr/></tbody>') );\n\n\t\t\t// Remove any assigned widths from the footer (from scrolling)\n\t\t\ttmpTable.find('tfoot th, tfoot td').css('width', '');\n\n\t\t\tvar tr = tmpTable.find( 'tbody tr' );\n\n\t\t\t// Apply custom sizing to the cloned header\n\t\t\theaderCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );\n\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\n\t\t\t\theaderCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?\n\t\t\t\t\t_fnStringToCss( column.sWidthOrig ) :\n\t\t\t\t\t'';\n\t\t\t}\n\n\t\t\t// Find the widest cell for each column and put it into the table\n\t\t\tif ( oSettings.aoData.length ) {\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumnIdx = visibleColumns[i];\n\t\t\t\t\tcolumn = columns[ columnIdx ];\n\n\t\t\t\t\t$( _fnGetWidestNode( oSettings, columnIdx ) )\n\t\t\t\t\t\t.clone( false )\n\t\t\t\t\t\t.append( column.sContentPadding )\n\t\t\t\t\t\t.appendTo( tr );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Table has been built, attach to the document so we can work with it\n\t\t\ttmpTable.appendTo( tableContainer );\n\n\t\t\t// When scrolling (X or Y) we want to set the width of the table as\n\t\t\t// appropriate. However, when not scrolling leave the table width as it\n\t\t\t// is. This results in slightly different, but I think correct behaviour\n\t\t\tif ( scrollX && scrollXInner ) {\n\t\t\t\ttmpTable.width( scrollXInner );\n\t\t\t}\n\t\t\telse if ( scrollX ) {\n\t\t\t\ttmpTable.css( 'width', 'auto' );\n\n\t\t\t\tif ( tmpTable.width() < tableContainer.offsetWidth ) {\n\t\t\t\t\ttmpTable.width( tableContainer.offsetWidth );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( scrollY ) {\n\t\t\t\ttmpTable.width( tableContainer.offsetWidth );\n\t\t\t}\n\t\t\telse if ( tableWidthAttr ) {\n\t\t\t\ttmpTable.width( tableWidthAttr );\n\t\t\t}\n\n\t\t\t// Take into account the y scrollbar\n\t\t\t_fnScrollingWidthAdjust( oSettings, tmpTable[0] );\n\n\t\t\t// Browsers need a bit of a hand when a width is assigned to any columns\n\t\t\t// when x-scrolling as they tend to collapse the table to the min-width,\n\t\t\t// even if we sent the column widths. So we need to keep track of what\n\t\t\t// the table width should be by summing the user given values, and the\n\t\t\t// automatic values\n\t\t\tif ( scrollX )\n\t\t\t{\n\t\t\t\tvar total = 0;\n\n\t\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\t\t\t\touterWidth = $(headerCells[i]).outerWidth();\n\n\t\t\t\t\ttotal += column.sWidthOrig === null ?\n\t\t\t\t\t\touterWidth :\n\t\t\t\t\t\tparseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();\n\t\t\t\t}\n\n\t\t\t\ttmpTable.width( _fnStringToCss( total ) );\n\t\t\t\ttable.style.width = _fnStringToCss( total );\n\t\t\t}\n\n\t\t\t// Get the width of each column in the constructed table\n\t\t\tfor ( i=0 ; i<visibleColumns.length ; i++ ) {\n\t\t\t\tcolumn = columns[ visibleColumns[i] ];\n\t\t\t\twidth = $(headerCells[i]).width();\n\n\t\t\t\tif ( width ) {\n\t\t\t\t\tcolumn.sWidth = _fnStringToCss( width );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttable.style.width = _fnStringToCss( tmpTable.css('width') );\n\n\t\t\t// Finished with the table - ditch it\n\t\t\ttmpTable.remove();\n\t\t}\n\n\t\t// If there is a width attr, we want to attach an event listener which\n\t\t// allows the table sizing to automatically adjust when the window is\n\t\t// resized. Use the width attr rather than CSS, since we can't know if the\n\t\t// CSS is a relative value or absolute - DOM read is always px.\n\t\tif ( tableWidthAttr ) {\n\t\t\ttable.style.width = _fnStringToCss( tableWidthAttr );\n\n\t\t\tif ( ! oSettings._reszEvt ) {\n\t\t\t\t$(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {\n\t\t\t\t\t_fnAdjustColumnSizing( oSettings );\n\t\t\t\t} ) );\n\n\t\t\t\toSettings._reszEvt = true;\n\t\t\t}\n\t\t}\n\t}\n\n\n\tfunction _fnThrottle( fn ) {\n\t\tvar\n\t\t\tfrequency = 200,\n\t\t\tlast,\n\t\t\ttimer;\n\n\t\treturn function () {\n\t\t\tvar\n\t\t\t\tnow = +new Date(),\n\t\t\t\targs = arguments;\n\n\t\t\tif ( last && now < last + frequency ) {\n\t\t\t\tclearTimeout( timer );\n\n\t\t\t\ttimer = setTimeout( function () {\n\t\t\t\t\tlast = now;\n\t\t\t\t\tfn();\n\t\t\t\t}, frequency );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlast = now;\n\t\t\t\tfn();\n\t\t\t}\n\t\t};\n\t}\n\n\n\t/**\n\t * Convert a CSS unit width to pixels (e.g. 2em)\n\t *  @param {string} width width to be converted\n\t *  @param {node} parent parent to get the with for (required for relative widths) - optional\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnConvertToWidth ( width, parent )\n\t{\n\t\tif ( ! width ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar n = $('<div/>')\n\t\t\t.css( 'width', _fnStringToCss( width ) )\n\t\t\t.appendTo( parent || document.body );\n\n\t\tvar val = n[0].offsetWidth;\n\t\tn.remove();\n\n\t\treturn val;\n\t}\n\n\n\t/**\n\t * Adjust a table's width to take account of vertical scroll bar\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {node} n table node\n\t *  @memberof DataTable#oApi\n\t */\n\n\tfunction _fnScrollingWidthAdjust ( settings, n )\n\t{\n\t\tvar scroll = settings.oScroll;\n\n\t\tif ( scroll.sX || scroll.sY ) {\n\t\t\t// When y-scrolling only, we want to remove the width of the scroll bar\n\t\t\t// so the table + scroll bar will fit into the area available, otherwise\n\t\t\t// we fix the table at its current size with no adjustment\n\t\t\tvar correction = ! scroll.sX ? scroll.iBarWidth : 0;\n\t\t\tn.style.width = _fnStringToCss( $(n).outerWidth() - correction );\n\t\t}\n\t}\n\n\n\t/**\n\t * Get the widest node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {node} widest table node\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetWidestNode( settings, colIdx )\n\t{\n\t\tvar idx = _fnGetMaxLenString( settings, colIdx );\n\t\tif ( idx < 0 ) {\n\t\t\treturn null;\n\t\t}\n\n\t\tvar data = settings.aoData[ idx ];\n\t\treturn ! data.nTr ? // Might not have been created when deferred rendering\n\t\t\t$('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :\n\t\t\tdata.anCells[ colIdx ];\n\t}\n\n\n\t/**\n\t * Get the maximum strlen for each data column\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} colIdx column of interest\n\t *  @returns {string} max string length for each column\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnGetMaxLenString( settings, colIdx )\n\t{\n\t\tvar s, max=-1, maxIdx = -1;\n\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\ts = _fnGetCellData( settings, i, colIdx, 'display' )+'';\n\t\t\ts = s.replace( __re_html_remove, '' );\n\n\t\t\tif ( s.length > max ) {\n\t\t\t\tmax = s.length;\n\t\t\t\tmaxIdx = i;\n\t\t\t}\n\t\t}\n\n\t\treturn maxIdx;\n\t}\n\n\n\t/**\n\t * Append a CSS unit (only if required) to a string\n\t *  @param {string} value to css-ify\n\t *  @returns {string} value with css unit\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnStringToCss( s )\n\t{\n\t\tif ( s === null ) {\n\t\t\treturn '0px';\n\t\t}\n\n\t\tif ( typeof s == 'number' ) {\n\t\t\treturn s < 0 ?\n\t\t\t\t'0px' :\n\t\t\t\ts+'px';\n\t\t}\n\n\t\t// Check it has a unit character already\n\t\treturn s.match(/\\d$/) ?\n\t\t\ts+'px' :\n\t\t\ts;\n\t}\n\n\n\t/**\n\t * Get the width of a scroll bar in this browser being used\n\t *  @returns {int} width in pixels\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnScrollBarWidth ()\n\t{\n\t\t// On first run a static variable is set, since this is only needed once.\n\t\t// Subsequent runs will just use the previously calculated value\n\t\tif ( ! DataTable.__scrollbarWidth ) {\n\t\t\tvar inner = $('<p/>').css( {\n\t\t\t\twidth: '100%',\n\t\t\t\theight: 200,\n\t\t\t\tpadding: 0\n\t\t\t} )[0];\n\n\t\t\tvar outer = $('<div/>')\n\t\t\t\t.css( {\n\t\t\t\t\tposition: 'absolute',\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: 0,\n\t\t\t\t\twidth: 200,\n\t\t\t\t\theight: 150,\n\t\t\t\t\tpadding: 0,\n\t\t\t\t\toverflow: 'hidden',\n\t\t\t\t\tvisibility: 'hidden'\n\t\t\t\t} )\n\t\t\t\t.append( inner )\n\t\t\t\t.appendTo( 'body' );\n\n\t\t\tvar w1 = inner.offsetWidth;\n\t\t\touter.css( 'overflow', 'scroll' );\n\t\t\tvar w2 = inner.offsetWidth;\n\n\t\t\tif ( w1 === w2 ) {\n\t\t\t\tw2 = outer[0].clientWidth;\n\t\t\t}\n\n\t\t\touter.remove();\n\n\t\t\tDataTable.__scrollbarWidth = w1 - w2;\n\t\t}\n\n\t\treturn DataTable.__scrollbarWidth;\n\t}\n\n\n\n\tfunction _fnSortFlatten ( settings )\n\t{\n\t\tvar\n\t\t\ti, iLen, k, kLen,\n\t\t\taSort = [],\n\t\t\taiOrig = [],\n\t\t\taoColumns = settings.aoColumns,\n\t\t\taDataSort, iCol, sType, srcCol,\n\t\t\tfixed = settings.aaSortingFixed,\n\t\t\tfixedObj = $.isPlainObject( fixed ),\n\t\t\tnestedSort = [],\n\t\t\tadd = function ( a ) {\n\t\t\t\tif ( a.length && ! $.isArray( a[0] ) ) {\n\t\t\t\t\t// 1D array\n\t\t\t\t\tnestedSort.push( a );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// 2D array\n\t\t\t\t\tnestedSort.push.apply( nestedSort, a );\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Build the sort array, with pre-fix and post-fix options if they have been\n\t\t// specified\n\t\tif ( $.isArray( fixed ) ) {\n\t\t\tadd( fixed );\n\t\t}\n\n\t\tif ( fixedObj && fixed.pre ) {\n\t\t\tadd( fixed.pre );\n\t\t}\n\n\t\tadd( settings.aaSorting );\n\n\t\tif (fixedObj && fixed.post ) {\n\t\t\tadd( fixed.post );\n\t\t}\n\n\t\tfor ( i=0 ; i<nestedSort.length ; i++ )\n\t\t{\n\t\t\tsrcCol = nestedSort[i][0];\n\t\t\taDataSort = aoColumns[ srcCol ].aDataSort;\n\n\t\t\tfor ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )\n\t\t\t{\n\t\t\t\tiCol = aDataSort[k];\n\t\t\t\tsType = aoColumns[ iCol ].sType || 'string';\n\n\t\t\t\taSort.push( {\n\t\t\t\t\tsrc:       srcCol,\n\t\t\t\t\tcol:       iCol,\n\t\t\t\t\tdir:       nestedSort[i][1],\n\t\t\t\t\tindex:     nestedSort[i][2],\n\t\t\t\t\ttype:      sType,\n\t\t\t\t\tformatter: DataTable.ext.type.order[ sType+\"-pre\" ]\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\treturn aSort;\n\t}\n\n\t/**\n\t * Change the order of the table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t *  @todo This really needs split up!\n\t */\n\tfunction _fnSort ( oSettings )\n\t{\n\t\tvar\n\t\t\ti, ien, iLen, j, jLen, k, kLen,\n\t\t\tsDataType, nTh,\n\t\t\taiOrig = [],\n\t\t\toExtSort = DataTable.ext.type.order,\n\t\t\taoData = oSettings.aoData,\n\t\t\taoColumns = oSettings.aoColumns,\n\t\t\taDataSort, data, iCol, sType, oSort,\n\t\t\tformatters = 0,\n\t\t\tsortCol,\n\t\t\tdisplayMaster = oSettings.aiDisplayMaster,\n\t\t\taSort = _fnSortFlatten( oSettings );\n\n\t\t// Resolve any column types that are unknown due to addition or invalidation\n\t\t// @todo Can this be moved into a 'data-ready' handler which is called when\n\t\t//   data is going to be used in the table?\n\t\t_fnColumnTypes( oSettings );\n\n\t\tfor ( i=0, ien=aSort.length ; i<ien ; i++ ) {\n\t\t\tsortCol = aSort[i];\n\n\t\t\t// Track if we can use the fast sort algorithm\n\t\t\tif ( sortCol.formatter ) {\n\t\t\t\tformatters++;\n\t\t\t}\n\n\t\t\t// Load the data needed for the sort, for each cell\n\t\t\t_fnSortData( oSettings, sortCol.col );\n\t\t}\n\n\t\t/* No sorting required if server-side or no sorting array */\n\t\tif ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )\n\t\t{\n\t\t\t// Create a value - key array of the current row positions such that we can use their\n\t\t\t// current position during the sort, if values match, in order to perform stable sorting\n\t\t\tfor ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {\n\t\t\t\taiOrig[ displayMaster[i] ] = i;\n\t\t\t}\n\n\t\t\t/* Do the sort - here we want multi-column sorting based on a given data source (column)\n\t\t\t * and sorting function (from oSort) in a certain direction. It's reasonably complex to\n\t\t\t * follow on it's own, but this is what we want (example two column sorting):\n\t\t\t *  fnLocalSorting = function(a,b){\n\t\t\t *    var iTest;\n\t\t\t *    iTest = oSort['string-asc']('data11', 'data12');\n\t\t\t *      if (iTest !== 0)\n\t\t\t *        return iTest;\n\t\t\t *    iTest = oSort['numeric-desc']('data21', 'data22');\n\t\t\t *    if (iTest !== 0)\n\t\t\t *      return iTest;\n\t\t\t *    return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );\n\t\t\t *  }\n\t\t\t * Basically we have a test for each sorting column, if the data in that column is equal,\n\t\t\t * test the next column. If all columns match, then we use a numeric sort on the row\n\t\t\t * positions in the original data array to provide a stable sort.\n\t\t\t *\n\t\t\t * Note - I know it seems excessive to have two sorting methods, but the first is around\n\t\t\t * 15% faster, so the second is only maintained for backwards compatibility with sorting\n\t\t\t * methods which do not have a pre-sort formatting function.\n\t\t\t */\n\t\t\tif ( formatters === aSort.length ) {\n\t\t\t\t// All sort types have formatting functions\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, test, sort,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\n\t\t\t\t\t\ttest = x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn sort.dir === 'asc' ? test : -test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Depreciated - remove in 1.11 (providing a plug-in option)\n\t\t\t\t// Not all sort types have formatting methods, so we have to call their sorting\n\t\t\t\t// methods.\n\t\t\t\tdisplayMaster.sort( function ( a, b ) {\n\t\t\t\t\tvar\n\t\t\t\t\t\tx, y, k, l, test, sort, fn,\n\t\t\t\t\t\tlen=aSort.length,\n\t\t\t\t\t\tdataA = aoData[a]._aSortData,\n\t\t\t\t\t\tdataB = aoData[b]._aSortData;\n\n\t\t\t\t\tfor ( k=0 ; k<len ; k++ ) {\n\t\t\t\t\t\tsort = aSort[k];\n\n\t\t\t\t\t\tx = dataA[ sort.col ];\n\t\t\t\t\t\ty = dataB[ sort.col ];\n\n\t\t\t\t\t\tfn = oExtSort[ sort.type+\"-\"+sort.dir ] || oExtSort[ \"string-\"+sort.dir ];\n\t\t\t\t\t\ttest = fn( x, y );\n\t\t\t\t\t\tif ( test !== 0 ) {\n\t\t\t\t\t\t\treturn test;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tx = aiOrig[a];\n\t\t\t\t\ty = aiOrig[b];\n\t\t\t\t\treturn x<y ? -1 : x>y ? 1 : 0;\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\n\t\t/* Tell the draw function that we have sorted the data */\n\t\toSettings.bSorted = true;\n\t}\n\n\n\tfunction _fnSortAria ( settings )\n\t{\n\t\tvar label;\n\t\tvar nextSort;\n\t\tvar columns = settings.aoColumns;\n\t\tvar aSort = _fnSortFlatten( settings );\n\t\tvar oAria = settings.oLanguage.oAria;\n\n\t\t// ARIA attributes - need to loop all columns, to update all (removing old\n\t\t// attributes as needed)\n\t\tfor ( var i=0, iLen=columns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\tvar col = columns[i];\n\t\t\tvar asSorting = col.asSorting;\n\t\t\tvar sTitle = col.sTitle.replace( /<.*?>/g, \"\" );\n\t\t\tvar jqTh = $(col.nTh).removeAttr('aria-sort');\n\n\t\t\t/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */\n\t\t\tif ( col.bSortable ) {\n\t\t\t\tif ( aSort.length > 0 && aSort[0].col == i ) {\n\t\t\t\t\tjqTh.attr('aria-sort', aSort[0].dir==\"asc\" ? \"ascending\" : \"descending\" );\n\t\t\t\t\tnextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnextSort = asSorting[0];\n\t\t\t\t}\n\n\t\t\t\tlabel = sTitle + ( nextSort === \"asc\" ?\n\t\t\t\t\toAria.sSortAscending :\n\t\t\t\t\toAria.sSortDescending\n\t\t\t\t);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tlabel = sTitle;\n\t\t\t}\n\n\t\t\tjqTh.attr('aria-label', label);\n\t\t}\n\t}\n\n\n\t/**\n\t * Function to run on user sort request\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {boolean} [append=false] Append the requested sort to the existing\n\t *    sort if true (i.e. multi-column sort)\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortListener ( settings, colIdx, append, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\t\tvar sorting = settings.aaSorting;\n\t\tvar asSorting = col.asSorting;\n\t\tvar nextSortIdx;\n\t\tvar next = function ( a ) {\n\t\t\tvar idx = a._idx;\n\t\t\tif ( idx === undefined ) {\n\t\t\t\tidx = $.inArray( a[1], asSorting );\n\t\t\t}\n\n\t\t\treturn idx+1 >= asSorting.length ? 0 : idx+1;\n\t\t};\n\n\t\t// If appending the sort then we are multi-column sorting\n\t\tif ( append && settings.oFeatures.bSortMulti ) {\n\t\t\t// Are we already doing some kind of sort on this column?\n\t\t\tvar sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );\n\n\t\t\tif ( sortIdx !== -1 ) {\n\t\t\t\t// Yes, modify the sort\n\t\t\t\tnextSortIdx = next( sorting[sortIdx] );\n\n\t\t\t\tsorting[sortIdx][1] = asSorting[ nextSortIdx ];\n\t\t\t\tsorting[sortIdx]._idx = nextSortIdx;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// No sort on this column yet\n\t\t\t\tsorting.push( [ colIdx, asSorting[0], 0 ] );\n\t\t\t\tsorting[sorting.length-1]._idx = 0;\n\t\t\t}\n\t\t}\n\t\telse if ( sorting.length && sorting[0][0] == colIdx ) {\n\t\t\t// Single column - already sorting on this column, modify the sort\n\t\t\tnextSortIdx = next( sorting[0] );\n\n\t\t\tsorting.length = 1;\n\t\t\tsorting[0][1] = asSorting[ nextSortIdx ];\n\t\t\tsorting[0]._idx = nextSortIdx;\n\t\t}\n\t\telse {\n\t\t\t// Single column - sort only on this column\n\t\t\tsorting.length = 0;\n\t\t\tsorting.push( [ colIdx, asSorting[0] ] );\n\t\t\tsorting[0]._idx = 0;\n\t\t}\n\n\t\t// Run the sort by calling a full redraw\n\t\t_fnReDraw( settings );\n\n\t\t// callback used for async user interaction\n\t\tif ( typeof callback == 'function' ) {\n\t\t\tcallback( settings );\n\t\t}\n\t}\n\n\n\t/**\n\t * Attach a sort handler (click) to a node\n\t *  @param {object} settings dataTables settings object\n\t *  @param {node} attachTo node to attach the handler to\n\t *  @param {int} colIdx column sorting index\n\t *  @param {function} [callback] callback function\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortAttachListener ( settings, attachTo, colIdx, callback )\n\t{\n\t\tvar col = settings.aoColumns[ colIdx ];\n\n\t\t_fnBindAction( attachTo, {}, function (e) {\n\t\t\t/* If the column is not sortable - don't to anything */\n\t\t\tif ( col.bSortable === false ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_fnProcessingDisplay( settings, true );\n\n\t\t\t// Use a timeout to allow the processing display to be shown.\n\t\t\tsetTimeout( function() {\n\t\t\t\t_fnSortListener( settings, colIdx, e.shiftKey, callback );\n\n\t\t\t\t// In server-side processing, the draw callback will remove the\n\t\t\t\t// processing display\n\t\t\t\tif ( _fnDataSource( settings ) !== 'ssp' ) {\n\t\t\t\t\t_fnProcessingDisplay( settings, false );\n\t\t\t\t}\n\t\t\t}, 0 );\n\t\t} );\n\t}\n\n\n\t/**\n\t * Set the sorting classes on table's body, Note: it is safe to call this function\n\t * when bSort and bSortClasses are false\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSortingClasses( settings )\n\t{\n\t\tvar oldSort = settings.aLastSort;\n\t\tvar sortClass = settings.oClasses.sSortColumn;\n\t\tvar sort = _fnSortFlatten( settings );\n\t\tvar features = settings.oFeatures;\n\t\tvar i, ien, colIdx;\n\n\t\tif ( features.bSort && features.bSortClasses ) {\n\t\t\t// Remove old sorting classes\n\t\t\tfor ( i=0, ien=oldSort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = oldSort[i].src;\n\n\t\t\t\t// Remove column sorting\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.removeClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\n\t\t\t// Add new column sorting\n\t\t\tfor ( i=0, ien=sort.length ; i<ien ; i++ ) {\n\t\t\t\tcolIdx = sort[i].src;\n\n\t\t\t\t$( _pluck( settings.aoData, 'anCells', colIdx ) )\n\t\t\t\t\t.addClass( sortClass + (i<2 ? i+1 : 3) );\n\t\t\t}\n\t\t}\n\n\t\tsettings.aLastSort = sort;\n\t}\n\n\n\t// Get the data to sort a column, be it from cache, fresh (populating the\n\t// cache), or from a sort formatter\n\tfunction _fnSortData( settings, idx )\n\t{\n\t\t// Custom sorting function - provided by the sort data type\n\t\tvar column = settings.aoColumns[ idx ];\n\t\tvar customSort = DataTable.ext.order[ column.sSortDataType ];\n\t\tvar customData;\n\n\t\tif ( customSort ) {\n\t\t\tcustomData = customSort.call( settings.oInstance, settings, idx,\n\t\t\t\t_fnColumnIndexToVisible( settings, idx )\n\t\t\t);\n\t\t}\n\n\t\t// Use / populate cache\n\t\tvar row, cellData;\n\t\tvar formatter = DataTable.ext.type.order[ column.sType+\"-pre\" ];\n\n\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\trow = settings.aoData[i];\n\n\t\t\tif ( ! row._aSortData ) {\n\t\t\t\trow._aSortData = [];\n\t\t\t}\n\n\t\t\tif ( ! row._aSortData[idx] || customSort ) {\n\t\t\t\tcellData = customSort ?\n\t\t\t\t\tcustomData[i] : // If there was a custom sort function, use data from there\n\t\t\t\t\t_fnGetCellData( settings, i, idx, 'sort' );\n\n\t\t\t\trow._aSortData[ idx ] = formatter ?\n\t\t\t\t\tformatter( cellData ) :\n\t\t\t\t\tcellData;\n\t\t\t}\n\t\t}\n\t}\n\n\n\n\t/**\n\t * Save the state of a table\n\t *  @param {object} oSettings dataTables settings object\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSaveState ( oSettings )\n\t{\n\t\tif ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t/* Store the interesting variables */\n\t\tvar i, iLen;\n\t\tvar oState = {\n\t\t\t\"iCreate\":      new Date().getTime(),\n\t\t\t\"iStart\":       oSettings._iDisplayStart,\n\t\t\t\"iLength\":      oSettings._iDisplayLength,\n\t\t\t\"aaSorting\":    $.extend( true, [], oSettings.aaSorting ),\n\t\t\t\"oSearch\":      $.extend( true, {}, oSettings.oPreviousSearch ),\n\t\t\t\"aoSearchCols\": $.extend( true, [], oSettings.aoPreSearchCols ),\n\t\t\t\"abVisCols\":    []\n\t\t};\n\n\t\tfor ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )\n\t\t{\n\t\t\toState.abVisCols.push( oSettings.aoColumns[i].bVisible );\n\t\t}\n\n\t\t_fnCallbackFire( oSettings, \"aoStateSaveParams\", 'stateSaveParams', [oSettings, oState] );\n\n\t\toSettings.fnStateSaveCallback.call( oSettings.oInstance, oSettings, oState );\n\t}\n\n\n\t/**\n\t * Attempt to load a saved table state\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {object} oInit DataTables init object so we can override settings\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLoadState ( oSettings, oInit )\n\t{\n\t\tvar i, ien;\n\t\tvar columns = oSettings.aoColumns;\n\n\t\tif ( !oSettings.oFeatures.bStateSave )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\tvar oData = oSettings.fnStateLoadCallback.call( oSettings.oInstance, oSettings );\n\t\tif ( !oData )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t/* Allow custom and plug-in manipulation functions to alter the saved data set and\n\t\t * cancelling of loading by returning false\n\t\t */\n\t\tvar abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );\n\t\tif ( $.inArray( false, abStateLoad ) !== -1 )\n\t\t{\n\t\t\treturn;\n\t\t}\n\n\t\t/* Reject old data */\n\t\tif ( oData.iCreate < new Date().getTime() - (oSettings.iStateDuration*1000) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Number of columns have changed - all bets are off, no restore of settings\n\t\tif ( columns.length !== oData.aoSearchCols.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\t/* Store the saved state so it might be accessed at any time */\n\t\toSettings.oLoadedState = $.extend( true, {}, oData );\n\n\t\t/* Restore key features */\n\t\toSettings._iDisplayStart    = oData.iStart;\n\t\toSettings.iInitDisplayStart = oData.iStart;\n\t\toSettings._iDisplayLength   = oData.iLength;\n\t\toSettings.aaSorting         = [];\n\n\t\tvar savedSort = oData.aaSorting;\n\t\tfor ( i=0, ien=savedSort.length ; i<ien ; i++ ) {\n\t\t\toSettings.aaSorting.push( savedSort[i][0] >= columns.length ?\n\t\t\t\t[ 0, savedSort[i][1] ] :\n\t\t\t\tsavedSort[i]\n\t\t\t);\n\t\t}\n\n\t\t/* Search filtering  */\n\t\t$.extend( oSettings.oPreviousSearch, oData.oSearch );\n\t\t$.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );\n\n\t\t/* Column visibility state */\n\t\tfor ( i=0, ien=oData.abVisCols.length ; i<ien ; i++ ) {\n\t\t\tcolumns[i].bVisible = oData.abVisCols[i];\n\t\t}\n\n\t\t_fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );\n\t}\n\n\n\n\t/**\n\t * Return the settings object for a particular table\n\t *  @param {node} table table we are using as a dataTable\n\t *  @returns {object} Settings object - or null if not found\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnSettingsFromNode ( table )\n\t{\n\t\tvar settings = DataTable.settings;\n\t\tvar idx = $.inArray( table, _pluck( settings, 'nTable' ) );\n\n\t\treturn idx !== -1 ?\n\t\t\tsettings[ idx ] :\n\t\t\tnull;\n\t}\n\n\n\t/**\n\t * Log an error message\n\t *  @param {object} settings dataTables settings object\n\t *  @param {int} level log error messages, or display them to the user\n\t *  @param {string} msg error message\n\t *  @param {int} tn Technical note id to get more information about the error.\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnLog( settings, level, msg, tn )\n\t{\n\t\tmsg = 'DataTables warning: '+\n\t\t\t(settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;\n\n\t\tif ( tn ) {\n\t\t\tmsg += '. For more information about this error, please see '+\n\t\t\t'http://datatables.net/tn/'+tn;\n\t\t}\n\n\t\tif ( ! level  ) {\n\t\t\t// Backwards compatibility pre 1.10\n\t\t\tvar ext = DataTable.ext;\n\t\t\tvar type = ext.sErrMode || ext.errMode;\n\n\t\t\tif ( type == 'alert' ) {\n\t\t\t\talert( msg );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthrow new Error(msg);\n\t\t\t}\n\t\t}\n\t\telse if ( window.console && console.log ) {\n\t\t\tconsole.log( msg );\n\t\t}\n\t}\n\n\n\t/**\n\t * See if a property is defined on one object, if so assign it to the other object\n\t *  @param {object} ret target object\n\t *  @param {object} src source object\n\t *  @param {string} name property\n\t *  @param {string} [mappedName] name to map too - optional, name used if not given\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnMap( ret, src, name, mappedName )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\t$.each( name, function (i, val) {\n\t\t\t\tif ( $.isArray( val ) ) {\n\t\t\t\t\t_fnMap( ret, src, val[0], val[1] );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t_fnMap( ret, src, val );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn;\n\t\t}\n\n\t\tif ( mappedName === undefined ) {\n\t\t\tmappedName = name;\n\t\t}\n\n\t\tif ( src[name] !== undefined ) {\n\t\t\tret[mappedName] = src[name];\n\t\t}\n\t}\n\n\n\t/**\n\t * Extend objects - very similar to jQuery.extend, but deep copy objects, and\n\t * shallow copy arrays. The reason we need to do this, is that we don't want to\n\t * deep copy array init values (such as aaSorting) since the dev wouldn't be\n\t * able to override them, but we do want to deep copy arrays.\n\t *  @param {object} out Object to extend\n\t *  @param {object} extender Object from which the properties will be applied to\n\t *      out\n\t *  @param {boolean} breakRefs If true, then arrays will be sliced to take an\n\t *      independent copy with the exception of the `data` or `aaData` parameters\n\t *      if they are present. This is so you can pass in a collection to\n\t *      DataTables and have that used as your data source without breaking the\n\t *      references\n\t *  @returns {object} out Reference, just for convenience - out === the return.\n\t *  @memberof DataTable#oApi\n\t *  @todo This doesn't take account of arrays inside the deep copied objects.\n\t */\n\tfunction _fnExtend( out, extender, breakRefs )\n\t{\n\t\tvar val;\n\n\t\tfor ( var prop in extender ) {\n\t\t\tif ( extender.hasOwnProperty(prop) ) {\n\t\t\t\tval = extender[prop];\n\n\t\t\t\tif ( $.isPlainObject( val ) ) {\n\t\t\t\t\tif ( ! $.isPlainObject( out[prop] ) ) {\n\t\t\t\t\t\tout[prop] = {};\n\t\t\t\t\t}\n\t\t\t\t\t$.extend( true, out[prop], val );\n\t\t\t\t}\n\t\t\t\telse if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {\n\t\t\t\t\tout[prop] = val.slice();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tout[prop] = val;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t}\n\n\n\t/**\n\t * Bind an event handers to allow a click or return key to activate the callback.\n\t * This is good for accessibility since a return on the keyboard will have the\n\t * same effect as a click, if the element has focus.\n\t *  @param {element} n Element to bind the action to\n\t *  @param {object} oData Data object to pass to the triggered function\n\t *  @param {function} fn Callback function for when the event is triggered\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnBindAction( n, oData, fn )\n\t{\n\t\t$(n)\n\t\t\t.bind( 'click.DT', oData, function (e) {\n\t\t\t\t\tn.blur(); // Remove focus outline for mouse users\n\t\t\t\t\tfn(e);\n\t\t\t\t} )\n\t\t\t.bind( 'keypress.DT', oData, function (e){\n\t\t\t\tif ( e.which === 13 ) {\n\t\t\t\t\tfn(e);\n\t\t\t\t} } )\n\t\t\t.bind( 'selectstart.DT', function () {\n\t\t\t\t/* Take the brutal approach to cancelling text selection */\n\t\t\t\treturn false;\n\t\t\t\t} );\n\t}\n\n\n\t/**\n\t * Register a callback function. Easily allows a callback function to be added to\n\t * an array store of callback functions that can then all be called together.\n\t *  @param {object} oSettings dataTables settings object\n\t *  @param {string} sStore Name of the array storage for the callbacks in oSettings\n\t *  @param {function} fn Function to be called back\n\t *  @param {string} sName Identifying name for the callback (i.e. a label)\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackReg( oSettings, sStore, fn, sName )\n\t{\n\t\tif ( fn )\n\t\t{\n\t\t\toSettings[sStore].push( {\n\t\t\t\t\"fn\": fn,\n\t\t\t\t\"sName\": sName\n\t\t\t} );\n\t\t}\n\t}\n\n\n\t/**\n\t * Fire callback functions and trigger events. Note that the loop over the\n\t * callback array store is done backwards! Further note that you do not want to\n\t * fire off triggers in time sensitive applications (for example cell creation)\n\t * as its slow.\n\t *  @param {object} settings dataTables settings object\n\t *  @param {string} callbackArr Name of the array storage for the callbacks in\n\t *      oSettings\n\t *  @param {string} event Name of the jQuery custom event to trigger. If null no\n\t *      trigger is fired\n\t *  @param {array} args Array of arguments to pass to the callback function /\n\t *      trigger\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnCallbackFire( settings, callbackArr, event, args )\n\t{\n\t\tvar ret = [];\n\n\t\tif ( callbackArr ) {\n\t\t\tret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {\n\t\t\t\treturn val.fn.apply( settings.oInstance, args );\n\t\t\t} );\n\t\t}\n\n\t\tif ( event !== null ) {\n\t\t\t$(settings.nTable).trigger( event+'.dt', args );\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\n\tfunction _fnLengthOverflow ( settings )\n\t{\n\t\tvar\n\t\t\tstart = settings._iDisplayStart,\n\t\t\tend = settings.fnDisplayEnd(),\n\t\t\tlen = settings._iDisplayLength;\n\n\t\t/* If we have space to show extra rows (backing up from the end point - then do so */\n\t\tif ( end === settings.fnRecordsDisplay() )\n\t\t{\n\t\t\tstart = end - len;\n\t\t}\n\n\t\tif ( len === -1 || start < 0 )\n\t\t{\n\t\t\tstart = 0;\n\t\t}\n\n\t\tsettings._iDisplayStart = start;\n\t}\n\n\n\tfunction _fnRenderer( settings, type )\n\t{\n\t\tvar renderer = settings.renderer;\n\t\tvar host = DataTable.ext.renderer[type];\n\n\t\tif ( $.isPlainObject( renderer ) && renderer[type] ) {\n\t\t\t// Specific renderer for this type. If available use it, otherwise use\n\t\t\t// the default.\n\t\t\treturn host[renderer[type]] || host._;\n\t\t}\n\t\telse if ( typeof renderer === 'string' ) {\n\t\t\t// Common renderer - if there is one available for this type use it,\n\t\t\t// otherwise use the default\n\t\t\treturn host[renderer] || host._;\n\t\t}\n\n\t\t// Use the default\n\t\treturn host._;\n\t}\n\n\n\t/**\n\t * Detect the data source being used for the table. Used to simplify the code\n\t * a little (ajax) and to make it compress a little smaller.\n\t *\n\t *  @param {object} settings dataTables settings object\n\t *  @returns {string} Data source\n\t *  @memberof DataTable#oApi\n\t */\n\tfunction _fnDataSource ( settings )\n\t{\n\t\tif ( settings.oFeatures.bServerSide ) {\n\t\t\treturn 'ssp';\n\t\t}\n\t\telse if ( settings.ajax || settings.sAjaxSource ) {\n\t\t\treturn 'ajax';\n\t\t}\n\t\treturn 'dom';\n\t}\n\n\n\tDataTable = function( options )\n\t{\n\t\t/**\n\t\t * Perform a jQuery selector action on the table's TR elements (from the tbody) and\n\t\t * return the resulting jQuery object.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter\n\t\t *    criterion (\"applied\") or all TR elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {object} jQuery object, filtered by the given selector.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Highlight every second row\n\t\t *      oTable.$('tr:odd').css('backgroundColor', 'blue');\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to rows with 'Webkit' in them, add a background colour and then\n\t\t *      // remove the filter, thus highlighting the 'Webkit' rows only.\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      oTable.$('tr', {\"search\": \"applied\"}).css('backgroundColor', 'blue');\n\t\t *      oTable.fnFilter('');\n\t\t *    } );\n\t\t */\n\t\tthis.$ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).$( sSelector, oOpts );\n\t\t};\n\n\n\t\t/**\n\t\t * Almost identical to $ in operation, but in this case returns the data for the matched\n\t\t * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes\n\t\t * rather than any descendants, so the data can be obtained for the row/cell. If matching\n\t\t * rows are found, the data returned is the original data array/object that was used to\n\t\t * create the row (or a generated array if from a DOM source).\n\t\t *\n\t\t * This method is often useful in-combination with $ where both functions are given the\n\t\t * same parameters and the array indexes will match identically.\n\t\t *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on\n\t\t *  @param {object} [oOpts] Optional parameters for modifying the rows to be included\n\t\t *  @param {string} [oOpts.filter=none] Select elements that meet the current filter\n\t\t *    criterion (\"applied\") or all elements (i.e. no filter).\n\t\t *  @param {string} [oOpts.order=current] Order of the data in the processed array.\n\t\t *    Can be either 'current', whereby the current sorting of the table is used, or\n\t\t *    'original' whereby the original order the data was read into the table is used.\n\t\t *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page\n\t\t *    (\"current\") or not (\"all\"). If 'current' is given, then order is assumed to be\n\t\t *    'current' and filter is 'applied', regardless of what they might be given as.\n\t\t *  @returns {array} Data for the matched elements. If any elements, as a result of the\n\t\t *    selector, were not TR, TD or TH elements in the DataTable, they will have a null\n\t\t *    entry in the array.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the data from the first row in the table\n\t\t *      var data = oTable._('tr:first');\n\t\t *\n\t\t *      // Do something useful with the data\n\t\t *      alert( \"First cell is: \"+data[0] );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Filter to 'Webkit' and get all data for\n\t\t *      oTable.fnFilter('Webkit');\n\t\t *      var data = oTable._('tr', {\"search\": \"applied\"});\n\t\t *\n\t\t *      // Do something with the data\n\t\t *      alert( data.length+\" rows matched the search\" );\n\t\t *    } );\n\t\t */\n\t\tthis._ = function ( sSelector, oOpts )\n\t\t{\n\t\t\treturn this.api(true).rows( sSelector, oOpts ).data();\n\t\t};\n\n\n\t\t/**\n\t\t * Create a DataTables Api instance, with the currently selected tables for\n\t\t * the Api's context.\n\t\t * @param {boolean} [traditional=false] Set the API instance's context to be\n\t\t *   only the table referred to by the `DataTable.ext.iApiIndex` option, as was\n\t\t *   used in the API presented by DataTables 1.9- (i.e. the traditional mode),\n\t\t *   or if all tables captured in the jQuery object should be used.\n\t\t * @return {DataTables.Api}\n\t\t */\n\t\tthis.api = function ( traditional )\n\t\t{\n\t\t\treturn traditional ?\n\t\t\t\tnew _Api(\n\t\t\t\t\t_fnSettingsFromNode( this[ _ext.iApiIndex ] )\n\t\t\t\t) :\n\t\t\t\tnew _Api( this );\n\t\t};\n\n\n\t\t/**\n\t\t * Add a single new row or multiple rows of data to the table. Please note\n\t\t * that this is suitable for client-side processing only - if you are using\n\t\t * server-side processing (i.e. \"bServerSide\": true), then to add data, you\n\t\t * must add it to the data source, i.e. the server-side, through an Ajax call.\n\t\t *  @param {array|object} data The data to be added to the table. This can be:\n\t\t *    <ul>\n\t\t *      <li>1D array of data - add a single row with the data provided</li>\n\t\t *      <li>2D array of arrays - add multiple rows in a single call</li>\n\t\t *      <li>object - data object when using <i>mData</i></li>\n\t\t *      <li>array of objects - multiple data objects when using <i>mData</i></li>\n\t\t *    </ul>\n\t\t *  @param {bool} [redraw=true] redraw the table or not\n\t\t *  @returns {array} An array of integers, representing the list of indexes in\n\t\t *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to\n\t\t *    the table.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Global var for counter\n\t\t *    var giCount = 2;\n\t\t *\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example').dataTable();\n\t\t *    } );\n\t\t *\n\t\t *    function fnClickAddRow() {\n\t\t *      $('#example').dataTable().fnAddData( [\n\t\t *        giCount+\".1\",\n\t\t *        giCount+\".2\",\n\t\t *        giCount+\".3\",\n\t\t *        giCount+\".4\" ]\n\t\t *      );\n\t\t *\n\t\t *      giCount++;\n\t\t *    }\n\t\t */\n\t\tthis.fnAddData = function( data, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\n\t\t\t/* Check if we want to add multiple rows or not */\n\t\t\tvar rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?\n\t\t\t\tapi.rows.add( data ) :\n\t\t\t\tapi.row.add( data );\n\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\n\t\t\treturn rows.flatten().toArray();\n\t\t};\n\n\n\t\t/**\n\t\t * This function will make DataTables recalculate the column sizes, based on the data\n\t\t * contained in the table and the sizes applied to the columns (in the DOM, CSS or\n\t\t * through the sWidth parameter). This can be useful when the width of the table's\n\t\t * parent element changes (for example a window resize).\n\t\t *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable( {\n\t\t *        \"sScrollY\": \"200px\",\n\t\t *        \"bPaginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      $(window).bind('resize', function () {\n\t\t *        oTable.fnAdjustColumnSizing();\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnAdjustColumnSizing = function ( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).columns.adjust();\n\t\t\tvar settings = api.settings()[0];\n\t\t\tvar scroll = settings.oScroll;\n\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw( false );\n\t\t\t}\n\t\t\telse if ( scroll.sX !== \"\" || scroll.sY !== \"\" ) {\n\t\t\t\t/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */\n\t\t\t\t_fnScrollDraw( settings );\n\t\t\t}\n\t\t};\n\n\n\t\t/**\n\t\t * Quickly and simply clear a table\n\t\t *  @param {bool} [bRedraw=true] redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)\n\t\t *      oTable.fnClearTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClearTable = function( bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).clear();\n\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t};\n\n\n\t\t/**\n\t\t * The exact opposite of 'opening' a row, this function will close any rows which\n\t\t * are currently 'open'.\n\t\t *  @param {node} nTr the table row to 'close'\n\t\t *  @returns {int} 0 on success, or 1 if failed (can't find the row)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnClose = function( nTr )\n\t\t{\n\t\t\tthis.api( true ).row( nTr ).child.hide();\n\t\t};\n\n\n\t\t/**\n\t\t * Remove a row for the table\n\t\t *  @param {mixed} target The index of the row from aoData to be deleted, or\n\t\t *    the TR element you want to delete\n\t\t *  @param {function|null} [callBack] Callback function\n\t\t *  @param {bool} [redraw=true] Redraw the table or not\n\t\t *  @returns {array} The row that was deleted\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Immediately remove the first row\n\t\t *      oTable.fnDeleteRow( 0 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnDeleteRow = function( target, callback, redraw )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar rows = api.rows( target );\n\t\t\tvar settings = rows.settings()[0];\n\t\t\tvar data = settings.aoData[ rows[0][0] ];\n\n\t\t\trows.remove();\n\n\t\t\tif ( callback ) {\n\t\t\t\tcallback.call( this, settings, data );\n\t\t\t}\n\n\t\t\tif ( redraw === undefined || redraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\n\t\t\treturn data;\n\t\t};\n\n\n\t\t/**\n\t\t * Restore the table to it's original state in the DOM by removing all of DataTables\n\t\t * enhancements, alterations to the DOM structure of the table and event listeners.\n\t\t *  @param {boolean} [remove=false] Completely remove the table from the DOM\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      // This example is fairly pointless in reality, but shows how fnDestroy can be used\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnDestroy();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDestroy = function ( remove )\n\t\t{\n\t\t\tthis.api( true ).destroy( remove );\n\t\t};\n\n\n\t\t/**\n\t\t * Redraw the table\n\t\t *  @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)\n\t\t *      oTable.fnDraw();\n\t\t *    } );\n\t\t */\n\t\tthis.fnDraw = function( complete )\n\t\t{\n\t\t\t// Note that this isn't an exact match to the old call to _fnDraw - it takes\n\t\t\t// into account the new data, but can old position.\n\t\t\tthis.api( true ).draw( ! complete );\n\t\t};\n\n\n\t\t/**\n\t\t * Filter the input based on data\n\t\t *  @param {string} sInput String to filter the table on\n\t\t *  @param {int|null} [iColumn] Column to limit filtering to\n\t\t *  @param {bool} [bRegex=false] Treat as regular expression or not\n\t\t *  @param {bool} [bSmart=true] Perform smart filtering or not\n\t\t *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)\n\t\t *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sometime later - filter...\n\t\t *      oTable.fnFilter( 'test string' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )\n\t\t{\n\t\t\tvar api = this.api( true );\n\n\t\t\tif ( iColumn === null || iColumn === undefined ) {\n\t\t\t\tapi.search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );\n\t\t\t}\n\n\t\t\tapi.draw();\n\t\t};\n\n\n\t\t/**\n\t\t * Get the data for the whole table, an individual row or an individual cell based on the\n\t\t * provided parameters.\n\t\t *  @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as\n\t\t *    a TR node then the data source for the whole row will be returned. If given as a\n\t\t *    TD/TH cell node then iCol will be automatically calculated and the data for the\n\t\t *    cell returned. If given as an integer, then this is treated as the aoData internal\n\t\t *    data index for the row (see fnGetPosition) and the data for that row used.\n\t\t *  @param {int} [col] Optional column index that you want the data of.\n\t\t *  @returns {array|object|string} If mRow is undefined, then the data for all rows is\n\t\t *    returned. If mRow is defined, just data for that row, and is iCol is\n\t\t *    defined, only data for the designated cell is returned.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    // Row data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('tr').click( function () {\n\t\t *        var data = oTable.fnGetData( this );\n\t\t *        // ... do something with the array / object of data for the row\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Individual cell data\n\t\t *    $(document).ready(function() {\n\t\t *      oTable = $('#example').dataTable();\n\t\t *\n\t\t *      oTable.$('td').click( function () {\n\t\t *        var sData = oTable.fnGetData( this );\n\t\t *        alert( 'The cell clicked on had the value of '+sData );\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetData = function( src, col )\n\t\t{\n\t\t\tvar api = this.api( true );\n\n\t\t\tif ( src !== undefined ) {\n\t\t\t\tvar type = src.nodeName ? src.nodeName.toLowerCase() : '';\n\n\t\t\t\treturn col !== undefined || type == 'td' || type == 'th' ?\n\t\t\t\t\tapi.cell( src, col ).data() :\n\t\t\t\t\tapi.row( src ).data();\n\t\t\t}\n\n\t\t\treturn api.data().toArray();\n\t\t};\n\n\n\t\t/**\n\t\t * Get an array of the TR nodes that are used in the table's body. Note that you will\n\t\t * typically want to use the '$' API method in preference to this as it is more\n\t\t * flexible.\n\t\t *  @param {int} [iRow] Optional row index for the TR element you want\n\t\t *  @returns {array|node} If iRow is undefined, returns an array of all TR elements\n\t\t *    in the table's body, or iRow is defined, just the TR element requested.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Get the nodes from the table\n\t\t *      var nNodes = oTable.fnGetNodes( );\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetNodes = function( iRow )\n\t\t{\n\t\t\tvar api = this.api( true );\n\n\t\t\treturn iRow !== undefined ?\n\t\t\t\tapi.row( iRow ).node() :\n\t\t\t\tapi.rows().nodes().toArray();\n\t\t};\n\n\n\t\t/**\n\t\t * Get the array indexes of a particular cell from it's DOM element\n\t\t * and column index including hidden columns\n\t\t *  @param {node} node this can either be a TR, TD or TH in the table's body\n\t\t *  @returns {int} If nNode is given as a TR, then a single index is returned, or\n\t\t *    if given as a cell, an array of [row index, column index (visible),\n\t\t *    column index (all)] is given.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      $('#example tbody td').click( function () {\n\t\t *        // Get the position of the current data from the node\n\t\t *        var aPos = oTable.fnGetPosition( this );\n\t\t *\n\t\t *        // Get the data array for this row\n\t\t *        var aData = oTable.fnGetData( aPos[0] );\n\t\t *\n\t\t *        // Update the data array and return the value\n\t\t *        aData[ aPos[1] ] = 'clicked';\n\t\t *        this.innerHTML = 'clicked';\n\t\t *      } );\n\t\t *\n\t\t *      // Init DataTables\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnGetPosition = function( node )\n\t\t{\n\t\t\tvar api = this.api( true );\n\t\t\tvar nodeName = node.nodeName.toUpperCase();\n\n\t\t\tif ( nodeName == 'TR' ) {\n\t\t\t\treturn api.row( node ).index();\n\t\t\t}\n\t\t\telse if ( nodeName == 'TD' || nodeName == 'TH' ) {\n\t\t\t\tvar cell = api.cell( node ).index();\n\n\t\t\t\treturn [\n\t\t\t\t\tcell.row,\n\t\t\t\t\tcell.columnVisible,\n\t\t\t\t\tcell.column\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\n\n\t\t/**\n\t\t * Check to see if a row is 'open' or not.\n\t\t *  @param {node} nTr the table row to check\n\t\t *  @returns {boolean} true if the row is currently open, false otherwise\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnIsOpen = function( nTr )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child.isShown();\n\t\t};\n\n\n\t\t/**\n\t\t * This function will place a new row directly after a row which is currently\n\t\t * on display on the page, with the HTML contents that is passed into the\n\t\t * function. This can be used, for example, to ask for confirmation that a\n\t\t * particular record should be deleted.\n\t\t *  @param {node} nTr The table row to 'open'\n\t\t *  @param {string|node|jQuery} mHtml The HTML to put into the row\n\t\t *  @param {string} sClass Class to give the new TD cell\n\t\t *  @returns {node} The row opened. Note that if the table row passed in as the\n\t\t *    first parameter, is not found in the table, this method will silently\n\t\t *    return.\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable;\n\t\t *\n\t\t *      // 'open' an information row when a row is clicked on\n\t\t *      $('#example tbody tr').click( function () {\n\t\t *        if ( oTable.fnIsOpen(this) ) {\n\t\t *          oTable.fnClose( this );\n\t\t *        } else {\n\t\t *          oTable.fnOpen( this, \"Temporary row opened\", \"info_row\" );\n\t\t *        }\n\t\t *      } );\n\t\t *\n\t\t *      oTable = $('#example').dataTable();\n\t\t *    } );\n\t\t */\n\t\tthis.fnOpen = function( nTr, mHtml, sClass )\n\t\t{\n\t\t\treturn this.api( true ).row( nTr ).child( mHtml, sClass ).show();\n\t\t};\n\n\n\t\t/**\n\t\t * Change the pagination - provides the internal logic for pagination in a simple API\n\t\t * function. With this function you can have a DataTables table go to the next,\n\t\t * previous, first or last pages.\n\t\t *  @param {string|int} mAction Paging action to take: \"first\", \"previous\", \"next\" or \"last\"\n\t\t *    or page number to jump to (integer), note that page 0 is the first page.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnPageChange( 'next' );\n\t\t *    } );\n\t\t */\n\t\tthis.fnPageChange = function ( mAction, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).page( mAction );\n\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw(false);\n\t\t\t}\n\t\t};\n\n\n\t\t/**\n\t\t * Show a particular column\n\t\t *  @param {int} iCol The column whose display should be changed\n\t\t *  @param {bool} bShow Show (true) or hide (false) the column\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Hide the second column after initialisation\n\t\t *      oTable.fnSetColumnVis( 1, false );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSetColumnVis = function ( iCol, bShow, bRedraw )\n\t\t{\n\t\t\tvar api = this.api( true ).column( iCol ).visible( bShow );\n\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.columns.adjust().draw();\n\t\t\t}\n\t\t};\n\n\n\t\t/**\n\t\t * Get the settings for a particular table for external manipulation\n\t\t *  @returns {object} DataTables settings object. See\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      var oSettings = oTable.fnSettings();\n\t\t *\n\t\t *      // Show an example parameter from the settings\n\t\t *      alert( oSettings._iDisplayStart );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSettings = function()\n\t\t{\n\t\t\treturn _fnSettingsFromNode( this[_ext.iApiIndex] );\n\t\t};\n\n\n\t\t/**\n\t\t * Sort the table by a particular column\n\t\t *  @param {int} iCol the data index to sort on. Note that this will not match the\n\t\t *    'display index' if you have hidden data entries\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort immediately with columns 0 and 1\n\t\t *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSort = function( aaSort )\n\t\t{\n\t\t\tthis.api( true ).order( aaSort ).draw();\n\t\t};\n\n\n\t\t/**\n\t\t * Attach a sort listener to an element for a given column\n\t\t *  @param {node} nNode the element to attach the sort listener to\n\t\t *  @param {int} iColumn the column that a click on this node will sort on\n\t\t *  @param {function} [fnCallback] callback function when sort is run\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *\n\t\t *      // Sort on column 1, when 'sorter' is clicked on\n\t\t *      oTable.fnSortListener( document.getElementById('sorter'), 1 );\n\t\t *    } );\n\t\t */\n\t\tthis.fnSortListener = function( nNode, iColumn, fnCallback )\n\t\t{\n\t\t\tthis.api( true ).order.listener( nNode, iColumn, fnCallback );\n\t\t};\n\n\n\t\t/**\n\t\t * Update a table cell or row - this method will accept either a single value to\n\t\t * update the cell with, an array of values with one element for each column or\n\t\t * an object in the same format as the original data source. The function is\n\t\t * self-referencing in order to make the multi column updates easier.\n\t\t *  @param {object|array|string} mData Data to update the cell/row with\n\t\t *  @param {node|int} mRow TR element you want to update or the aoData index\n\t\t *  @param {int} [iColumn] The column to update, give as null or undefined to\n\t\t *    update a whole row.\n\t\t *  @param {bool} [bRedraw=true] Redraw the table or not\n\t\t *  @param {bool} [bAction=true] Perform pre-draw actions or not\n\t\t *  @returns {int} 0 on success, 1 on error\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell\n\t\t *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row\n\t\t *    } );\n\t\t */\n\t\tthis.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )\n\t\t{\n\t\t\tvar api = this.api( true );\n\n\t\t\tif ( iColumn === undefined || iColumn === null ) {\n\t\t\t\tapi.row( mRow ).data( mData );\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapi.cell( mRow, iColumn ).data( mData );\n\t\t\t}\n\n\t\t\tif ( bAction === undefined || bAction ) {\n\t\t\t\tapi.columns.adjust();\n\t\t\t}\n\n\t\t\tif ( bRedraw === undefined || bRedraw ) {\n\t\t\t\tapi.draw();\n\t\t\t}\n\t\t\treturn 0;\n\t\t};\n\n\n\t\t/**\n\t\t * Provide a common method for plug-ins to check the version of DataTables being used, in order\n\t\t * to ensure compatibility.\n\t\t *  @param {string} sVersion Version string to check for, in the format \"X.Y.Z\". Note that the\n\t\t *    formats \"X\" and \"X.Y\" are also acceptable.\n\t\t *  @returns {boolean} true if this version of DataTables is greater or equal to the required\n\t\t *    version, or false if this version of DataTales is not suitable\n\t\t *  @method\n\t\t *  @dtopt API\n\t\t *  @deprecated Since v1.10\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready(function() {\n\t\t *      var oTable = $('#example').dataTable();\n\t\t *      alert( oTable.fnVersionCheck( '1.9.0' ) );\n\t\t *    } );\n\t\t */\n\t\tthis.fnVersionCheck = _ext.fnVersionCheck;\n\n\n\t\t/*\n\t\t * This is really a good bit rubbish this method of exposing the internal methods\n\t\t * publicly... - To be fixed in 2.0 using methods on the prototype\n\t\t */\n\n\n\t\t/**\n\t\t * Create a wrapper function for exporting an internal functions to an external API.\n\t\t *  @param {string} fn API function name\n\t\t *  @returns {function} wrapped function\n\t\t *  @memberof DataTable#internal\n\t\t */\n\t\tfunction _fnExternApiFunc (fn)\n\t\t{\n\t\t\treturn function() {\n\t\t\t\tvar args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(\n\t\t\t\t\tArray.prototype.slice.call(arguments)\n\t\t\t\t);\n\t\t\t\treturn DataTable.ext.internal[fn].apply( this, args );\n\t\t\t};\n\t\t}\n\n\n\t\t/**\n\t\t * Reference to internal functions for use by plug-in developers. Note that\n\t\t * these methods are references to internal functions and are considered to be\n\t\t * private. If you use these methods, be aware that they are liable to change\n\t\t * between versions.\n\t\t *  @namespace\n\t\t */\n\t\tthis.oApi = this.internal = {\n\t\t\t_fnExternApiFunc: _fnExternApiFunc,\n\t\t\t_fnBuildAjax: _fnBuildAjax,\n\t\t\t_fnAjaxUpdate: _fnAjaxUpdate,\n\t\t\t_fnAjaxParameters: _fnAjaxParameters,\n\t\t\t_fnAjaxUpdateDraw: _fnAjaxUpdateDraw,\n\t\t\t_fnAjaxDataSrc: _fnAjaxDataSrc,\n\t\t\t_fnAddColumn: _fnAddColumn,\n\t\t\t_fnColumnOptions: _fnColumnOptions,\n\t\t\t_fnAdjustColumnSizing: _fnAdjustColumnSizing,\n\t\t\t_fnVisibleToColumnIndex: _fnVisibleToColumnIndex,\n\t\t\t_fnColumnIndexToVisible: _fnColumnIndexToVisible,\n\t\t\t_fnVisbleColumns: _fnVisbleColumns,\n\t\t\t_fnGetColumns: _fnGetColumns,\n\t\t\t_fnColumnTypes: _fnColumnTypes,\n\t\t\t_fnApplyColumnDefs: _fnApplyColumnDefs,\n\t\t\t_fnHungarianMap: _fnHungarianMap,\n\t\t\t_fnCamelToHungarian: _fnCamelToHungarian,\n\t\t\t_fnLanguageCompat: _fnLanguageCompat,\n\t\t\t_fnBrowserDetect: _fnBrowserDetect,\n\t\t\t_fnAddData: _fnAddData,\n\t\t\t_fnAddTr: _fnAddTr,\n\t\t\t_fnNodeToDataIndex: _fnNodeToDataIndex,\n\t\t\t_fnNodeToColumnIndex: _fnNodeToColumnIndex,\n\t\t\t_fnGetRowData: _fnGetRowData,\n\t\t\t_fnGetCellData: _fnGetCellData,\n\t\t\t_fnSetCellData: _fnSetCellData,\n\t\t\t_fnSplitObjNotation: _fnSplitObjNotation,\n\t\t\t_fnGetObjectDataFn: _fnGetObjectDataFn,\n\t\t\t_fnSetObjectDataFn: _fnSetObjectDataFn,\n\t\t\t_fnGetDataMaster: _fnGetDataMaster,\n\t\t\t_fnClearTable: _fnClearTable,\n\t\t\t_fnDeleteIndex: _fnDeleteIndex,\n\t\t\t_fnInvalidateRow: _fnInvalidateRow,\n\t\t\t_fnGetRowElements: _fnGetRowElements,\n\t\t\t_fnCreateTr: _fnCreateTr,\n\t\t\t_fnBuildHead: _fnBuildHead,\n\t\t\t_fnDrawHead: _fnDrawHead,\n\t\t\t_fnDraw: _fnDraw,\n\t\t\t_fnReDraw: _fnReDraw,\n\t\t\t_fnAddOptionsHtml: _fnAddOptionsHtml,\n\t\t\t_fnDetectHeader: _fnDetectHeader,\n\t\t\t_fnGetUniqueThs: _fnGetUniqueThs,\n\t\t\t_fnFeatureHtmlFilter: _fnFeatureHtmlFilter,\n\t\t\t_fnFilterComplete: _fnFilterComplete,\n\t\t\t_fnFilterCustom: _fnFilterCustom,\n\t\t\t_fnFilterColumn: _fnFilterColumn,\n\t\t\t_fnFilter: _fnFilter,\n\t\t\t_fnFilterCreateSearch: _fnFilterCreateSearch,\n\t\t\t_fnEscapeRegex: _fnEscapeRegex,\n\t\t\t_fnFilterData: _fnFilterData,\n\t\t\t_fnFeatureHtmlInfo: _fnFeatureHtmlInfo,\n\t\t\t_fnUpdateInfo: _fnUpdateInfo,\n\t\t\t_fnInfoMacros: _fnInfoMacros,\n\t\t\t_fnInitialise: _fnInitialise,\n\t\t\t_fnInitComplete: _fnInitComplete,\n\t\t\t_fnLengthChange: _fnLengthChange,\n\t\t\t_fnFeatureHtmlLength: _fnFeatureHtmlLength,\n\t\t\t_fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,\n\t\t\t_fnPageChange: _fnPageChange,\n\t\t\t_fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,\n\t\t\t_fnProcessingDisplay: _fnProcessingDisplay,\n\t\t\t_fnFeatureHtmlTable: _fnFeatureHtmlTable,\n\t\t\t_fnScrollDraw: _fnScrollDraw,\n\t\t\t_fnApplyToChildren: _fnApplyToChildren,\n\t\t\t_fnCalculateColumnWidths: _fnCalculateColumnWidths,\n\t\t\t_fnThrottle: _fnThrottle,\n\t\t\t_fnConvertToWidth: _fnConvertToWidth,\n\t\t\t_fnScrollingWidthAdjust: _fnScrollingWidthAdjust,\n\t\t\t_fnGetWidestNode: _fnGetWidestNode,\n\t\t\t_fnGetMaxLenString: _fnGetMaxLenString,\n\t\t\t_fnStringToCss: _fnStringToCss,\n\t\t\t_fnScrollBarWidth: _fnScrollBarWidth,\n\t\t\t_fnSortFlatten: _fnSortFlatten,\n\t\t\t_fnSort: _fnSort,\n\t\t\t_fnSortAria: _fnSortAria,\n\t\t\t_fnSortListener: _fnSortListener,\n\t\t\t_fnSortAttachListener: _fnSortAttachListener,\n\t\t\t_fnSortingClasses: _fnSortingClasses,\n\t\t\t_fnSortData: _fnSortData,\n\t\t\t_fnSaveState: _fnSaveState,\n\t\t\t_fnLoadState: _fnLoadState,\n\t\t\t_fnSettingsFromNode: _fnSettingsFromNode,\n\t\t\t_fnLog: _fnLog,\n\t\t\t_fnMap: _fnMap,\n\t\t\t_fnBindAction: _fnBindAction,\n\t\t\t_fnCallbackReg: _fnCallbackReg,\n\t\t\t_fnCallbackFire: _fnCallbackFire,\n\t\t\t_fnLengthOverflow: _fnLengthOverflow,\n\t\t\t_fnRenderer: _fnRenderer,\n\t\t\t_fnDataSource: _fnDataSource,\n\t\t\t_fnRowAttributes: _fnRowAttributes\n\t\t};\n\n\t\t$.extend( DataTable.ext.internal, this.internal );\n\n\t\tfor ( var fn in DataTable.ext.internal ) {\n\t\t\tif ( fn ) {\n\t\t\t\tthis[fn] = _fnExternApiFunc(fn);\n\t\t\t}\n\t\t}\n\n\n\t\tvar _that = this;\n\t\tvar emptyInit = options === undefined;\n\t\tvar len = this.length;\n\n\t\tif ( emptyInit ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\tthis.each(function() {\n\t\t\t// For each initialisation we want to give it a clean initialisation\n\t\t\t// object that can be bashed around\n\t\t\tvar o = {};\n\t\t\tvar oInit = len > 1 ? // optimisation for single table case\n\t\t\t\t_fnExtend( o, options, true ) :\n\t\t\t\toptions;\n\n\t\t\t/*global oInit,_that,emptyInit*/\n\t\t\tvar i=0, iLen, j, jLen, k, kLen;\n\t\t\tvar sId = this.getAttribute( 'id' );\n\t\t\tvar bInitHandedOff = false;\n\t\t\tvar defaults = DataTable.defaults;\n\n\n\t\t\t/* Sanity check */\n\t\t\tif ( this.nodeName.toLowerCase() != 'table' )\n\t\t\t{\n\t\t\t\t_fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t/* Backwards compatibility for the defaults */\n\t\t\t_fnCompatOpts( defaults );\n\t\t\t_fnCompatCols( defaults.column );\n\n\t\t\t/* Convert the camel-case defaults to Hungarian */\n\t\t\t_fnCamelToHungarian( defaults, defaults, true );\n\t\t\t_fnCamelToHungarian( defaults.column, defaults.column, true );\n\n\t\t\t/* Setting up the initialisation object */\n\t\t\t_fnCamelToHungarian( defaults, oInit );\n\n\t\t\t/* Check to see if we are re-initialising a table */\n\t\t\tvar allSettings = DataTable.settings;\n\t\t\tfor ( i=0, iLen=allSettings.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t/* Base check on table node */\n\t\t\t\tif ( allSettings[i].nTable == this )\n\t\t\t\t{\n\t\t\t\t\tvar bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;\n\t\t\t\t\tvar bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;\n\n\t\t\t\t\tif ( emptyInit || bRetrieve )\n\t\t\t\t\t{\n\t\t\t\t\t\treturn allSettings[i].oInstance;\n\t\t\t\t\t}\n\t\t\t\t\telse if ( bDestroy )\n\t\t\t\t\t{\n\t\t\t\t\t\tallSettings[i].oInstance.fnDestroy();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\t_fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t/* If the element we are initialising has the same ID as a table which was previously\n\t\t\t\t * initialised, but the table nodes don't match (from before) then we destroy the old\n\t\t\t\t * instance by simply deleting it. This is under the assumption that the table has been\n\t\t\t\t * destroyed by other methods. Anyone using non-id selectors will need to do this manually\n\t\t\t\t */\n\t\t\t\tif ( allSettings[i].sTableId == this.id )\n\t\t\t\t{\n\t\t\t\t\tallSettings.splice( i, 1 );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Ensure the table has an ID - required for accessibility */\n\t\t\tif ( sId === null || sId === \"\" )\n\t\t\t{\n\t\t\t\tsId = \"DataTables_Table_\"+(DataTable.ext._unique++);\n\t\t\t\tthis.id = sId;\n\t\t\t}\n\n\t\t\t/* Create the settings object for this table and set some of the default parameters */\n\t\t\tvar oSettings = $.extend( true, {}, DataTable.models.oSettings, {\n\t\t\t\t\"nTable\":        this,\n\t\t\t\t\"oApi\":          _that.internal,\n\t\t\t\t\"oInit\":         oInit,\n\t\t\t\t\"sDestroyWidth\": $(this)[0].style.width,\n\t\t\t\t\"sInstance\":     sId,\n\t\t\t\t\"sTableId\":      sId\n\t\t\t} );\n\t\t\tallSettings.push( oSettings );\n\n\t\t\t// Need to add the instance after the instance after the settings object has been added\n\t\t\t// to the settings array, so we can self reference the table instance if more than one\n\t\t\toSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();\n\n\t\t\t// Backwards compatibility, before we apply all the defaults\n\t\t\t_fnCompatOpts( oInit );\n\n\t\t\tif ( oInit.oLanguage )\n\t\t\t{\n\t\t\t\t_fnLanguageCompat( oInit.oLanguage );\n\t\t\t}\n\n\t\t\t// If the length menu is given, but the init display length is not, use the length menu\n\t\t\tif ( oInit.aLengthMenu && ! oInit.iDisplayLength )\n\t\t\t{\n\t\t\t\toInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?\n\t\t\t\t\toInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];\n\t\t\t}\n\n\t\t\t// Apply the defaults and init options to make a single init object will all\n\t\t\t// options defined from defaults and instance options.\n\t\t\toInit = _fnExtend( $.extend( true, {}, defaults ), oInit );\n\n\n\t\t\t// Map the initialisation options onto the settings object\n\t\t\t_fnMap( oSettings.oFeatures, oInit, [\n\t\t\t\t\"bPaginate\",\n\t\t\t\t\"bLengthChange\",\n\t\t\t\t\"bFilter\",\n\t\t\t\t\"bSort\",\n\t\t\t\t\"bSortMulti\",\n\t\t\t\t\"bInfo\",\n\t\t\t\t\"bProcessing\",\n\t\t\t\t\"bAutoWidth\",\n\t\t\t\t\"bSortClasses\",\n\t\t\t\t\"bServerSide\",\n\t\t\t\t\"bDeferRender\"\n\t\t\t] );\n\t\t\t_fnMap( oSettings, oInit, [\n\t\t\t\t\"asStripeClasses\",\n\t\t\t\t\"ajax\",\n\t\t\t\t\"fnServerData\",\n\t\t\t\t\"fnFormatNumber\",\n\t\t\t\t\"sServerMethod\",\n\t\t\t\t\"aaSorting\",\n\t\t\t\t\"aaSortingFixed\",\n\t\t\t\t\"aLengthMenu\",\n\t\t\t\t\"sPaginationType\",\n\t\t\t\t\"sAjaxSource\",\n\t\t\t\t\"sAjaxDataProp\",\n\t\t\t\t\"iStateDuration\",\n\t\t\t\t\"sDom\",\n\t\t\t\t\"bSortCellsTop\",\n\t\t\t\t\"iTabIndex\",\n\t\t\t\t\"fnStateLoadCallback\",\n\t\t\t\t\"fnStateSaveCallback\",\n\t\t\t\t\"renderer\",\n\t\t\t\t[ \"iCookieDuration\", \"iStateDuration\" ], // backwards compat\n\t\t\t\t[ \"oSearch\", \"oPreviousSearch\" ],\n\t\t\t\t[ \"aoSearchCols\", \"aoPreSearchCols\" ],\n\t\t\t\t[ \"iDisplayLength\", \"_iDisplayLength\" ],\n\t\t\t\t[ \"bJQueryUI\", \"bJUI\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oScroll, oInit, [\n\t\t\t\t[ \"sScrollX\", \"sX\" ],\n\t\t\t\t[ \"sScrollXInner\", \"sXInner\" ],\n\t\t\t\t[ \"sScrollY\", \"sY\" ],\n\t\t\t\t[ \"bScrollCollapse\", \"bCollapse\" ]\n\t\t\t] );\n\t\t\t_fnMap( oSettings.oLanguage, oInit, \"fnInfoCallback\" );\n\n\t\t\t/* Callback functions which are array driven */\n\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );\n\t\t\t_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );\n\n\t\t\t// @todo Remove in 1.11\n\t\t\tif ( oInit.bJQueryUI )\n\t\t\t{\n\t\t\t\t/* Use the JUI classes object for display. You could clone the oStdClasses object if\n\t\t\t\t * you want to have multiple tables with multiple independent classes\n\t\t\t\t */\n\t\t\t\t$.extend( oSettings.oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );\n\n\t\t\t\tif ( oInit.sDom === defaults.sDom && defaults.sDom === \"lfrtip\" )\n\t\t\t\t{\n\t\t\t\t\t/* Set the DOM to use a layout suitable for jQuery UI's theming */\n\t\t\t\t\toSettings.sDom = '<\"H\"lfr>t<\"F\"ip>';\n\t\t\t\t}\n\n\t\t\t\tif ( ! oSettings.renderer ) {\n\t\t\t\t\toSettings.renderer = 'jqueryui';\n\t\t\t\t}\n\t\t\t\telse if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {\n\t\t\t\t\toSettings.renderer.header = 'jqueryui';\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( oSettings.oClasses, DataTable.ext.classes, oInit.oClasses );\n\t\t\t}\n\t\t\t$(this).addClass( oSettings.oClasses.sTable );\n\n\t\t\t/* Calculate the scroll bar width and cache it for use later on */\n\t\t\tif ( oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\" )\n\t\t\t{\n\t\t\t\toSettings.oScroll.iBarWidth = _fnScrollBarWidth();\n\t\t\t}\n\t\t\tif ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling\n\t\t\t\toSettings.oScroll.sX = '100%';\n\t\t\t}\n\n\t\t\tif ( oSettings.iInitDisplayStart === undefined )\n\t\t\t{\n\t\t\t\t/* Display start point, taking into account the save saving */\n\t\t\t\toSettings.iInitDisplayStart = oInit.iDisplayStart;\n\t\t\t\toSettings._iDisplayStart = oInit.iDisplayStart;\n\t\t\t}\n\n\t\t\tif ( oInit.iDeferLoading !== null )\n\t\t\t{\n\t\t\t\toSettings.bDeferLoading = true;\n\t\t\t\tvar tmp = $.isArray( oInit.iDeferLoading );\n\t\t\t\toSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;\n\t\t\t\toSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;\n\t\t\t}\n\n\t\t\t/* Language definitions */\n\t\t\tif ( oInit.oLanguage.sUrl !== \"\" )\n\t\t\t{\n\t\t\t\t/* Get the language definitions from a file - because this Ajax call makes the language\n\t\t\t\t * get async to the remainder of this function we use bInitHandedOff to indicate that\n\t\t\t\t * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor\n\t\t\t\t */\n\t\t\t\toSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;\n\t\t\t\t$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {\n\t\t\t\t\t_fnLanguageCompat( json );\n\t\t\t\t\t_fnCamelToHungarian( defaults.oLanguage, json );\n\t\t\t\t\t$.extend( true, oSettings.oLanguage, oInit.oLanguage, json );\n\t\t\t\t\t_fnInitialise( oSettings );\n\t\t\t\t} );\n\t\t\t\tbInitHandedOff = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t$.extend( true, oSettings.oLanguage, oInit.oLanguage );\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t * Stripes\n\t\t\t */\n\t\t\tif ( oInit.asStripeClasses === null )\n\t\t\t{\n\t\t\t\toSettings.asStripeClasses =[\n\t\t\t\t\toSettings.oClasses.sStripeOdd,\n\t\t\t\t\toSettings.oClasses.sStripeEven\n\t\t\t\t];\n\t\t\t}\n\n\t\t\t/* Remove row stripe classes if they are already on the table row */\n\t\t\tvar stripeClasses = oSettings.asStripeClasses;\n\t\t\tvar rowOne = $('tbody tr:eq(0)', this);\n\t\t\tif ( $.inArray( true, $.map( stripeClasses, function(el, i) {\n\t\t\t\treturn rowOne.hasClass(el);\n\t\t\t} ) ) !== -1 ) {\n\t\t\t\t$('tbody tr', this).removeClass( stripeClasses.join(' ') );\n\t\t\t\toSettings.asDestroyStripes = stripeClasses.slice();\n\t\t\t}\n\n\t\t\t/*\n\t\t\t * Columns\n\t\t\t * See if we should load columns automatically or use defined ones\n\t\t\t */\n\t\t\tvar anThs = [];\n\t\t\tvar aoColumnsInit;\n\t\t\tvar nThead = this.getElementsByTagName('thead');\n\t\t\tif ( nThead.length !== 0 )\n\t\t\t{\n\t\t\t\t_fnDetectHeader( oSettings.aoHeader, nThead[0] );\n\t\t\t\tanThs = _fnGetUniqueThs( oSettings );\n\t\t\t}\n\n\t\t\t/* If not given a column array, generate one with nulls */\n\t\t\tif ( oInit.aoColumns === null )\n\t\t\t{\n\t\t\t\taoColumnsInit = [];\n\t\t\t\tfor ( i=0, iLen=anThs.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\taoColumnsInit.push( null );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\taoColumnsInit = oInit.aoColumns;\n\t\t\t}\n\n\t\t\t/* Add the columns */\n\t\t\tfor ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )\n\t\t\t{\n\t\t\t\t_fnAddColumn( oSettings, anThs ? anThs[i] : null );\n\t\t\t}\n\n\t\t\t/* Apply the column definitions */\n\t\t\t_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {\n\t\t\t\t_fnColumnOptions( oSettings, iCol, oDef );\n\t\t\t} );\n\n\t\t\t/* HTML5 attribute detection - build an mData object automatically if the\n\t\t\t * attributes are found\n\t\t\t */\n\t\t\tif ( rowOne.length ) {\n\t\t\t\tvar a = function ( cell, name ) {\n\t\t\t\t\treturn cell.getAttribute( 'data-'+name ) ? name : null;\n\t\t\t\t};\n\n\t\t\t\t$.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {\n\t\t\t\t\tvar col = oSettings.aoColumns[i];\n\n\t\t\t\t\tif ( col.mData === i ) {\n\t\t\t\t\t\tvar sort = a( cell, 'sort' ) || a( cell, 'order' );\n\t\t\t\t\t\tvar filter = a( cell, 'filter' ) || a( cell, 'search' );\n\n\t\t\t\t\t\tif ( sort !== null || filter !== null ) {\n\t\t\t\t\t\t\tcol.mData = {\n\t\t\t\t\t\t\t\t_:      i+'.display',\n\t\t\t\t\t\t\t\tsort:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\ttype:   sort !== null   ? i+'.@data-'+sort   : undefined,\n\t\t\t\t\t\t\t\tfilter: filter !== null ? i+'.@data-'+filter : undefined\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t_fnColumnOptions( oSettings, i );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\n\t\t\t/* Must be done after everything which can be overridden by the state saving! */\n\t\t\tif ( oInit.bStateSave )\n\t\t\t{\n\t\t\t\toSettings.oFeatures.bStateSave = true;\n\t\t\t\t_fnLoadState( oSettings, oInit );\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );\n\t\t\t}\n\n\n\t\t\t/*\n\t\t\t * Sorting\n\t\t\t * @todo For modularisation (1.11) this needs to do into a sort start up handler\n\t\t\t */\n\n\t\t\t// If aaSorting is not defined, then we use the first indicator in asSorting\n\t\t\t// in case that has been altered, so the default sort reflects that option\n\t\t\tif ( oInit.aaSorting === undefined )\n\t\t\t{\n\t\t\t\tfor ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )\n\t\t\t\t{\n\t\t\t\t\toSettings.aaSorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* Do a first pass on the sorting classes (allows any size changes to be taken into\n\t\t\t * account, and also will apply sorting disabled classes if disabled\n\t\t\t */\n\t\t\t_fnSortingClasses( oSettings );\n\n\t\t\tif ( oSettings.oFeatures.bSort )\n\t\t\t{\n\t\t\t\t_fnCallbackReg( oSettings, 'aoDrawCallback', function () {\n\t\t\t\t\tif ( oSettings.bSorted ) {\n\t\t\t\t\t\tvar aSort = _fnSortFlatten( oSettings );\n\t\t\t\t\t\tvar sortedColumns = {};\n\n\t\t\t\t\t\t$.each( aSort, function (i, val) {\n\t\t\t\t\t\t\tsortedColumns[ val.src ] = val.dir;\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t_fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );\n\t\t\t\t\t\t_fnSortingClasses( oSettings );\n\t\t\t\t\t\t_fnSortAria( oSettings );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\n\n\n\t\t\t/*\n\t\t\t * Final init\n\t\t\t * Cache the header, body and footer as required, creating them if needed\n\t\t\t */\n\n\t\t\t/* Browser support detection */\n\t\t\t_fnBrowserDetect( oSettings );\n\n\t\t\t// Work around for Webkit bug 83867 - store the caption-side before removing from doc\n\t\t\tvar captions = $(this).children('caption').each( function () {\n\t\t\t\tthis._captionSide = $(this).css('caption-side');\n\t\t\t} );\n\n\t\t\tvar thead = $(this).children('thead');\n\t\t\tif ( thead.length === 0 )\n\t\t\t{\n\t\t\t\tthead = $('<thead/>').appendTo(this);\n\t\t\t}\n\t\t\toSettings.nTHead = thead[0];\n\n\t\t\tvar tbody = $(this).children('tbody');\n\t\t\tif ( tbody.length === 0 )\n\t\t\t{\n\t\t\t\ttbody = $('<tbody/>').appendTo(this);\n\t\t\t}\n\t\t\toSettings.nTBody = tbody[0];\n\n\t\t\tvar tfoot = $(this).children('tfoot');\n\t\t\tif ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== \"\" || oSettings.oScroll.sY !== \"\") )\n\t\t\t{\n\t\t\t\t// If we are a scrolling table, and no footer has been given, then we need to create\n\t\t\t\t// a tfoot element for the caption element to be appended to\n\t\t\t\ttfoot = $('<tfoot/>').appendTo(this);\n\t\t\t}\n\n\t\t\tif ( tfoot.length === 0 || tfoot.children().length === 0 ) {\n\t\t\t\t$(this).addClass( oSettings.oClasses.sNoFooter );\n\t\t\t}\n\t\t\telse if ( tfoot.length > 0 ) {\n\t\t\t\toSettings.nTFoot = tfoot[0];\n\t\t\t\t_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );\n\t\t\t}\n\n\t\t\t/* Check if there is data passing into the constructor */\n\t\t\tif ( oInit.aaData )\n\t\t\t{\n\t\t\t\tfor ( i=0 ; i<oInit.aaData.length ; i++ )\n\t\t\t\t{\n\t\t\t\t\t_fnAddData( oSettings, oInit.aaData[ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )\n\t\t\t{\n\t\t\t\t/* Grab the data from the page - only do this when deferred loading or no Ajax\n\t\t\t\t * source since there is no point in reading the DOM data if we are then going\n\t\t\t\t * to replace it with Ajax data\n\t\t\t\t */\n\t\t\t\t_fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );\n\t\t\t}\n\n\t\t\t/* Copy the data index array */\n\t\t\toSettings.aiDisplay = oSettings.aiDisplayMaster.slice();\n\n\t\t\t/* Initialisation complete - table can be drawn */\n\t\t\toSettings.bInitialised = true;\n\n\t\t\t/* Check if we need to initialise the table (it might not have been handed off to the\n\t\t\t * language processor)\n\t\t\t */\n\t\t\tif ( bInitHandedOff === false )\n\t\t\t{\n\t\t\t\t_fnInitialise( oSettings );\n\t\t\t}\n\t\t} );\n\t\t_that = null;\n\t\treturn this;\n\t};\n\n\n\n\t/**\n\t * Computed structure of the DataTables API, defined by the options passed to\n\t * `DataTable.Api.register()` when building the API.\n\t *\n\t * The structure is built in order to speed creation and extension of the Api\n\t * objects since the extensions are effectively pre-parsed.\n\t *\n\t * The array is an array of objects with the following structure, where this\n\t * base array represents the Api prototype base:\n\t *\n\t *     [\n\t *       {\n\t *         name:      'data'                -- string   - Property name\n\t *         val:       function () {},       -- function - Api method (or undefined if just an object\n\t *         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t *         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t *       },\n\t *       {\n\t *         name:     'row'\n\t *         val:       {},\n\t *         methodExt: [ ... ],\n\t *         propExt:   [\n\t *           {\n\t *             name:      'data'\n\t *             val:       function () {},\n\t *             methodExt: [ ... ],\n\t *             propExt:   [ ... ]\n\t *           },\n\t *           ...\n\t *         ]\n\t *       }\n\t *     ]\n\t *\n\t * @type {Array}\n\t * @ignore\n\t */\n\tvar __apiStruct = [];\n\n\n\t/**\n\t * `Array.prototype` reference.\n\t *\n\t * @type object\n\t * @ignore\n\t */\n\tvar __arrayProto = Array.prototype;\n\n\n\n\n\t/**\n\t * Abstraction for `context` parameter of the `Api` constructor to allow it to\n\t * take several different forms for ease of use.\n\t *\n\t * Each of the input parameter types will be converted to a DataTables settings\n\t * object where possible.\n\t *\n\t * @param  {string|node|jQuery|object} mixed DataTable identifier. Can be one\n\t *   of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @return {array|null} Matching DataTables settings objects. `null` or\n\t *   `undefined` is returned if no matching DataTable is found.\n\t * @ignore\n\t */\n\tvar _toSettings = function ( mixed )\n\t{\n\t\tvar idx, jq;\n\t\tvar settings = DataTable.settings;\n\t\tvar tables = $.map( settings, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\n\t\tif ( mixed.nTable && mixed.oApi ) {\n\t\t\t// DataTables settings object\n\t\t\treturn [ mixed ];\n\t\t}\n\t\telse if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {\n\t\t\t// Table node\n\t\t\tidx = $.inArray( mixed, tables );\n\t\t\treturn idx !== -1 ? [ settings[idx] ] : null;\n\t\t}\n\t\telse if ( typeof mixed === 'string' ) {\n\t\t\t// jQuery selector\n\t\t\tjq = $(mixed);\n\t\t}\n\t\telse if ( mixed instanceof $ ) {\n\t\t\t// jQuery object (also DataTables instance)\n\t\t\tjq = mixed;\n\t\t}\n\n\t\tif ( jq ) {\n\t\t\treturn jq.map( function(i) {\n\t\t\t\tidx = $.inArray( this, tables );\n\t\t\t\treturn idx !== -1 ? settings[idx] : null;\n\t\t\t} );\n\t\t}\n\t};\n\n\n\t/**\n\t * DataTables API class - used to control and interface with  one or more\n\t * DataTables enhanced tables.\n\t *\n\t * The API class is heavily based on jQuery, presenting a chainable interface\n\t * that you can use to interact with tables. Each instance of the API class has\n\t * a \"context\" - i.e. the tables that it will operate on. This could be a single\n\t * table, all tables on a page or a sub-set thereof.\n\t *\n\t * Additionally the API is designed to allow you to easily work with the data in\n\t * the tables, retrieving and manipulating it as required. This is done by\n\t * presenting the API class as an array like interface. The contents of the\n\t * array depend upon the actions requested by each method (for example\n\t * `rows().nodes()` will return an array of nodes, while `rows().data()` will\n\t * return an array of objects or arrays depending upon your table's\n\t * configuration). The API object has a number of array like methods (`push`,\n\t * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,\n\t * `unique` etc) to assist your working with the data held in a table.\n\t *\n\t * Most methods (those which return an Api instance) are chainable, which means\n\t * the return from a method call also has all of the methods available that the\n\t * top level object had. For example, these two calls are equivalent:\n\t *\n\t *     // Not chained\n\t *     api.row.add( {...} );\n\t *     api.draw();\n\t *\n\t *     // Chained\n\t *     api.row.add( {...} ).draw();\n\t *\n\t * @class DataTable.Api\n\t * @param {array|object|string|jQuery} context DataTable identifier. This is\n\t *   used to define which DataTables enhanced tables this API will operate on.\n\t *   Can be one of:\n\t *\n\t *   * `string` - jQuery selector. Any DataTables' matching the given selector\n\t *     with be found and used.\n\t *   * `node` - `TABLE` node which has already been formed into a DataTable.\n\t *   * `jQuery` - A jQuery object of `TABLE` nodes.\n\t *   * `object` - DataTables settings object\n\t * @param {array} [data] Data to initialise the Api instance with.\n\t *\n\t * @example\n\t *   // Direct initialisation during DataTables construction\n\t *   var api = $('#example').DataTable();\n\t *\n\t * @example\n\t *   // Initialisation using a DataTables jQuery object\n\t *   var api = $('#example').dataTable().api();\n\t *\n\t * @example\n\t *   // Initialisation as a constructor\n\t *   var api = new $.fn.DataTable.Api( 'table.dataTable' );\n\t */\n\tDataTable.Api = _Api = function ( context, data )\n\t{\n\t\tif ( ! this instanceof _Api ) {\n\t\t\tthrow 'DT API must be constructed as a new object';\n\t\t\t// or should it do the 'new' for the caller?\n\t\t\t// return new _Api.apply( this, arguments );\n\t\t}\n\n\t\tvar settings = [];\n\t\tvar ctxSettings = function ( o ) {\n\t\t\tvar a = _toSettings( o );\n\t\t\tif ( a ) {\n\t\t\t\tsettings.push.apply( settings, a );\n\t\t\t}\n\t\t};\n\n\t\tif ( $.isArray( context ) ) {\n\t\t\tfor ( var i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tctxSettings( context[i] );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tctxSettings( context );\n\t\t}\n\n\t\t// Remove duplicates\n\t\tthis.context = _unique( settings );\n\n\t\t// Initial data\n\t\tif ( data ) {\n\t\t\tthis.push.apply( this, data );\n\t\t}\n\n\t\t// selector\n\t\tthis.selector = {\n\t\t\trows: null,\n\t\t\tcols: null,\n\t\t\topts: null\n\t\t};\n\n\t\t_Api.extend( this, this, __apiStruct );\n\t};\n\n\n\t_Api.prototype = /** @lends DataTables.Api */{\n\t\t/**\n\t\t * Return a new Api instance, comprised of the data held in the current\n\t\t * instance, join with the other array(s) and/or value(s).\n\t\t *\n\t\t * An alias for `Array.prototype.concat`.\n\t\t *\n\t\t * @type method\n\t\t * @param {*} value1 Arrays and/or values to concatenate.\n\t\t * @param {*} [...] Additional arrays and/or values to concatenate.\n\t\t * @returns {DataTables.Api} New API instance, comprising of the combined\n\t\t *   array.\n\t\t */\n\t\tconcat:  __arrayProto.concat,\n\n\n\t\tcontext: [], // array of table settings objects\n\n\n\t\teach: function ( fn )\n\t\t{\n\t\t\tif ( __arrayProto.forEach ) {\n\t\t\t\t// Where possible, use the built-in forEach\n\t\t\t\t__arrayProto.forEach.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien; i++ ) {\n\t\t\t\t\t// In strict mode the execution scope is the passed value\n\t\t\t\t\tfn.call( this, this[i], i, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this;\n\t\t},\n\n\n\t\tfilter: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\n\t\t\tif ( __arrayProto.filter ) {\n\t\t\t\ta = __arrayProto.filter.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\tif ( fn.call( this, this[i], i, this ) ) {\n\t\t\t\t\t\ta.push( this[i] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\n\n\t\tflatten: function ()\n\t\t{\n\t\t\tvar a = [];\n\t\t\treturn new _Api( this.context, a.concat.apply( a, this ) );\n\t\t},\n\n\n\t\tjoin:    __arrayProto.join,\n\n\n\t\tindexOf: __arrayProto.indexOf || function (obj, start)\n\t\t{\n\t\t\tfor ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( this[i] === obj ) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn -1;\n\t\t},\n\n\t\t// Internal only at the moment - relax?\n\t\titerator: function ( flatten, type, fn ) {\n\t\t\tvar\n\t\t\t\ta = [], ret,\n\t\t\t\ti, ien, j, jen,\n\t\t\t\tcontext = this.context,\n\t\t\t\trows, items, item,\n\t\t\t\tselector = this.selector;\n\n\t\t\t// Argument shifting\n\t\t\tif ( typeof flatten === 'string' ) {\n\t\t\t\tfn = type;\n\t\t\t\ttype = flatten;\n\t\t\t\tflatten = false;\n\t\t\t}\n\n\t\t\tfor ( i=0, ien=context.length ; i<ien ; i++ ) {\n\t\t\t\tif ( type === 'table' ) {\n\t\t\t\t\tret = fn( context[i], i );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'columns' || type === 'rows' ) {\n\t\t\t\t\t// this has same length as context - one entry for each table\n\t\t\t\t\tret = fn( context[i], this[i], i );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {\n\t\t\t\t\t// columns and rows share the same structure.\n\t\t\t\t\t// 'this' is an array of column indexes for each context\n\t\t\t\t\titems = this[i];\n\n\t\t\t\t\tif ( type === 'column-rows' ) {\n\t\t\t\t\t\trows = _selector_row_indexes( context[i], selector.opts );\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( j=0, jen=items.length ; j<jen ; j++ ) {\n\t\t\t\t\t\titem = items[j];\n\n\t\t\t\t\t\tif ( type === 'cell' ) {\n\t\t\t\t\t\t\tret = fn( context[i], item.row, item.column, i, j );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tret = fn( context[i], item, i, j, rows );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\t\ta.push( ret );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( a.length ) {\n\t\t\t\tvar api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );\n\t\t\t\tvar apiSelector = api.selector;\n\t\t\t\tapiSelector.rows = selector.rows;\n\t\t\t\tapiSelector.cols = selector.cols;\n\t\t\t\tapiSelector.opts = selector.opts;\n\t\t\t\treturn api;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\n\n\t\tlastIndexOf: __arrayProto.lastIndexOf || function (obj, start)\n\t\t{\n\t\t\t// Bit cheeky...\n\t\t\treturn this.indexOf.apply( this.toArray.reverse(), arguments );\n\t\t},\n\n\n\t\tlength:  0,\n\n\n\t\tmap: function ( fn )\n\t\t{\n\t\t\tvar a = [];\n\n\t\t\tif ( __arrayProto.map ) {\n\t\t\t\ta = __arrayProto.map.call( this, fn, this );\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Compatibility for browsers without EMCA-252-5 (JS 1.6)\n\t\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\t\ta.push( fn.call( this, this[i], i ) );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new _Api( this.context, a );\n\t\t},\n\n\n\t\tpluck: function ( prop )\n\t\t{\n\t\t\treturn this.map( function ( el ) {\n\t\t\t\treturn el[ prop ];\n\t\t\t} );\n\t\t},\n\n\t\tpop:     __arrayProto.pop,\n\n\n\t\tpush:    __arrayProto.push,\n\n\n\t\t// Does not return an API instance\n\t\treduce: __arrayProto.reduce || function ( fn, init )\n\t\t{\n\t\t\tvar\n\t\t\t\tvalue,\n\t\t\t\tisSet = false;\n\n\t\t\tif ( arguments.length > 1 ) {\n\t\t\t\tvalue = init;\n\t\t\t\tisSet = true;\n\t\t\t}\n\n\t\t\tfor ( var i=0, ien=this.length ; i<ien ; i++ ) {\n\t\t\t\tif ( ! this.hasOwnProperty(i) ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvalue = isSet ?\n\t\t\t\t\tfn( value, this[i], i, this ) :\n\t\t\t\t\tthis[i];\n\n\t\t\t\tisSet = true;\n\t\t\t}\n\n\t\t\treturn value;\n\t\t},\n\n\n\t\treduceRight: __arrayProto.reduceRight || function ( fn, init )\n\t\t{\n\t\t\tvar\n\t\t\t\tvalue,\n\t\t\t\tisSet = false;\n\n\t\t\tif ( arguments.length > 1 ) {\n\t\t\t\tvalue = init;\n\t\t\t\tisSet = true;\n\t\t\t}\n\n\t\t\tfor ( var i=this.length-1 ; i>=0 ; i-- ) {\n\t\t\t\tif ( ! this.hasOwnProperty(i) ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tvalue = isSet ?\n\t\t\t\t\tfn( value, this[i], i, this ) :\n\t\t\t\t\tthis[i];\n\n\t\t\t\tisSet = true;\n\t\t\t}\n\n\t\t\treturn value;\n\t\t},\n\n\t\treverse: __arrayProto.reverse,\n\n\n\t\t// Object with rows, columns and opts\n\t\tselector: null,\n\n\n\t\tshift:   __arrayProto.shift,\n\n\n\t\tsort:    __arrayProto.sort, // ? name - order?\n\n\n\t\tsplice:  __arrayProto.splice,\n\n\n\t\ttoArray: function ()\n\t\t{\n\t\t\treturn __arrayProto.slice.call( this );\n\t\t},\n\n\n\t\tto$: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\n\n\t\ttoJQuery: function ()\n\t\t{\n\t\t\treturn $( this );\n\t\t},\n\n\n\t\tunique: function ()\n\t\t{\n\t\t\treturn new _Api( this.context, _unique(this) );\n\t\t},\n\n\n\t\tunshift: __arrayProto.unshift\n\t};\n\n\n\n\n\t_Api.extend = function ( scope, obj, ext )\n\t{\n\t\t// Only extend API instances and static properties of the API\n\t\tif ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar\n\t\t\ti, ien,\n\t\t\tj, jen,\n\t\t\tstruct, inner,\n\t\t\tmethodScoping = function ( fn, struc ) {\n\t\t\t\treturn function () {\n\t\t\t\t\tvar ret = fn.apply( scope, arguments );\n\n\t\t\t\t\t// Method extension\n\t\t\t\t\t_Api.extend( ret, ret, struc.methodExt );\n\t\t\t\t\treturn ret;\n\t\t\t\t};\n\t\t\t};\n\n\t\tfor ( i=0, ien=ext.length ; i<ien ; i++ ) {\n\t\t\tstruct = ext[i];\n\n\t\t\t// Value\n\t\t\tobj[ struct.name ] = typeof struct.val === 'function' ?\n\t\t\t\tmethodScoping( struct.val, struct ) :\n\t\t\t\tstruct.val;\n\n\t\t\tobj[ struct.name ].__dt_wrapper = true;\n\n\t\t\t// Property extension\n\t\t\t_Api.extend( scope, obj[ struct.name ], struct.propExt );\n\t\t}\n\t};\n\n\n\t// @todo - Is there need for an augment function?\n\t// _Api.augment = function ( inst, name )\n\t// {\n\t// \t// Find src object in the structure from the name\n\t// \tvar parts = name.split('.');\n\n\t// \t_Api.extend( inst, obj );\n\t// };\n\n\n\t//     [\n\t//       {\n\t//         name:      'data'                -- string   - Property name\n\t//         val:       function () {},       -- function - Api method (or undefined if just an object\n\t//         methodExt: [ ... ],              -- array    - Array of Api object definitions to extend the method result\n\t//         propExt:   [ ... ]               -- array    - Array of Api object definitions to extend the property\n\t//       },\n\t//       {\n\t//         name:     'row'\n\t//         val:       {},\n\t//         methodExt: [ ... ],\n\t//         propExt:   [\n\t//           {\n\t//             name:      'data'\n\t//             val:       function () {},\n\t//             methodExt: [ ... ],\n\t//             propExt:   [ ... ]\n\t//           },\n\t//           ...\n\t//         ]\n\t//       }\n\t//     ]\n\n\t_Api.register = _api_register = function ( name, val )\n\t{\n\t\tif ( $.isArray( name ) ) {\n\t\t\tfor ( var j=0, jen=name.length ; j<jen ; j++ ) {\n\t\t\t\t_Api.register( name[j], val );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tvar\n\t\t\ti, ien,\n\t\t\their = name.split('.'),\n\t\t\tstruct = __apiStruct,\n\t\t\tkey, method;\n\n\t\tvar find = function ( src, name ) {\n\t\t\tfor ( var i=0, ien=src.length ; i<ien ; i++ ) {\n\t\t\t\tif ( src[i].name === name ) {\n\t\t\t\t\treturn src[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\n\t\tfor ( i=0, ien=heir.length ; i<ien ; i++ ) {\n\t\t\tmethod = heir[i].indexOf('()') !== -1;\n\t\t\tkey = method ?\n\t\t\t\their[i].replace('()', '') :\n\t\t\t\their[i];\n\n\t\t\tvar src = find( struct, key );\n\t\t\tif ( ! src ) {\n\t\t\t\tsrc = {\n\t\t\t\t\tname:      key,\n\t\t\t\t\tval:       {},\n\t\t\t\t\tmethodExt: [],\n\t\t\t\t\tpropExt:   []\n\t\t\t\t};\n\t\t\t\tstruct.push( src );\n\t\t\t}\n\n\t\t\tif ( i === ien-1 ) {\n\t\t\t\tsrc.val = val;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstruct = method ?\n\t\t\t\t\tsrc.methodExt :\n\t\t\t\t\tsrc.propExt;\n\t\t\t}\n\t\t}\n\n\t\t// Rebuild the API with the new construct\n\t\tif ( _Api.ready ) {\n\t\t\tDataTable.api.build();\n\t\t}\n\t};\n\n\n\t_Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {\n\t\t_Api.register( pluralName, val );\n\n\t\t_Api.register( singularName, function () {\n\t\t\tvar ret = val.apply( this, arguments );\n\n\t\t\tif ( ret === this ) {\n\t\t\t\t// Returned item is the API instance that was passed in, return it\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\telse if ( ret instanceof _Api ) {\n\t\t\t\t// New API instance returned, want the value from the first item\n\t\t\t\t// in the returned array for the singular result.\n\t\t\t\treturn ret.length ?\n\t\t\t\t\t$.isArray( ret[0] ) ?\n\t\t\t\t\t\tnew _Api( ret.context, ret[0] ) : // Array results are 'enhanced'\n\t\t\t\t\t\tret[0] :\n\t\t\t\t\tundefined;\n\t\t\t}\n\n\t\t\t// Non-API return - just fire it back\n\t\t\treturn ret;\n\t\t} );\n\t};\n\n\n\t/**\n\t * Selector for HTML tables. Apply the given selector to the give array of\n\t * DataTables settings objects.\n\t *\n\t * @param {string|integer} [selector] jQuery selector string or integer\n\t * @param  {array} Array of DataTables settings objects to be filtered\n\t * @return {array}\n\t * @ignore\n\t */\n\tvar __table_selector = function ( selector, a )\n\t{\n\t\t// Integer is used to pick out a table by index\n\t\tif ( typeof selector === 'number' ) {\n\t\t\treturn [ a[ selector ] ];\n\t\t}\n\n\t\t// Perform a jQuery selector on the table nodes\n\t\tvar nodes = $.map( a, function (el, i) {\n\t\t\treturn el.nTable;\n\t\t} );\n\n\t\treturn $(nodes)\n\t\t\t.filter( selector )\n\t\t\t.map( function (i) {\n\t\t\t\t// Need to translate back from the table node to the settings\n\t\t\t\tvar idx = $.inArray( this, nodes );\n\t\t\t\treturn a[ idx ];\n\t\t\t} )\n\t\t\t.toArray();\n\t};\n\n\n\n\t/**\n\t * Context selector for the API's context (i.e. the tables the API instance\n\t * refers to.\n\t *\n\t * @name    DataTable.Api#tables\n\t * @param {string|integer} [selector] Selector to pick which tables the iterator\n\t *   should operate on. If not given, all tables in the current context are\n\t *   used. This can be given as a jQuery selector (for example `':gt(0)'`) to\n\t *   select multiple tables or as an integer to select a single table.\n\t * @returns {DataTable.Api} Returns a new API instance if a selector is given.\n\t */\n\t_api_register( 'tables()', function ( selector ) {\n\t\t// A new instance is created if there was a selector specified\n\t\treturn selector ?\n\t\t\tnew _Api( __table_selector( selector, this.context ) ) :\n\t\t\tthis;\n\t} );\n\n\n\t_api_register( 'table()', function ( selector ) {\n\t\tvar tables = this.tables( selector );\n\t\tvar ctx = tables.context;\n\n\t\t// Truncate to the first matched table\n\t\tif ( ctx.length ) {\n\t\t\tctx.length = 1;\n\t\t}\n\n\t\treturn tables;\n\t} );\n\n\n\t_api_registerPlural( 'tables().nodes()', 'table().node()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTable;\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'tables().body()', 'table().body()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTBody;\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'tables().header()', 'table().header()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTHead;\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'tables().footer()', 'table().footer()' , function () {\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\treturn ctx.nTFoot;\n\t\t} );\n\t} );\n\n\n\n\t/**\n\t * Redraw the tables in the current context.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'draw()', function ( resetPaging ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnReDraw( settings, resetPaging===false );\n\t\t} );\n\t} );\n\n\n\n\t/**\n\t * Get the current page index.\n\t *\n\t * @return {integer} Current page index (zero based)\n\t *//**\n\t * Set the current page.\n\t *\n\t * Note that if you attempt to show a page which does not exist, DataTables will\n\t * not throw an error, but rather reset the paging.\n\t *\n\t * @param {integer|string} action The paging action to take. This can be one of:\n\t *  * `integer` - The page index to jump to\n\t *  * `string` - An action to take:\n\t *    * `first` - Jump to first page.\n\t *    * `next` - Jump to the next page\n\t *    * `previous` - Jump to previous page\n\t *    * `last` - Jump to the last page.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page()', function ( action ) {\n\t\tif ( action === undefined ) {\n\t\t\treturn this.page.info().page; // not an expensive call\n\t\t}\n\n\t\t// else, have an action to take on all tables\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnPageChange( settings, action );\n\t\t} );\n\t} );\n\n\n\t/**\n\t * Paging information for the first table in the current context.\n\t *\n\t * If you require paging information for another table, use the `table()` method\n\t * with a suitable selector.\n\t *\n\t * @return {object} Object with the following properties set:\n\t *  * `page` - Current page index (zero based - i.e. the first page is `0`)\n\t *  * `pages` - Total number of pages\n\t *  * `start` - Display index for the first record shown on the current page\n\t *  * `end` - Display index for the last record shown on the current page\n\t *  * `length` - Display length (number of records). Note that generally `start\n\t *    + length = end`, but this is not always true, for example if there are\n\t *    only 2 records to show on the final page, with a length of 10.\n\t *  * `recordsTotal` - Full data set length\n\t *  * `recordsDisplay` - Data set length once the current filtering criterion\n\t *    are applied.\n\t */\n\t_api_register( 'page.info()', function ( action ) {\n\t\tif ( this.context.length === 0 ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tvar\n\t\t\tsettings   = this.context[0],\n\t\t\tstart      = settings._iDisplayStart,\n\t\t\tlen        = settings._iDisplayLength,\n\t\t\tvisRecords = settings.fnRecordsDisplay(),\n\t\t\tall        = len === -1;\n\n\t\treturn {\n\t\t\t\"page\":           all ? 0 : Math.floor( start / len ),\n\t\t\t\"pages\":          all ? 1 : Math.ceil( visRecords / len ),\n\t\t\t\"start\":          start,\n\t\t\t\"end\":            settings.fnDisplayEnd(),\n\t\t\t\"length\":         len,\n\t\t\t\"recordsTotal\":   settings.fnRecordsTotal(),\n\t\t\t\"recordsDisplay\": visRecords\n\t\t};\n\t} );\n\n\n\t/**\n\t * Get the current page length.\n\t *\n\t * @return {integer} Current page length. Note `-1` indicates that all records\n\t *   are to be shown.\n\t *//**\n\t * Set the current page length.\n\t *\n\t * @param {integer} Page length to set. Use `-1` to show all records.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'page.len()', function ( len ) {\n\t\t// Note that we can't call this function 'length()' because `length`\n\t\t// is a Javascript property of functions which defines how many arguments\n\t\t// the function expects.\n\t\tif ( len === undefined ) {\n\t\t\treturn this.context.length !== 0 ?\n\t\t\t\tthis.context[0]._iDisplayLength :\n\t\t\t\tundefined;\n\t\t}\n\n\t\t// else, set the page length\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnLengthChange( settings, len );\n\t\t} );\n\t} );\n\n\n\n\tvar __reload = function ( settings, holdPosition, callback ) {\n\t\tif ( _fnDataSource( settings ) == 'ssp' ) {\n\t\t\t_fnReDraw( settings, holdPosition );\n\t\t}\n\t\telse {\n\t\t\t// Trigger xhr\n\t\t\t_fnBuildAjax( settings, [], function( json ) {\n\t\t\t\t// xxx can this be reduced?\n\t\t\t\t_fnClearTable( settings );\n\n\t\t\t\tvar data = _fnAjaxDataSrc( settings, json );\n\t\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\t\t_fnAddData( settings, data[i] );\n\t\t\t\t}\n\n\t\t\t\t_fnReDraw( settings, holdPosition );\n\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback( json );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\n\n\t/**\n\t * Get the JSON response from the last Ajax request that DataTables made to the\n\t * server. Note that this returns the JSON from the first table in the current\n\t * context.\n\t *\n\t * @return {object} JSON received from the server.\n\t */\n\t_api_register( 'ajax.json()', function () {\n\t\tvar ctx = this.context;\n\n\t\tif ( ctx.length > 0 ) {\n\t\t\treturn ctx[0].json;\n\t\t}\n\n\t\t// else return undefined;\n\t} );\n\n\n\t/**\n\t * Reload tables from the Ajax data source. Note that this function will\n\t * automatically re-draw the table when the remote data has been loaded.\n\t *\n\t * @param {boolean} [reset=true] Reset (default) or hold the current paging\n\t *   position. A full re-sort and re-filter is performed when this method is\n\t *   called, which is why the pagination reset is the default action.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.reload()', function ( callback, resetPaging ) {\n\t\treturn this.iterator( 'table', function (settings) {\n\t\t\t__reload( settings, resetPaging===false, callback );\n\t\t} );\n\t} );\n\n\n\t/**\n\t * Get the current Ajax URL. Note that this returns the URL from the first\n\t * table in the current context.\n\t *\n\t * @return {string} Current Ajax source URL\n\t *//**\n\t * Set the Ajax URL. Note that this will set the URL for all tables in the\n\t * current context.\n\t *\n\t * @param {string} url URL to set.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url()', function ( url ) {\n\t\tvar ctx = this.context;\n\n\t\tif ( url === undefined ) {\n\t\t\t// get\n\t\t\tif ( ctx.length === 0 ) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tctx = ctx[0];\n\n\t\t\treturn ctx.ajax ?\n\t\t\t\t$.isPlainObject( ctx.ajax ) ?\n\t\t\t\t\tctx.ajax.url :\n\t\t\t\t\tctx.ajax :\n\t\t\t\tctx.sAjaxSource;\n\t\t}\n\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( $.isPlainObject( settings.ajax ) ) {\n\t\t\t\tsettings.ajax.url = url;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tsettings.ajax = url;\n\t\t\t}\n\t\t\t// No need to consider sAjaxSource here since DataTables gives priority\n\t\t\t// to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any\n\t\t\t// value of `sAjaxSource` redundant.\n\t\t} );\n\t} );\n\n\n\t/**\n\t * Load data from the newly set Ajax URL. Note that this method is only\n\t * available when `ajax.url()` is used to set a URL. Additionally, this method\n\t * has the same effect as calling `ajax.reload()` but is provided for\n\t * convenience when setting a new URL. Like `ajax.reload()` it will\n\t * automatically redraw the table once the remote data has been loaded.\n\t *\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'ajax.url().load()', function ( callback, resetPaging ) {\n\t\t// Same as a reload, but makes sense to present it for easy access after a\n\t\t// url change\n\t\treturn this.iterator( 'table', function ( ctx ) {\n\t\t\t__reload( ctx, resetPaging===false, callback );\n\t\t} );\n\t} );\n\n\n\n\n\tvar _selector_run = function ( selector, select )\n\t{\n\t\tvar\n\t\t\tout = [], res,\n\t\t\ta, i, ien, j, jen;\n\n\t\tif ( ! $.isArray( selector ) ) {\n\t\t\tselector = [ selector ];\n\t\t}\n\n\t\tfor ( i=0, ien=selector.length ; i<ien ; i++ ) {\n\t\t\ta = selector[i] && selector[i].split ?\n\t\t\t\tselector[i].split(',') :\n\t\t\t\t[ selector[i] ];\n\n\t\t\tfor ( j=0, jen=a.length ; j<jen ; j++ ) {\n\t\t\t\tres = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );\n\n\t\t\t\tif ( res && res.length ) {\n\t\t\t\t\tout.push.apply( out, res );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t};\n\n\n\tvar _selector_opts = function ( opts )\n\t{\n\t\tif ( ! opts ) {\n\t\t\topts = {};\n\t\t}\n\n\t\t// Backwards compatibility for 1.9- which used the terminology filter rather\n\t\t// than search\n\t\tif ( opts.filter && ! opts.search ) {\n\t\t\topts.search = opts.filter;\n\t\t}\n\n\t\treturn {\n\t\t\tsearch: opts.search || 'none',\n\t\t\torder:  opts.order  || 'current',\n\t\t\tpage:   opts.page   || 'all'\n\t\t};\n\t};\n\n\n\tvar _selector_first = function ( inst )\n\t{\n\t\t// Reduce the API instance to the first item found\n\t\tfor ( var i=0, ien=inst.length ; i<ien ; i++ ) {\n\t\t\tif ( inst[i].length > 0 ) {\n\t\t\t\t// Assign the first element to the first item in the instance\n\t\t\t\t// and truncate the instance and context\n\t\t\t\tinst[0] = inst[i];\n\t\t\t\tinst.length = 1;\n\t\t\t\tinst.context = [ inst.context[i] ];\n\n\t\t\t\treturn inst;\n\t\t\t}\n\t\t}\n\n\t\t// Not found - return an empty instance\n\t\tinst.length = 0;\n\t\treturn inst;\n\t};\n\n\n\tvar _selector_row_indexes = function ( settings, opts )\n\t{\n\t\tvar\n\t\t\ti, ien, tmp, a=[],\n\t\t\tdisplayFiltered = settings.aiDisplay,\n\t\t\tdisplayMaster = settings.aiDisplayMaster;\n\n\t\tvar\n\t\t\tsearch = opts.search,  // none, applied, removed\n\t\t\torder  = opts.order,   // applied, current, index (original - compatibility with 1.9)\n\t\t\tpage   = opts.page;    // all, current\n\n\t\t// Current page implies that order=current and fitler=applied, since it is\n\t\t// fairly senseless otherwise, regardless of what order and search actually\n\t\t// are\n\t\tif ( page == 'current' )\n\t\t{\n\t\t\tfor ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {\n\t\t\t\ta.push( displayFiltered[i] );\n\t\t\t}\n\t\t}\n\t\telse if ( order == 'current' || order == 'applied' ) {\n\t\t\ta = search == 'none' ?\n\t\t\t\tdisplayMaster.slice() :                      // no search\n\t\t\t\tsearch == 'applied' ?\n\t\t\t\t\tdisplayFiltered.slice() :                // applied search\n\t\t\t\t\t$.map( displayMaster, function (el, i) { // removed search\n\t\t\t\t\t\treturn $.inArray( el, displayFiltered ) === -1 ? el : null;\n\t\t\t\t\t} );\n\t\t}\n\t\telse if ( order == 'index' || order == 'original' ) {\n\t\t\tfor ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\tif ( search == 'none' ) {\n\t\t\t\t\ta.push( i );\n\t\t\t\t}\n\t\t\t\telse { // applied | removed\n\t\t\t\t\ttmp = $.inArray( i, displayFiltered );\n\n\t\t\t\t\tif ((tmp === -1 && search == 'removed') ||\n\t\t\t\t\t\t(tmp === 1  && search == 'applied') )\n\t\t\t\t\t{\n\t\t\t\t\t\ta.push( i );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn a;\n\t};\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Rows\n\t *\n\t * {}          - no selector - use all available rows\n\t * {integer}   - row aoData index\n\t * {node}      - TR node\n\t * {string}    - jQuery selector to apply to the TR elements\n\t * {array}     - jQuery array of nodes, or simply an array of TR nodes\n\t *\n\t */\n\n\n\tvar __row_selector = function ( settings, selector, opts )\n\t{\n\t\treturn _selector_run( selector, function ( sel ) {\n\t\t\tvar selInt = _intVal( sel );\n\n\t\t\t// Short cut - selector is a number and no options provided (default is\n\t\t\t// all records, so no need to check if the index is in there, since it\n\t\t\t// must be - dev error if the index doesn't exist).\n\t\t\tif ( selInt !== null && ! opts ) {\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\n\t\t\tvar rows = _selector_row_indexes( settings, opts );\n\n\t\t\tif ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {\n\t\t\t\t// Selector - integer\n\t\t\t\treturn [ selInt ];\n\t\t\t}\n\t\t\telse if ( ! sel ) {\n\t\t\t\t// Selector - none\n\t\t\t\treturn rows;\n\t\t\t}\n\n\t\t\t// Get nodes in the order from the `rows` array (can't use `pluck`) @todo - use pluck_order\n\t\t\tvar nodes = [];\n\t\t\tfor ( var i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\tnodes.push( settings.aoData[ rows[i] ].nTr );\n\t\t\t}\n\n\t\t\tif ( sel.nodeName ) {\n\t\t\t\t// Selector - node\n\t\t\t\tif ( $.inArray( sel, nodes ) !== -1 ) {\n\t\t\t\t\treturn [ sel._DT_RowIndex ];// sel is a TR node that is in the table\n\t\t\t\t\t\t\t\t\t\t\t// and DataTables adds a prop for fast lookup\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Selector - jQuery selector string, array of nodes or jQuery object/\n\t\t\t// As jQuery's .filter() allows jQuery objects to be passed in filter,\n\t\t\t// it also allows arrays, so this will cope with all three options\n\t\t\treturn $(nodes)\n\t\t\t\t.filter( sel )\n\t\t\t\t.map( function () {\n\t\t\t\t\treturn this._DT_RowIndex;\n\t\t\t\t} )\n\t\t\t\t.toArray();\n\t\t} );\n\t};\n\n\n\t/**\n\t *\n\t */\n\t_api_register( 'rows()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\n\t\topts = _selector_opts( opts );\n\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __row_selector( settings, selector, opts );\n\t\t} );\n\n\t\t// Want argument shifting here and in __row_selector?\n\t\tinst.selector.rows = selector;\n\t\tinst.selector.opts = opts;\n\n\t\treturn inst;\n\t} );\n\n\n\t_api_registerPlural( 'rows().nodes()', 'row().node()' , function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t// use pluck order on an array rather - rows gives an array, row gives it individually\n\t\t\treturn settings.aoData[ row ].nTr || undefined;\n\t\t} );\n\t} );\n\n\n\t_api_register( 'rows().data()', function () {\n\t\treturn this.iterator( true, 'rows', function ( settings, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, '_aData' );\n\t\t} );\n\t} );\n\n\t_api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\tvar r = settings.aoData[ row ];\n\t\t\treturn type === 'search' ? r._aFilterData : r._aSortData;\n\t\t} );\n\t} );\n\n\t_api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\t_fnInvalidateRow( settings, row, src );\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'rows().indexes()', 'row().index()', function () {\n\t\treturn this.iterator( 'row', function ( settings, row ) {\n\t\t\treturn row;\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'rows().remove()', 'row().remove()', function () {\n\t\tvar that = this;\n\n\t\treturn this.iterator( 'row', function ( settings, row, thatIdx ) {\n\t\t\tvar data = settings.aoData;\n\n\t\t\tdata.splice( row, 1 );\n\n\t\t\t// Update the _DT_RowIndex parameter on all rows in the table\n\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\tif ( data[i].nTr !== null ) {\n\t\t\t\t\tdata[i].nTr._DT_RowIndex = i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove the target row from the search array\n\t\t\tvar displayIndex = $.inArray( row, settings.aiDisplay );\n\n\t\t\t// Delete from the display arrays\n\t\t\t_fnDeleteIndex( settings.aiDisplayMaster, row );\n\t\t\t_fnDeleteIndex( settings.aiDisplay, row );\n\t\t\t_fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes\n\n\t\t\t// Check for an 'overflow' they case for displaying the table\n\t\t\t_fnLengthOverflow( settings );\n\t\t} );\n\t} );\n\n\n\t_api_register( 'rows.add()', function ( rows ) {\n\t\tvar newRows = this.iterator( 'table', function ( settings ) {\n\t\t\t\tvar row, i, ien;\n\t\t\t\tvar out = [];\n\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\n\t\t\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\t\t\tout.push( _fnAddTr( settings, row )[0] );\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tout.push( _fnAddData( settings, row ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn out;\n\t\t\t} );\n\n\t\t// Return an Api.rows() extended instance, so rows().nodes() etc can be used\n\t\tvar modRows = this.rows( -1 );\n\t\tmodRows.pop();\n\t\tmodRows.push.apply( modRows, newRows );\n\n\t\treturn modRows;\n\t} );\n\n\n\n\n\n\t/**\n\t *\n\t */\n\t_api_register( 'row()', function ( selector, opts ) {\n\t\treturn _selector_first( this.rows( selector, opts ) );\n\t} );\n\n\n\t_api_register( 'row().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._aData :\n\t\t\t\tundefined;\n\t\t}\n\n\t\t// Set\n\t\tctx[0].aoData[ this[0] ]._aData = data;\n\n\t\t// Automatically invalidate\n\t\t_fnInvalidateRow( ctx[0], this[0], 'data' );\n\n\t\treturn this;\n\t} );\n\n\n\t_api_register( 'row.add()', function ( row ) {\n\t\t// Allow a jQuery object to be passed in - only a single row is added from\n\t\t// it though - the first element in the set\n\t\tif ( row instanceof $ && row.length ) {\n\t\t\trow = row[0];\n\t\t}\n\n\t\tvar rows = this.iterator( 'table', function ( settings ) {\n\t\t\tif ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {\n\t\t\t\treturn _fnAddTr( settings, row )[0];\n\t\t\t}\n\t\t\treturn _fnAddData( settings, row );\n\t\t} );\n\n\t\t// Return an Api.rows() extended instance, with the newly added row selected\n\t\treturn this.row( rows[0] );\n\t} );\n\n\n\n\tvar __details_add = function ( ctx, row, data, klass )\n\t{\n\t\t// Convert to array of TR elements\n\t\tvar rows = [];\n\t\tvar addRow = function ( r, k ) {\n\t\t\tif ( ! r.nodeName || r.nodeName.toUpperCase() !== 'tr' ) {\n\t\t\t\tr = $('<tr><td></td></tr>').find('td').html( r ).parent();\n\t\t\t}\n\n\t\t\t$('td', r).addClass( k )[0].colSpan = _fnVisbleColumns( ctx );\n\t\t\trows.push( r[0] );\n\t\t};\n\n\t\tif ( $.isArray( data ) || data instanceof $ ) {\n\t\t\tfor ( var i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\taddRow( data[i], klass );\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\taddRow( data, klass );\n\t\t}\n\n\t\tif ( row._details ) {\n\t\t\trow._details.remove();\n\t\t}\n\n\t\trow._details = $(rows);\n\n\t\t// If the children were already shown, that state should be retained\n\t\tif ( row._detailsShow ) {\n\t\t\trow._details.insertAfter( row.nTr );\n\t\t}\n\t};\n\n\n\tvar __details_display = function ( show ) {\n\t\tvar ctx = this.context;\n\n\t\tif ( ctx.length && this.length ) {\n\t\t\tvar row = ctx[0].aoData[ this[0] ];\n\n\t\t\tif ( row._details ) {\n\t\t\t\trow._detailsShow = show;\n\t\t\t\tif ( show ) {\n\t\t\t\t\trow._details.insertAfter( row.nTr );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\trow._details.remove();\n\t\t\t\t}\n\n\t\t\t\t__details_events( ctx[0] );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t};\n\n\n\tvar __details_events = function ( settings )\n\t{\n\t\tvar table = $(settings.nTable);\n\n\t\ttable.off('draw.DT_details');\n\t\ttable.off('column-visibility.DT_details');\n\n\t\tif ( _pluck( settings.aoData, '_details' ).length > 0 ) {\n\t\t\t// On each draw, insert the required elements into the document\n\t\t\ttable.on('draw.DT_details', function () {\n\t\t\t\ttable.find('tbody tr').each( function () {\n\t\t\t\t\t// Look up the row index for each row and append open row\n\t\t\t\t\tvar rowIdx = _fnNodeToDataIndex( settings, this );\n\t\t\t\t\tvar row = settings.aoData[ rowIdx ];\n\n\t\t\t\t\tif ( row._detailsShow ) {\n\t\t\t\t\t\trow._details.insertAfter( this );\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\t// Column visibility change - update the colspan\n\t\t\ttable.on( 'column-visibility.DT_details', function ( e, settings, idx, vis ) {\n\t\t\t\t// Update the colspan for the details rows (note, only if it already has\n\t\t\t\t// a colspan)\n\t\t\t\tvar row, visible = _fnVisbleColumns( settings );\n\n\t\t\t\tfor ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = settings.aoData[i];\n\n\t\t\t\t\tif ( row._details ) {\n\t\t\t\t\t\trow._details.children('td[colspan]').attr('colspan', visible );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t};\n\n\t// data can be:\n\t//  tr\n\t//  string\n\t//  jQuery or array of any of the above\n\t_api_register( 'row().child()', function ( data, klass ) {\n\t\tvar ctx = this.context;\n\n\t\tif ( data === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length && this.length ?\n\t\t\t\tctx[0].aoData[ this[0] ]._details :\n\t\t\t\tundefined;\n\t\t}\n\t\telse if ( ctx.length && this.length ) {\n\t\t\t// set\n\t\t\t__details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );\n\t\t}\n\n\t\treturn this;\n\t} );\n\n\t_api_register( [\n\t\t'row().child.show()',\n\t\t'row().child().show()'\n\t], function () {\n\t\t__details_display.call( this, true );\n\t} );\n\n\t_api_register( [\n\t\t'row().child.hide()',\n\t\t'row().child().hide()'\n\t], function () {\n\t\t__details_display.call( this, false );\n\t} );\n\n\t_api_register( 'row().child.isShown()', function () {\n\t\tvar ctx = this.context;\n\n\t\tif ( ctx.length && this.length ) {\n\t\t\t// _detailsShown as false or undefined will fall through to return false\n\t\t\treturn ctx[0].aoData[ this[0] ]._detailsShow || false;\n\t\t}\n\t\treturn false;\n\t} );\n\n\n\n\t/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t * Columns\n\t *\n\t * {integer}           - column index (>=0 count from left, <0 count from right)\n\t * \"{integer}:visIdx\"  - visible column index (i.e. translate to column index)  (>=0 count from left, <0 count from right)\n\t * \"{integer}:visible\" - alias for {integer}:visIdx  (>=0 count from left, <0 count from right)\n\t * \"{string}:name\"     - column name\n\t * \"{string}\"          - jQuery selector on column header nodes\n\t *\n\t */\n\n\t// can be an array of these items, comma separated list, or an array of comma\n\t// separated lists\n\n\tvar __re_column_selector = /^(.*):(name|visIdx|visible)$/;\n\n\tvar __column_selector = function ( settings, selector, opts )\n\t{\n\t\tvar\n\t\t\tcolumns = settings.aoColumns,\n\t\t\tnames = _pluck( columns, 'sName' ),\n\t\t\tnodes = _pluck( columns, 'nTh' );\n\n\t\treturn _selector_run( selector, function ( s ) {\n\t\t\tvar selInt = _intVal( s );\n\n\t\t\tif ( s === '' ) {\n\t\t\t\t// All columns\n\t\t\t\treturn _range( settings.aoColumns.length );\n\t\t\t}\n\t\t\telse if ( selInt !== null ) {\n\t\t\t\t// Integer selector\n\t\t\t\treturn [ selInt >= 0 ?\n\t\t\t\t\tselInt : // Count from left\n\t\t\t\t\tcolumns.length + selInt // Count from right (+ because its a negative value)\n\t\t\t\t];\n\t\t\t}\n\t\t\telse {\n\t\t\t\tvar match = s.match( __re_column_selector );\n\n\t\t\t\tif ( match ) {\n\t\t\t\t\tswitch( match[2] ) {\n\t\t\t\t\t\tcase 'visIdx':\n\t\t\t\t\t\tcase 'visible':\n\t\t\t\t\t\t\tvar idx = parseInt( match[1], 10 );\n\t\t\t\t\t\t\t// Visible index given, convert to column index\n\t\t\t\t\t\t\tif ( idx < 0 ) {\n\t\t\t\t\t\t\t\t// Counting from the right\n\t\t\t\t\t\t\t\tvar visColumns = $.map( columns, function (col,i) {\n\t\t\t\t\t\t\t\t\treturn col.bVisible ? i : null;\n\t\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t\t\treturn [ visColumns[ visColumns.length + idx ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// Counting from the left\n\t\t\t\t\t\t\treturn [ _fnVisibleToColumnIndex( settings, idx ) ];\n\n\t\t\t\t\t\tcase 'name':\n\t\t\t\t\t\t\t// match by name. `names` is column index complete and in order\n\t\t\t\t\t\t\treturn $.map( names, function (name, i) {\n\t\t\t\t\t\t\t\treturn name === match[1] ? i : null;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// jQuery selector on the TH elements for the columns\n\t\t\t\t\treturn $( nodes )\n\t\t\t\t\t\t.filter( s )\n\t\t\t\t\t\t.map( function () {\n\t\t\t\t\t\t\treturn $.inArray( this, nodes ); // `nodes` is column index complete and in order\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.toArray();\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t};\n\n\n\n\n\n\tvar __setColumnVis = function ( settings, column, vis ) {\n\t\tvar\n\t\t\tcols = settings.aoColumns,\n\t\t\tcol  = cols[ column ],\n\t\t\tdata = settings.aoData,\n\t\t\trow, cells, i, ien, tr;\n\n\t\t// Get\n\t\tif ( vis === undefined ) {\n\t\t\treturn col.bVisible;\n\t\t}\n\n\t\t// Set\n\t\t// No change\n\t\tif ( col.bVisible === vis ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( vis ) {\n\t\t\t// Insert column\n\t\t\t// Need to decide if we should use appendChild or insertBefore\n\t\t\tvar insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );\n\n\t\t\tfor ( i=0, ien=data.length ; i<ien ; i++ ) {\n\t\t\t\ttr = data[i].nTr;\n\t\t\t\tcells = data[i].anCells;\n\n\t\t\t\tif ( tr ) {\n\t\t\t\t\t// insertBefore can act like appendChild if 2nd arg is null\n\t\t\t\t\ttr.insertBefore( cells[ column ], cells[ insertBefore ] || null );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// Remove column\n\t\t\t$( _pluck( settings.aoData, 'anCells', column ) ).remove();\n\n\t\t\tcol.bVisible = false;\n\t\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t\t_fnDrawHead( settings, settings.aoFooter );\n\n\t\t\t_fnSaveState( settings );\n\t\t}\n\n\t\t// Common actions\n\t\tcol.bVisible = vis;\n\t\t_fnDrawHead( settings, settings.aoHeader );\n\t\t_fnDrawHead( settings, settings.aoFooter );\n\n\t\t// Automatically adjust column sizing\n\t\t_fnAdjustColumnSizing( settings );\n\n\t\t// Realign columns for scrolling\n\t\tif ( settings.oScroll.sX || settings.oScroll.sY ) {\n\t\t\t_fnScrollDraw( settings );\n\t\t}\n\n\t\t_fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );\n\n\t\t_fnSaveState( settings );\n\t};\n\n\n\t/**\n\t *\n\t */\n\t_api_register( 'columns()', function ( selector, opts ) {\n\t\t// argument shifting\n\t\tif ( selector === undefined ) {\n\t\t\tselector = '';\n\t\t}\n\t\telse if ( $.isPlainObject( selector ) ) {\n\t\t\topts = selector;\n\t\t\tselector = '';\n\t\t}\n\n\t\topts = _selector_opts( opts );\n\n\t\tvar inst = this.iterator( 'table', function ( settings ) {\n\t\t\treturn __column_selector( settings, selector, opts );\n\t\t} );\n\n\t\t// Want argument shifting here and in _row_selector?\n\t\tinst.selector.cols = selector;\n\t\tinst.selector.opts = opts;\n\n\t\treturn inst;\n\t} );\n\n\n\t/**\n\t *\n\t */\n\t_api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTh;\n\t\t} );\n\t} );\n\n\n\t/**\n\t *\n\t */\n\t_api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn settings.aoColumns[column].nTf;\n\t\t} );\n\t} );\n\n\n\t/**\n\t *\n\t */\n\t_api_registerPlural( 'columns().data()', 'column().data()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\tvar a = [];\n\t\t\tfor ( var row=0, ien=rows.length ; row<ien ; row++ ) {\n\t\t\t\ta.push( _fnGetCellData( settings, rows[row], column, '' ) );\n\t\t\t}\n\t\t\treturn a;\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows,\n\t\t\t\ttype === 'search' ? '_aFilterData' : '_aSortData', column\n\t\t\t);\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {\n\t\treturn this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {\n\t\t\treturn _pluck_order( settings.aoData, rows, 'anCells', column ) ;\n\t\t} );\n\t} );\n\n\n\n\t_api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn __setColumnVis( settings, column, vis );\n\t\t} );\n\t} );\n\n\n\n\t_api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\treturn type === 'visible' ?\n\t\t\t\t_fnColumnIndexToVisible( settings, column ) :\n\t\t\t\tcolumn;\n\t\t} );\n\t} );\n\n\n\t// _api_register( 'columns().show()', function () {\n\t// \tvar selector = this.selector;\n\t// \treturn this.columns( selector.cols, selector.opts ).visible( true );\n\t// } );\n\n\n\t// _api_register( 'columns().hide()', function () {\n\t// \tvar selector = this.selector;\n\t// \treturn this.columns( selector.cols, selector.opts ).visible( false );\n\t// } );\n\n\n\n\t_api_register( 'columns.adjust()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnAdjustColumnSizing( settings );\n\t\t} );\n\t} );\n\n\n\t// Convert from one column index type, to another type\n\t_api_register( 'column.index()', function ( type, idx ) {\n\t\tif ( this.context.length !== 0 ) {\n\t\t\tvar ctx = this.context[0];\n\n\t\t\tif ( type === 'fromVisible' || type === 'toData' ) {\n\t\t\t\treturn _fnColumnIndexToVisible( ctx, idx );\n\t\t\t}\n\t\t\telse if ( type === 'fromData' || type === 'toVisible' ) {\n\t\t\t\treturn _fnVisibleToColumnIndex( ctx, idx );\n\t\t\t}\n\t\t}\n\t} );\n\n\n\t_api_register( 'column()', function ( selector, opts ) {\n\t\treturn _selector_first( this.columns( selector, opts ) );\n\t} );\n\n\n\n\n\tvar __cell_selector = function ( settings, selector, opts )\n\t{\n\t\tvar data = settings.aoData;\n\t\tvar rows = _selector_row_indexes( settings, opts );\n\t\tvar cells = _pluck_order( data, rows, 'anCells' );\n\t\tvar allCells = $( [].concat.apply([], cells) );\n\t\tvar row;\n\t\tvar columns = settings.aoColumns.length;\n\t\tvar a, i, ien, j;\n\n\t\treturn _selector_run( selector, function ( s ) {\n\t\t\tif ( ! s ) {\n\t\t\t\t// All cells\n\t\t\t\ta = [];\n\n\t\t\t\tfor ( i=0, ien=rows.length ; i<ien ; i++ ) {\n\t\t\t\t\trow = rows[i];\n\n\t\t\t\t\tfor ( j=0 ; j<columns ; j++ ) {\n\t\t\t\t\t\ta.push( {\n\t\t\t\t\t\t\trow: row,\n\t\t\t\t\t\t\tcolumn: j\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn a;\n\t\t\t}\n\n\t\t\t// jQuery filtered cells\n\t\t\treturn allCells.filter( s ).map( function (i, el) {\n\t\t\t\trow = el.parentNode._DT_RowIndex;\n\n\t\t\t\treturn {\n\t\t\t\t\trow: row,\n\t\t\t\t\tcolumn: $.inArray( el, data[ row ].anCells )\n\t\t\t\t};\n\t\t\t} );\n\t\t} );\n\t};\n\n\n\n\n\t_api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {\n\t\t// Argument shifting\n\t\tif ( $.isPlainObject( rowSelector ) ) {\n\t\t\topts = rowSelector;\n\t\t\trowSelector = null;\n\t\t}\n\t\tif ( $.isPlainObject( columnSelector ) ) {\n\t\t\topts = columnSelector;\n\t\t\tcolumnSelector = null;\n\t\t}\n\n\t\t// Cell selector\n\t\tif ( columnSelector === null || columnSelector === undefined ) {\n\t\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t\treturn __cell_selector( settings, rowSelector, _selector_opts( opts ) );\n\t\t\t} );\n\t\t}\n\n\t\t// Row + column selector\n\t\tvar columns = this.columns( columnSelector, opts );\n\t\tvar rows = this.rows( rowSelector, opts );\n\t\tvar a, i, ien, j, jen;\n\n\t\tvar cells = this.iterator( 'table', function ( settings, idx ) {\n\t\t\ta = [];\n\n\t\t\tfor ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {\n\t\t\t\tfor ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {\n\t\t\t\t\ta.push( {\n\t\t\t\t\t\trow:    rows[idx][i],\n\t\t\t\t\t\tcolumn: columns[idx][j]\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn a;\n\t\t} );\n\n\t\t$.extend( cells.selector, {\n\t\t\tcols: columnSelector,\n\t\t\trows: rowSelector,\n\t\t\topts: opts\n\t\t} );\n\n\t\treturn cells;\n\t} );\n\n\n\t_api_registerPlural( 'cells().nodes()', 'cell().node()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ].anCells[ column ];\n\t\t} );\n\t} );\n\n\n\t_api_register( 'cells().data()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn _fnGetCellData( settings, row, column );\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {\n\t\ttype = type === 'search' ? '_aFilterData' : '_aSortData';\n\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn settings.aoData[ row ][ type ][ column ];\n\t\t} );\n\t} );\n\n\n\t_api_registerPlural( 'cells().indexes()', 'cell().index()', function () {\n\t\treturn this.iterator( 'cell', function ( settings, row, column ) {\n\t\t\treturn {\n\t\t\t\trow: row,\n\t\t\t\tcolumn: column,\n\t\t\t\tcolumnVisible: _fnColumnIndexToVisible( settings, column )\n\t\t\t};\n\t\t} );\n\t} );\n\n\n\t_api_register( [\n\t\t'cells().invalidate()',\n\t\t'cell().invalidate()'\n\t], function ( src ) {\n\t\tvar selector = this.selector;\n\n\t\t// Use the rows method of the instance to perform the invalidation, rather\n\t\t// than doing it here. This avoids needing to handle duplicate rows from\n\t\t// the cells.\n\t\tthis.rows( selector.rows, selector.opts ).invalidate( src );\n\n\t\treturn this;\n\t} );\n\n\n\n\n\t_api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {\n\t\treturn _selector_first( this.cells( rowSelector, columnSelector, opts ) );\n\t} );\n\n\n\n\t_api_register( 'cell().data()', function ( data ) {\n\t\tvar ctx = this.context;\n\t\tvar cell = this[0];\n\n\t\tif ( data === undefined ) {\n\t\t\t// Get\n\t\t\treturn ctx.length && cell.length ?\n\t\t\t\t_fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :\n\t\t\t\tundefined;\n\t\t}\n\n\t\t// Set\n\t\t_fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );\n\t\t_fnInvalidateRow( ctx[0], cell[0].row, 'data', cell[0].column );\n\n\t\treturn this;\n\t} );\n\n\n\n\t/**\n\t * Get current ordering (sorting) that has been applied to the table.\n\t *\n\t * @returns {array} 2D array containing the sorting information for the first\n\t *   table in the current context. Each element in the parent array represents\n\t *   a column being sorted upon (i.e. multi-sorting with two columns would have\n\t *   2 inner arrays). The inner arrays may have 2 or 3 elements. The first is\n\t *   the column index that the sorting condition applies to, the second is the\n\t *   direction of the sort (`desc` or `asc`) and, optionally, the third is the\n\t *   index of the sorting order from the `column.sorting` initialisation array.\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {integer} order Column index to sort upon.\n\t * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 1D array of sorting information to be applied.\n\t * @param {array} [...] Optional additional sorting conditions\n\t * @returns {DataTables.Api} this\n\t *//**\n\t * Set the ordering for the table.\n\t *\n\t * @param {array} order 2D array of sorting information to be applied.\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order()', function ( order, dir ) {\n\t\tvar ctx = this.context;\n\n\t\tif ( order === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].aaSorting :\n\t\t\t\tundefined;\n\t\t}\n\n\t\t// set\n\t\tif ( typeof order === 'number' ) {\n\t\t\t// Simple column / direction passed in\n\t\t\torder = [ [ order, dir ] ];\n\t\t}\n\t\telse if ( ! $.isArray( order[0] ) ) {\n\t\t\t// Arguments passed in (list of 1D arrays)\n\t\t\torder = Array.prototype.slice.call( arguments );\n\t\t}\n\t\t// otherwise a 2D array was passed in\n\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tsettings.aaSorting = order.slice();\n\t\t} );\n\t} );\n\n\n\t/**\n\t * Attach a sort listener to an element for a given column\n\t *\n\t * @param {node|jQuery|string} node Identifier for the element(s) to attach the\n\t *   listener to. This can take the form of a single DOM node, a jQuery\n\t *   collection of nodes or a jQuery selector which will identify the node(s).\n\t * @param {integer} column the column that a click on this node will sort on\n\t * @param {function} [callback] callback function when sort is run\n\t * @returns {DataTables.Api} this\n\t */\n\t_api_register( 'order.listener()', function ( node, column, callback ) {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnSortAttachListener( settings, node, column, callback );\n\t\t} );\n\t} );\n\n\n\t// Order by the selected column(s)\n\t_api_register( [\n\t\t'columns().order()',\n\t\t'column().order()'\n\t], function ( dir ) {\n\t\tvar that = this;\n\n\t\treturn this.iterator( 'table', function ( settings, i ) {\n\t\t\tvar sort = [];\n\n\t\t\t$.each( that[i], function (j, col) {\n\t\t\t\tsort.push( [ col, dir ] );\n\t\t\t} );\n\n\t\t\tsettings.aaSorting = sort;\n\t\t} );\n\t} );\n\n\n\n\t_api_register( 'search()', function ( input, regex, smart, caseInsen ) {\n\t\tvar ctx = this.context;\n\n\t\tif ( input === undefined ) {\n\t\t\t// get\n\t\t\treturn ctx.length !== 0 ?\n\t\t\t\tctx[0].oPreviousSearch.sSearch :\n\t\t\t\tundefined;\n\t\t}\n\n\t\t// set\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t_fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} ), 1 );\n\t\t} );\n\t} );\n\n\n\t_api_register( [\n\t\t'columns().search()',\n\t\t'column().search()'\n\t], function ( input, regex, smart, caseInsen ) {\n\t\treturn this.iterator( 'column', function ( settings, column ) {\n\t\t\tvar preSearch = settings.aoPreSearchCols;\n\n\t\t\tif ( input === undefined ) {\n\t\t\t\t// get\n\t\t\t\treturn preSearch[ column ].sSearch;\n\t\t\t}\n\n\t\t\t// set\n\t\t\tif ( ! settings.oFeatures.bFilter ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t$.extend( preSearch[ column ], {\n\t\t\t\t\"sSearch\": input+\"\",\n\t\t\t\t\"bRegex\":  regex === null ? false : regex,\n\t\t\t\t\"bSmart\":  smart === null ? true  : smart,\n\t\t\t\t\"bCaseInsensitive\": caseInsen === null ? true : caseInsen\n\t\t\t} );\n\n\t\t\t_fnFilterComplete( settings, settings.oPreviousSearch, 1 );\n\t\t} );\n\t} );\n\n\n\n\t/**\n\t * Provide a common method for plug-ins to check the version of DataTables being\n\t * used, in order to ensure compatibility.\n\t *\n\t *  @param {string} version Version string to check for, in the format \"X.Y.Z\".\n\t *    Note that the formats \"X\" and \"X.Y\" are also acceptable.\n\t *  @returns {boolean} true if this version of DataTables is greater or equal to\n\t *    the required version, or false if this version of DataTales is not\n\t *    suitable\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    alert( $.fn.dataTable.versionCheck( '1.9.0' ) );\n\t */\n\tDataTable.versionCheck = DataTable.fnVersionCheck = function( version )\n\t{\n\t\tvar aThis = DataTable.version.split('.');\n\t\tvar aThat = version.split('.');\n\t\tvar iThis, iThat;\n\n\t\tfor ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {\n\t\t\tiThis = parseInt( aThis[i], 10 ) || 0;\n\t\t\tiThat = parseInt( aThat[i], 10 ) || 0;\n\n\t\t\t// Parts are the same, keep comparing\n\t\t\tif (iThis === iThat) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Parts are different, return immediately\n\t\t\treturn iThis > iThat;\n\t\t}\n\n\t\treturn true;\n\t};\n\n\n\t/**\n\t * Check if a `<table>` node is a DataTable table already or not.\n\t *\n\t *  @param {node|jquery|string} table Table node, jQuery object or jQuery\n\t *      selector for the table to test. Note that if more than more than one\n\t *      table is passed on, only the first will be checked\n\t *  @returns {boolean} true the table given is a DataTable, or false otherwise\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {\n\t *      $('#example').dataTable();\n\t *    }\n\t */\n\tDataTable.isDataTable = DataTable.fnIsDataTable = function ( table )\n\t{\n\t\tvar t = $(table).get(0);\n\t\tvar is = false;\n\n\t\t$.each( DataTable.settings, function (i, o) {\n\t\t\tif ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {\n\t\t\t\tis = true;\n\t\t\t}\n\t\t} );\n\n\t\treturn is;\n\t};\n\n\n\t/**\n\t * Get all DataTable tables that have been initialised - optionally you can\n\t * select to get only currently visible tables.\n\t *\n\t *  @param {boolean} [visible=false] Flag to indicate if you want all (default)\n\t *    or visible tables only.\n\t *  @returns {array} Array of `table` nodes (not DataTable instances) which are\n\t *    DataTables\n\t *  @static\n\t *  @dtopt API-Static\n\t *\n\t *  @example\n\t *    $.each( $.fn.dataTable.tables(true), function () {\n\t *      $(table).DataTable().columns.adjust();\n\t *    } );\n\t */\n\tDataTable.tables = DataTable.fnTables = function ( visible )\n\t{\n\t\treturn jQuery.map( DataTable.settings, function (o) {\n\t\t\tif ( !visible || (visible && $(o.nTable).is(':visible')) ) {\n\t\t\t\treturn o.nTable;\n\t\t\t}\n\t\t} );\n\t};\n\n\n\n\t/**\n\t *\n\t */\n\t_api_register( '$()', function ( selector, opts ) {\n\t\tvar\n\t\t\trows   = this.rows( opts ).nodes(), // Get all rows\n\t\t\tjqRows = $(rows);\n\n\t\treturn $( [].concat(\n\t\t\tjqRows.filter( selector ).toArray(),\n\t\t\tjqRows.find( selector ).toArray()\n\t\t) );\n\t} );\n\n\n\t// jQuery functions to operate on the tables\n\t$.each( [ 'on', 'one', 'off' ], function (i, key) {\n\t\t_api_register( key+'()', function ( /* event, handler */ ) {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\n\t\t\t// Add the `dt` namespace automatically if it isn't already present\n\t\t\tif ( args[0].indexOf( '.dt' ) === -1 ) {\n\t\t\t\targs[0] += '.dt';\n\t\t\t}\n\n\t\t\tvar inst = $( this.tables().nodes() );\n\t\t\tinst[key].apply( inst, args );\n\t\t\treturn this;\n\t\t} );\n\t} );\n\n\n\t_api_register( 'clear()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\t_fnClearTable( settings );\n\t\t} );\n\t} );\n\n\n\t_api_register( 'settings()', function () {\n\t\treturn new _Api( this.context, this.context );\n\t} );\n\n\n\t_api_register( 'data()', function () {\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\treturn _pluck( settings.aoData, '_aData' );\n\t\t} ).flatten();\n\t} );\n\n\n\t_api_register( 'destroy()', function ( remove ) {\n\t\tremove = remove || false;\n\n\t\treturn this.iterator( 'table', function ( settings ) {\n\t\t\tvar orig      = settings.nTableWrapper.parentNode;\n\t\t\tvar classes   = settings.oClasses;\n\t\t\tvar table     = settings.nTable;\n\t\t\tvar tbody     = settings.nTBody;\n\t\t\tvar thead     = settings.nTHead;\n\t\t\tvar tfoot     = settings.nTFoot;\n\t\t\tvar jqTable   = $(table);\n\t\t\tvar jqTbody   = $(tbody);\n\t\t\tvar jqWrapper = $(settings.nTableWrapper);\n\t\t\tvar rows      = $.map( settings.aoData, function (r) { return r.nTr; } );\n\t\t\tvar i, ien;\n\n\t\t\t// Flag to note that the table is currently being destroyed - no action\n\t\t\t// should be taken\n\t\t\tsettings.bDestroying = true;\n\n\t\t\t// Fire off the destroy callbacks for plug-ins etc\n\t\t\t_fnCallbackFire( settings, \"aoDestroyCallback\", \"destroy\", [settings] );\n\n\t\t\t// If not being removed from the document, make all columns visible\n\t\t\tif ( ! remove ) {\n\t\t\t\tnew _Api( settings ).columns().visible( true );\n\t\t\t}\n\n\t\t\t// Blitz all DT events\n\t\t\tjqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');\n\t\t\t$(window).unbind('.DT-'+settings.sInstance);\n\n\t\t\t// When scrolling we had to break the table up - restore it\n\t\t\tif ( table != thead.parentNode ) {\n\t\t\t\tjqTable.children('thead').remove();\n\t\t\t\tjqTable.append( thead );\n\t\t\t}\n\n\t\t\tif ( tfoot && table != tfoot.parentNode ) {\n\t\t\t\tjqTable.children('tfoot').remove();\n\t\t\t\tjqTable.append( tfoot );\n\t\t\t}\n\n\t\t\t// Remove the DataTables generated nodes, events and classes\n\t\t\tjqTable.remove();\n\t\t\tjqWrapper.remove();\n\n\t\t\tsettings.aaSorting = [];\n\t\t\tsettings.aaSortingFixed = [];\n\t\t\t_fnSortingClasses( settings );\n\n\t\t\t$( rows ).removeClass( settings.asStripeClasses.join(' ') );\n\n\t\t\t$('th, td', thead).removeClass( classes.sSortable+' '+\n\t\t\t\tclasses.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone\n\t\t\t);\n\n\t\t\tif ( settings.bJUI ) {\n\t\t\t\t$('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).remove();\n\t\t\t\t$('th, td', thead).each( function () {\n\t\t\t\t\tvar wrapper = $('div.'+classes.sSortJUIWrapper, this);\n\t\t\t\t\t$(this).append( wrapper.contents() );\n\t\t\t\t\twrapper.remove();\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tif ( ! remove ) {\n\t\t\t\t// insertBefore acts like appendChild if !arg[1]\n\t\t\t\torig.insertBefore( table, settings.nTableReinsertBefore );\n\t\t\t}\n\n\t\t\t// Add the TR elements back into the table in their original order\n\t\t\tjqTbody.children().detach();\n\t\t\tjqTbody.append( rows );\n\n\t\t\t// Restore the width of the original table - was read from the style property,\n\t\t\t// so we can restore directly to that\n\t\t\tjqTable\n\t\t\t\t.css( 'width', settings.sDestroyWidth )\n\t\t\t\t.removeClass( classes.sTable );\n\n\t\t\t// If the were originally stripe classes - then we add them back here.\n\t\t\t// Note this is not fool proof (for example if not all rows had stripe\n\t\t\t// classes - but it's a good effort without getting carried away\n\t\t\tien = settings.asDestroyStripes.length;\n\n\t\t\tif ( ien ) {\n\t\t\t\tjqTbody.children().each( function (i) {\n\t\t\t\t\t$(this).addClass( settings.asDestroyStripes[i % ien] );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\t/* Remove the settings object from the settings array */\n\t\t\tvar idx = $.inArray( settings, DataTable.settings );\n\t\t\tif ( idx !== -1 ) {\n\t\t\t\tDataTable.settings.splice( idx, 1 );\n\t\t\t}\n\t\t} );\n\t} );\n\n\n\t/**\n\t * Version string for plug-ins to check compatibility. Allowed format is\n\t * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used\n\t * only for non-release builds. See http://semver.org/ for more information.\n\t *  @member\n\t *  @type string\n\t *  @default Version number\n\t */\n\tDataTable.version = \"1.10.0-dev\";\n\n\t/**\n\t * Private data store, containing all of the settings objects that are\n\t * created for the tables on a given page.\n\t *\n\t * Note that the `DataTable.settings` object is aliased to\n\t * `jQuery.fn.dataTableExt` through which it may be accessed and\n\t * manipulated, or `jQuery.fn.dataTable.settings`.\n\t *  @member\n\t *  @type array\n\t *  @default []\n\t *  @private\n\t */\n\tDataTable.settings = [];\n\n\t/**\n\t * Object models container, for the various models that DataTables has\n\t * available to it. These models define the objects that are used to hold\n\t * the active state and configuration of the table.\n\t *  @namespace\n\t */\n\tDataTable.models = {};\n\n\n\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * search information for the global filter and individual column filters.\n\t *  @namespace\n\t */\n\tDataTable.models.oSearch = {\n\t\t/**\n\t\t * Flag to indicate if the filtering should be case insensitive or not\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bCaseInsensitive\": true,\n\n\t\t/**\n\t\t * Applied search term\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sSearch\": \"\",\n\n\t\t/**\n\t\t * Flag to indicate if the search term should be interpreted as a\n\t\t * regular expression (true) or not (false) and therefore and special\n\t\t * regex characters escaped.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bRegex\": false,\n\n\t\t/**\n\t\t * Flag to indicate if DataTables is to use its smart filtering or not.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bSmart\": true\n\t};\n\n\n\n\n\t/**\n\t * Template object for the way in which DataTables holds information about\n\t * each individual row. This is the object format used for the settings\n\t * aoData array.\n\t *  @namespace\n\t */\n\tDataTable.models.oRow = {\n\t\t/**\n\t\t * TR element for the row\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTr\": null,\n\n\t\t/**\n\t\t * Array of TD elements for each row. This is null until the row has been\n\t\t * created.\n\t\t *  @type array nodes\n\t\t *  @default []\n\t\t */\n\t\t\"anCells\": null,\n\n\t\t/**\n\t\t * Data object from the original data source for the row. This is either\n\t\t * an array if using the traditional form of DataTables, or an object if\n\t\t * using mData options. The exact type will depend on the passed in\n\t\t * data from the data source, or will be an array if using DOM a data\n\t\t * source.\n\t\t *  @type array|object\n\t\t *  @default []\n\t\t */\n\t\t\"_aData\": [],\n\n\t\t/**\n\t\t * Sorting data cache - this array is ostensibly the same length as the\n\t\t * number of columns (although each index is generated only as it is\n\t\t * needed), and holds the data that is used for sorting each column in the\n\t\t * row. We do this cache generation at the start of the sort in order that\n\t\t * the formatting of the sort data need be done only once for each cell\n\t\t * per sort. This array should not be read from or written to by anything\n\t\t * other than the master sorting methods.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aSortData\": null,\n\n\t\t/**\n\t\t * Per cell filtering data cache. As per the sort data cache, used to\n\t\t * increase the performance of the filtering in DataTables\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_aFilterData\": null,\n\n\t\t/**\n\t\t * Filtering data cache. This is the same as the cell filtering cache, but\n\t\t * in this case a string rather than an array. This is easily computed with\n\t\t * a join on `_aFilterData`, but is provided as a cache so the join isn't\n\t\t * needed on every search (memory traded for performance)\n\t\t *  @type array\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sFilterRow\": null,\n\n\t\t/**\n\t\t * Cache of the class name that DataTables has applied to the row, so we\n\t\t * can quickly look at this variable rather than needing to do a DOM check\n\t\t * on className for the nTr property.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *  @private\n\t\t */\n\t\t\"_sRowStripe\": \"\",\n\n\t\t/**\n\t\t * Denote if the original data source was from the DOM, or the data source\n\t\t * object. This is used for invalidating data, so DataTables can\n\t\t * automatically read data from the original source, unless uninstructed\n\t\t * otherwise.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"src\": null\n\t};\n\n\n\n\t/**\n\t * Template object for the column information object in DataTables. This object\n\t * is held in the settings aoColumns array and contains all the information that\n\t * DataTables needs about each individual column.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults.column}\n\t * but this one is the internal data store for DataTables's cache of columns.\n\t * It should NOT be manipulated outside of DataTables. Any configuration should\n\t * be done through the initialisation options.\n\t *  @namespace\n\t */\n\tDataTable.models.oColumn = {\n\t\t/**\n\t\t * A list of the columns that sorting should occur on when this column\n\t\t * is sorted. That this property is an array allows multi-column sorting\n\t\t * to be defined for a column (for example first name / last name columns\n\t\t * would benefit from this). The values are integers pointing to the\n\t\t * columns to be sorted on (typically it will be a single integer pointing\n\t\t * at itself, but that doesn't need to be the case).\n\t\t *  @type array\n\t\t */\n\t\t\"aDataSort\": null,\n\n\t\t/**\n\t\t * Define the sorting directions that are applied to the column, in sequence\n\t\t * as the column is repeatedly sorted upon - i.e. the first value is used\n\t\t * as the sorting direction when the column if first sorted (clicked on).\n\t\t * Sort it again (click again) and it will move on to the next index.\n\t\t * Repeat until loop.\n\t\t *  @type array\n\t\t */\n\t\t\"asSorting\": null,\n\n\t\t/**\n\t\t * Flag to indicate if the column is searchable, and thus should be included\n\t\t * in the filtering or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSearchable\": null,\n\n\t\t/**\n\t\t * Flag to indicate if the column is sortable or not.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortable\": null,\n\n\t\t/**\n\t\t * Flag to indicate if the column is currently visible in the table or not\n\t\t *  @type boolean\n\t\t */\n\t\t\"bVisible\": null,\n\n\t\t/**\n\t\t * Store for manual type assignment using the `column.type` option. This\n\t\t * is held in store so we can manipulate the column's `sType` property.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *  @private\n\t\t */\n\t\t\"_sManualType\": null,\n\n\t\t/**\n\t\t * Flag to indicate if HTML5 data attributes should be used as the data\n\t\t * source for filtering or sorting. True is either are.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @private\n\t\t */\n\t\t\"_bAttrSrc\": false,\n\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} nTd The TD node that has been created\n\t\t *  @param {*} sData The Data for the cell\n\t\t *  @param {array|object} oData The data for the whole row\n\t\t *  @param {int} iRow The row index for the aoData data store\n\t\t *  @default null\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\n\t\t/**\n\t\t * Function to get data from a cell in a column. You should <b>never</b>\n\t\t * access data directly through _aData internally in DataTables - always use\n\t\t * the method attached to this property. It allows mData to function as\n\t\t * required. This function is automatically assigned by the column\n\t\t * initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {string} sSpecific The specific data type you want to get -\n\t\t *    'display', 'type' 'filter' 'sort'\n\t\t *  @returns {*} The data for the cell from the given row's data\n\t\t *  @default null\n\t\t */\n\t\t\"fnGetData\": null,\n\n\t\t/**\n\t\t * Function to set data for a cell in the column. You should <b>never</b>\n\t\t * set the data directly to _aData internally in DataTables - always use\n\t\t * this method. It allows mData to function as required. This function\n\t\t * is automatically assigned by the column initialisation method\n\t\t *  @type function\n\t\t *  @param {array|object} oData The data array/object for the array\n\t\t *    (i.e. aoData[]._aData)\n\t\t *  @param {*} sValue Value to set\n\t\t *  @default null\n\t\t */\n\t\t\"fnSetData\": null,\n\n\t\t/**\n\t\t * Property to read the value for the cells in the column from the data\n\t\t * source array / object. If null, then the default content is used, if a\n\t\t * function is given then the return from the function is used.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mData\": null,\n\n\t\t/**\n\t\t * Partner property to mData which is used (only when defined) to get\n\t\t * the data - i.e. it is basically the same as mData, but without the\n\t\t * 'set' option, and also the data fed to it is the result from mData.\n\t\t * This is the rendering method to match the data method of mData.\n\t\t *  @type function|int|string|null\n\t\t *  @default null\n\t\t */\n\t\t\"mRender\": null,\n\n\t\t/**\n\t\t * Unique header TH/TD element for this column - this is what the sorting\n\t\t * listener is attached to (if sorting is enabled.)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTh\": null,\n\n\t\t/**\n\t\t * Unique footer TH/TD element for this column (if there is one). Not used\n\t\t * in DataTables as such, but can be used for plug-ins to reference the\n\t\t * footer for each column.\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTf\": null,\n\n\t\t/**\n\t\t * The class to apply to all TD elements in the table's TBODY for the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sClass\": null,\n\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t *  @type string\n\t\t */\n\t\t\"sContentPadding\": null,\n\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because mData\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDefaultContent\": null,\n\n\t\t/**\n\t\t * Name for the column, allowing reference to the column by name as well as\n\t\t * by index (needs a lookup to work by name).\n\t\t *  @type string\n\t\t */\n\t\t\"sName\": null,\n\n\t\t/**\n\t\t * Custom sorting data type - defines which of the available plug-ins in\n\t\t * afnSortData the custom sorting will use - if any is defined.\n\t\t *  @type string\n\t\t *  @default std\n\t\t */\n\t\t\"sSortDataType\": 'std',\n\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClass\": null,\n\n\t\t/**\n\t\t * Class to be applied to the header element when sorting on this column -\n\t\t * when jQuery UI theming is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sSortingClassJUI\": null,\n\n\t\t/**\n\t\t * Title of the column - what is seen in the TH element (nTh).\n\t\t *  @type string\n\t\t */\n\t\t\"sTitle\": null,\n\n\t\t/**\n\t\t * Column sorting and filtering type\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sType\": null,\n\n\t\t/**\n\t\t * Width of the column\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidth\": null,\n\n\t\t/**\n\t\t * Width of the column when it was first \"encountered\"\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sWidthOrig\": null\n\t};\n\n\n\t/*\n\t * Developer note: The properties of the object below are given in Hungarian\n\t * notation, that was used as the interface for DataTables prior to v1.10, however\n\t * from v1.10 onwards the primary interface is camel case. In order to avoid\n\t * breaking backwards compatibility utterly with this change, the Hungarian\n\t * version is still, internally the primary interface, but is is not documented\n\t * - hence the @name tags in each doc comment. This allows a Javascript function\n\t * to create a map from Hungarian notation to camel case (going the other direction\n\t * would require each property to be listed, which would at around 3K to the size\n\t * of DataTables, while this method is about a 0.5K hit.\n\t *\n\t * Ultimately this does pave the way for Hungarian notation to be dropped\n\t * completely, but that is a massive amount of work and will break current\n\t * installs (therefore is on-hold until v2).\n\t */\n\n\t/**\n\t * Initialisation options that can be given to DataTables at initialisation\n\t * time.\n\t *  @namespace\n\t */\n\tDataTable.defaults = {\n\t\t/**\n\t\t * An array of data to use for the table, passed in at initialisation which\n\t\t * will be used in preference to any data which is already in the DOM. This is\n\t\t * particularly useful for constructing tables purely in Javascript, for\n\t\t * example with a custom Ajax call.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.data\n\t\t *\n\t\t *  @example\n\t\t *    // Using a 2D array data source\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],\n\t\t *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\" },\n\t\t *          { \"title\": \"Browser\" },\n\t\t *          { \"title\": \"Platform\" },\n\t\t *          { \"title\": \"Version\" },\n\t\t *          { \"title\": \"Grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using an array of objects as a data source (`data`)\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"data\": [\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 4.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  4,\n\t\t *            \"grade\":    \"X\"\n\t\t *          },\n\t\t *          {\n\t\t *            \"engine\":   \"Trident\",\n\t\t *            \"browser\":  \"Internet Explorer 5.0\",\n\t\t *            \"platform\": \"Win 95+\",\n\t\t *            \"version\":  5,\n\t\t *            \"grade\":    \"C\"\n\t\t *          }\n\t\t *        ],\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"Engine\",   \"data\": \"engine\" },\n\t\t *          { \"title\": \"Browser\",  \"data\": \"browser\" },\n\t\t *          { \"title\": \"Platform\", \"data\": \"platform\" },\n\t\t *          { \"title\": \"Version\",  \"data\": \"version\" },\n\t\t *          { \"title\": \"Grade\",    \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaData\": null,\n\n\n\t\t/**\n\t\t * If ordering is enabled, then DataTables will perform a first pass sort on\n\t\t * initialisation. You can define which column(s) the sort is performed\n\t\t * upon, and the sorting direction, with this variable. The `sorting` array\n\t\t * should contain an array for each column to be sorted initially containing\n\t\t * the column's index and a direction string ('asc' or 'desc').\n\t\t *  @type array\n\t\t *  @default [[0,'asc']]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.order\n\t\t *\n\t\t *  @example\n\t\t *    // Sort by 3rd column first, and then 4th column\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": [[2,'asc'], [3,'desc']]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *    // No initial sorting\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"order\": []\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aaSorting\": [[0,'asc']],\n\n\n\t\t/**\n\t\t * This parameter is basically identical to the `sorting` parameter, but\n\t\t * cannot be overridden by user interaction with the table. What this means\n\t\t * is that you could have a column (visible or hidden) which the sorting\n\t\t * will always be forced on first - any sorting after that (from the user)\n\t\t * will then be performed as required. This can be useful for grouping rows\n\t\t * together.\n\t\t *  @type array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.orderFixed\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderFixed\": [[0,'asc']]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\n\n\t\t/**\n\t\t * DataTables can be instructed to load data to display in the table from a\n\t\t * Ajax source. This option defines how that Ajax call is made and where to.\n\t\t *\n\t\t * The `ajax` property has three different modes of operation, depending on\n\t\t * how it is defined. These are:\n\t\t *\n\t\t * * `string` - Set the URL from where the data should be loaded from.\n\t\t * * `object` - Define properties for `jQuery.ajax`.\n\t\t * * `function` - Custom data get function\n\t\t *\n\t\t * `string`\n\t\t * --------\n\t\t *\n\t\t * As a string, the `ajax` property simply defines the URL from which\n\t\t * DataTables will load data.\n\t\t *\n\t\t * `object`\n\t\t * --------\n\t\t *\n\t\t * As an object, the parameters in the object are passed to\n\t\t * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control\n\t\t * of the Ajax request. DataTables has a number of default parameters which\n\t\t * you can override using this option. Please refer to the jQuery\n\t\t * documentation for a full description of the options available, although\n\t\t * the following parameters provide additional options in DataTables or\n\t\t * require special consideration:\n\t\t *\n\t\t * * `data` - As with jQuery, `data` can be provided as an object, but it\n\t\t *   can also be used as a function to manipulate the data DataTables sends\n\t\t *   to the server. The function takes a single parameter, an object of\n\t\t *   parameters with the values that DataTables has readied for sending. An\n\t\t *   object may be returned which will be merged into the DataTables\n\t\t *   defaults, or you can add the items to the object that was passed in and\n\t\t *   not return anything from the function. This supersedes `fnServerParams`\n\t\t *   from DataTables 1.9-.\n\t\t *\n\t\t * * `dataSrc` - By default DataTables will look for the property `data` (or\n\t\t *   `aaData` for compatibility with DataTables 1.9-) when obtaining data\n\t\t *   from an Ajax source or for server-side processing - this parameter\n\t\t *   allows that property to be changed. You can use Javascript dotted\n\t\t *   object notation to get a data source for multiple levels of nesting, or\n\t\t *   it my be used as a function. As a function it takes a single parameter,\n\t\t *   the JSON returned from the server, which can be manipulated as\n\t\t *   required, with the returned value being that used by DataTables as the\n\t\t *   data source for the table. This supersedes `sAjaxDataProp` from\n\t\t *   DataTables 1.9-.\n\t\t *\n\t\t * * `success` - Should not be overridden it is used internally in\n\t\t *   DataTables. To manipulate / transform the data returned by the server\n\t\t *   use `ajax.dataSrc`, or use `ajax` as a function (see below).\n\t\t *\n\t\t * `function`\n\t\t * ----------\n\t\t *\n\t\t * As a function, making the Ajax call is left up to yourself allowing\n\t\t * complete control of the Ajax request. Indeed, if desired, a method other\n\t\t * than Ajax could be used to obtain the required data, such as Web storage\n\t\t * or an AIR database.\n\t\t *\n\t\t * The function is given four parameters and no return is required. The\n\t\t * parameters are:\n\t\t *\n\t\t * 1. _object_ - Data to send to the server\n\t\t * 2. _function_ - Callback function that must be executed when the required\n\t\t *    data has been obtained. That data should be passed into the callback\n\t\t *    as the only parameter\n\t\t * 3. _object_ - DataTables settings object for the table\n\t\t *\n\t\t * Note that this supersedes `fnServerData` from DataTables 1.9-.\n\t\t *\n\t\t *  @type string|object|function\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.ajax\n\t\t *  @since 1.10.0\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax.\n\t\t *   // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": \"data.json\"\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to change\n\t\t *   // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"tableData\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get JSON data from a file via Ajax, using `dataSrc` to read data\n\t\t *   // from a plain array rather than an array in an object\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": \"\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Manipulate the data returned from the server - add a link to data\n\t\t *   // (note this can, should, be done using `render` for the column - this\n\t\t *   // is just a simple example of how the data can be manipulated).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"dataSrc\": function ( json ) {\n\t\t *         for ( var i=0, ien=json.length ; i<ien ; i++ ) {\n\t\t *           json[i][0] = '<a href=\"/message/'+json[i][0]+'>View message</a>';\n\t\t *         }\n\t\t *         return json;\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Add data to the request\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"data\": function ( d ) {\n\t\t *         return {\n\t\t *           \"extra_search\": $('#extra').val()\n\t\t *         };\n\t\t *       }\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Send request as POST\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": {\n\t\t *       \"url\": \"data.json\",\n\t\t *       \"type\": \"POST\"\n\t\t *     }\n\t\t *   } );\n\t\t *\n\t\t * @example\n\t\t *   // Get the data from localStorage (could interface with a form for\n\t\t *   // adding, editing and removing rows).\n\t\t *   $('#example').dataTable( {\n\t\t *     \"ajax\": function (data, callback, settings) {\n\t\t *       callback(\n\t\t *         JSON.parse( localStorage.getItem('dataTablesData') )\n\t\t *       );\n\t\t *     }\n\t\t *   } );\n\t\t */\n\t\t\"ajax\": null,\n\n\n\t\t/**\n\t\t * This parameter allows you to readily specify the entries in the length drop\n\t\t * down menu that DataTables shows when pagination is enabled. It can be\n\t\t * either a 1D array of options which will be used for both the displayed\n\t\t * option and the value, or a 2D array which will use the array in the first\n\t\t * position as the value, and the array in the second position as the\n\t\t * displayed options (useful for language strings such as 'All').\n\t\t *\n\t\t * Note that the `pageLength` property will be automatically set to the\n\t\t * first value given in this array, unless `pageLength` is also provided.\n\t\t *  @type array\n\t\t *  @default [ 10, 25, 50, 100 ]\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.lengthMenu\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthMenu\": [[10, 25, 50, -1], [10, 25, 50, \"All\"]]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aLengthMenu\": [ 10, 25, 50, 100 ],\n\n\n\t\t/**\n\t\t * The `columns` option in the initialisation parameter allows you to define\n\t\t * details about the way individual columns behave. For a full list of\n\t\t * column options that can be set, please see\n\t\t * {@link DataTable.defaults.column}. Note that if you use `columns` to\n\t\t * define your columns, you must have an entry in the array for every single\n\t\t * column that you have in your table (these can be null if you don't which\n\t\t * to specify any options).\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.column\n\t\t */\n\t\t\"aoColumns\": null,\n\n\t\t/**\n\t\t * Very similar to `columns`, `columnDefs` allows you to target a specific\n\t\t * column, multiple columns, or all columns, using the `targets` property of\n\t\t * each object in the array. This allows great flexibility when creating\n\t\t * tables, as the `columnDefs` arrays can be of any length, targeting the\n\t\t * columns you specifically want. `columnDefs` may use any of the column\n\t\t * options available: {@link DataTable.defaults.column}, but it _must_\n\t\t * have `targets` defined in each object in the array. Values in the `targets`\n\t\t * array may be:\n\t\t *   <ul>\n\t\t *     <li>a string - class name will be matched on the TH for the column</li>\n\t\t *     <li>0 or a positive integer - column index counting from the left</li>\n\t\t *     <li>a negative integer - column index counting from the right</li>\n\t\t *     <li>the string \"_all\" - all columns (i.e. assign a default)</li>\n\t\t *   </ul>\n\t\t *  @member\n\t\t *\n\t\t *  @name DataTable.defaults.columnDefs\n\t\t */\n\t\t\"aoColumnDefs\": null,\n\n\n\t\t/**\n\t\t * Basically the same as `search`, this parameter defines the individual column\n\t\t * filtering state at initialisation time. The array must be of the same size\n\t\t * as the number of columns, and each element be an object with the parameters\n\t\t * `search` and `escapeRegex` (the latter is optional). 'null' is also\n\t\t * accepted and the default will be used.\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.searchCols\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searchCols\": [\n\t\t *          null,\n\t\t *          { \"search\": \"My filter\" },\n\t\t *          null,\n\t\t *          { \"search\": \"^[0-9]\", \"escapeRegex\": false }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"aoSearchCols\": [],\n\n\n\t\t/**\n\t\t * An array of CSS classes that should be applied to displayed rows. This\n\t\t * array may be of any length, and DataTables will apply each class\n\t\t * sequentially, looping when required.\n\t\t *  @type array\n\t\t *  @default null <i>Will take the values determined by the `oClasses.stripe*`\n\t\t *    options</i>\n\t\t *\n\t\t *  @dtopt Option\n\t\t *  @name DataTable.defaults.stripeClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stripeClasses\": [ 'strip1', 'strip2', 'strip3' ]\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"asStripeClasses\": null,\n\n\n\t\t/**\n\t\t * Enable or disable automatic column width calculation. This can be disabled\n\t\t * as an optimisation (it takes some time to calculate the widths) if the\n\t\t * tables widths are passed in using `columns`.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.autoWidth\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"autoWidth\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bAutoWidth\": true,\n\n\n\t\t/**\n\t\t * Deferred rendering can provide DataTables with a huge speed boost when you\n\t\t * are using an Ajax or JS data source for the table. This option, when set to\n\t\t * true, will cause DataTables to defer the creation of the table elements for\n\t\t * each row until they are needed for a draw - saving a significant amount of\n\t\t * time.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.deferRender\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajax\": \"sources/arrays.txt\",\n\t\t *        \"deferRender\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDeferRender\": false,\n\n\n\t\t/**\n\t\t * Replace a DataTable which matches the given selector and replace it with\n\t\t * one which has the properties of the new initialisation object passed. If no\n\t\t * table matches the selector, then the new DataTable will be constructed as\n\t\t * per normal.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.destroy\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"srollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *\n\t\t *      // Some time later....\n\t\t *      $('#example').dataTable( {\n\t\t *        \"filter\": false,\n\t\t *        \"destroy\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bDestroy\": false,\n\n\n\t\t/**\n\t\t * Enable or disable filtering of data. Filtering in DataTables is \"smart\" in\n\t\t * that it allows the end user to input multiple words (space separated) and\n\t\t * will match a row containing those words, even if not in the order that was\n\t\t * specified (this allow matching across multiple columns). Note that if you\n\t\t * wish to use filtering in DataTables this must remain 'true' - to remove the\n\t\t * default filtering input box and retain filtering abilities, please use\n\t\t * {@link DataTable.defaults.dom}.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.searching\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"searching\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bFilter\": true,\n\n\n\t\t/**\n\t\t * Enable or disable the table information display. This shows information\n\t\t * about the data that is currently visible on the page, including information\n\t\t * about filtered data if that action is being performed.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.info\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"info\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bInfo\": true,\n\n\n\t\t/**\n\t\t * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some\n\t\t * slightly different and additional mark-up from what DataTables has\n\t\t * traditionally used).\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.jQueryUI\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"jQueryUI\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bJQueryUI\": false,\n\n\n\t\t/**\n\t\t * Allows the end user to select the size of a formatted page from a select\n\t\t * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.lengthChange\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"lengthChange\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bLengthChange\": true,\n\n\n\t\t/**\n\t\t * Enable or disable pagination.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.paging\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"paging\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bPaginate\": true,\n\n\n\t\t/**\n\t\t * Enable or disable the display of a 'processing' indicator when the table is\n\t\t * being processed (e.g. a sort). This is particularly useful for tables with\n\t\t * large amounts of data where it can take a noticeable amount of time to sort\n\t\t * the entries.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.processing\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"processing\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bProcessing\": false,\n\n\n\t\t/**\n\t\t * Retrieve the DataTables object for the given selector. Note that if the\n\t\t * table has already been initialised, this parameter will cause DataTables\n\t\t * to simply return the object that has already been set up - it will not take\n\t\t * account of any changes you might have made to the initialisation object\n\t\t * passed to DataTables (setting this parameter to true is an acknowledgement\n\t\t * that you understand this). `destroy` can be used to reinitialise a table if\n\t\t * you need.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.retrieve\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      initTable();\n\t\t *      tableActions();\n\t\t *    } );\n\t\t *\n\t\t *    function initTable ()\n\t\t *    {\n\t\t *      return $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false,\n\t\t *        \"retrieve\": true\n\t\t *      } );\n\t\t *    }\n\t\t *\n\t\t *    function tableActions ()\n\t\t *    {\n\t\t *      var table = initTable();\n\t\t *      // perform API operations with oTable\n\t\t *    }\n\t\t */\n\t\t\"bRetrieve\": false,\n\n\n\t\t/**\n\t\t * When vertical (y) scrolling is enabled, DataTables will force the height of\n\t\t * the table's viewport to the given height at all times (useful for layout).\n\t\t * However, this can look odd when filtering data down to a small data set,\n\t\t * and the footer is left \"floating\" further down. This parameter (when\n\t\t * enabled) will cause DataTables to collapse the table's viewport down when\n\t\t * the result set will fit within the given Y height.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollCollapse\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200\",\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bScrollCollapse\": false,\n\n\n\t\t/**\n\t\t * Configure DataTables to use server-side processing. Note that the\n\t\t * `ajax` parameter must also be given in order to give DataTables a\n\t\t * source to obtain the required data for each draw.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverSide\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"xhr.php\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bServerSide\": false,\n\n\n\t\t/**\n\t\t * Enable or disable sorting of columns. Sorting of individual columns can be\n\t\t * disabled by the `sortable` option for each column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.ordering\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ordering\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSort\": true,\n\n\n\t\t/**\n\t\t * Enable or display DataTables' ability to sort multiple columns at the\n\t\t * same time (activated by shift-click by the user).\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderMulti\n\t\t *\n\t\t *  @example\n\t\t *    // Disable multiple column sorting ability\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderMulti\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortMulti\": true,\n\n\n\t\t/**\n\t\t * Allows control over whether DataTables should use the top (true) unique\n\t\t * cell that is found for a single column, or the bottom (false - default).\n\t\t * This is useful when using complex headers.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.orderCellsTop\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderCellsTop\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortCellsTop\": false,\n\n\n\t\t/**\n\t\t * Enable or disable the addition of the classes `sorting\\_1`, `sorting\\_2` and\n\t\t * `sorting\\_3` to the columns which are currently being sorted on. This is\n\t\t * presented as a feature switch as it can increase processing time (while\n\t\t * classes are removed and added) so for large data sets you might want to\n\t\t * turn this off.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.orderClasses\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"orderClasses\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortClasses\": true,\n\n\n\t\t/**\n\t\t * Enable or disable state saving. When enabled HTML5 `localStorage` will be\n\t\t * used to save table display information such as pagination information,\n\t\t * display length, filtering and sorting. As such when the end user reloads\n\t\t * the page the display display will match what thy had previously set up.\n\t\t *\n\t\t * Due to the use of `localStorage` the default state saving is not supported\n\t\t * in IE6 or 7. If state saving is required in those browsers, use\n\t\t * `stateSaveCallback` to provide a storage solution such as cookies.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.stateSave\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function () {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"bStateSave\": false,\n\n\n\t\t/**\n\t\t * This function is called when a TR element is created (and all TD child\n\t\t * elements have been inserted), or registered if using a DOM source, allowing\n\t\t * manipulation of the TR element (adding classes etc).\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} dataIndex The index of this row in the internal aoData array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.createdRow\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"createdRow\": function( row, data, dataIndex ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" )\n\t\t *          {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedRow\": null,\n\n\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify any aspect you want about the created DOM.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.drawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"drawCallback\": function( settings ) {\n\t\t *          alert( 'DataTables has redrawn the table' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnDrawCallback\": null,\n\n\n\t\t/**\n\t\t * Identical to fnHeaderCallback() but for the table footer this function\n\t\t * allows you to modify the table footer on every 'draw' event.\n\t\t *  @type function\n\t\t *  @param {node} foot \"TR\" element for the footer\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.footerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"footerCallback\": function( tfoot, data, start, end, display ) {\n\t\t *          tfoot.getElementsByTagName('th')[0].innerHTML = \"Starting index is \"+start;\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnFooterCallback\": null,\n\n\n\t\t/**\n\t\t * When rendering large numbers in the information element for the table\n\t\t * (i.e. \"Showing 1 to 10 of 57 entries\") DataTables will render large numbers\n\t\t * to have a comma separator for the 'thousands' units (e.g. 1 million is\n\t\t * rendered as \"1,000,000\") to help readability for the end user. This\n\t\t * function will override the default method DataTables uses.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {int} toFormat number to be formatted\n\t\t *  @returns {string} formatted string for DataTables to show the number\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.formatNumber\n\t\t *\n\t\t *  @example\n\t\t *    // Format a number using a single quote for the separator (note that\n\t\t *    // this can also be done with the language.infoThousands option)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"formatNumber\": function ( toFormat ) {\n\t\t *          return toFormat.toString().replace(\n\t\t *            /\\B(?=(\\d{3})+(?!\\d))/g, \"'\"\n\t\t *          );\n\t\t *        };\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnFormatNumber\": function ( toFormat ) {\n\t\t\treturn toFormat.toString().replace(\n\t\t\t\t/\\B(?=(\\d{3})+(?!\\d))/g,\n\t\t\t\tthis.oLanguage.sInfoThousands\n\t\t\t);\n\t\t},\n\n\n\t\t/**\n\t\t * This function is called on every 'draw' event, and allows you to\n\t\t * dynamically modify the header row. This can be used to calculate and\n\t\t * display useful information about the table.\n\t\t *  @type function\n\t\t *  @param {node} head \"TR\" element for the header\n\t\t *  @param {array} data Full table data (as derived from the original HTML)\n\t\t *  @param {int} start Index for the current display starting point in the\n\t\t *    display array\n\t\t *  @param {int} end Index for the current display ending point in the\n\t\t *    display array\n\t\t *  @param {array int} display Index array to translate the visual position\n\t\t *    to the full data array\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.headerCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"fheaderCallback\": function( head, data, start, end, display ) {\n\t\t *          head.getElementsByTagName('th')[0].innerHTML = \"Displaying \"+(end-start)+\" records\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnHeaderCallback\": null,\n\n\n\t\t/**\n\t\t * The information element can be used to convey information about the current\n\t\t * state of the table. Although the internationalisation options presented by\n\t\t * DataTables are quite capable of dealing with most customisations, there may\n\t\t * be times where you wish to customise the string further. This callback\n\t\t * allows you to do exactly that.\n\t\t *  @type function\n\t\t *  @param {object} oSettings DataTables settings object\n\t\t *  @param {int} start Starting position in data for the draw\n\t\t *  @param {int} end End position in data for the draw\n\t\t *  @param {int} max Total number of rows in the table (regardless of\n\t\t *    filtering)\n\t\t *  @param {int} total Total number of rows in the data set, after filtering\n\t\t *  @param {string} pre The string that DataTables has formatted using it's\n\t\t *    own rules\n\t\t *  @returns {string} The string to be displayed in the information element.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.infoCallback\n\t\t *\n\t\t *  @example\n\t\t *    $('#example').dataTable( {\n\t\t *      \"infoCallback\": function( settings, start, end, max, total, pre ) {\n\t\t *        return start +\" to \"+ end;\n\t\t *      }\n\t\t *    } );\n\t\t */\n\t\t\"fnInfoCallback\": null,\n\n\n\t\t/**\n\t\t * Called when the table has been initialised. Normally DataTables will\n\t\t * initialise sequentially and there will be no need for this function,\n\t\t * however, this does not hold true when using external language information\n\t\t * since that is obtained using an async XHR call.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} json The JSON object request from the server - only\n\t\t *    present if client-side Ajax sourced data is used\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.initComplete\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"initComplete\": function(settings, json) {\n\t\t *          alert( 'DataTables has finished its initialisation.' );\n\t\t *        }\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"fnInitComplete\": null,\n\n\n\t\t/**\n\t\t * Called at the very start of each table draw and can be used to cancel the\n\t\t * draw by returning false, any other return (including undefined) results in\n\t\t * the full draw occurring).\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @returns {boolean} False will cancel the draw, anything else (including no\n\t\t *    return) will allow it to complete.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.preDrawCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"preDrawCallback\": function( settings ) {\n\t\t *          if ( $('#test').val() == 1 ) {\n\t\t *            return false;\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnPreDrawCallback\": null,\n\n\n\t\t/**\n\t\t * This function allows you to 'post process' each row after it have been\n\t\t * generated for each table draw, but before it is rendered on screen. This\n\t\t * function might be used for setting the row class name etc.\n\t\t *  @type function\n\t\t *  @param {node} row \"TR\" element for the current row\n\t\t *  @param {array} data Raw data array for this row\n\t\t *  @param {int} displayIndex The display index for the current table draw\n\t\t *  @param {int} displayIndexFull The index of the data in the full list of\n\t\t *    rows (after filtering)\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.rowCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"rowCallback\": function( row, data, displayIndex, displayIndexFull ) {\n\t\t *          // Bold the grade for all 'A' grade browsers\n\t\t *          if ( data[4] == \"A\" ) {\n\t\t *            $('td:eq(4)', row).html( '<b>A</b>' );\n\t\t *          }\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnRowCallback\": null,\n\n\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * This parameter allows you to override the default function which obtains\n\t\t * the data from the server so something more suitable for your application.\n\t\t * For example you could use POST data, or pull information from a Gears or\n\t\t * AIR database.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {string} source HTTP source to obtain the data from (`ajax`)\n\t\t *  @param {array} data A key/value pair object containing the data to send\n\t\t *    to the server\n\t\t *  @param {function} callback to be called on completion of the data get\n\t\t *    process that will draw the data on the page.\n\t\t *  @param {object} settings DataTables settings object\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverData\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerData\": null,\n\n\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t *  It is often useful to send extra data to the server when making an Ajax\n\t\t * request - for example custom filtering information, and this callback\n\t\t * function makes it trivial to send extra information to the server. The\n\t\t * passed in parameter is the data set that has been constructed by\n\t\t * DataTables, and you can add to this or modify it as you require.\n\t\t *  @type function\n\t\t *  @param {array} data Data array (array of objects which are name/value\n\t\t *    pairs) that has been constructed by DataTables and will be sent to the\n\t\t *    server. In the case of Ajax sourced data with server-side processing\n\t\t *    this will be an empty array, for server-side processing there will be a\n\t\t *    significant number of parameters!\n\t\t *  @returns {undefined} Ensure that you modify the data array passed in,\n\t\t *    as this is passed by reference.\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverParams\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"fnServerParams\": null,\n\n\n\t\t/**\n\t\t * Load the table state. With this function you can define from where, and how, the\n\t\t * state of a table is loaded. By default DataTables will load from `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @return {object} The DataTables state object to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadCallback\": function (settings) {\n\t\t *          var o;\n\t\t *\n\t\t *          // Send an Ajax request to the server to get the data. Note that\n\t\t *          // this is a synchronous request.\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_load\",\n\t\t *            \"async\": false,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"success\": function (json) {\n\t\t *              o = json;\n\t\t *            }\n\t\t *          } );\n\t\t *\n\t\t *          return o;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadCallback\": function ( settings ) {\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(\n\t\t\t\t\tlocalStorage.getItem('DataTables_'+settings.sInstance+'_'+window.location.pathname)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\n\n\t\t/**\n\t\t * Callback which allows modification of the saved state prior to loading that state.\n\t\t * This callback is called when the table is loading state from the stored data, but\n\t\t * prior to the settings object being modified by the saved state. Note that for\n\t\t * plug-in authors, you should use the `stateLoadParams` event to load parameters for\n\t\t * a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that is to be loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoadParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never loaded\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Disallow state loading by returning false\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoadParams\": function (settings, data) {\n\t\t *          return false;\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoadParams\": null,\n\n\n\t\t/**\n\t\t * Callback that is called when the state has been loaded from the state saving method\n\t\t * and the DataTables settings object has been modified as a result of the loaded state.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object that was loaded\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateLoaded\n\t\t *\n\t\t *  @example\n\t\t *    // Show an alert with the filtering value that was saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateLoaded\": function (settings, data) {\n\t\t *          alert( 'Saved filter was: '+data.oSearch.sSearch );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateLoaded\": null,\n\n\n\t\t/**\n\t\t * Save the table state. This function allows you to define where and how the state\n\t\t * information for the table is stored By default DataTables will use `localStorage`\n\t\t * but you might wish to use a server-side database or cookies.\n\t\t *  @type function\n\t\t *  @member\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveCallback\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveCallback\": function (settings, data) {\n\t\t *          // Send an Ajax request to the server with the state object\n\t\t *          $.ajax( {\n\t\t *            \"url\": \"/state_save\",\n\t\t *            \"data\": data,\n\t\t *            \"dataType\": \"json\",\n\t\t *            \"method\": \"POST\"\n\t\t *            \"success\": function () {}\n\t\t *          } );\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveCallback\": function ( settings, data ) {\n\t\t\ttry {\n\t\t\t\tlocalStorage.setItem(\n\t\t\t\t\t'DataTables_'+settings.sInstance+'_'+window.location.pathname,\n\t\t\t\t\tJSON.stringify(data)\n\t\t\t\t);\n\t\t\t} catch (e) {}\n\t\t},\n\n\n\t\t/**\n\t\t * Callback which allows modification of the state to be saved. Called when the table\n\t\t * has changed state a new state save is required. This method allows modification of\n\t\t * the state saving object prior to actually doing the save, including addition or\n\t\t * other state properties or modification. Note that for plug-in authors, you should\n\t\t * use the `stateSaveParams` event to save parameters for a plug-in.\n\t\t *  @type function\n\t\t *  @param {object} settings DataTables settings object\n\t\t *  @param {object} data The state object to be saved\n\t\t *\n\t\t *  @dtopt Callbacks\n\t\t *  @name DataTable.defaults.stateSaveParams\n\t\t *\n\t\t *  @example\n\t\t *    // Remove a saved filter, so filtering is never saved\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateSave\": true,\n\t\t *        \"stateSaveParams\": function (settings, data) {\n\t\t *          data.oSearch.sSearch = \"\";\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"fnStateSaveParams\": null,\n\n\n\t\t/**\n\t\t * Duration for which the saved state information is considered valid. After this period\n\t\t * has elapsed the state will be returned to the default.\n\t\t * Value is given in seconds.\n\t\t *  @type int\n\t\t *  @default 7200 <i>(2 hours)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.stateDuration\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"stateDuration\": 60*60*24; // 1 day\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iStateDuration\": 7200,\n\n\n\t\t/**\n\t\t * When enabled DataTables will not make a request to the server for the first\n\t\t * page draw - rather it will use the data already on the page (no sorting etc\n\t\t * will be applied to it), thus saving on an XHR at load time. `deferLoading`\n\t\t * is used to indicate that deferred loading is required, but it is also used\n\t\t * to tell DataTables how many records there are in the full table (allowing\n\t\t * the information element and pagination to be displayed correctly). In the case\n\t\t * where a filtering is applied to the table on initial load, this can be\n\t\t * indicated by giving the parameter as an array, where the first element is\n\t\t * the number of records available after filtering and the second element is the\n\t\t * number of records without filtering (allowing the table information element\n\t\t * to be shown correctly).\n\t\t *  @type int | array\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.deferLoading\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records available in the table, no filtering applied\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": 57\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // 57 records after filtering, 100 without filtering (an initial filter applied)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"serverSide\": true,\n\t\t *        \"ajax\": \"scripts/server_processing.php\",\n\t\t *        \"deferLoading\": [ 57, 100 ],\n\t\t *        \"search\": {\n\t\t *          \"search\": \"my_filter\"\n\t\t *        }\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iDeferLoading\": null,\n\n\n\t\t/**\n\t\t * Number of rows to display on a single page when using pagination. If\n\t\t * feature enabled (`lengthChange`) then the end user will be able to override\n\t\t * this to a custom setting using a pop-up menu.\n\t\t *  @type int\n\t\t *  @default 10\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pageLength\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pageLength\": 50\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayLength\": 10,\n\n\n\t\t/**\n\t\t * Define the starting point for data display when using DataTables with\n\t\t * pagination. Note that this parameter is the number of records, rather than\n\t\t * the page number, so if you have 10 records per page and want to start on\n\t\t * the third page, it should be \"20\".\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.displayStart\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"displayStart\": 20\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"iDisplayStart\": 0,\n\n\n\t\t/**\n\t\t * By default DataTables allows keyboard navigation of the table (sorting, paging,\n\t\t * and filtering) by adding a `tabindex` attribute to the required elements. This\n\t\t * allows you to tab through the controls and press the enter key to activate them.\n\t\t * The tabindex is default 0, meaning that the tab follows the flow of the document.\n\t\t * You can overrule this using this parameter if you wish. Use a value of -1 to\n\t\t * disable built-in keyboard navigation.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.tabIndex\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"tabIndex\": 1\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"iTabIndex\": 0,\n\n\n\t\t/**\n\t\t * Classes that DataTables assigns to the various components and features\n\t\t * that it adds to the HTML table. This allows classes to be configured\n\t\t * during initialisation in addition to through the static\n\t\t * {@link DataTable.ext.oStdClasses} object).\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.classes\n\t\t */\n\t\t\"oClasses\": {},\n\n\n\t\t/**\n\t\t * All strings that DataTables uses in the user interface that it creates\n\t\t * are defined in this object, allowing you to modified them individually or\n\t\t * completely replace them all as required.\n\t\t *  @namespace\n\t\t *  @name DataTable.defaults.language\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Strings that are used for WAI-ARIA labels and controls only (these are not\n\t\t\t * actually visible on the page, but will be read by screenreaders, and thus\n\t\t\t * must be internationalised as well).\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.aria\n\t\t\t */\n\t\t\t\"oAria\": {\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted ascending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortAscending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortAscending\": \" - click/return to sort ascending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortAscending\": \"：激活排序列升序\",\n\n\t\t\t\t/**\n\t\t\t\t * ARIA label that is added to the table headers when the column may be\n\t\t\t\t * sorted descending by activing the column (click or return when focused).\n\t\t\t\t * Note that the column header is prefixed to this string.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default : activate to sort column ascending\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.aria.sortDescending\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"aria\": {\n\t\t\t\t *            \"sortDescending\": \" - click/return to sort descending\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sSortDescending\": \"：激活排序列降序\"\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * Pagination string used by DataTables for the built-in pagination\n\t\t\t * control types.\n\t\t\t *  @namespace\n\t\t\t *  @name DataTable.defaults.language.paginate\n\t\t\t */\n\t\t\t\"oPaginate\": {\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the first page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default First\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.first\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"first\": \"First page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sFirst\": \"第一页\",\n\n\n\t\t\t\t/**\n\t\t\t\t * Text to use when using the 'full_numbers' type of pagination for the\n\t\t\t\t * button to take the user to the last page.\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Last\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.last\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"last\": \"Last page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sLast\": \"最后一页\",\n\n\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'next' pagination button (to take the user to the\n\t\t\t\t * next page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Next\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.next\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"next\": \"Next page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sNext\": \"下一页\",\n\n\n\t\t\t\t/**\n\t\t\t\t * Text to use for the 'previous' pagination button (to take the user to\n\t\t\t\t * the previous page).\n\t\t\t\t *  @type string\n\t\t\t\t *  @default Previous\n\t\t\t\t *\n\t\t\t\t *  @dtopt Language\n\t\t\t\t *  @name DataTable.defaults.language.paginate.previous\n\t\t\t\t *\n\t\t\t\t *  @example\n\t\t\t\t *    $(document).ready( function() {\n\t\t\t\t *      $('#example').dataTable( {\n\t\t\t\t *        \"language\": {\n\t\t\t\t *          \"paginate\": {\n\t\t\t\t *            \"previous\": \"Previous page\"\n\t\t\t\t *          }\n\t\t\t\t *        }\n\t\t\t\t *      } );\n\t\t\t\t *    } );\n\t\t\t\t */\n\t\t\t\t\"sPrevious\": \"上一页\"\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * This string is shown in preference to `zeroRecords` when the table is\n\t\t\t * empty of data (regardless of filtering). Note that this is an optional\n\t\t\t * parameter - if it is not given, the value of `zeroRecords` will be used\n\t\t\t * instead (either the default or given value).\n\t\t\t *  @type string\n\t\t\t *  @default No data available in table\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.emptyTable\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"emptyTable\": \"No data available in table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sEmptyTable\": \"没有数据\",\n\n\n\t\t\t/**\n\t\t\t * This string gives information to the end user about the information\n\t\t\t * that is current on display on the page. The following tokens can be\n\t\t\t * used in the string and will be dynamically replaced as the table\n\t\t\t * display updates. This tokens can be placed anywhere in the string, or\n\t\t\t * removed as needed by the language requires:\n\t\t\t *\n\t\t\t * * `\\_START\\_` - Display index of the first record on the current page\n\t\t\t * * `\\_END\\_` - Display index of the last record on the current page\n\t\t\t * * `\\_TOTAL\\_` - Number of records in the table after filtering\n\t\t\t * * `\\_MAX\\_` - Number of records in the table without filtering\n\t\t\t * * `\\_PAGE\\_` - Current page number\n\t\t\t * * `\\_PAGES\\_` - Total number of pages of data in the table\n\t\t\t *\n\t\t\t *  @type string\n\t\t\t *  @default Showing _START_ to _END_ of _TOTAL_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.info\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"info\": \"Showing page _PAGE_ of _PAGES_\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfo\": \"显示 _START_ 到 _END_ 项，共 _TOTAL_ 项\",\n\n\n\t\t\t/**\n\t\t\t * Display information string for when the table is empty. Typically the\n\t\t\t * format of this string should match `info`.\n\t\t\t *  @type string\n\t\t\t *  @default Showing 0 to 0 of 0 entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoEmpty\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoEmpty\": \"No entries to show\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoEmpty\": \"显示0项\",\n\n\n\t\t\t/**\n\t\t\t * When a user filters the information in a table, this string is appended\n\t\t\t * to the information (`info`) to give an idea of how strong the filtering\n\t\t\t * is. The variable _MAX_ is dynamically updated.\n\t\t\t *  @type string\n\t\t\t *  @default (filtered from _MAX_ total entries)\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoFiltered\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoFiltered\": \" - filtering from _MAX_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoFiltered\": \"（从 _MAX_ 中筛选）\",\n\n\n\t\t\t/**\n\t\t\t * If can be useful to append extra information to the info string at times,\n\t\t\t * and this variable does exactly that. This information will be appended to\n\t\t\t * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are\n\t\t\t * being used) at all times.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoPostFix\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoPostFix\": \"All records shown are derived from real information.\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoPostFix\": \"\",\n\n\n\t\t\t/**\n\t\t\t * DataTables has a build in number formatter (`formatNumber`) which is used\n\t\t\t * to format large numbers that are used in the table information. By\n\t\t\t * default a comma is used, but this can be trivially changed to any\n\t\t\t * character you wish with this parameter.\n\t\t\t *  @type string\n\t\t\t *  @default ,\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.infoThousands\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"infoThousands\": \"'\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sInfoThousands\": \",\",\n\n\n\t\t\t/**\n\t\t\t * Detail the action that will be taken when the drop down menu for the\n\t\t\t * pagination length option is changed. The '_MENU_' variable is replaced\n\t\t\t * with a default select list of 10, 25, 50 and 100, and can be replaced\n\t\t\t * with a custom select box if required.\n\t\t\t *  @type string\n\t\t\t *  @default Show _MENU_ entries\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.lengthMenu\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language change only\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": \"Display _MENU_ records\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Language and options change\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"lengthMenu\": 'Display <select>'+\n\t\t\t *            '<option value=\"10\">10</option>'+\n\t\t\t *            '<option value=\"20\">20</option>'+\n\t\t\t *            '<option value=\"30\">30</option>'+\n\t\t\t *            '<option value=\"40\">40</option>'+\n\t\t\t *            '<option value=\"50\">50</option>'+\n\t\t\t *            '<option value=\"-1\">All</option>'+\n\t\t\t *            '</select> records'\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLengthMenu\": \"显示 _MENU_ entries\",\n\n\n\t\t\t/**\n\t\t\t * When using Ajax sourced data and during the first draw when DataTables is\n\t\t\t * gathering the data, this message is shown in an empty row in the table to\n\t\t\t * indicate to the end user the the data is being loaded. Note that this\n\t\t\t * parameter is not used when loading data by server-side processing, just\n\t\t\t * Ajax sourced data with client-side processing.\n\t\t\t *  @type string\n\t\t\t *  @default Loading...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.loadingRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"loadingRecords\": \"Please wait - loading...\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sLoadingRecords\": \"加载中…\",\n\n\n\t\t\t/**\n\t\t\t * Text which is displayed when the table is processing a user action\n\t\t\t * (usually a sort command or similar).\n\t\t\t *  @type string\n\t\t\t *  @default Processing...\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.processing\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"processing\": \"DataTables is currently busy\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sProcessing\": \"处理中…\",\n\n\n\t\t\t/**\n\t\t\t * Details the actions that will be taken when the user types into the\n\t\t\t * filtering input text box. The variable \"_INPUT_\", if used in the string,\n\t\t\t * is replaced with the HTML text box for the filtering input allowing\n\t\t\t * control over where it appears in the string. If \"_INPUT_\" is not given\n\t\t\t * then the input box is appended to the string automatically.\n\t\t\t *  @type string\n\t\t\t *  @default Search:\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.search\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Input text box will be appended at the end automatically\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Filter records:\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Specify where the filter should appear\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"search\": \"Apply filter _INPUT_ to table\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sSearch\": \"查找：\",\n\n\n\t\t\t/**\n\t\t\t * All of the language information can be stored in a file on the\n\t\t\t * server-side, which DataTables will look up if this parameter is passed.\n\t\t\t * It must store the URL of the language file, which is in a JSON format,\n\t\t\t * and the object has the same properties as the oLanguage object in the\n\t\t\t * initialiser object (i.e. the above parameters). Please refer to one of\n\t\t\t * the example language files to see how this works in action.\n\t\t\t *  @type string\n\t\t\t *  @default <i>Empty string - i.e. disabled</i>\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.url\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"url\": \"http://www.sprymedia.co.uk/dataTables/lang.txt\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sUrl\": \"\",\n\n\n\t\t\t/**\n\t\t\t * Text shown inside the table records when the is no information to be\n\t\t\t * displayed after filtering. `emptyTable` is shown when there is simply no\n\t\t\t * information in the table at all (regardless of filtering).\n\t\t\t *  @type string\n\t\t\t *  @default No matching records found\n\t\t\t *\n\t\t\t *  @dtopt Language\n\t\t\t *  @name DataTable.defaults.language.zeroRecords\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $(document).ready( function() {\n\t\t\t *      $('#example').dataTable( {\n\t\t\t *        \"language\": {\n\t\t\t *          \"zeroRecords\": \"No records to display\"\n\t\t\t *        }\n\t\t\t *      } );\n\t\t\t *    } );\n\t\t\t */\n\t\t\t\"sZeroRecords\": \"没有找到符合条件的记录\"\n\t\t},\n\n\n\t\t/**\n\t\t * This parameter allows you to have define the global filtering state at\n\t\t * initialisation time. As an object the `search` parameter must be\n\t\t * defined, but all other parameters are optional. When `regex` is true,\n\t\t * the search string will be treated as a regular expression, when false\n\t\t * (default) it will be treated as a straight string. When `smart`\n\t\t * DataTables will use it's smart filtering methods (to word match at\n\t\t * any point in the data), when false this will not be done.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.search\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"search\": {\"search\": \"Initial search\"}\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"oSearch\": $.extend( {}, DataTable.models.oSearch ),\n\n\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * By default DataTables will look for the property `data` (or `aaData` for\n\t\t * compatibility with DataTables 1.9-) when obtaining data from an Ajax\n\t\t * source or for server-side processing - this parameter allows that\n\t\t * property to be changed. You can use Javascript dotted object notation to\n\t\t * get a data source for multiple levels of nesting.\n\t\t *  @type string\n\t\t *  @default data\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxDataProp\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxDataProp\": \"data\",\n\n\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * You can instruct DataTables to load data from an external\n\t\t * source using this parameter (use aData if you want to pass data in you\n\t\t * already have). Simply provide a url a JSON object can be obtained from.\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.ajaxSource\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sAjaxSource\": null,\n\n\n\t\t/**\n\t\t * This initialisation variable allows you to specify exactly where in the\n\t\t * DOM you want DataTables to inject the various controls it adds to the page\n\t\t * (for example you might want the pagination controls at the top of the\n\t\t * table). DIV elements (with or without a custom class) can also be added to\n\t\t * aid styling. The follow syntax is used:\n\t\t *   <ul>\n\t\t *     <li>The following options are allowed:\n\t\t *       <ul>\n\t\t *         <li>'l' - Length changing</li>\n\t\t *         <li>'f' - Filtering input</li>\n\t\t *         <li>'t' - The table!</li>\n\t\t *         <li>'i' - Information</li>\n\t\t *         <li>'p' - Pagination</li>\n\t\t *         <li>'r' - pRocessing</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following constants are allowed:\n\t\t *       <ul>\n\t\t *         <li>'H' - jQueryUI theme \"header\" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>\n\t\t *         <li>'F' - jQueryUI theme \"footer\" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>The following syntax is expected:\n\t\t *       <ul>\n\t\t *         <li>'&lt;' and '&gt;' - div elements</li>\n\t\t *         <li>'&lt;\"class\" and '&gt;' - div with a class</li>\n\t\t *         <li>'&lt;\"#id\" and '&gt;' - div with an ID</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *     <li>Examples:\n\t\t *       <ul>\n\t\t *         <li>'&lt;\"wrapper\"flipt&gt;'</li>\n\t\t *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>\n\t\t *       </ul>\n\t\t *     </li>\n\t\t *   </ul>\n\t\t *  @type string\n\t\t *  @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>\n\t\t *    <\"H\"lfr>t<\"F\"ip> <i>(when `jQueryUI` is true)</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.dom\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"dom\": '&lt;\"top\"i&gt;rt&lt;\"bottom\"flp&gt;&lt;\"clear\"&gt;'\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDom\": \"lfrtip\",\n\n\n\t\t/**\n\t\t * DataTables features four different built-in options for the buttons to\n\t\t * display for pagination control:\n\t\t *\n\t\t * * `simple` - 'Previous' and 'Next' buttons only\n\t\t * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers\n\t\t * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons\n\t\t * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus\n\t\t *   page numbers\n\t\t *\n\t\t * Further methods can be added using {@link DataTable.ext.oPagination}.\n\t\t *  @type string\n\t\t *  @default simple_numbers\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.pagingType\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"pagingType\": \"full_numbers\"\n\t\t *      } );\n\t\t *    } )\n\t\t */\n\t\t\"sPaginationType\": \"simple_numbers\",\n\n\n\t\t/**\n\t\t * Enable horizontal scrolling. When a table is too wide to fit into a\n\t\t * certain layout, or you have a large number of columns in the table, you\n\t\t * can enable x-scrolling to show the table in a viewport, which can be\n\t\t * scrolled. This property can be `true` which will allow the table to\n\t\t * scroll horizontally when needed, or any CSS unit, or a number (in which\n\t\t * case it will be treated as a pixel measurement). Setting as simply `true`\n\t\t * is recommended.\n\t\t *  @type boolean|string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollX\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": true,\n\t\t *        \"scrollCollapse\": true\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollX\": \"\",\n\n\n\t\t/**\n\t\t * This property can be used to force a DataTable to use more width than it\n\t\t * might otherwise do when x-scrolling is enabled. For example if you have a\n\t\t * table which requires to be well spaced, this parameter is useful for\n\t\t * \"over-sizing\" the table, and thus forcing scrolling. This property can by\n\t\t * any CSS unit, or a number (in which case it will be treated as a pixel\n\t\t * measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @name DataTable.defaults.scrollXInner\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollX\": \"100%\",\n\t\t *        \"scrollXInner\": \"110%\"\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollXInner\": \"\",\n\n\n\t\t/**\n\t\t * Enable vertical scrolling. Vertical scrolling will constrain the DataTable\n\t\t * to the given height, and enable scrolling for any data which overflows the\n\t\t * current viewport. This can be used as an alternative to paging to display\n\t\t * a lot of data in a small area (although paging and scrolling can both be\n\t\t * enabled at the same time). This property can be any CSS unit, or a number\n\t\t * (in which case it will be treated as a pixel measurement).\n\t\t *  @type string\n\t\t *  @default <i>blank string - i.e. disabled</i>\n\t\t *\n\t\t *  @dtopt Features\n\t\t *  @name DataTable.defaults.scrollY\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"scrollY\": \"200px\",\n\t\t *        \"paginate\": false\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sScrollY\": \"\",\n\n\n\t\t/**\n\t\t * __Deprecated__ The functionality provided by this parameter has now been\n\t\t * superseded by that provided through `ajax`, which should be used instead.\n\t\t *\n\t\t * Set the HTTP method that is used to make the Ajax call for server-side\n\t\t * processing or Ajax sourced data.\n\t\t *  @type string\n\t\t *  @default GET\n\t\t *\n\t\t *  @dtopt Options\n\t\t *  @dtopt Server-side\n\t\t *  @name DataTable.defaults.serverMethod\n\t\t *\n\t\t *  @deprecated 1.10. Please use `ajax` for this functionality now.\n\t\t */\n\t\t\"sServerMethod\": \"GET\",\n\n\n\t\t/**\n\t\t * DataTables makes use of renderers when displaying HTML elements for\n\t\t * a table. These renderers can be added or modified by plug-ins to\n\t\t * generate suitable mark-up for a site. For example the Bootstrap\n\t\t * integration plug-in for DataTables uses a paging button renderer to\n\t\t * display pagination buttons in the mark-up required by Bootstrap.\n\t\t *\n\t\t * For further information about the renderers available see\n\t\t * DataTable.ext.renderer\n\t\t *  @type string|object\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.renderer\n\t\t *\n\t\t */\n\t\t\"renderer\": null\n\t};\n\n\t_fnHungarianMap( DataTable.defaults );\n\n\n\n\t/*\n\t * Developer note - See note in model.defaults.js about the use of Hungarian\n\t * notation and camel case.\n\t */\n\n\t/**\n\t * Column options that can be given to DataTables at initialisation time.\n\t *  @namespace\n\t */\n\tDataTable.defaults.column = {\n\t\t/**\n\t\t * Define which column(s) an order will occur on for this column. This\n\t\t * allows a column's ordering to take multiple columns into account when\n\t\t * doing a sort or use the data from a different column. For example first\n\t\t * name / last name columns make sense to do a multi-column sort over the\n\t\t * two columns.\n\t\t *  @type array|int\n\t\t *  @default null <i>Takes the value of the column index automatically</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderData\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderData\": [ 0, 1 ], \"targets\": [ 0 ] },\n\t\t *          { \"orderData\": [ 1, 0 ], \"targets\": [ 1 ] },\n\t\t *          { \"orderData\": 2, \"targets\": [ 2 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderData\": [ 0, 1 ] },\n\t\t *          { \"orderData\": [ 1, 0 ] },\n\t\t *          { \"orderData\": 2 },\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"aDataSort\": null,\n\t\t\"iDataSort\": -1,\n\n\n\t\t/**\n\t\t * You can control the default ordering direction, and even alter the\n\t\t * behaviour of the sort handler (i.e. only allow ascending ordering etc)\n\t\t * using this parameter.\n\t\t *  @type array\n\t\t *  @default [ 'asc', 'desc' ]\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderSequence\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderSequence\": [ \"asc\" ], \"targets\": [ 1 ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ], \"targets\": [ 2 ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ], \"targets\": [ 3 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          { \"orderSequence\": [ \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\", \"asc\", \"asc\" ] },\n\t\t *          { \"orderSequence\": [ \"desc\" ] },\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"asSorting\": [ 'asc', 'desc' ],\n\n\n\t\t/**\n\t\t * Enable or disable filtering on the data in this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.searchable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"searchable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"searchable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSearchable\": true,\n\n\n\t\t/**\n\t\t * Enable or disable ordering on this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderable\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderable\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"orderable\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bSortable\": true,\n\n\n\t\t/**\n\t\t * Enable or disable the display of this column.\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t *\n\t\t *  @name DataTable.defaults.column.visible\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"visible\": false, \"targets\": [ 0 ] }\n\t\t *        ] } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"visible\": false },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ] } );\n\t\t *    } );\n\t\t */\n\t\t\"bVisible\": true,\n\n\n\t\t/**\n\t\t * Developer definable function that is called whenever a cell is created (Ajax source,\n\t\t * etc) or processed for input (DOM source). This can be used as a compliment to mRender\n\t\t * allowing you to modify the DOM element (add background colour for example) when the\n\t\t * element is available.\n\t\t *  @type function\n\t\t *  @param {element} td The TD node that has been created\n\t\t *  @param {*} cellData The Data for the cell\n\t\t *  @param {array|object} rowData The data for the whole row\n\t\t *  @param {int} row The row index for the aoData data store\n\t\t *  @param {int} col The column index for aoColumns\n\t\t *\n\t\t *  @name DataTable.defaults.column.createdCell\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [3],\n\t\t *          \"createdCell\": function (td, cellData, rowData, row, col) {\n\t\t *            if ( cellData == \"1.7\" ) {\n\t\t *              $(td).css('color', 'blue')\n\t\t *            }\n\t\t *          }\n\t\t *        } ]\n\t\t *      });\n\t\t *    } );\n\t\t */\n\t\t\"fnCreatedCell\": null,\n\n\n\t\t/**\n\t\t * This parameter has been replaced by `data` in DataTables to ensure naming\n\t\t * consistency. `dataProp` can still be used, as there is backwards\n\t\t * compatibility in DataTables for this option, but it is strongly\n\t\t * recommended that you use `data` in preference to `dataProp`.\n\t\t *  @name DataTable.defaults.column.dataProp\n\t\t */\n\n\n\t\t/**\n\t\t * This property can be used to read data from any data source property,\n\t\t * including deeply nested objects / properties. `data` can be given in a\n\t\t * number of different ways which effect its behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object. Note that\n\t\t *      function notation is recommended for use in `render` rather than\n\t\t *      `data` as it is much simpler to use as a renderer.\n\t\t * * `null` - use the original data source for the row rather than plucking\n\t\t *   data directly from it. This action has effects on two other\n\t\t *   initialisation options:\n\t\t *    * `defaultContent` - When null is given as the `data` option and\n\t\t *      `defaultContent` is specified for the column, the value defined by\n\t\t *      `defaultContent` will be used for the cell.\n\t\t *    * `render` - When null is used for the `data` option and the `render`\n\t\t *      option is specified for the column, the whole data source for the\n\t\t *      row is used for the renderer.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * `{array|object}` The data source for the row\n\t\t *      * `{string}` The type call data requested - this will be 'set' when\n\t\t *        setting data or 'filter', 'display', 'type', 'sort' or undefined\n\t\t *        when gathering data. Note that when `undefined` is given for the\n\t\t *        type DataTables expects to get the raw data for the object back<\n\t\t *      * `{*}` Data to set when the second parameter is 'set'.\n\t\t *    * Return:\n\t\t *      * The return value from the function is not required when 'set' is\n\t\t *        the type of call, but otherwise the return is what will be used\n\t\t *        for the data requested.\n\t\t *\n\t\t * Note that `data` is a getter and setter option. If you just require\n\t\t * formatting of data for output, you will likely want to use `render` which\n\t\t * is simply a getter and thus simpler to use.\n\t\t *\n\t\t * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The\n\t\t * name change reflects the flexibility of this property and is consistent\n\t\t * with the naming of mRender. If 'mDataProp' is given, then it will still\n\t\t * be used by DataTables, as it automatically maps the old name to the new\n\t\t * if required.\n\t\t *\n\t\t *  @type string|int|function|null\n\t\t *  @default null <i>Use automatically calculated column index</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.data\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Read table data from objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {value},\n\t\t *    //      \"version\": {value},\n\t\t *    //      \"grade\": {value}\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/objects.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform\" },\n\t\t *          { \"data\": \"version\" },\n\t\t *          { \"data\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Read information from deeply nested objects\n\t\t *    // JSON structure for each row:\n\t\t *    //   {\n\t\t *    //      \"engine\": {value},\n\t\t *    //      \"browser\": {value},\n\t\t *    //      \"platform\": {\n\t\t *    //         \"inner\": {value}\n\t\t *    //      },\n\t\t *    //      \"details\": [\n\t\t *    //         {value}, {value}\n\t\t *    //      ]\n\t\t *    //   }\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          { \"data\": \"platform.inner\" },\n\t\t *          { \"data\": \"platform.details.0\" },\n\t\t *          { \"data\": \"platform.details.1\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `data` as a function to provide different information for\n\t\t *    // sorting, filtering and display. In this case, currency (price)\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": function ( source, type, val ) {\n\t\t *            if (type === 'set') {\n\t\t *              source.price = val;\n\t\t *              // Store the computed dislay and filter values for efficiency\n\t\t *              source.price_display = val==\"\" ? \"\" : \"$\"+numberFormat(val);\n\t\t *              source.price_filter  = val==\"\" ? \"\" : \"$\"+numberFormat(val)+\" \"+val;\n\t\t *              return;\n\t\t *            }\n\t\t *            else if (type === 'display') {\n\t\t *              return source.price_display;\n\t\t *            }\n\t\t *            else if (type === 'filter') {\n\t\t *              return source.price_filter;\n\t\t *            }\n\t\t *            // 'sort', 'type' and undefined all just use the integer\n\t\t *            return source.price;\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using default content\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null,\n\t\t *          \"defaultContent\": \"Click to edit\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using array notation - outputting a list from an array\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"name[, ]\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t */\n\t\t\"mData\": null,\n\n\n\t\t/**\n\t\t * This property is the rendering partner to `data` and it is suggested that\n\t\t * when you want to manipulate data for display (including filtering,\n\t\t * sorting etc) without altering the underlying data for the table, use this\n\t\t * property. `render` can be considered to be the the read only companion to\n\t\t * `data` which is read / write (then as such more complex). Like `data`\n\t\t * this option can be given in a number of different ways to effect its\n\t\t * behaviour:\n\t\t *\n\t\t * * `integer` - treated as an array index for the data source. This is the\n\t\t *   default that DataTables uses (incrementally increased for each column).\n\t\t * * `string` - read an object property from the data source. There are\n\t\t *   three 'special' options that can be used in the string to alter how\n\t\t *   DataTables reads the data from the source object:\n\t\t *    * `.` - Dotted Javascript notation. Just as you use a `.` in\n\t\t *      Javascript to read from nested objects, so to can the options\n\t\t *      specified in `data`. For example: `browser.version` or\n\t\t *      `browser.name`. If your object parameter name contains a period, use\n\t\t *      `\\\\` to escape it - i.e. `first\\\\.name`.\n\t\t *    * `[]` - Array notation. DataTables can automatically combine data\n\t\t *      from and array source, joining the data with the characters provided\n\t\t *      between the two brackets. For example: `name[, ]` would provide a\n\t\t *      comma-space separated list from the source array. If no characters\n\t\t *      are provided between the brackets, the original array source is\n\t\t *      returned.\n\t\t *    * `()` - Function notation. Adding `()` to the end of a parameter will\n\t\t *      execute a function of the name given. For example: `browser()` for a\n\t\t *      simple function on the data source, `browser.version()` for a\n\t\t *      function in a nested property or even `browser().version` to get an\n\t\t *      object property if the function called returns an object.\n\t\t * * `object` - use different data for the different data types requested by\n\t\t *   DataTables ('filter', 'display', 'type' or 'sort'). The property names\n\t\t *   of the object is the data type the property refers to and the value can\n\t\t *   defined using an integer, string or function using the same rules as\n\t\t *   `render` normally does. Note that an `_` option _must_ be specified.\n\t\t *   This is the default value to use if you haven't specified a value for\n\t\t *   the data type requested by DataTables.\n\t\t * * `function` - the function given will be executed whenever DataTables\n\t\t *   needs to set or get the data for a cell in the column. The function\n\t\t *   takes three parameters:\n\t\t *    * Parameters:\n\t\t *      * {array|object} The data source for the row (based on `data`)\n\t\t *      * {string} The type call data requested - this will be 'filter',\n\t\t *        'display', 'type' or 'sort'.\n\t\t *      * {array|object} The full data source for the row (not based on\n\t\t *        `data`)\n\t\t *    * Return:\n\t\t *      * The return value from the function is what will be used for the\n\t\t *        data requested.\n\t\t *\n\t\t *  @type string|int|function|object|null\n\t\t *  @default null Use the data source value.\n\t\t *\n\t\t *  @name DataTable.defaults.column.render\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Create a comma separated list from an array of objects\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"ajaxSource\": \"sources/deep.txt\",\n\t\t *        \"columns\": [\n\t\t *          { \"data\": \"engine\" },\n\t\t *          { \"data\": \"browser\" },\n\t\t *          {\n\t\t *            \"data\": \"platform\",\n\t\t *            \"render\": \"[, ].name\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Execute a function to obtain data\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": \"browserName()\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // As an object, extracting different data for the different types\n\t\t *    // This would be used with a data source such as:\n\t\t *    //   { \"phone\": 5552368, \"phone_filter\": \"5552368 555-2368\", \"phone_display\": \"555-2368\" }\n\t\t *    // Here the `phone` integer is used for sorting and type detection, while `phone_filter`\n\t\t *    // (which has both forms) is used for filtering for if a user inputs either format, while\n\t\t *    // the formatted phone number is the one that is shown in the table.\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": null, // Use the full data source object for the renderer's source\n\t\t *          \"render\": {\n\t\t *            \"_\": \"phone\",\n\t\t *            \"filter\": \"phone_filter\",\n\t\t *            \"display\": \"phone_display\"\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Use as a function to create a link from the data source\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"data\": \"download_link\",\n\t\t *          \"render\": function ( data, type, full ) {\n\t\t *            return '<a href=\"'+data+'\">Download</a>';\n\t\t *          }\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"mRender\": null,\n\n\n\t\t/**\n\t\t * Change the cell type created for the column - either TD cells or TH cells. This\n\t\t * can be useful as TH cells have semantic meaning in the table body, allowing them\n\t\t * to act as a header for a row (you may wish to add scope='row' to the TH elements).\n\t\t *  @type string\n\t\t *  @default td\n\t\t *\n\t\t *  @name DataTable.defaults.column.cellType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Make the first column use TH cells\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [ {\n\t\t *          \"targets\": [ 0 ],\n\t\t *          \"cellType\": \"th\"\n\t\t *        } ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sCellType\": \"td\",\n\n\n\t\t/**\n\t\t * Class to give to each cell in this column.\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.class\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"class\": \"my_class\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"class\": \"my_class\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sClass\": \"\",\n\n\t\t/**\n\t\t * When DataTables calculates the column widths to assign to each column,\n\t\t * it finds the longest string in each column and then constructs a\n\t\t * temporary table and reads the widths from that. The problem with this\n\t\t * is that \"mmm\" is much wider then \"iiii\", but the latter is a longer\n\t\t * string - thus the calculation can go wrong (doing it properly and putting\n\t\t * it into an DOM object and measuring that is horribly(!) slow). Thus as\n\t\t * a \"work around\" we provide this option. It will append its value to the\n\t\t * text that is found to be the longest string for the column - i.e. padding.\n\t\t * Generally you shouldn't need this!\n\t\t *  @type string\n\t\t *  @default <i>Empty string<i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.contentPadding\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"contentPadding\": \"mmm\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sContentPadding\": \"\",\n\n\n\t\t/**\n\t\t * Allows a default value to be given for a column's data, and will be used\n\t\t * whenever a null data source is encountered (this can be because `data`\n\t\t * is set to null, or because the data source itself is null).\n\t\t *  @type string\n\t\t *  @default null\n\t\t *\n\t\t *  @name DataTable.defaults.column.defaultContent\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\",\n\t\t *            \"targets\": [ -1 ]\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          {\n\t\t *            \"data\": null,\n\t\t *            \"defaultContent\": \"Edit\"\n\t\t *          }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sDefaultContent\": null,\n\n\n\t\t/**\n\t\t * This parameter is only used in DataTables' server-side processing. It can\n\t\t * be exceptionally useful to know what columns are being displayed on the\n\t\t * client side, and to map these to database fields. When defined, the names\n\t\t * also allow DataTables to reorder information from the server if it comes\n\t\t * back in an unexpected order (i.e. if you switch your columns around on the\n\t\t * client-side, your server-side code does not also need updating).\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.name\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"name\": \"engine\", \"targets\": [ 0 ] },\n\t\t *          { \"name\": \"browser\", \"targets\": [ 1 ] },\n\t\t *          { \"name\": \"platform\", \"targets\": [ 2 ] },\n\t\t *          { \"name\": \"version\", \"targets\": [ 3 ] },\n\t\t *          { \"name\": \"grade\", \"targets\": [ 4 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"name\": \"engine\" },\n\t\t *          { \"name\": \"browser\" },\n\t\t *          { \"name\": \"platform\" },\n\t\t *          { \"name\": \"version\" },\n\t\t *          { \"name\": \"grade\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sName\": \"\",\n\n\n\t\t/**\n\t\t * Defines a data source type for the ordering which can be used to read\n\t\t * real-time information from the table (updating the internally cached\n\t\t * version) prior to ordering. This allows ordering to occur on user\n\t\t * editable elements such as form inputs.\n\t\t *  @type string\n\t\t *  @default std\n\t\t *\n\t\t *  @name DataTable.defaults.column.orderDataType\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"orderDataType\": \"dom-text\", \"targets\": [ 2, 3 ] },\n\t\t *          { \"type\": \"numeric\", \"targets\": [ 3 ] },\n\t\t *          { \"orderDataType\": \"dom-select\", \"targets\": [ 4 ] },\n\t\t *          { \"orderDataType\": \"dom-checkbox\", \"targets\": [ 5 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          null,\n\t\t *          null,\n\t\t *          { \"orderDataType\": \"dom-text\" },\n\t\t *          { \"orderDataType\": \"dom-text\", \"type\": \"numeric\" },\n\t\t *          { \"orderDataType\": \"dom-select\" },\n\t\t *          { \"orderDataType\": \"dom-checkbox\" }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sSortDataType\": \"std\",\n\n\n\t\t/**\n\t\t * The title of this column.\n\t\t *  @type string\n\t\t *  @default null <i>Derived from the 'TH' value for this column in the\n\t\t *    original HTML table.</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.title\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"title\": \"My column title\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"title\": \"My column title\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sTitle\": null,\n\n\n\t\t/**\n\t\t * The type allows you to specify how the data for this column will be\n\t\t * ordered. Four types (string, numeric, date and html (which will strip\n\t\t * HTML tags before ordering)) are currently available. Note that only date\n\t\t * formats understood by Javascript's Date() object will be accepted as type\n\t\t * date. For example: \"Mar 26, 2008 5:03 PM\". May take the values: 'string',\n\t\t * 'numeric', 'date' or 'html' (by default). Further types can be adding\n\t\t * through plug-ins.\n\t\t *  @type string\n\t\t *  @default null <i>Auto-detected from raw data</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.type\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"type\": \"html\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"type\": \"html\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sType\": null,\n\n\n\t\t/**\n\t\t * Defining the width of the column, this parameter may take any CSS value\n\t\t * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not\n\t\t * been given a specific width through this interface ensuring that the table\n\t\t * remains readable.\n\t\t *  @type string\n\t\t *  @default null <i>Automatic</i>\n\t\t *\n\t\t *  @name DataTable.defaults.column.width\n\t\t *  @dtopt Columns\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columnDefs`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columnDefs\": [\n\t\t *          { \"width\": \"20%\", \"targets\": [ 0 ] }\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t *\n\t\t *  @example\n\t\t *    // Using `columns`\n\t\t *    $(document).ready( function() {\n\t\t *      $('#example').dataTable( {\n\t\t *        \"columns\": [\n\t\t *          { \"width\": \"20%\" },\n\t\t *          null,\n\t\t *          null,\n\t\t *          null,\n\t\t *          null\n\t\t *        ]\n\t\t *      } );\n\t\t *    } );\n\t\t */\n\t\t\"sWidth\": null\n\t};\n\n\t_fnHungarianMap( DataTable.defaults.column );\n\n\n\n\t/**\n\t * DataTables settings object - this holds all the information needed for a\n\t * given table, including configuration, data and current application of the\n\t * table options. DataTables does not have a single instance for each DataTable\n\t * with the settings attached to that instance, but rather instances of the\n\t * DataTable \"class\" are created on-the-fly as needed (typically by a\n\t * $().dataTable() call) and the settings object is then applied to that\n\t * instance.\n\t *\n\t * Note that this object is related to {@link DataTable.defaults} but this\n\t * one is the internal data store for DataTables's cache of columns. It should\n\t * NOT be manipulated outside of DataTables. Any configuration should be done\n\t * through the initialisation options.\n\t *  @namespace\n\t *  @todo Really should attach the settings object to individual instances so we\n\t *    don't need to create new instances on each $().dataTable() call (if the\n\t *    table already exists). It would also save passing oSettings around and\n\t *    into every single function. However, this is a very significant\n\t *    architecture change for DataTables and will almost certainly break\n\t *    backwards compatibility with older installations. This is something that\n\t *    will be done in 2.0.\n\t */\n\tDataTable.models.oSettings = {\n\t\t/**\n\t\t * Primary features of DataTables and their enablement state.\n\t\t *  @namespace\n\t\t */\n\t\t\"oFeatures\": {\n\n\t\t\t/**\n\t\t\t * Flag to say if DataTables should automatically try to calculate the\n\t\t\t * optimum table and columns widths (true) or not (false).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bAutoWidth\": null,\n\n\t\t\t/**\n\t\t\t * Delay the creation of TR and TD elements until they are actually\n\t\t\t * needed by a driven page draw. This can give a significant speed\n\t\t\t * increase for Ajax source and Javascript source data, but makes no\n\t\t\t * difference at all fro DOM and server-side processing tables.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bDeferRender\": null,\n\n\t\t\t/**\n\t\t\t * Enable filtering on the table or not. Note that if this is disabled\n\t\t\t * then there is no filtering at all on the table, including fnFilter.\n\t\t\t * To just remove the filtering input use sDom and remove the 'f' option.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bFilter\": null,\n\n\t\t\t/**\n\t\t\t * Table information element (the 'Showing x of y records' div) enable\n\t\t\t * flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bInfo\": null,\n\n\t\t\t/**\n\t\t\t * Present a user control allowing the end user to change the page size\n\t\t\t * when pagination is enabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bLengthChange\": null,\n\n\t\t\t/**\n\t\t\t * Pagination enabled or not. Note that if this is disabled then length\n\t\t\t * changing must also be disabled.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bPaginate\": null,\n\n\t\t\t/**\n\t\t\t * Processing indicator enable flag whenever DataTables is enacting a\n\t\t\t * user request - typically an Ajax request for server-side processing.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bProcessing\": null,\n\n\t\t\t/**\n\t\t\t * Server-side processing enabled flag - when enabled DataTables will\n\t\t\t * get all data from the server for every draw - there is no filtering,\n\t\t\t * sorting or paging done on the client-side.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bServerSide\": null,\n\n\t\t\t/**\n\t\t\t * Sorting enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSort\": null,\n\n\t\t\t/**\n\t\t\t * Multi-column sorting\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortMulti\": null,\n\n\t\t\t/**\n\t\t\t * Apply a class to the columns which are being sorted to provide a\n\t\t\t * visual highlight or not. This can slow things down when enabled since\n\t\t\t * there is a lot of DOM interaction.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bSortClasses\": null,\n\n\t\t\t/**\n\t\t\t * State saving enablement flag.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bStateSave\": null\n\t\t},\n\n\n\t\t/**\n\t\t * Scrolling settings for a table.\n\t\t *  @namespace\n\t\t */\n\t\t\"oScroll\": {\n\t\t\t/**\n\t\t\t * When the table is shorter in height than sScrollY, collapse the\n\t\t\t * table container down to the height of the table (when true).\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type boolean\n\t\t\t */\n\t\t\t\"bCollapse\": null,\n\n\t\t\t/**\n\t\t\t * Width of the scrollbar for the web-browser's platform. Calculated\n\t\t\t * during table initialisation.\n\t\t\t *  @type int\n\t\t\t *  @default 0\n\t\t\t */\n\t\t\t\"iBarWidth\": 0,\n\n\t\t\t/**\n\t\t\t * Viewport width for horizontal scrolling. Horizontal scrolling is\n\t\t\t * disabled if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sX\": null,\n\n\t\t\t/**\n\t\t\t * Width to expand the table to when using x-scrolling. Typically you\n\t\t\t * should not need to use this.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t *  @deprecated\n\t\t\t */\n\t\t\t\"sXInner\": null,\n\n\t\t\t/**\n\t\t\t * Viewport height for vertical scrolling. Vertical scrolling is disabled\n\t\t\t * if an empty string.\n\t\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t\t * set a default use {@link DataTable.defaults}.\n\t\t\t *  @type string\n\t\t\t */\n\t\t\t\"sY\": null\n\t\t},\n\n\t\t/**\n\t\t * Language information for the table.\n\t\t *  @namespace\n\t\t *  @extends DataTable.defaults.oLanguage\n\t\t */\n\t\t\"oLanguage\": {\n\t\t\t/**\n\t\t\t * Information callback function. See\n\t\t\t * {@link DataTable.defaults.fnInfoCallback}\n\t\t\t *  @type function\n\t\t\t *  @default null\n\t\t\t */\n\t\t\t\"fnInfoCallback\": null\n\t\t},\n\n\t\t/**\n\t\t * Browser support parameters\n\t\t *  @namespace\n\t\t */\n\t\t\"oBrowser\": {\n\t\t\t/**\n\t\t\t * Indicate if the browser incorrectly calculates width:100% inside a\n\t\t\t * scrolling element (IE6/7)\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollOversize\": false,\n\n\t\t\t/**\n\t\t\t * Determine if the vertical scrollbar is on the right or left of the\n\t\t\t * scrolling container - needed for rtl language layout, although not\n\t\t\t * all browsers move the scrollbar (Safari).\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\t\"bScrollbarLeft\": false\n\t\t},\n\n\n\t\t\"ajax\": null,\n\n\n\t\t/**\n\t\t * Array referencing the nodes which are used for the features. The\n\t\t * parameters of this object match what is allowed by sDom - i.e.\n\t\t *   <ul>\n\t\t *     <li>'l' - Length changing</li>\n\t\t *     <li>'f' - Filtering input</li>\n\t\t *     <li>'t' - The table!</li>\n\t\t *     <li>'i' - Information</li>\n\t\t *     <li>'p' - Pagination</li>\n\t\t *     <li>'r' - pRocessing</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aanFeatures\": [],\n\n\t\t/**\n\t\t * Store data information - see {@link DataTable.models.oRow} for detailed\n\t\t * information.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoData\": [],\n\n\t\t/**\n\t\t * Array of indexes which are in the current display (after filtering etc)\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplay\": [],\n\n\t\t/**\n\t\t * Array of indexes for display - no filtering\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aiDisplayMaster\": [],\n\n\t\t/**\n\t\t * Store information about each column that is in use\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoColumns\": [],\n\n\t\t/**\n\t\t * Store information about the table's header\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeader\": [],\n\n\t\t/**\n\t\t * Store information about the table's footer\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooter\": [],\n\n\t\t/**\n\t\t * Store the applied global search information in case we want to force a\n\t\t * research or compare the old search to a new one.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @namespace\n\t\t *  @extends DataTable.models.oSearch\n\t\t */\n\t\t\"oPreviousSearch\": {},\n\n\t\t/**\n\t\t * Store the applied search for each column - see\n\t\t * {@link DataTable.models.oSearch} for the format that is used for the\n\t\t * filtering information for each column.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreSearchCols\": [],\n\n\t\t/**\n\t\t * Sorting that is applied to the table. Note that the inner arrays are\n\t\t * used in the following manner:\n\t\t * <ul>\n\t\t *   <li>Index 0 - column number</li>\n\t\t *   <li>Index 1 - current sorting direction</li>\n\t\t * </ul>\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @todo These inner arrays should really be objects\n\t\t */\n\t\t\"aaSorting\": null,\n\n\t\t/**\n\t\t * Sorting that is always applied to the table (i.e. prefixed in front of\n\t\t * aaSorting).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aaSortingFixed\": [],\n\n\t\t/**\n\t\t * Classes to use for the striping of a table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asStripeClasses\": null,\n\n\t\t/**\n\t\t * If restoring a table - we should restore its striping classes as well\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"asDestroyStripes\": [],\n\n\t\t/**\n\t\t * If restoring a table - we should restore its width\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"sDestroyWidth\": 0,\n\n\t\t/**\n\t\t * Callback functions array for every time a row is inserted (i.e. on a draw).\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCallback\": [],\n\n\t\t/**\n\t\t * Callback functions for the header on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoHeaderCallback\": [],\n\n\t\t/**\n\t\t * Callback function for the footer on each draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoFooterCallback\": [],\n\n\t\t/**\n\t\t * Array of callback functions for draw callback functions\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDrawCallback\": [],\n\n\t\t/**\n\t\t * Array of callback functions for row created function\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoRowCreatedCallback\": [],\n\n\t\t/**\n\t\t * Callback functions for just before the table is redrawn. A return of\n\t\t * false will be used to cancel the draw.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoPreDrawCallback\": [],\n\n\t\t/**\n\t\t * Callback functions for when the table has been initialised.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoInitComplete\": [],\n\n\n\t\t/**\n\t\t * Callbacks for modifying the settings to be stored for state saving, prior to\n\t\t * saving state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSaveParams\": [],\n\n\t\t/**\n\t\t * Callbacks for modifying the settings that have been stored for state saving\n\t\t * prior to using the stored values to restore the state.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoadParams\": [],\n\n\t\t/**\n\t\t * Callbacks for operating on the settings object once the saved state has been\n\t\t * loaded\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoaded\": [],\n\n\t\t/**\n\t\t * Cache the table ID for quick access\n\t\t *  @type string\n\t\t *  @default <i>Empty string</i>\n\t\t */\n\t\t\"sTableId\": \"\",\n\n\t\t/**\n\t\t * The TABLE node for the main table\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTable\": null,\n\n\t\t/**\n\t\t * Permanent ref to the thead element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTHead\": null,\n\n\t\t/**\n\t\t * Permanent ref to the tfoot element - if it exists\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTFoot\": null,\n\n\t\t/**\n\t\t * Permanent ref to the tbody element\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTBody\": null,\n\n\t\t/**\n\t\t * Cache the wrapper node (contains all DataTables controlled elements)\n\t\t *  @type node\n\t\t *  @default null\n\t\t */\n\t\t\"nTableWrapper\": null,\n\n\t\t/**\n\t\t * Indicate if when using server-side processing the loading of data\n\t\t * should be deferred until the second draw.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDeferLoading\": false,\n\n\t\t/**\n\t\t * Indicate if all required information has been read in\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bInitialised\": false,\n\n\t\t/**\n\t\t * Information about open rows. Each object in the array has the parameters\n\t\t * 'nTr' and 'nParent'\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoOpenRows\": [],\n\n\t\t/**\n\t\t * Dictate the positioning of DataTables' control elements - see\n\t\t * {@link DataTable.model.oInit.sDom}.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sDom\": null,\n\n\t\t/**\n\t\t * Which type of pagination should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default two_button\n\t\t */\n\t\t\"sPaginationType\": \"two_button\",\n\n\t\t/**\n\t\t * The state duration (for `stateSave`) in seconds.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iStateDuration\": 0,\n\n\t\t/**\n\t\t * Array of callback functions for state saving. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the JSON string to save that has been thus far created. Returns\n\t\t *       a JSON string to be inserted into a json object\n\t\t *       (i.e. '\"param\": [ 0, 1, 2]')</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateSave\": [],\n\n\t\t/**\n\t\t * Array of callback functions for state loading. Each array element is an\n\t\t * object with the following parameters:\n\t\t *   <ul>\n\t\t *     <li>function:fn - function to call. Takes two parameters, oSettings\n\t\t *       and the object stored. May return false to cancel state loading</li>\n\t\t *     <li>string:sName - name of callback</li>\n\t\t *   </ul>\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoStateLoad\": [],\n\n\t\t/**\n\t\t * State that was loaded. Useful for back reference\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oLoadedState\": null,\n\n\t\t/**\n\t\t * Source url for AJAX data for the table.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sAjaxSource\": null,\n\n\t\t/**\n\t\t * Property from a given object from which to read the table data from. This\n\t\t * can be an empty string (when not server-side processing), in which case\n\t\t * it is  assumed an an array is given directly.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sAjaxDataProp\": null,\n\n\t\t/**\n\t\t * Note if draw should be blocked while getting data\n\t\t *  @type boolean\n\t\t *  @default true\n\t\t */\n\t\t\"bAjaxDataGet\": true,\n\n\t\t/**\n\t\t * The last jQuery XHR object that was used for server-side data gathering.\n\t\t * This can be used for working with the XHR information in one of the\n\t\t * callbacks\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"jqXHR\": null,\n\n\t\t/**\n\t\t * JSON returned from the server in the last Ajax request\n\t\t *  @type object\n\t\t *  @default undefined\n\t\t */\n\t\t\"json\": undefined,\n\n\t\t/**\n\t\t * Function to get the server-side data.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnServerData\": null,\n\n\t\t/**\n\t\t * Functions which are called prior to sending an Ajax request so extra\n\t\t * parameters can easily be sent to the server\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoServerParams\": [],\n\n\t\t/**\n\t\t * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if\n\t\t * required).\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type string\n\t\t */\n\t\t\"sServerMethod\": null,\n\n\t\t/**\n\t\t * Format numbers for display.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type function\n\t\t */\n\t\t\"fnFormatNumber\": null,\n\n\t\t/**\n\t\t * List of options that can be used for the user selectable length menu.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLengthMenu\": null,\n\n\t\t/**\n\t\t * Counter for the draws that the table does. Also used as a tracker for\n\t\t * server-side processing\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"iDraw\": 0,\n\n\t\t/**\n\t\t * Indicate if a redraw is being done - useful for Ajax\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t */\n\t\t\"bDrawing\": false,\n\n\t\t/**\n\t\t * Draw index (iDraw) of the last error when parsing the returned data\n\t\t *  @type int\n\t\t *  @default -1\n\t\t */\n\t\t\"iDrawError\": -1,\n\n\t\t/**\n\t\t * Paging display length\n\t\t *  @type int\n\t\t *  @default 10\n\t\t */\n\t\t\"_iDisplayLength\": 10,\n\n\t\t/**\n\t\t * Paging start point - aiDisplay index\n\t\t *  @type int\n\t\t *  @default 0\n\t\t */\n\t\t\"_iDisplayStart\": 0,\n\n\t\t/**\n\t\t * Server-side processing - number of records in the result set\n\t\t * (i.e. before filtering), Use fnRecordsTotal rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type int\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsTotal\": 0,\n\n\t\t/**\n\t\t * Server-side processing - number of records in the current display set\n\t\t * (i.e. after filtering). Use fnRecordsDisplay rather than\n\t\t * this property to get the value of the number of records, regardless of\n\t\t * the server-side processing setting.\n\t\t *  @type boolean\n\t\t *  @default 0\n\t\t *  @private\n\t\t */\n\t\t\"_iRecordsDisplay\": 0,\n\n\t\t/**\n\t\t * Flag to indicate if jQuery UI marking and classes should be used.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bJUI\": null,\n\n\t\t/**\n\t\t * The classes to use for the table\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oClasses\": {},\n\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if filtering has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bFiltered\": false,\n\n\t\t/**\n\t\t * Flag attached to the settings object so you can check in the draw\n\t\t * callback if sorting has been done in the draw. Deprecated in favour of\n\t\t * events.\n\t\t *  @type boolean\n\t\t *  @default false\n\t\t *  @deprecated\n\t\t */\n\t\t\"bSorted\": false,\n\n\t\t/**\n\t\t * Indicate that if multiple rows are in the header and there is more than\n\t\t * one unique cell per column, if the top one (true) or bottom one (false)\n\t\t * should be used for sorting / title by DataTables.\n\t\t * Note that this parameter will be set by the initialisation routine. To\n\t\t * set a default use {@link DataTable.defaults}.\n\t\t *  @type boolean\n\t\t */\n\t\t\"bSortCellsTop\": null,\n\n\t\t/**\n\t\t * Initialisation object that is used for the table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInit\": null,\n\n\t\t/**\n\t\t * Destroy callback functions - for plug-ins to attach themselves to the\n\t\t * destroy so they can clean up markup and events.\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aoDestroyCallback\": [],\n\n\n\t\t/**\n\t\t * Get the number of records in the current record set, before filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsTotal\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsTotal * 1 :\n\t\t\t\tthis.aiDisplayMaster.length;\n\t\t},\n\n\t\t/**\n\t\t * Get the number of records in the current record set, after filtering\n\t\t *  @type function\n\t\t */\n\t\t\"fnRecordsDisplay\": function ()\n\t\t{\n\t\t\treturn _fnDataSource( this ) == 'ssp' ?\n\t\t\t\tthis._iRecordsDisplay * 1 :\n\t\t\t\tthis.aiDisplay.length;\n\t\t},\n\n\t\t/**\n\t\t * Get the display end point - aiDisplay index\n\t\t *  @type function\n\t\t */\n\t\t\"fnDisplayEnd\": function ()\n\t\t{\n\t\t\tvar\n\t\t\t\tlen      = this._iDisplayLength,\n\t\t\t\tstart    = this._iDisplayStart,\n\t\t\t\tcalc     = start + len,\n\t\t\t\trecords  = this.aiDisplay.length,\n\t\t\t\tfeatures = this.oFeatures,\n\t\t\t\tpaginate = features.bPaginate;\n\n\t\t\tif ( features.bServerSide ) {\n\t\t\t\treturn paginate === false || len === -1 ?\n\t\t\t\t\tstart + records :\n\t\t\t\t\tMath.min( start+len, this._iRecordsDisplay );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn ! paginate || calc>records || len===-1 ?\n\t\t\t\t\trecords :\n\t\t\t\t\tcalc;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * The DataTables object for this table\n\t\t *  @type object\n\t\t *  @default null\n\t\t */\n\t\t\"oInstance\": null,\n\n\t\t/**\n\t\t * Unique identifier for each instance of the DataTables object. If there\n\t\t * is an ID on the table node, then it takes that value, otherwise an\n\t\t * incrementing internal counter is used.\n\t\t *  @type string\n\t\t *  @default null\n\t\t */\n\t\t\"sInstance\": null,\n\n\t\t/**\n\t\t * tabindex attribute value that is added to DataTables control elements, allowing\n\t\t * keyboard navigation of the table and its controls.\n\t\t */\n\t\t\"iTabIndex\": 0,\n\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollHead\": null,\n\n\t\t/**\n\t\t * DIV container for the footer scrolling table if scrolling\n\t\t */\n\t\t\"nScrollFoot\": null,\n\n\t\t/**\n\t\t * Last applied sort\n\t\t *  @type array\n\t\t *  @default []\n\t\t */\n\t\t\"aLastSort\": [],\n\n\t\t/**\n\t\t * Stored plug-in instances\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\t\"oPlugins\": {}\n\t};\n\n\t/**\n\t * Extension object for DataTables that is used to provide all extension\n\t * options.\n\t *\n\t * Note that the `DataTable.ext` object is available through\n\t * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is\n\t * also aliased to `jQuery.fn.dataTableExt` for historic reasons.\n\t *  @namespace\n\t *  @extends DataTable.models.ext\n\t */\n\n\n\t/**\n\t * DataTables extensions\n\t *\n\t * This namespace acts as a collection area for plug-ins that can be used to\n\t * extend DataTables capabilities. Indeed many of the build in methods\n\t * use this method to provide their own capabilities (sorting methods for\n\t * example).\n\t *\n\t * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy\n\t * reasons\n\t *\n\t *  @namespace\n\t */\n\tDataTable.ext = _ext = {\n\t\t/**\n\t\t * Element class names\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tclasses: {},\n\n\n\t\t/**\n\t\t * Error reporting.\n\t\t *\n\t\t * How should DataTables report an error. Can take the value 'alert' or\n\t\t * 'throw'\n\t\t *\n\t\t *  @type string\n\t\t *  @default alert\n\t\t */\n\t\terrMode: \"alert\",\n\n\n\t\t/**\n\t\t * Feature plug-ins.\n\t\t *\n\t\t * This is an array of objects which describe the feature plug-ins that are\n\t\t * available to DataTables. These feature plug-ins are then available for\n\t\t * use through the `dom` initialisation option.\n\t\t *\n\t\t * Each feature plug-in is described by an object which must have the\n\t\t * following properties:\n\t\t *\n\t\t * * `fnInit` - function that is used to initialise the plug-in,\n\t\t * * `cFeature` - a character so the feature can be enabled by the `dom`\n\t\t *   instillation option. This is case sensitive.\n\t\t *\n\t\t * The `fnInit` function has the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {node|null} The element which contains your feature. Note that the\n\t\t *   return may also be void if your plug-in does not require to inject any\n\t\t *   DOM elements into DataTables control (`dom`) - for example this might\n\t\t *   be useful when developing a plug-in which allows table control via\n\t\t *   keyboard entry\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    $.fn.dataTable.ext.features.push( {\n\t\t *      \"fnInit\": function( oSettings ) {\n\t\t *        return new TableTools( { \"oDTSettings\": oSettings } );\n\t\t *      },\n\t\t *      \"cFeature\": \"T\"\n\t\t *    } );\n\t\t */\n\t\tfeature: [],\n\n\n\t\t/**\n\t\t * Row searching.\n\t\t *\n\t\t * This method of searching is complimentary to the default type based\n\t\t * searching, and a lot more comprehensive as it allows you complete control\n\t\t * over the searching logic. Each element in this array is a function\n\t\t * (parameters described below) that is called for every row in the table,\n\t\t * and your logic decides if it should be included in the searching data set\n\t\t * or not.\n\t\t *\n\t\t * Searching functions have the following input parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{array|object}` Data for the row to be processed (same as the\n\t\t *    original format that was passed in as the data source, or an array\n\t\t *    from a DOM data source\n\t\t * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which\n\t\t *    can be useful to retrieve the `TR` element if you need DOM interaction.\n\t\t *\n\t\t * And the following return is expected:\n\t\t *\n\t\t * * {boolean} Include the row in the searched result set (true) or not\n\t\t *   (false)\n\t\t *\n\t\t * Note that as with the main search ability in DataTables, technically this\n\t\t * is \"filtering\", since it is subtractive. However, for consistency in\n\t\t * naming we call it searching here.\n\t\t *\n\t\t *  @type array\n\t\t *  @default []\n\t\t *\n\t\t *  @example\n\t\t *    // The following example shows custom search being applied to the\n\t\t *    // fourth column (i.e. the data[3] index) based on two input values\n\t\t *    // from the end-user, matching the data in a certain range.\n\t\t *    $.fn.dataTable.ext.search.push(\n\t\t *      function( settings, data, dataIndex ) {\n\t\t *        var min = document.getElementById('min').value * 1;\n\t\t *        var max = document.getElementById('max').value * 1;\n\t\t *        var version = data[3] == \"-\" ? 0 : data[3]*1;\n\t\t *\n\t\t *        if ( min == \"\" && max == \"\" ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min == \"\" && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && \"\" == max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        else if ( min < version && version < max ) {\n\t\t *          return true;\n\t\t *        }\n\t\t *        return false;\n\t\t *      }\n\t\t *    );\n\t\t */\n\t\tsearch: [],\n\n\n\t\t/**\n\t\t * Internal functions, exposed for used in plug-ins.\n\t\t *\n\t\t * Please note that you should not need to use the internal methods for\n\t\t * anything other than a plug-in (and even then, try to avoid if possible).\n\t\t * The internal function may change between releases.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t */\n\t\tinternal: {},\n\n\n\t\t/**\n\t\t * Legacy configuration options. Enable and disable legacy options that\n\t\t * are available in DataTables.\n\t\t *\n\t\t *  @type object\n\t\t */\n\t\tlegacy: {\n\t\t\t/**\n\t\t\t * Enable / disable DataTables 1.9 compatible server-side processing\n\t\t\t * requests\n\t\t\t *\n\t\t\t *  @type boolean\n\t\t\t *  @default false\n\t\t\t */\n\t\t\tajax: false\n\t\t},\n\n\n\t\t/**\n\t\t * Pagination plug-in methods.\n\t\t *\n\t\t * Each entry in this object is a function and defines which buttons should\n\t\t * be shown by the pagination rendering method that is used for the table:\n\t\t * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the\n\t\t * buttons are displayed in the document, while the functions here tell it\n\t\t * what buttons to display. This is done by returning an array of button\n\t\t * descriptions (what each button will do).\n\t\t *\n\t\t * Pagination types (the four built in options and any additional plug-in\n\t\t * options defined here) can be used through the `paginationType`\n\t\t * initialisation parameter.\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{int} page` The current page index\n\t\t * 2. `{int} pages` The number of pages in the table\n\t\t *\n\t\t * Each function is expected to return an array where each element of the\n\t\t * array can be one of:\n\t\t *\n\t\t * * `first` - Jump to first page when activated\n\t\t * * `last` - Jump to last page when activated\n\t\t * * `previous` - Show previous page when activated\n\t\t * * `next` - Show next page when activated\n\t\t * * `{int}` - Show page of the index given\n\t\t * * `{array}` - A nested array containing the above elements to add a\n\t\t *   containing 'DIV' element (might be useful for styling).\n\t\t *\n\t\t * Note that DataTables v1.9- used this object slightly differently whereby\n\t\t * an object with two functions would be defined for each plug-in. That\n\t\t * ability is still supported by DataTables 1.10+ to provide backwards\n\t\t * compatibility, but this option of use is now decremented and no longer\n\t\t * documented in DataTables 1.10+.\n\t\t *\n\t\t *  @type object\n\t\t *  @default {}\n\t\t *\n\t\t *  @example\n\t\t *    // Show previous, next and current page buttons only\n\t\t *    $.fn.dataTableExt.oPagination.current = function ( page, pages ) {\n\t\t *      return [ 'previous', page, 'next' ];\n\t\t *    };\n\t\t */\n\t\tpager: {},\n\n\n\t\trenderer: {\n\t\t\tpageButton: {},\n\t\t\theader: {}\n\t\t},\n\n\n\t\t/**\n\t\t * Ordering plug-ins - custom data source\n\t\t *\n\t\t * The extension options for ordering of data available here is complimentary\n\t\t * to the default type based ordering that DataTables typically uses. It\n\t\t * allows much greater control over the the data that is being used to\n\t\t * order a column, but is necessarily therefore more complex.\n\t\t *\n\t\t * This type of ordering is useful if you want to do ordering based on data\n\t\t * live from the DOM (for example the contents of an 'input' element) rather\n\t\t * than just the static string that DataTables knows of.\n\t\t *\n\t\t * The way these plug-ins work is that you create an array of the values you\n\t\t * wish to be ordering for the column in question and then return that\n\t\t * array. The data in the array much be in the index order of the rows in\n\t\t * the table (not the currently ordering order!). Which order data gathering\n\t\t * function is run here depends on the `dt-init columns.orderDataType`\n\t\t * parameter that is used for the column (if any).\n\t\t *\n\t\t * The functions defined take two parameters:\n\t\t *\n\t\t * 1. `{object}` DataTables settings object: see\n\t\t *    {@link DataTable.models.oSettings}\n\t\t * 2. `{int}` Target column index\n\t\t *\n\t\t * Each function is expected to return an array:\n\t\t *\n\t\t * * `{array}` Data for the column to be ordering upon\n\t\t *\n\t\t *  @type array\n\t\t *\n\t\t *  @example\n\t\t *    // Ordering using `input` node values\n\t\t *    $.fn.dataTable.ext.order['dom-text'] = function  ( settings, col )\n\t\t *    {\n\t\t *      return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {\n\t\t *        return $('input', td).val();\n\t\t *      } );\n\t\t *    }\n\t\t */\n\t\torder: {},\n\n\n\t\t/**\n\t\t * Type based plug-ins.\n\t\t *\n\t\t * Each column in DataTables has a type assigned to it, either by automatic\n\t\t * detection or by direct assignment using the `type` option for the column.\n\t\t * The type of a column will effect how it is ordering and search (plug-ins\n\t\t * can also make use of the column type if required).\n\t\t *\n\t\t * @namespace\n\t\t */\n\t\ttype: {\n\t\t\t/**\n\t\t\t * Type detection functions.\n\t\t\t *\n\t\t\t * The functions defined in this object are used to automatically detect\n\t\t\t * a column's type, making initialisation of DataTables super easy, even\n\t\t\t * when complex data is in the table.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be analysed\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Data type detected, or null if unknown (and thus\n\t\t\t *   pass it on to the other type detection functions.\n\t\t\t *\n\t\t\t *  @type array\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Currency type detection plug-in:\n\t\t\t *    $.fn.dataTable.ext.type.detect.push(\n\t\t\t *      function ( data ) {\n\t\t\t *        // Check the numeric part\n\t\t\t *        if ( ! $.isNumeric( data.substring(1) ) ) {\n\t\t\t *          return null;\n\t\t\t *        }\n\t\t\t *\n\t\t\t *        // Check prefixed by currency\n\t\t\t *        if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {\n\t\t\t *          return 'currency';\n\t\t\t *        }\n\t\t\t *        return null;\n\t\t\t *      }\n\t\t\t *    );\n\t\t\t */\n\t\t\tdetect: [],\n\n\n\t\t\t/**\n\t\t\t * Type based search formatting.\n\t\t\t *\n\t\t\t * The type based searching functions can be used to pre-format the\n\t\t\t * data to be search on. For example, it can be used to strip HTML\n\t\t\t * tags or to de-format telephone numbers for numeric only searching.\n\t\t\t *\n\t\t\t * Note that is a search is not defined for a column of a given type,\n\t\t\t * no search formatting will be performed.\n\t\t\t *\n\t\t\t * Pre-processing of searching data plug-ins - When you assign the sType\n\t\t\t * for a column (or have it automatically detected for you by DataTables\n\t\t\t * or a type detection plug-in), you will typically be using this for\n\t\t\t * custom sorting, but it can also be used to provide custom searching\n\t\t\t * by allowing you to pre-processing the data and returning the data in\n\t\t\t * the format that should be searched upon. This is done by adding\n\t\t\t * functions this object with a parameter name which matches the sType\n\t\t\t * for that target column. This is the corollary of <i>afnSortData</i>\n\t\t\t * for searching data.\n\t\t\t *\n\t\t\t * The functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for searching\n\t\t\t *\n\t\t\t * Each function is expected to return:\n\t\t\t *\n\t\t\t * * `{string|null}` Formatted string that will be used for the searching.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {\n\t\t\t *      return d.replace(/\\n/g,\" \").replace( /<.*?>/g, \"\" );\n\t\t\t *    }\n\t\t\t */\n\t\t\tsearch: {},\n\n\n\t\t\t/**\n\t\t\t * Type based ordering.\n\t\t\t *\n\t\t\t * The column type tells DataTables what ordering to apply to the table\n\t\t\t * when a column is sorted upon. The order for each type that is defined,\n\t\t\t * is defined by the functions available in this object.\n\t\t\t *\n\t\t\t * Each ordering option can be described by three properties added to\n\t\t\t * this object:\n\t\t\t *\n\t\t\t * * `{type}-pre` - Pre-formatting function\n\t\t\t * * `{type}-asc` - Ascending order function\n\t\t\t * * `{type}-desc` - Descending order function\n\t\t\t *\n\t\t\t * All three can be used together, only `{type}-pre` or only\n\t\t\t * `{type}-asc` and `{type}-desc` together. It is generally recommended\n\t\t\t * that only `{type}-pre` is used, as this provides the optimal\n\t\t\t * implementation in terms of speed, although the others are provided\n\t\t\t * for compatibility with existing Javascript sort functions.\n\t\t\t *\n\t\t\t * `{type}-pre`: Functions defined take a single parameter:\n\t\t\t *\n\t\t     *  1. `{*}` Data from the column cell to be prepared for ordering\n\t\t\t *\n\t\t\t * And return:\n\t\t\t *\n\t\t\t * * `{*}` Data to be sorted upon\n\t\t\t *\n\t\t\t * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort\n\t\t\t * functions, taking two parameters:\n\t\t\t *\n\t\t     *  1. `{*}` Data to compare to the second parameter\n\t\t     *  2. `{*}` Data to compare to the first parameter\n\t\t\t *\n\t\t\t * And returning:\n\t\t\t *\n\t\t\t * * `{*}` Ordering match: <0 if first parameter should be sorted lower\n\t\t\t *   than the second parameter, ===0 if the two parameters are equal and\n\t\t\t *   >0 if the first parameter should be sorted height than the second\n\t\t\t *   parameter.\n\t\t\t *\n\t\t\t *  @type object\n\t\t\t *  @default {}\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Numeric ordering of formatted numbers with a pre-formatter\n\t\t\t *    $.extend( $.fn.dataTable.ext.type.order, {\n\t\t\t *      \"string-pre\": function(x) {\n\t\t\t *        a = (a === \"-\" || a === \"\") ? 0 : a.replace( /[^\\d\\-\\.]/g, \"\" );\n\t\t\t *        return parseFloat( a );\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t *\n\t\t\t *  @example\n\t\t\t *    // Case-sensitive string ordering, with no pre-formatting method\n\t\t\t *    $.extend( $.fn.dataTable.ext.order, {\n\t\t\t *      \"string-case-asc\": function(x,y) {\n\t\t\t *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t\t *      },\n\t\t\t *      \"string-case-desc\": function(x,y) {\n\t\t\t *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t\t *      }\n\t\t\t *    } );\n\t\t\t */\n\t\t\torder: {}\n\t\t},\n\n\t\t/**\n\t\t * Unique DataTables instance counter\n\t\t *\n\t\t * @type int\n\t\t * @private\n\t\t */\n\t\t_unique: 0,\n\n\n\t\t//\n\t\t// Depreciated\n\t\t// The following properties are retained for backwards compatiblity only.\n\t\t// The should not be used in new projects and will be removed in a future\n\t\t// version\n\t\t//\n\n\t\t/**\n\t\t * Version check function.\n\t\t *  @type function\n\t\t *  @depreciated Since 1.10\n\t\t */\n\t\tfnVersionCheck: DataTable.fnVersionCheck,\n\n\n\t\t/**\n\t\t * Index for what 'this' index API functions should use\n\t\t *  @type int\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tiApiIndex: 0,\n\n\n\t\t/**\n\t\t * jQuery UI class container\n\t\t *  @type object\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\toJUIClasses: {},\n\n\n\t\t/**\n\t\t * Software version\n\t\t *  @type string\n\t\t *  @deprecated Since v1.10\n\t\t */\n\t\tsVersion: DataTable.version\n\t};\n\n\n\t//\n\t// Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts\n\t//\n\t$.extend( _ext, {\n\t\tafnFiltering: _ext.filter,\n\t\taTypes:       _ext.type.detect,\n\t\tofnSearch:    _ext.type.search,\n\t\toSort:        _ext.type.order,\n\t\tafnSortData:  _ext.order,\n\t\taoFeatures:   _ext.feature,\n\t\toApi:         _ext.internal,\n\t\toStdClasses:  _ext.classes,\n\t\toPagination:  _ext.pager\n\t} );\n\n\n\t$.extend( DataTable.ext.classes, {\n\t\t\"sTable\": \"dataTable\",\n\t\t\"sNoFooter\": \"no-footer\",\n\n\t\t/* Paging buttons */\n\t\t\"sPageButton\": \"paginate_button\",\n\t\t\"sPageButtonActive\": \"current\",\n\t\t\"sPageButtonDisabled\": \"disabled\",\n\n\t\t/* Striping classes */\n\t\t\"sStripeOdd\": \"odd\",\n\t\t\"sStripeEven\": \"even\",\n\n\t\t/* Empty row */\n\t\t\"sRowEmpty\": \"dataTables_empty\",\n\n\t\t/* Features */\n\t\t\"sWrapper\": \"dataTables_wrapper\",\n\t\t\"sFilter\": \"dataTables_filter\",\n\t\t\"sInfo\": \"dataTables_info\",\n\t\t\"sPaging\": \"dataTables_paginate paging_\", /* Note that the type is postfixed */\n\t\t\"sLength\": \"dataTables_length\",\n\t\t\"sProcessing\": \"dataTables_processing\",\n\n\t\t/* Sorting */\n\t\t\"sSortAsc\": \"sorting_asc\",\n\t\t\"sSortDesc\": \"sorting_desc\",\n\t\t\"sSortable\": \"sorting\", /* Sortable in both directions */\n\t\t\"sSortableAsc\": \"sorting_asc_disabled\",\n\t\t\"sSortableDesc\": \"sorting_desc_disabled\",\n\t\t\"sSortableNone\": \"sorting_disabled\",\n\t\t\"sSortColumn\": \"sorting_\", /* Note that an int is postfixed for the sorting order */\n\n\t\t/* Filtering */\n\t\t\"sFilterInput\": \"\",\n\n\t\t/* Page length */\n\t\t\"sLengthSelect\": \"\",\n\n\t\t/* Scrolling */\n\t\t\"sScrollWrapper\": \"dataTables_scroll\",\n\t\t\"sScrollHead\": \"dataTables_scrollHead\",\n\t\t\"sScrollHeadInner\": \"dataTables_scrollHeadInner\",\n\t\t\"sScrollBody\": \"dataTables_scrollBody\",\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot\",\n\t\t\"sScrollFootInner\": \"dataTables_scrollFootInner\",\n\n\t\t/* Misc */\n\t\t\"sHeaderTH\": \"\",\n\t\t\"sFooterTH\": \"\",\n\n\t\t// Deprecated\n\t\t\"sSortJUIAsc\": \"\",\n\t\t\"sSortJUIDesc\": \"\",\n\t\t\"sSortJUI\": \"\",\n\t\t\"sSortJUIAscAllowed\": \"\",\n\t\t\"sSortJUIDescAllowed\": \"\",\n\t\t\"sSortJUIWrapper\": \"\",\n\t\t\"sSortIcon\": \"\",\n\t\t\"sJUIHeader\": \"\",\n\t\t\"sJUIFooter\": \"\"\n\t} );\n\n\n\t(function() {\n\n\t// Reused strings for better compression. Closure compiler appears to have a\n\t// weird edge case where it is trying to expand strings rather than use the\n\t// variable version. This results in about 200 bytes being added, for very\n\t// little preference benefit since it this run on script load only.\n\tvar _empty = '';\n\t_empty = '';\n\n\tvar _stateDefault = _empty + 'ui-state-default';\n\tvar _sortIcon     = _empty + 'css_right ui-icon ui-icon-';\n\tvar _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';\n\n\t$.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {\n\t\t/* Full numbers paging buttons */\n\t\t\"sPageButton\":         \"fg-button ui-button \"+_stateDefault,\n\t\t\"sPageButtonActive\":   \"ui-state-disabled\",\n\t\t\"sPageButtonDisabled\": \"ui-state-disabled\",\n\n\t\t/* Features */\n\t\t\"sPaging\": \"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi \"+\n\t\t\t\"ui-buttonset-multi paging_\", /* Note that the type is postfixed */\n\n\t\t/* Sorting */\n\t\t\"sSortAsc\":            _stateDefault+\" sorting_asc\",\n\t\t\"sSortDesc\":           _stateDefault+\" sorting_desc\",\n\t\t\"sSortable\":           _stateDefault+\" sorting\",\n\t\t\"sSortableAsc\":        _stateDefault+\" sorting_asc_disabled\",\n\t\t\"sSortableDesc\":       _stateDefault+\" sorting_desc_disabled\",\n\t\t\"sSortableNone\":       _stateDefault+\" sorting_disabled\",\n\t\t\"sSortJUIAsc\":         _sortIcon+\"triangle-1-n\",\n\t\t\"sSortJUIDesc\":        _sortIcon+\"triangle-1-s\",\n\t\t\"sSortJUI\":            _sortIcon+\"carat-2-n-s\",\n\t\t\"sSortJUIAscAllowed\":  _sortIcon+\"carat-1-n\",\n\t\t\"sSortJUIDescAllowed\": _sortIcon+\"carat-1-s\",\n\t\t\"sSortJUIWrapper\":     \"DataTables_sort_wrapper\",\n\t\t\"sSortIcon\":           \"DataTables_sort_icon\",\n\n\t\t/* Scrolling */\n\t\t\"sScrollHead\": \"dataTables_scrollHead \"+_stateDefault,\n\t\t\"sScrollFoot\": \"dataTables_scrollFoot \"+_stateDefault,\n\n\t\t/* Misc */\n\t\t\"sHeaderTH\":  _stateDefault,\n\t\t\"sFooterTH\":  _stateDefault,\n\t\t\"sJUIHeader\": _headerFooter+\" ui-corner-tl ui-corner-tr\",\n\t\t\"sJUIFooter\": _headerFooter+\" ui-corner-bl ui-corner-br\"\n\t} );\n\n\t}());\n\n\n\n\tvar extPagination = DataTable.ext.pager;\n\n\tfunction _numbers ( page, pages ) {\n\t\tvar\n\t\t\tnumbers = [],\n\t\t\tbuttons = extPagination.numbers_length,\n\t\t\thalf = Math.floor( buttons / 2 ),\n\t\t\ti = 1;\n\n\t\tif ( pages <= buttons ) {\n\t\t\tnumbers = _range( 0, pages );\n\t\t}\n\t\telse if ( page <= half ) {\n\t\t\tnumbers = _range( 0, buttons-2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t}\n\t\telse if ( page >= pages - 1 - half ) {\n\t\t\tnumbers = _range( pages-(buttons-2), pages );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\t\telse {\n\t\t\tnumbers = _range( page-1, page+2 );\n\t\t\tnumbers.push( 'ellipsis' );\n\t\t\tnumbers.push( pages-1 );\n\t\t\tnumbers.splice( 0, 0, 'ellipsis' );\n\t\t\tnumbers.splice( 0, 0, 0 );\n\t\t}\n\n\t\tnumbers.DT_el = 'span';\n\t\treturn numbers;\n\t}\n\n\n\t$.extend( extPagination, {\n\t\tsimple: function ( page, pages ) {\n\t\t\treturn [ 'previous', 'next' ];\n\t\t},\n\n\t\tfull: function ( page, pages ) {\n\t\t\treturn [  'first', 'previous', 'next', 'last' ];\n\t\t},\n\n\t\tsimple_numbers: function ( page, pages ) {\n\t\t\treturn [ 'previous', _numbers(page, pages), 'next' ];\n\t\t},\n\n\t\tfull_numbers: function ( page, pages ) {\n\t\t\treturn [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];\n\t\t},\n\n\t\t// For testing and plug-ins to use\n\t\t_numbers: _numbers,\n\t\tnumbers_length: 7\n\t} );\n\n\n\t$.extend( true, DataTable.ext.renderer, {\n\t\tpageButton: {\n\t\t\t_: function ( settings, host, idx, buttons, page, pages ) {\n\t\t\t\tvar classes = settings.oClasses;\n\t\t\t\tvar lang = settings.oLanguage.oPaginate;\n\t\t\t\tvar btnDisplay, btnClass;\n\n\t\t\t\tvar attach = function( container, buttons ) {\n\t\t\t\t\tvar i, ien, node, button;\n\t\t\t\t\tvar clickHandler = function ( e ) {\n\t\t\t\t\t\t_fnPageChange( settings, e.data.action, true );\n\t\t\t\t\t};\n\n\t\t\t\t\tfor ( i=0, ien=buttons.length ; i<ien ; i++ ) {\n\t\t\t\t\t\tbutton = buttons[i];\n\n\t\t\t\t\t\tif ( $.isArray( button ) ) {\n\t\t\t\t\t\t\tvar inner = $( '<'+(button.DT_el || 'div')+'/>' )\n\t\t\t\t\t\t\t\t.appendTo( container );\n\t\t\t\t\t\t\tattach( inner, button );\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tbtnDisplay = '';\n\t\t\t\t\t\t\tbtnClass = '';\n\n\t\t\t\t\t\t\tswitch ( button ) {\n\t\t\t\t\t\t\t\tcase 'ellipsis':\n\t\t\t\t\t\t\t\t\tcontainer.append('<span>&hellip;</span>');\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'first':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sFirst;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'previous':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sPrevious;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page > 0 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'next':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sNext;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tcase 'last':\n\t\t\t\t\t\t\t\t\tbtnDisplay = lang.sLast;\n\t\t\t\t\t\t\t\t\tbtnClass = button + (page < pages-1 ?\n\t\t\t\t\t\t\t\t\t\t'' : ' '+classes.sPageButtonDisabled);\n\t\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t\tbtnDisplay = button + 1;\n\t\t\t\t\t\t\t\t\tbtnClass = page === button ?\n\t\t\t\t\t\t\t\t\t\tclasses.sPageButtonActive : '';\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( btnDisplay ) {\n\t\t\t\t\t\t\t\tnode = $('<a>', {\n\t\t\t\t\t\t\t\t\t\t'class': classes.sPageButton+' '+btnClass,\n\t\t\t\t\t\t\t\t\t\t'aria-controls': settings.sTableId,\n\t\t\t\t\t\t\t\t\t\t'tabindex': settings.iTabIndex,\n\t\t\t\t\t\t\t\t\t\t'id': idx === 0 && typeof button === 'string' ?\n\t\t\t\t\t\t\t\t\t\t\tsettings.sTableId +'_'+ button :\n\t\t\t\t\t\t\t\t\t\t\tnull\n\t\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t\t.html( btnDisplay )\n\t\t\t\t\t\t\t\t\t.appendTo( container );\n\n\t\t\t\t\t\t\t\t_fnBindAction(\n\t\t\t\t\t\t\t\t\tnode, {action: button}, clickHandler\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\tattach( $(host).empty(), buttons );\n\t\t\t}\n\t\t}\n\t} );\n\n\n\n\tvar __numericReplace = function ( d, re1, re2 ) {\n\t\tif ( !d || d === '-' ) {\n\t\t\treturn -Infinity;\n\t\t}\n\n\t\tif ( d.replace ) {\n\t\t\tif ( re1 ) {\n\t\t\t\td = d.replace( re1, '' );\n\t\t\t}\n\n\t\t\tif ( re2 ) {\n\t\t\t\td = d.replace( re2, '' );\n\t\t\t}\n\t\t}\n\n\t\treturn d * 1;\n\t};\n\n\n\t$.extend( DataTable.ext.type.order, {\n\t\t// Dates\n\t\t\"date-pre\": function ( d )\n\t\t{\n\t\t\treturn Date.parse( d ) || 0;\n\t\t},\n\n\t\t// Plain numbers\n\t\t\"numeric-pre\": function ( d )\n\t\t{\n\t\t\treturn __numericReplace( d );\n\t\t},\n\n\t\t// Formatted numbers\n\t\t\"numeric-fmt-pre\": function ( d )\n\t\t{\n\t\t\treturn __numericReplace( d, _re_formatted_numeric );\n\t\t},\n\n\t\t// HTML numeric\n\t\t\"html-numeric-pre\": function ( d )\n\t\t{\n\t\t\treturn __numericReplace( d, _re_html );\n\t\t},\n\n\t\t// HTML numeric, formatted\n\t\t\"html-numeric-fmt-pre\": function ( d )\n\t\t{\n\t\t\treturn __numericReplace( d, _re_html, _re_formatted_numeric );\n\t\t},\n\n\t\t// html\n\t\t\"html-pre\": function ( a )\n\t\t{\n\t\t\treturn a.replace ?\n\t\t\t\ta.replace( /<.*?>/g, \"\" ).toLowerCase() :\n\t\t\t\ta+'';\n\t\t},\n\n\t\t// string\n\t\t\"string-pre\": function ( a )\n\t\t{\n\t\t\treturn typeof a === 'string' ?\n\t\t\t\ta.toLowerCase() :\n\t\t\t\t! a || ! a.toString ?\n\t\t\t\t\t'' :\n\t\t\t\t\ta.toString();\n\t\t},\n\n\t\t// string-asc and -desc are retained only for compatibility with the old\n\t\t// sort methods\n\t\t\"string-asc\": function ( x, y )\n\t\t{\n\t\t\treturn ((x < y) ? -1 : ((x > y) ? 1 : 0));\n\t\t},\n\n\t\t\"string-desc\": function ( x, y )\n\t\t{\n\t\t\treturn ((x < y) ? 1 : ((x > y) ? -1 : 0));\n\t\t}\n\t} );\n\n\n\t// Built in type detection. See model.ext.aTypes for information about\n\t// what is required from this methods.\n\t$.extend( DataTable.ext.type.detect, [\n\t\t// Plain numbers - first since V8 detects some plain numbers as dates\n\t\t// e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _isNumber( d ) ? 'numeric' : null;\n\t\t},\n\n\t\t// Dates (only those recognised by the browser's Date.parse)\n\t\tfunction ( d )\n\t\t{\n\t\t\t// V8 will remove any unknown characters at the start of the expression,\n\t\t\t// leading to false matches such as `$245.12` being a valid date. See\n\t\t\t// forum thread 18941 for detail.\n\t\t\tif ( d && ! _re_date_start.test(d) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tvar parsed = Date.parse(d);\n\t\t\treturn (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;\n\t\t},\n\n\t\t// Formatted numbers\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _isNumber( d, true ) ? 'numeric-fmt' : null;\n\t\t},\n\n\t\t// HTML numeric\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _htmlNumeric( d ) ? 'html-numeric' : null;\n\t\t},\n\n\t\t// HTML numeric, formatted\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _htmlNumeric( d, true ) ? 'html-numeric-fmt' : null;\n\t\t},\n\n\t\t// HTML (this is strict checking - there much be html)\n\t\tfunction ( d )\n\t\t{\n\t\t\treturn _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?\n\t\t\t\t'html' : null;\n\t\t}\n\t] );\n\n\n\n\t// Filter formatting functions. See model.ext.ofnSearch for information about\n\t// what is required from these methods.\n\n\n\t$.extend( DataTable.ext.type.search, {\n\t\thtml: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata\n\t\t\t\t\t\t.replace( _re_new_lines, \" \" )\n\t\t\t\t\t\t.replace( _re_html, \"\" ) :\n\t\t\t\t\t'';\n\t\t},\n\n\t\tstring: function ( data ) {\n\t\t\treturn _empty(data) ?\n\t\t\t\t'' :\n\t\t\t\ttypeof data === 'string' ?\n\t\t\t\t\tdata.replace( _re_new_lines, \" \" ) :\n\t\t\t\t\tdata;\n\t\t}\n\t} );\n\n\n\n\t$.extend( true, DataTable.ext.renderer, {\n\t\theader: {\n\t\t\t_: function ( settings, cell, column, idx, classes ) {\n\t\t\t\t// No additional mark-up required\n\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt', function ( e, settings, sorting, columns ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tcolumn.sSortingClass +' '+\n\t\t\t\t\t\t\tclasses.sSortAsc +' '+\n\t\t\t\t\t\t\tclasses.sSortDesc\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ idx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ idx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t},\n\n\t\t\tjqueryui: function ( settings, cell, column, idx, classes ) {\n\t\t\t\t$('<div/>')\n\t\t\t\t\t.addClass( classes.sSortJUIWrapper )\n\t\t\t\t\t.append( cell.contents() )\n\t\t\t\t\t.append( $('<span/>')\n\t\t\t\t\t\t.addClass( classes.sSortIcon+' '+column.sSortingClassJUI )\n\t\t\t\t\t)\n\t\t\t\t\t.appendTo( cell );\n\n\t\t\t\t// Attach a sort listener to update on sort\n\t\t\t\t$(settings.nTable).on( 'order.dt', function ( e, settings, sorting, columns ) {\n\t\t\t\t\tcell\n\t\t\t\t\t\t.removeClass( classes.sSortAsc +\" \"+classes.sSortDesc )\n\t\t\t\t\t\t.addClass( columns[ idx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortAsc : columns[ idx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClass\n\t\t\t\t\t\t);\n\n\t\t\t\t\tcell\n\t\t\t\t\t\t.find( 'span' )\n\t\t\t\t\t\t.removeClass(\n\t\t\t\t\t\t\tclasses.sSortJUIAsc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDesc +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUI +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIAscAllowed +\" \"+\n\t\t\t\t\t\t\tclasses.sSortJUIDescAllowed\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.addClass( columns[ idx ] == 'asc' ?\n\t\t\t\t\t\t\tclasses.sSortJUIAsc : columns[ idx ] == 'desc' ?\n\t\t\t\t\t\t\t\tclasses.sSortJUIDesc :\n\t\t\t\t\t\t\t\tcolumn.sSortingClassJUI\n\t\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\t\t}\n\t} );\n\n\n\t// jQuery access\n\t$.fn.dataTable = DataTable;\n\n\t// Legacy aliases\n\t$.fn.dataTableSettings = DataTable.settings;\n\t$.fn.dataTableExt = DataTable.ext;\n\n\t// With a capital `D` we return a DataTables API instance rather than a\n\t// jQuery object\n\t$.fn.DataTable = function ( opts ) {\n\t\treturn $(this).dataTable( opts ).api();\n\t};\n\n\t// All properties that are available to $.fn.dataTable should also be\n\t// available on $.fn.DataTable\n\t$.each( DataTable, function ( prop, val ) {\n\t\t$.fn.DataTable[ prop ] = val;\n\t} );\n\n\n\t// Information about events fired by DataTables - for documentation.\n\t/**\n\t * Draw event, fired whenever the table is redrawn on the page, at the same\n\t * point as fnDrawCallback. This may be useful for binding events or\n\t * performing calculations when the table is altered at all.\n\t *  @name DataTable#draw.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Search event, fired when the searching applied to the table (using the\n\t * built-in global search, or column filters) is altered.\n\t *  @name DataTable#search.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page change event, fired when the paging of the table is altered.\n\t *  @name DataTable#page.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Order event, fired when the ordering applied to the table is altered.\n\t *  @name DataTable#order.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * DataTables initialisation complete event, fired when the table is fully\n\t * drawn, including Ajax data loaded, if Ajax data is required.\n\t *  @name DataTable#init.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The JSON object request from the server - only\n\t *    present if client-side Ajax sourced data is used</li></ol>\n\t */\n\n\t/**\n\t * State save event, fired when the table has changed state a new state save\n\t * is required. This event allows modification of the state saving object\n\t * prior to actually doing the save, including addition or other state\n\t * properties (for plug-ins) or modification of a DataTables core property.\n\t *  @name DataTable#stateSaveParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The state information to be saved\n\t */\n\n\t/**\n\t * State load event, fired when the table is loading state from the stored\n\t * data, but prior to the settings object being modified by the saved state\n\t * - allowing modification of the saved state is required or loading of\n\t * state for a plug-in.\n\t *  @name DataTable#stateLoadParams.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * State loaded event, fired when state has been loaded from stored data and\n\t * the settings object has been modified by the loaded data.\n\t *  @name DataTable#stateLoaded.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {object} json The saved state information\n\t */\n\n\t/**\n\t * Processing event, fired when DataTables is doing some kind of processing\n\t * (be it, order, searcg or anything else). It can be used to indicate to\n\t * the end user that there is something happening, or that something has\n\t * finished.\n\t *  @name DataTable#processing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} oSettings DataTables settings object\n\t *  @param {boolean} bShow Flag for if DataTables is doing processing or not\n\t */\n\n\t/**\n\t * Ajax (XHR) event, fired whenever an Ajax request is completed from a\n\t * request to made to the server for new data. This event is called before\n\t * DataTables processed the returned data, so it can also be used to pre-\n\t * process the data returned from the server, if needed.\n\t *\n\t * Note that this trigger is called in `fnServerData`, if you override\n\t * `fnServerData` and which to use this event, you need to trigger it in you\n\t * success function.\n\t *  @name DataTable#xhr.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {object} json JSON returned from the server\n\t *\n\t *  @example\n\t *     // Use a custom property returned from the server in another DOM element\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       $('#status').html( json.status );\n\t *     } );\n\t *\n\t *  @example\n\t *     // Pre-process the data returned from the server\n\t *     $('#table').dataTable().on('xhr.dt', function (e, settings, json) {\n\t *       for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {\n\t *         json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;\n\t *       }\n\t *       // Note no return - manipulate the data directly in the JSON object.\n\t *     } );\n\t */\n\n\t/**\n\t * Destroy event, fired when the DataTable is destroyed by calling fnDestroy\n\t * or passing the bDestroy:true parameter in the initialisation object. This\n\t * can be used to remove bound events, added DOM nodes, etc.\n\t *  @name DataTable#destroy.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Page length change event, fired when number of records to show on each\n\t * page (the length) is changed.\n\t *  @name DataTable#length.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {integer} len New length\n\t */\n\n\t/**\n\t * Column sizing has changed.\n\t *  @name DataTable#column-sizing.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t */\n\n\t/**\n\t * Column visibility has changed.\n\t *  @name DataTable#column-visibility.dt\n\t *  @event\n\t *  @param {event} e jQuery event object\n\t *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}\n\t *  @param {int} column Column index\n\t *  @param {bool} vis `false` if column now hidden, or `true` if visible\n\t */\n}));\n\n}(window, document, jQuery));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/jquery-treegrid/extension/jquery.treegrid.extension.js",
    "content": "(function($) {\n\t\"use strict\";\n\n\t$.fn.bootstrapTreeTable = function(options, param) {\n\t\t// 如果是调用方法\n\t\tif (typeof options == 'string') {\n\t\t\treturn $.fn.bootstrapTreeTable.methods[options](this, param);\n\t\t}\n\n\t\t// 如果是初始化组件\n\t\toptions = $.extend({}, $.fn.bootstrapTreeTable.defaults, options || {});\n\t\t// 是否有radio或checkbox\n\t\tvar hasSelectItem = false;\n\t\tvar target = $(this);\n\t\t// 在外层包装一下div，样式用的bootstrap-table的\n\t\tvar _main_div = $(\"<div class='fixed-table-container'></div>\");\n\t\ttarget.before(_main_div);\n\t\t_main_div.append(target);\n\t\ttarget.addClass(\"table table-hover treegrid-table\");\n\t\tif (options.striped) {\n\t\t\ttarget.addClass('table-striped');\n\t\t}\n\t\t// 工具条在外层包装一下div，样式用的bootstrap-table的\n\t\tif(options.toolbar){\n\t\t\tvar _tool_div = $(\"<div class='fixed-table-toolbar'></div>\");\n\t\t\tvar _tool_left_div = $(\"<div class='bs-bars pull-left'></div>\");\n\t\t\t_tool_left_div.append($(options.toolbar));\n\t\t\t_tool_div.append(_tool_left_div);\n\t\t\t_main_div.before(_tool_div);\n\t\t}\n\t\t// 得到根节点\n\t\ttarget.getRootNodes = function(data) {\n\t\t\t// 指定Root节点值\n\t\t\tvar _root = options.rootCodeValue?options.rootCodeValue:null\n\t\t\tvar result = [];\n\t\t\t$.each(data, function(index, item) {\n\t\t\t\t// 这里兼容几种常见Root节点写法\n\t\t\t\t// 默认的几种判断\n\t\t\t\tvar _defaultRootFlag = item[options.parentCode] == '0'\n\t\t\t\t\t|| item[options.parentCode] == 0\n\t\t\t\t\t|| item[options.parentCode] == null\n\t\t\t\t\t|| item[options.parentCode] == '';\n\t\t\t\tif (!item[options.parentCode] || (_root?(item[options.parentCode] == options.rootCodeValue):_defaultRootFlag)){\n\t\t\t\t\tresult.push(item);\n\t\t\t\t}\n\t\t\t\t// 添加一个默认属性，用来判断当前节点有没有被显示\n\t\t\t\titem.isShow = false;\n\t\t\t});\n\t\t\treturn result;\n\t\t};\n\t\tvar j = 0;\n\t\t// 递归获取子节点并且设置子节点\n\t\ttarget.getChildNodes = function(data, parentNode, parentIndex, tbody) {\n\t\t\t$.each(data, function(i, item) {\n\t\t\t\tif (item[options.parentCode] == parentNode[options.code]) {\n\t\t\t\t\tvar tr = $('<tr></tr>');\n\t\t\t\t\tvar nowParentIndex = (parentIndex + (j++) + 1);\n\t\t\t\t\ttr.addClass('treegrid-' + nowParentIndex);\n\t\t\t\t\ttr.addClass('treegrid-parent-' + parentIndex);\n\t\t\t\t\ttarget.renderRow(tr,item);\n\t\t\t\t\titem.isShow = true;\n\t\t\t\t\ttbody.append(tr);\n\t\t\t\t\ttarget.getChildNodes(data, item, nowParentIndex, tbody)\n\n\t\t\t\t}\n\t\t\t});\n\t\t};\n\t\t// 绘制行\n\t\ttarget.renderRow = function(tr,item){\n\t\t\t$.each(options.columns, function(index, column) {\n\t\t\t\t// 判断有没有选择列\n\t\t\t\tif(index==0&&column.field=='selectItem'){\n\t\t\t\t\thasSelectItem = false;\n\t\t\t\t\tvar td = $('<td style=\"text-align:center;width:36px;vertical-align: middle;\"></td>');\n\t\t\t\t\tif(column.radio){\n\t\t\t\t\t\tvar _ipt = $('<input name=\"select_item\" type=\"radio\" value=\"'+item[options.id]+'\"></input>');\n\t\t\t\t\t\ttd.append(_ipt);\n\t\t\t\t\t} \n\t\t\t\t\tif(column.checkbox){\n\t\t\t\t\t\tvar _ipt = $('<input name=\"select_item\" type=\"checkbox\" value=\"'+item[options.id]+'\"></input>');\n\t\t\t\t\t\ttd.append(_ipt);\n\t\t\t\t\t} \n\t\t\t\t\ttr.append(td);\n\t\t\t\t}else{\n\t\t\t\t\tvar td = $('<td style=\"'+((column.width)?('width:'+column.width):'')+'\"></td>');\n                    // 增加formatter渲染\n                    if (column.formatter) {\n                        td.html(column.formatter.call(this, '', item, index));\n                    } else {\n                        td.text(item[column.field]);\n                    }\n\t\t\t\t\ttr.append(td);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\t// 加载数据\n\t\ttarget.load = function(parms){\n\t\t\t// 加载数据前先清空\n\t\t\ttarget.html(\"\");\n\t\t\t// 构造表头\n\t\t\tvar thr = $('<tr></tr>');\n\t\t\t$.each(options.columns, function(i, item) {\n\t\t\t\tvar th = null;\n\t\t\t\t// 判断有没有选择列\n\t\t\t\tif(i==0&&item.field=='selectItem'){\n\t\t\t\t\thasSelectItem = true;\n\t\t\t\t\tth = $('<th style=\"width:36px\"></th>');\n\t\t\t\t}else{\n\t\t\t\t\tth = $('<th style=\"padding:10px;'+((item.width)?('width:'+item.width):'')+'\"></th>');\n\t\t\t\t}\n\t\t\t\tth.text(item.title);\n\t\t\t\tthr.append(th);\n\t\t\t});\n\t\t\tvar thead = $('<thead class=\"treegrid-thead\"></thead>');\n\t\t\tthead.append(thr);\n\t\t\ttarget.append(thead);\n\t\t\t// 构造表体\n\t\t\tvar tbody = $('<tbody class=\"treegrid-tbody\"></tbody>');\n\t\t\ttarget.append(tbody);\n\t\t\t// 添加加载loading\n\t\t\tvar _loading = '<tr><td colspan=\"'+options.columns.length+'\"><div style=\"display: block;text-align: center;\">正在努力地加载数据中，请稍候……</div></td></tr>'\n\t\t\ttbody.html(_loading);\n\t\t\t// 默认高度\n\t\t\tif(options.height){\n\t\t\t\ttbody.css(\"height\",options.height);\n\t\t\t}\n\t\t\t$.ajax({\n\t\t\t\ttype : options.type,\n\t\t\t\turl : options.url,\n\t\t\t\tdata : parms?parms:options.ajaxParams,\n\t\t\t\tdataType : \"JSON\",\n\t\t\t\tsuccess : function(data, textStatus, jqXHR) {\n\t\t\t\t\t// 加载完数据先清空\n\t\t\t\t\ttbody.html(\"\");\n\t\t\t\t\tif(!data||data.length<=0){\n\t\t\t\t\t\tvar _empty = '<tr><td colspan=\"'+options.columns.length+'\"><div style=\"display: block;text-align: center;\">没有找到匹配的记录</div></td></tr>'\n\t\t\t\t\t\ttbody.html(_empty);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tvar rootNode = target.getRootNodes(data);\n\t\t\t\t\t$.each(rootNode, function(i, item) {\n\t\t\t\t\t\tvar tr = $('<tr></tr>');\n\t\t\t\t\t\ttr.addClass('treegrid-' + (j + \"_\" + i));\n\t\t\t\t\t\ttarget.renderRow(tr,item);\n\t\t\t\t\t\titem.isShow = true;\n\t\t\t\t\t\ttbody.append(tr);\n\t\t\t\t\t\ttarget.getChildNodes(data, item, (j + \"_\" + i), tbody);\n\t\t\t\t\t});\n\t\t\t\t\t// 下边的操作主要是为了查询时让一些没有根节点的节点显示\n\t\t\t\t\t$.each(data, function(i, item) {\n\t\t\t\t\t\tif(!item.isShow){\n\t\t\t\t\t\t\tvar tr = $('<tr></tr>');\n\t\t\t\t\t\t\ttr.addClass('treegrid-' + (j + \"_\" + i));\n\t\t\t\t\t\t\ttarget.renderRow(tr,item);\n\t\t\t\t\t\t\ttbody.append(tr);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\ttarget.append(tbody);\n\t\t\t\t\t// 初始化treegrid\n\t\t\t\t\ttarget.treegrid({\n\t\t\t\t\t\ttreeColumn: options.expandColumn?options.expandColumn:(hasSelectItem?1:0),//如果有radio或checkbox默认第二列层级显示，当前是在用户未设置的提前下\n\t\t\t\t\t\texpanderExpandedClass : options.expanderExpandedClass,\n\t\t\t\t\t\texpanderCollapsedClass : options.expanderCollapsedClass\n\t\t\t\t\t});\n\t\t\t\t\tif (!options.expandAll) {\n\t\t\t\t\t\ttarget.treegrid('collapseAll');\n\t\t\t\t\t}\n\t\t\t\t\t//动态设置表头宽度\n\t\t\t\t\tthead.css(\"width\", tbody.children(\":first\").css(\"width\"));\n\t\t\t\t\t// 行点击选中事件\n\t\t\t\t\ttarget.find(\"tbody\").find(\"tr\").click(function(){\n\t\t\t\t\t\tif(hasSelectItem){\n\t\t\t\t\t\t\tvar _ipt = $(this).find(\"input[name='select_item']\");\n\t\t\t\t\t\t\tif(_ipt.attr(\"type\")==\"radio\"){\n\t\t\t\t\t\t\t\t_ipt.prop('checked',true);\n\t\t\t\t\t\t\t\ttarget.find(\"tbody\").find(\"tr\").removeClass(\"treegrid-selected\");\n\t\t\t\t\t\t\t\t$(this).addClass(\"treegrid-selected\");\n\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\tif(_ipt.prop('checked')){\n\t\t\t\t\t\t\t\t\t_ipt.prop('checked',false);\n\t\t\t\t\t\t\t\t\t$(this).removeClass(\"treegrid-selected\");\n\t\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\t\t_ipt.prop('checked',true);\n\t\t\t\t\t\t\t\t\t$(this).addClass(\"treegrid-selected\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t    error:function(xhr,textStatus){\n\t\t\t\t\tvar _errorMsg = '<tr><td colspan=\"'+options.columns.length+'\"><div style=\"display: block;text-align: center;\">'+xhr.responseText+'</div></td></tr>'\n\t\t\t\t\ttbody.html(_errorMsg);\n\t\t\t\t\tdebugger;\n\t\t\t    },\n\t\t\t});\n\t\t}\n\t\tif (options.url) {\n\t\t\ttarget.load();\n\t\t} else {\n\t\t\t// 也可以通过defaults里面的data属性通过传递一个数据集合进来对组件进行初始化....有兴趣可以自己实现，思路和上述类似\n\t\t}\n\t\t\n\t\treturn target;\n\t};\n\n\t// 组件方法封装........\n\t$.fn.bootstrapTreeTable.methods = {\n\t\t// 返回选中记录的id（返回的id由配置中的id属性指定）\n\t\t// 为了兼容bootstrap-table的写法，统一返回数组，这里只返回了指定的id\n\t\tgetSelections : function(target, data) {\n\t\t\t// 所有被选中的记录input\n\t\t\tvar _ipt = target.find(\"tbody\").find(\"tr\").find(\"input[name='select_item']:checked\");\n\t\t\tvar chk_value =[]; \n\t\t\t// 如果是radio\n\t\t\tif(_ipt.attr(\"type\")==\"radio\"){\n\t\t\t\tchk_value.push({id:_ipt.val()}); \n\t\t\t}else{\n\t\t\t\t_ipt.each(function(_i,_item){ \n\t\t\t\t\tchk_value.push({id:$(_item).val()}); \n\t\t\t\t}); \n\t\t\t}\n\t\t\treturn chk_value;\n\t\t},\n\t\t// 刷新记录\n\t\trefresh : function(target, parms) {\n\t\t\tif(parms){\n\t\t\t\ttarget.load(parms);\n\t\t\t}else{\n                target.load();\n\t\t\t}\n\t\t},\n\t// 组件的其他方法也可以进行类似封装........\n\t};\n\n\t$.fn.bootstrapTreeTable.defaults = {\n\t\tid : 'id',// 选取记录返回的值\n\t\tcode : 'code',// 用于设置父子关系\n\t\tparentCode : 'parentId',// 用于设置父子关系\n\t\trootCodeValue: null,//设置根节点code值----可指定根节点，默认为null,\"\",0,\"0\"\n\t\tdata : [], // 构造table的数据集合\n\t\ttype : \"GET\", // 请求数据的ajax类型\n\t\turl : null, // 请求数据的ajax的url\n\t\tajaxParams : {}, // 请求数据的ajax的data属性\n\t\texpandColumn : null,// 在哪一列上面显示展开按钮\n\t\texpandAll : true, // 是否全部展开\n\t\tstriped : false, // 是否各行渐变色\n\t\tcolumns : [],\n        toolbar: null,//顶部工具条\n        height: 0,\n\t\texpanderExpandedClass : 'glyphicon glyphicon-chevron-down',// 展开的按钮的图标\n\t\texpanderCollapsedClass : 'glyphicon glyphicon-chevron-right'// 缩起的按钮的图标\n\n\t};\n})(jQuery);"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/jquery-treegrid/js/jquery.treegrid.bootstrap3.js",
    "content": "$.extend($.fn.treegrid.defaults, {\n    expanderExpandedClass: 'glyphicon glyphicon-chevron-down',\n    expanderCollapsedClass: 'glyphicon glyphicon-chevron-right'\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/extend/layer.ext.js",
    "content": "/*! layer弹层组件拓展类 */\n;!function(){layer.use(\"skin/layer.ext.css\",function(){layer.layui_layer_extendlayerextjs=!0});var a=layer.cache||{},b=function(b){return a.skin?\" \"+a.skin+\" \"+a.skin+\"-\"+b:\"\"};layer.prompt=function(a,c){a=a||{},\"function\"==typeof a&&(c=a);var d,e=2==a.formType?'<textarea class=\"layui-layer-input\">'+(a.value||\"\")+\"</textarea>\":function(){return'<input type=\"'+(1==a.formType?\"password\":\"text\")+'\" class=\"layui-layer-input\" value=\"'+(a.value||\"\")+'\">'}();return layer.open($.extend({btn:[\"&#x786E;&#x5B9A;\",\"&#x53D6;&#x6D88;\"],content:e,skin:\"layui-layer-prompt\"+b(\"prompt\"),success:function(a){d=a.find(\".layui-layer-input\"),d.focus()},yes:function(b){var e=d.val();\"\"===e?d.focus():e.length>(a.maxlength||500)?layer.tips(\"&#x6700;&#x591A;&#x8F93;&#x5165;\"+(a.maxlength||500)+\"&#x4E2A;&#x5B57;&#x6570;\",d,{tips:1}):c&&c(e,b,d)}},a))},layer.tab=function(a){a=a||{};var c=a.tab||{};return layer.open($.extend({type:1,skin:\"layui-layer-tab\"+b(\"tab\"),title:function(){var a=c.length,b=1,d=\"\";if(a>0)for(d='<span class=\"layui-layer-tabnow\">'+c[0].title+\"</span>\";a>b;b++)d+=\"<span>\"+c[b].title+\"</span>\";return d}(),content:'<ul class=\"layui-layer-tabmain\">'+function(){var a=c.length,b=1,d=\"\";if(a>0)for(d='<li class=\"layui-layer-tabli xubox_tab_layer\">'+(c[0].content||\"no content\")+\"</li>\";a>b;b++)d+='<li class=\"layui-layer-tabli\">'+(c[b].content||\"no  content\")+\"</li>\";return d}()+\"</ul>\",success:function(a){var b=a.find(\".layui-layer-title\").children(),c=a.find(\".layui-layer-tabmain\").children();b.on(\"mousedown\",function(a){a.stopPropagation?a.stopPropagation():a.cancelBubble=!0;var b=$(this),d=b.index();b.addClass(\"layui-layer-tabnow\").siblings().removeClass(\"layui-layer-tabnow\"),c.eq(d).show().siblings().hide()})}},a))},layer.photos=function(a,c,d){function e(a,b,c){var d=new Image;d.onload=function(){d.onload=null,b(d)},d.onerror=function(a){d.onerror=null,c(a)},d.src=a}var f={};if(a=a||{},a.photos){var g=a.photos.constructor===Object,h=g?a.photos:{},i=h.data||[],j=h.start||0;if(f.imgIndex=j+1,g){if(0===i.length)return void layer.msg(\"&#x6CA1;&#x6709;&#x56FE;&#x7247;\")}else{var k=$(a.photos),l=k.find(a.img||\"img\");if(0===l.length)return;if(c||k.find(h.img||\"img\").each(function(b){var c=$(this);i.push({alt:c.attr(\"alt\"),pid:c.attr(\"layer-pid\"),src:c.attr(\"layer-src\")||c.attr(\"src\"),thumb:c.attr(\"src\")}),c.on(\"click\",function(){layer.photos($.extend(a,{photos:{start:b,data:i,tab:a.tab},full:a.full}),!0)})}),!c)return}f.imgprev=function(a){f.imgIndex--,f.imgIndex<1&&(f.imgIndex=i.length),f.tabimg(a)},f.imgnext=function(a,b){f.imgIndex++,f.imgIndex>i.length&&(f.imgIndex=1,b)||f.tabimg(a)},f.keyup=function(a){if(!f.end){var b=a.keyCode;a.preventDefault(),37===b?f.imgprev(!0):39===b?f.imgnext(!0):27===b&&layer.close(f.index)}},f.tabimg=function(b){i.length<=1||(h.start=f.imgIndex-1,layer.close(f.index),layer.photos(a,!0,b))},f.event=function(){f.bigimg.hover(function(){f.imgsee.show()},function(){f.imgsee.hide()}),f.bigimg.find(\".layui-layer-imgprev\").on(\"click\",function(a){a.preventDefault(),f.imgprev()}),f.bigimg.find(\".layui-layer-imgnext\").on(\"click\",function(a){a.preventDefault(),f.imgnext()}),$(document).on(\"keyup\",f.keyup)},f.loadi=layer.load(1,{shade:\"shade\"in a?!1:.9,scrollbar:!1}),e(i[j].src,function(c){layer.close(f.loadi),f.index=layer.open($.extend({type:1,area:function(){var b=[c.width,c.height],d=[$(window).width()-100,$(window).height()-100];return!a.full&&b[0]>d[0]&&(b[0]=d[0],b[1]=b[0]*d[1]/b[0]),[b[0]+\"px\",b[1]+\"px\"]}(),title:!1,shade:.9,shadeClose:!0,closeBtn:!1,move:\".layui-layer-phimg img\",moveType:1,scrollbar:!1,moveOut:!0,shift:5*Math.random()|0,skin:\"layui-layer-photos\"+b(\"photos\"),content:'<div class=\"layui-layer-phimg\"><img src=\"'+i[j].src+'\" alt=\"'+(i[j].alt||\"\")+'\" layer-pid=\"'+i[j].pid+'\"><div class=\"layui-layer-imgsee\">'+(i.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:'+(d?\"block\":\"\")+'\"><span class=\"layui-layer-imgtit\"><a href=\"javascript:;\">'+(i[j].alt||\"\")+\"</a><em>\"+f.imgIndex+\"/\"+i.length+\"</em></span></div></div></div>\",success:function(b,c){f.bigimg=b.find(\".layui-layer-phimg\"),f.imgsee=b.find(\".layui-layer-imguide,.layui-layer-imgbar\"),f.event(b),a.tab&&a.tab(i[j],b)},end:function(){f.end=!0,$(document).off(\"keyup\",f.keyup)}},a))},function(){layer.close(f.loadi),layer.msg(\"&#x5F53;&#x524D;&#x56FE;&#x7247;&#x5730;&#x5740;&#x5F02;&#x5E38;<br>&#x662F;&#x5426;&#x7EE7;&#x7EED;&#x67E5;&#x770B;&#x4E0B;&#x4E00;&#x5F20;&#xFF1F;\",{time:3e4,btn:[\"下一张\",\"不看了\"],yes:function(){i.length>1&&f.imgnext(!0,!0)}})})}}}();\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/laydate/laydate.js",
    "content": "/**\n\n @Name : layDate v1.1 日期控件\n @Author: 贤心\n @Date: 2014-06-25\n @QQ群：176047195\n @Site：http://sentsin.com/layui/laydate\n\n */\n\n;!function(a){var b={path:\"\",defSkin:\"default\",format:\"YYYY-MM-DD\",min:\"1900-01-01 00:00:00\",max:\"2099-12-31 23:59:59\",isv:!1},c={},d=document,e=\"createElement\",f=\"getElementById\",g=\"getElementsByTagName\",h=[\"laydate_box\",\"laydate_void\",\"laydate_click\",\"LayDateSkin\",\"skins/\",\"/laydate.css\"];a.laydate=function(b){b=b||{};try{h.event=a.event?a.event:laydate.caller.arguments[0]}catch(d){}return c.run(b),laydate},laydate.v=\"1.1\",c.getPath=function(){var a=document.scripts,c=a[a.length-1].src;return b.path?b.path:c.substring(0,c.lastIndexOf(\"/\")+1)}(),c.use=function(a,b){var f=d[e](\"link\");f.type=\"text/css\",f.rel=\"stylesheet\",f.href=c.getPath+a+h[5],b&&(f.id=b),d[g](\"head\")[0].appendChild(f),f=null},c.trim=function(a){return a=a||\"\",a.replace(/^\\s|\\s$/g,\"\").replace(/\\s+/g,\" \")},c.digit=function(a){return 10>a?\"0\"+(0|a):a},c.stopmp=function(b){return b=b||a.event,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0,this},c.each=function(a,b){for(var c=0,d=a.length;d>c&&b(c,a[c])!==!1;c++);},c.hasClass=function(a,b){return a=a||{},new RegExp(\"\\\\b\"+b+\"\\\\b\").test(a.className)},c.addClass=function(a,b){return a=a||{},c.hasClass(a,b)||(a.className+=\" \"+b),a.className=c.trim(a.className),this},c.removeClass=function(a,b){if(a=a||{},c.hasClass(a,b)){var d=new RegExp(\"\\\\b\"+b+\"\\\\b\");a.className=a.className.replace(d,\"\")}return this},c.removeCssAttr=function(a,b){var c=a.style;c.removeProperty?c.removeProperty(b):c.removeAttribute(b)},c.shde=function(a,b){a.style.display=b?\"none\":\"block\"},c.query=function(a){var e,b,h,i,j;return a=c.trim(a).split(\" \"),b=d[f](a[0].substr(1)),b?a[1]?/^\\./.test(a[1])?(i=a[1].substr(1),j=new RegExp(\"\\\\b\"+i+\"\\\\b\"),e=[],h=d.getElementsByClassName?b.getElementsByClassName(i):b[g](\"*\"),c.each(h,function(a,b){j.test(b.className)&&e.push(b)}),e[0]?e:\"\"):(e=b[g](a[1]),e[0]?b[g](a[1]):\"\"):b:void 0},c.on=function(b,d,e){return b.attachEvent?b.attachEvent(\"on\"+d,function(){e.call(b,a.even)}):b.addEventListener(d,e,!1),c},c.stopMosup=function(a,b){\"mouseup\"!==a&&c.on(b,\"mouseup\",function(a){c.stopmp(a)})},c.run=function(a){var d,e,g,b=c.query,f=h.event;try{g=f.target||f.srcElement||{}}catch(i){g={}}if(d=a.elem?b(a.elem):g,f&&g.tagName){if(!d||d===c.elem)return;c.stopMosup(f.type,d),c.stopmp(f),c.view(d,a),c.reshow()}else e=a.event||\"click\",c.each((0|d.length)>0?d:[d],function(b,d){c.stopMosup(e,d),c.on(d,e,function(b){c.stopmp(b),d!==c.elem&&(c.view(d,a),c.reshow())})})},c.scroll=function(a){return a=a?\"scrollLeft\":\"scrollTop\",d.body[a]|d.documentElement[a]},c.winarea=function(a){return document.documentElement[a?\"clientWidth\":\"clientHeight\"]},c.isleap=function(a){return 0===a%4&&0!==a%100||0===a%400},c.checkVoid=function(a,b,d){var e=[];return a=0|a,b=0|b,d=0|d,a<c.mins[0]?e=[\"y\"]:a>c.maxs[0]?e=[\"y\",1]:a>=c.mins[0]&&a<=c.maxs[0]&&(a==c.mins[0]&&(b<c.mins[1]?e=[\"m\"]:b==c.mins[1]&&d<c.mins[2]&&(e=[\"d\"])),a==c.maxs[0]&&(b>c.maxs[1]?e=[\"m\",1]:b==c.maxs[1]&&d>c.maxs[2]&&(e=[\"d\",1]))),e},c.timeVoid=function(a,b){if(c.ymd[1]+1==c.mins[1]&&c.ymd[2]==c.mins[2]){if(0===b&&a<c.mins[3])return 1;if(1===b&&a<c.mins[4])return 1;if(2===b&&a<c.mins[5])return 1}else if(c.ymd[1]+1==c.maxs[1]&&c.ymd[2]==c.maxs[2]){if(0===b&&a>c.maxs[3])return 1;if(1===b&&a>c.maxs[4])return 1;if(2===b&&a>c.maxs[5])return 1}return a>(b?59:23)?1:void 0},c.check=function(){var a=c.options.format.replace(/YYYY|MM|DD|hh|mm|ss/g,\"\\\\d+\\\\\").replace(/\\\\$/g,\"\"),b=new RegExp(a),d=c.elem[h.elemv],e=d.match(/\\d+/g)||[],f=c.checkVoid(e[0],e[1],e[2]);if(\"\"!==d.replace(/\\s/g,\"\")){if(!b.test(d))return c.elem[h.elemv]=\"\",c.msg(\"日期不符合格式，请重新选择。\"),1;if(f[0])return c.elem[h.elemv]=\"\",c.msg(\"日期不在有效期内，请重新选择。\"),1;f.value=c.elem[h.elemv].match(b).join(),e=f.value.match(/\\d+/g),e[1]<1?(e[1]=1,f.auto=1):e[1]>12?(e[1]=12,f.auto=1):e[1].length<2&&(f.auto=1),e[2]<1?(e[2]=1,f.auto=1):e[2]>c.months[(0|e[1])-1]?(e[2]=31,f.auto=1):e[2].length<2&&(f.auto=1),e.length>3&&(c.timeVoid(e[3],0)&&(f.auto=1),c.timeVoid(e[4],1)&&(f.auto=1),c.timeVoid(e[5],2)&&(f.auto=1)),f.auto?c.creation([e[0],0|e[1],0|e[2]],1):f.value!==c.elem[h.elemv]&&(c.elem[h.elemv]=f.value)}},c.months=[31,null,31,30,31,30,31,31,30,31,30,31],c.viewDate=function(a,b,d){var f=(c.query,{}),g=new Date;a<(0|c.mins[0])&&(a=0|c.mins[0]),a>(0|c.maxs[0])&&(a=0|c.maxs[0]),g.setFullYear(a,b,d),f.ymd=[g.getFullYear(),g.getMonth(),g.getDate()],c.months[1]=c.isleap(f.ymd[0])?29:28,g.setFullYear(f.ymd[0],f.ymd[1],1),f.FDay=g.getDay(),f.PDay=c.months[0===b?11:b-1]-f.FDay+1,f.NDay=1,c.each(h.tds,function(a,b){var g,d=f.ymd[0],e=f.ymd[1]+1;b.className=\"\",a<f.FDay?(b.innerHTML=g=a+f.PDay,c.addClass(b,\"laydate_nothis\"),1===e&&(d-=1),e=1===e?12:e-1):a>=f.FDay&&a<f.FDay+c.months[f.ymd[1]]?(b.innerHTML=g=a-f.FDay+1,a-f.FDay+1===f.ymd[2]&&(c.addClass(b,h[2]),f.thisDay=b)):(b.innerHTML=g=f.NDay++,c.addClass(b,\"laydate_nothis\"),12===e&&(d+=1),e=12===e?1:e+1),c.checkVoid(d,e,g)[0]&&c.addClass(b,h[1]),c.options.festival&&c.festival(b,e+\".\"+g),b.setAttribute(\"y\",d),b.setAttribute(\"m\",e),b.setAttribute(\"d\",g),d=e=g=null}),c.valid=!c.hasClass(f.thisDay,h[1]),c.ymd=f.ymd,h.year.value=c.ymd[0]+\"年\",h.month.value=c.digit(c.ymd[1]+1)+\"月\",c.each(h.mms,function(a,b){var d=c.checkVoid(c.ymd[0],(0|b.getAttribute(\"m\"))+1);\"y\"===d[0]||\"m\"===d[0]?c.addClass(b,h[1]):c.removeClass(b,h[1]),c.removeClass(b,h[2]),d=null}),c.addClass(h.mms[c.ymd[1]],h[2]),f.times=[0|c.inymd[3]||0,0|c.inymd[4]||0,0|c.inymd[5]||0],c.each(new Array(3),function(a){c.hmsin[a].value=c.digit(c.timeVoid(f.times[a],a)?0|c.mins[a+3]:0|f.times[a])}),c[c.valid?\"removeClass\":\"addClass\"](h.ok,h[1])},c.festival=function(a,b){var c;switch(b){case\"1.1\":c=\"元旦\";break;case\"3.8\":c=\"妇女\";break;case\"4.5\":c=\"清明\";break;case\"5.1\":c=\"劳动\";break;case\"6.1\":c=\"儿童\";break;case\"9.10\":c=\"教师\";break;case\"10.1\":c=\"国庆\"}c&&(a.innerHTML=c),c=null},c.viewYears=function(a){var b=c.query,d=\"\";c.each(new Array(14),function(b){d+=7===b?\"<li \"+(parseInt(h.year.value)===a?'class=\"'+h[2]+'\"':\"\")+' y=\"'+a+'\">'+a+\"年</li>\":'<li y=\"'+(a-7+b)+'\">'+(a-7+b)+\"年</li>\"}),b(\"#laydate_ys\").innerHTML=d,c.each(b(\"#laydate_ys li\"),function(a,b){\"y\"===c.checkVoid(b.getAttribute(\"y\"))[0]?c.addClass(b,h[1]):c.on(b,\"click\",function(a){c.stopmp(a).reshow(),c.viewDate(0|this.getAttribute(\"y\"),c.ymd[1],c.ymd[2])})})},c.initDate=function(){var d=(c.query,new Date),e=c.elem[h.elemv].match(/\\d+/g)||[];e.length<3&&(e=c.options.start.match(/\\d+/g)||[],e.length<3&&(e=[d.getFullYear(),d.getMonth()+1,d.getDate()])),c.inymd=e,c.viewDate(e[0],e[1]-1,e[2])},c.iswrite=function(){var a=c.query,b={time:a(\"#laydate_hms\")};c.shde(b.time,!c.options.istime),c.shde(h.oclear,!(\"isclear\"in c.options?c.options.isclear:1)),c.shde(h.otoday,!(\"istoday\"in c.options?c.options.istoday:1)),c.shde(h.ok,!(\"issure\"in c.options?c.options.issure:1))},c.orien=function(a,b){var d,e=c.elem.getBoundingClientRect();a.style.left=e.left+(b?0:c.scroll(1))+\"px\",d=e.bottom+a.offsetHeight/1.5<=c.winarea()?e.bottom-1:e.top>a.offsetHeight/1.5?e.top-a.offsetHeight+1:c.winarea()-a.offsetHeight,a.style.top=d+(b?0:c.scroll())+\"px\"},c.follow=function(a){c.options.fixed?(a.style.position=\"fixed\",c.orien(a,1)):(a.style.position=\"absolute\",c.orien(a))},c.viewtb=function(){var a,b=[],f=[\"日\",\"一\",\"二\",\"三\",\"四\",\"五\",\"六\"],h={},i=d[e](\"table\"),j=d[e](\"thead\");return j.appendChild(d[e](\"tr\")),h.creath=function(a){var b=d[e](\"th\");b.innerHTML=f[a],j[g](\"tr\")[0].appendChild(b),b=null},c.each(new Array(6),function(d){b.push([]),a=i.insertRow(0),c.each(new Array(7),function(c){b[d][c]=0,0===d&&h.creath(c),a.insertCell(c)})}),i.insertBefore(j,i.children[0]),i.id=i.className=\"laydate_table\",a=b=null,i.outerHTML.toLowerCase()}(),c.view=function(a,f){var i,g=c.query,j={};f=f||a,c.elem=a,c.options=f,c.options.format||(c.options.format=b.format),c.options.start=c.options.start||\"\",c.mm=j.mm=[c.options.min||b.min,c.options.max||b.max],c.mins=j.mm[0].match(/\\d+/g),c.maxs=j.mm[1].match(/\\d+/g),h.elemv=/textarea|input/.test(c.elem.tagName.toLocaleLowerCase())?\"value\":\"innerHTML\",c.box?c.shde(c.box):(i=d[e](\"div\"),i.id=h[0],i.className=h[0],i.style.cssText=\"position: absolute;\",i.setAttribute(\"name\",\"laydate-v\"+laydate.v),i.innerHTML=j.html='<div class=\"laydate_top\"><div class=\"laydate_ym laydate_y\" id=\"laydate_YY\"><a class=\"laydate_choose laydate_chprev laydate_tab\"><cite></cite></a><input id=\"laydate_y\" readonly><label></label><a class=\"laydate_choose laydate_chnext laydate_tab\"><cite></cite></a><div class=\"laydate_yms\"><a class=\"laydate_tab laydate_chtop\"><cite></cite></a><ul id=\"laydate_ys\"></ul><a class=\"laydate_tab laydate_chdown\"><cite></cite></a></div></div><div class=\"laydate_ym laydate_m\" id=\"laydate_MM\"><a class=\"laydate_choose laydate_chprev laydate_tab\"><cite></cite></a><input id=\"laydate_m\" readonly><label></label><a class=\"laydate_choose laydate_chnext laydate_tab\"><cite></cite></a><div class=\"laydate_yms\" id=\"laydate_ms\">'+function(){var a=\"\";return c.each(new Array(12),function(b){a+='<span m=\"'+b+'\">'+c.digit(b+1)+\"月</span>\"}),a}()+\"</div>\"+\"</div>\"+\"</div>\"+c.viewtb+'<div class=\"laydate_bottom\">'+'<ul id=\"laydate_hms\">'+'<li class=\"laydate_sj\">时间</li>'+\"<li><input readonly>:</li>\"+\"<li><input readonly>:</li>\"+\"<li><input readonly></li>\"+\"</ul>\"+'<div class=\"laydate_time\" id=\"laydate_time\"></div>'+'<div class=\"laydate_btn\">'+'<a id=\"laydate_clear\">清空</a>'+'<a id=\"laydate_today\">今天</a>'+'<a id=\"laydate_ok\">确认</a>'+\"</div>\"+(b.isv?'<a href=\"http://sentsin.com/layui/laydate/\" class=\"laydate_v\" target=\"_blank\">laydate-v'+laydate.v+\"</a>\":\"\")+\"</div>\",d.body.appendChild(i),c.box=g(\"#\"+h[0]),c.events(),i=null),c.follow(c.box),f.zIndex?c.box.style.zIndex=f.zIndex:c.removeCssAttr(c.box,\"z-index\"),c.stopMosup(\"click\",c.box),c.initDate(),c.iswrite(),c.check()},c.reshow=function(){return c.each(c.query(\"#\"+h[0]+\" .laydate_show\"),function(a,b){c.removeClass(b,\"laydate_show\")}),this},c.close=function(){c.reshow(),c.shde(c.query(\"#\"+h[0]),1),c.elem=null},c.parse=function(a,d,e){return a=a.concat(d),e=e||(c.options?c.options.format:b.format),e.replace(/YYYY|MM|DD|hh|mm|ss/g,function(){return a.index=0|++a.index,c.digit(a[a.index])})},c.creation=function(a,b){var e=(c.query,c.hmsin),f=c.parse(a,[e[0].value,e[1].value,e[2].value]);c.elem[h.elemv]=f,b||(c.close(),\"function\"==typeof c.options.choose&&c.options.choose(f))},c.events=function(){var b=c.query,e={box:\"#\"+h[0]};c.addClass(d.body,\"laydate_body\"),h.tds=b(\"#laydate_table td\"),h.mms=b(\"#laydate_ms span\"),h.year=b(\"#laydate_y\"),h.month=b(\"#laydate_m\"),c.each(b(e.box+\" .laydate_ym\"),function(a,b){c.on(b,\"click\",function(b){c.stopmp(b).reshow(),c.addClass(this[g](\"div\")[0],\"laydate_show\"),a||(e.YY=parseInt(h.year.value),c.viewYears(e.YY))})}),c.on(b(e.box),\"click\",function(){c.reshow()}),e.tabYear=function(a){0===a?c.ymd[0]--:1===a?c.ymd[0]++:2===a?e.YY-=14:e.YY+=14,2>a?(c.viewDate(c.ymd[0],c.ymd[1],c.ymd[2]),c.reshow()):c.viewYears(e.YY)},c.each(b(\"#laydate_YY .laydate_tab\"),function(a,b){c.on(b,\"click\",function(b){c.stopmp(b),e.tabYear(a)})}),e.tabMonth=function(a){a?(c.ymd[1]++,12===c.ymd[1]&&(c.ymd[0]++,c.ymd[1]=0)):(c.ymd[1]--,-1===c.ymd[1]&&(c.ymd[0]--,c.ymd[1]=11)),c.viewDate(c.ymd[0],c.ymd[1],c.ymd[2])},c.each(b(\"#laydate_MM .laydate_tab\"),function(a,b){c.on(b,\"click\",function(b){c.stopmp(b).reshow(),e.tabMonth(a)})}),c.each(b(\"#laydate_ms span\"),function(a,b){c.on(b,\"click\",function(a){c.stopmp(a).reshow(),c.hasClass(this,h[1])||c.viewDate(c.ymd[0],0|this.getAttribute(\"m\"),c.ymd[2])})}),c.each(b(\"#laydate_table td\"),function(a,b){c.on(b,\"click\",function(a){c.hasClass(this,h[1])||(c.stopmp(a),c.creation([0|this.getAttribute(\"y\"),0|this.getAttribute(\"m\"),0|this.getAttribute(\"d\")]))})}),h.oclear=b(\"#laydate_clear\"),c.on(h.oclear,\"click\",function(){c.elem[h.elemv]=\"\",c.close()}),h.otoday=b(\"#laydate_today\"),c.on(h.otoday,\"click\",function(){c.elem[h.elemv]=laydate.now(0,c.options.format),c.close()}),h.ok=b(\"#laydate_ok\"),c.on(h.ok,\"click\",function(){c.valid&&c.creation([c.ymd[0],c.ymd[1]+1,c.ymd[2]])}),e.times=b(\"#laydate_time\"),c.hmsin=e.hmsin=b(\"#laydate_hms input\"),e.hmss=[\"小时\",\"分钟\",\"秒数\"],e.hmsarr=[],c.msg=function(a,d){var f='<div class=\"laydte_hsmtex\">'+(d||\"提示\")+\"<span>×</span></div>\";\"string\"==typeof a?(f+=\"<p>\"+a+\"</p>\",c.shde(b(\"#\"+h[0])),c.removeClass(e.times,\"laydate_time1\").addClass(e.times,\"laydate_msg\")):(e.hmsarr[a]?f=e.hmsarr[a]:(f+='<div id=\"laydate_hmsno\" class=\"laydate_hmsno\">',c.each(new Array(0===a?24:60),function(a){f+=\"<span>\"+a+\"</span>\"}),f+=\"</div>\",e.hmsarr[a]=f),c.removeClass(e.times,\"laydate_msg\"),c[0===a?\"removeClass\":\"addClass\"](e.times,\"laydate_time1\")),c.addClass(e.times,\"laydate_show\"),e.times.innerHTML=f},e.hmson=function(a,d){var e=b(\"#laydate_hmsno span\"),f=c.valid?null:1;c.each(e,function(b,e){f?c.addClass(e,h[1]):c.timeVoid(b,d)?c.addClass(e,h[1]):c.on(e,\"click\",function(){c.hasClass(this,h[1])||(a.value=c.digit(0|this.innerHTML))})}),c.addClass(e[0|a.value],\"laydate_click\")},c.each(e.hmsin,function(a,b){c.on(b,\"click\",function(b){c.stopmp(b).reshow(),c.msg(a,e.hmss[a]),e.hmson(this,a)})}),c.on(d,\"mouseup\",function(){var a=b(\"#\"+h[0]);a&&\"none\"!==a.style.display&&(c.check()||c.close())}).on(d,\"keydown\",function(b){b=b||a.event;var d=b.keyCode;13===d&&c.creation([c.ymd[0],c.ymd[1]+1,c.ymd[2]])})},c.init=function(){c.use(\"need\"),c.use(h[4]+b.defSkin,h[3]),c.skinLink=c.query(\"#\"+h[3])}(),laydate.reset=function(){c.box&&c.elem&&c.follow(c.box)},laydate.now=function(a,b){var d=new Date(0|a?function(a){return 864e5>a?+new Date+864e5*a:a}(parseInt(a)):+new Date);return c.parse([d.getFullYear(),d.getMonth()+1,d.getDate()],[d.getHours(),d.getMinutes(),d.getSeconds()],b)},laydate.skin=function(a){c.skinLink.href=c.getPath+h[4]+a+h[5]}}(window);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/laydate/need/laydate.css",
    "content": "/**\n\n @Name： laydate 核心样式\n @Author：贤心\n @Site：http://sentsin.com/layui/laydate\n\n**/\n\nhtml{_background-image:url(about:blank); _background-attachment:fixed;}\n.layer-date{display: inline-block!important;vertical-align:text-top;}\n.laydate_body .laydate_box, .laydate_body .laydate_box *{margin:0; padding:0;}\n.laydate-icon,\n.laydate-icon-default,\n.laydate-icon-danlan,\n.laydate-icon-dahong,\n.laydate-icon-molv{height:34px; padding-right:20px;min-width:34px;vertical-align: text-top;border:1px solid #C6C6C6; background-repeat:no-repeat; background-position:right center;  background-color:#fff; outline:0;}\n.laydate-icon-default{ background-image:url(../skins/default/icon.png)}\n.laydate-icon-danlan{border:1px solid #B1D2EC; background-image:url(../skins/danlan/icon.png)}\n.laydate-icon-dahong{background-image:url(../skins/dahong/icon.png)}\n.laydate-icon-molv{background-image:url(../skins/molv/icon.png)}\n.laydate_body .laydate_box{width:240px; font:12px '\\5B8B\\4F53'; z-index:99999999; *margin:-2px 0 0 -2px; *overflow:hidden; _margin:0; _position:absolute!important; background-color:#fff;}\n.laydate_body .laydate_box li{list-style:none;}\n.laydate_body .laydate_box .laydate_void{cursor:text!important;}\n.laydate_body .laydate_box a, .laydate_body .laydate_box a:hover{text-decoration:none; blr:expression(this.onFocus=this.blur()); cursor:pointer;}\n.laydate_body .laydate_box a:hover{text-decoration:none;}\n.laydate_body .laydate_box cite, .laydate_body .laydate_box label{position:absolute; width:0; height:0; border-width:5px; border-style:dashed; border-color:transparent; overflow:hidden; cursor:pointer;}\n.laydate_body .laydate_box .laydate_yms, .laydate_body .laydate_box .laydate_time{display:none;}\n.laydate_body .laydate_box .laydate_show{display:block;}\n.laydate_body .laydate_box input{outline:0; font-size:14px; background-color:#fff;}\n.laydate_body .laydate_top{position:relative; height:26px; padding:5px; *width:100%; z-index:99;}\n.laydate_body .laydate_ym{position:relative; float:left; height:24px; cursor:pointer;}\n.laydate_body .laydate_ym input{float:left; height:24px; line-height:24px; text-align:center; border:none; cursor:pointer;}\n.laydate_body .laydate_ym .laydate_yms{position:absolute; left: -1px; top: 24px; height:181px;}\n.laydate_body .laydate_y{width:121px;}\n.laydate_body .laydate_y input{width:64px; margin-right:15px;}\n.laydate_body .laydate_y .laydate_yms{width:121px; text-align:center;}\n.laydate_body .laydate_y .laydate_yms a{position:relative; display:block; height:20px;}\n.laydate_body .laydate_y .laydate_yms ul{height:139px; padding:0; *overflow:hidden;}\n.laydate_body .laydate_y .laydate_yms ul li{float:left; width:60px; height:20px; line-height: 20px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;}\n.laydate_box *{box-sizing:content-box!important;}\n.laydate_body .laydate_m{width:99px;float: right;margin-right:-2px;}\n.laydate_body .laydate_m .laydate_yms{width:99px; padding:0;}\n.laydate_body .laydate_m input{width:42px; margin-right:15px;}\n.laydate_body .laydate_m .laydate_yms span{display:block; float:left; width:42px; margin: 5px 0 0 5px; line-height:24px; text-align:center; _display:inline;}\n.laydate_body .laydate_choose{display:block; float:left; position:relative; width:20px; height:24px;}\n.laydate_body .laydate_choose cite, .laydate_body .laydate_tab cite{left:50%; top:50%;}\n.laydate_body .laydate_chtop cite{margin:-7px 0 0 -5px; border-bottom-style:solid;}\n.laydate_body .laydate_chdown cite, .laydate_body .laydate_ym label{top:50%; margin:-2px 0 0 -5px; border-top-style:solid;}\n.laydate_body .laydate_chprev cite{margin:-5px 0 0 -7px;}\n.laydate_body .laydate_chnext cite{margin:-5px 0 0 -2px;}\n.laydate_body .laydate_ym label{right:28px;}\n.laydate_body .laydate_table{ width:230px; margin:0 5px; border-collapse:collapse; border-spacing:0px; }\n.laydate_body .laydate_table td{width:31px; height:19px; line-height:19px; text-align: center; cursor:pointer; font-size: 12px;}\n.laydate_body .laydate_table thead{height:22px; line-height:22px;}\n.laydate_body .laydate_table thead th{font-weight:400; font-size:12px; text-align:center;}\n.laydate_body .laydate_bottom{position:relative; height:22px; line-height:20px; padding:5px; font-size:12px;}\n.laydate_body .laydate_bottom #laydate_hms{position: relative; z-index: 1; float:left; }\n.laydate_body .laydate_time{ position:absolute; left:5px; bottom: 26px; width:129px; height:125px; *overflow:hidden;}\n.laydate_body .laydate_time .laydate_hmsno{ padding:5px 0 0 5px;}\n.laydate_body .laydate_time .laydate_hmsno span{display:block; float:left; width:24px; height:19px; line-height:19px; text-align:center; cursor:pointer; *margin-bottom:-5px;}\n.laydate_body .laydate_time1{width:228px; height:154px;}\n.laydate_body .laydate_time1 .laydate_hmsno{padding: 6px 0 0 8px;}\n.laydate_body .laydate_time1 .laydate_hmsno span{width:21px; height:20px; line-height:20px;}\n.laydate_body .laydate_msg{left:49px; bottom:67px; width:141px; height:auto; overflow: hidden;}\n.laydate_body .laydate_msg p{padding:5px 10px;}\n.laydate_body .laydate_bottom li{float:left; height:20px; line-height:20px; border-right:none; font-weight:900;}\n.laydate_body .laydate_bottom .laydate_sj{width:33px; text-align:center; font-weight:400;}\n.laydate_body .laydate_bottom input{float:left; width:21px; height:20px; line-height:20px; border:none; text-align:center; cursor:pointer; font-size:12px;  font-weight:400;}\n.laydate_body .laydate_bottom .laydte_hsmtex{height:20px; line-height:20px; text-align:center;}\n.laydate_body .laydate_bottom .laydte_hsmtex span{position:absolute; width:20px; top:0; right:0px; cursor:pointer;}\n.laydate_body .laydate_bottom .laydte_hsmtex span:hover{font-size:14px;}\n.laydate_body .laydate_bottom .laydate_btn{position:absolute; right:5px; top:5px;}\n.laydate_body .laydate_bottom .laydate_btn a{float:left; height:20px; padding:0 6px; _padding:0 5px;}\n.laydate_body .laydate_bottom .laydate_v{position:absolute; left:10px; top:6px; font-family:Courier; z-index:0;}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/laydate/skins/default/laydate.css",
    "content": "/**\n\n @Name： laydate皮肤：墨绿\n @Author：贤心\n @Site：http://sentsin.com/layui/laydate\n\n**/\n\n.laydate-icon{border:1px solid #ccc; background-image:url(icon.png)}\n\n.laydate_body .laydate_bottom #laydate_hms,\n.laydate_body .laydate_time{border:1px solid #ccc;}\n\n.laydate_body .laydate_box,\n.laydate_body .laydate_ym .laydate_yms,\n.laydate_body .laydate_time{box-shadow: 2px 2px 5px rgba(0,0,0,.1);}\n\n.laydate_body .laydate_box{border-top:none; border-bottom:none; background-color:#fff; color:#00625A;}\n.laydate_body .laydate_box input{background:none!important; color:#fff;}\n.laydate_body .laydate_box .laydate_void{color:#00E8D7!important;}\n.laydate_body .laydate_box a, .laydate_body .laydate_box a:hover{color:#00625A;}\n.laydate_body .laydate_box a:hover{color:#666;}\n.laydate_body .laydate_click{background-color:#009F95!important; color:#fff!important;}\n.laydate_body .laydate_top{border-top:1px solid #009F95; background-color:#009F95}\n.laydate_body .laydate_ym{border:1px solid #009F95; background-color:#009F95;}\n.laydate_body .laydate_ym .laydate_yms{border:1px solid #009F95; background-color:#009F95; color:#fff;}\n.laydate_body .laydate_y .laydate_yms a{border-bottom:1px solid #009F95;}\n.laydate_body .laydate_y .laydate_yms .laydate_chdown{border-top:1px solid #009F95; border-bottom:none;}\n.laydate_body .laydate_choose{border-left:1px solid #009F95;}\n.laydate_body .laydate_chprev{border-left:none; border-right:1px solid #009F95;}\n.laydate_body .laydate_choose:hover,\n.laydate_body .laydate_y .laydate_yms a:hover{background-color:#00C1B3;}\n.laydate_body .laydate_chtop cite{border-bottom-color:#fff;}\n.laydate_body .laydate_chdown cite, .laydate_body .laydate_ym label{border-top-color:#fff;}\n.laydate_body .laydate_chprev cite{border-right-style:solid; border-right-color:#fff;}\n.laydate_body .laydate_chnext cite{border-left-style:solid; border-left-color:#fff;}\n.laydate_body .laydate_table{width: 240px!important; margin: 0!important; border:1px solid #ccc; border-top:none; border-bottom:none;}\n.laydate_body .laydate_table td{border:none;  height:21px!important; line-height:21px!important; background-color:#fff; color:#00625A;}\n.laydate_body .laydate_table .laydate_nothis{color:#999;}\n.laydate_body .laydate_table thead{border-bottom:1px solid #ccc; height:21px!important; line-height:21px!important;}\n.laydate_body .laydate_table thead th{}\n.laydate_body .laydate_bottom{border:1px solid #ccc; border-top:none;}\n.laydate_body .laydate_bottom #laydate_hms{background-color:#fff;}\n.laydate_body .laydate_time{background-color:#fff;}\n.laydate_body .laydate_time1{width: 226px!important; height: 152px!important;}\n.laydate_body .laydate_bottom .laydate_sj{width:31px!important; border-right:1px solid #ccc; background-color:#fff;}\n.laydate_body .laydate_bottom input{background-color:#fff; color:#00625A;}\n.laydate_body .laydate_bottom .laydte_hsmtex{border-bottom:1px solid #ccc;}\n.laydate_body .laydate_bottom .laydate_btn{border-right:1px solid #ccc;}\n.laydate_body .laydate_bottom .laydate_v{color:#999}\n.laydate_body .laydate_bottom .laydate_btn a{border: 1px solid #ccc; border-right:none; background-color:#fff;}\n.laydate_body .laydate_bottom .laydate_btn a:hover{background-color:#F6F6F6; color:#00625A;}\n\n.laydate_body .laydate_m .laydate_yms span:hover,\n.laydate_body .laydate_time .laydate_hmsno span:hover,\n.laydate_body .laydate_y .laydate_yms ul li:hover,\n.laydate_body .laydate_table td:hover{background-color:#00C1B3; color:#fff;}\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/layim/layim.css",
    "content": "/*\n\n @Name: layim WebIM 1.0.0\n @Author：贤心（子涵修改）\n @Date: 2014-04-25\n @Blog: http://sentsin.com\n\n */\nbody,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,input,button,textarea,p,blockquote,th,td,form{margin:0; padding:0;}\ninput,button,textarea,select,optgroup,option{font-family:inherit; font-size:inherit; font-style:inherit; font-weight:inherit; outline: 0;}\nli{list-style:none;}\n.xxim_icon, .xxim_main i, .layim_chatbox i{position:absolute;}\n.loading{background:url(loading.gif) no-repeat center center;}\n.layim_chatbox a, .layim_chatbox a:hover{color:#343434; text-decoration:none; }\n.layim_zero{position:absolute; width:0; height:0; border-style:dashed; border-color:transparent; overflow:hidden;}\n\n.xxim_main{position:fixed; right:1px; bottom:1px; width:230px; border:1px solid #BEBEBE; background-color:#fff; font-size:12px; box-shadow: 0 0 10px rgba(0,0,0,.2); z-index:99999999}\n.layim_chatbox textarea{resize:none;}\n.xxim_main em, .xxim_main i, .layim_chatbox em, .layim_chatbox i{font-style:normal; font-weight:400;}\n.xxim_main h5{font-size:100%; font-weight:400;}\n\n/* 搜索栏 */\n.xxim_search{position:relative; padding-left:40px; height:40px; border-bottom:1px solid #DCDCDC; background-color:#fff;}\n.xxim_search i{left:10px; top:12px; width:16px; height:16px;font-size: 16px;color:#999;}\n.xxim_search input{border:none; background:none; width: 180px; margin-top:10px; line-height:20px;}\n.xxim_search span{display:none; position:absolute; right:10px; top:10px; height:18px; line-height:18px;width:18px;text-align: center;background-color:#AFAFAF; color:#fff; cursor:pointer; border-radius:2px; font-size:12px; font-weight:900;}\n.xxim_search span:hover{background-color:#FCBE00;}\n\n/* 主面板tab */\n.xxim_tabs{height:45px; border-bottom:1px solid #DBDBDB; background-color:#F4F4F4; font-size:0;}\n.xxim_tabs span{position:relative; display:inline-block; *display:inline; *zoom:1; vertical-align:top; width:76px; height:45px; border-right:1px solid #DBDBDB; cursor:pointer; font-size:12px;}\n.xxim_tabs span i{top:12px; left:50%; width:20px; margin-left:-10px; height:20px;font-size:20px;color:#ccc;}\n.xxim_tabs .xxim_tabnow{height:46px; background-color:#fff;}\n.xxim_tabs .xxim_tabnow i{color:#1ab394;}\n.xxim_tabs .xxim_latechat{border-right:none;}\n.xxim_tabs .xxim_tabfriend i{width:14px; margin-left:-7px;}\n\n/* 主面板列表 */\n.xxim_list{display:none; height:350px; padding:5px 0; overflow:hidden;}\n.xxim_list:hover{ overflow-y:auto;}\n.xxim_list h5{position:relative; padding-left:32px; height:26px; line-height:26px; cursor:pointer; color:#000; font-size:0;}\n.xxim_list h5 span{display:inline-block; *display:inline; *zoom:1; vertical-align:top; max-width:140px; overflow:hidden; text-overflow: ellipsis; white-space:nowrap; font-size:12px;}\n.xxim_list h5 i{left:15px; top:8px; width:10px; height:10px;font-size:10px;color:#666;}\n.xxim_list h5 *{font-size:12px;}\n.xxim_list .xxim_chatlist{display:none;}\n.xxim_list .xxim_liston h5 i{width:8px; height:7px;}\n.xxim_list .xxim_liston .xxim_chatlist{display:block;}\n.xxim_chatlist {}\n.xxim_chatlist li{position:relative; height:40px; line-height:30px; padding:5px 10px; font-size:0; cursor:pointer;}\n.xxim_chatlist li:hover{background-color:#F2F4F8}\n.xxim_chatlist li *{display:inline-block; *display:inline; *zoom:1; vertical-align:top; font-size:12px;}\n.xxim_chatlist li span{padding-left:10px; max-width:120px;  overflow:hidden; text-overflow: ellipsis; white-space:nowrap;}\n.xxim_chatlist li img{width:30px; height:30px;}\n.xxim_chatlist li .xxim_time{position:absolute; right:10px; color:#999;}\n.xxim_list .xxim_errormsg{text-align:center; margin:50px 0; color:#999;}\n.xxim_searchmain{position:absolute; width:230px; height:491px; left:0; top:41px; z-index:10; background-color:#fff;}\n\n/* 主面板底部 */\n.xxim_bottom{height:34px; border-top:1px solid #D0DCF3; background-color:#F2F4F8;}\n.xxim_expend{border-left:1px solid #D0DCF3; border-bottom:1px solid #D0DCF3;}\n.xxim_bottom li{position:relative; width:50px; height:32px; line-height:32px; float:left; border-right:1px solid #D0DCF3;  cursor:pointer;}\n.xxim_bottom li i{ top:9px;}\n.xxim_bottom .xxim_hide{border-right:none;}\n.xxim_bottom .xxim_online{width:72px; padding-left:35px;}\n.xxim_online i{left:13px; width:14px; height:14px;font-size:14px;color:#FFA00A;}\n.xxim_setonline{display:none; position:absolute; left:-79px; bottom:-1px;  border:1px solid #DCDCDC; background-color:#fff;}\n.xxim_setonline span{position:relative; display:block; width:32px;width: 77px; padding:0 10px 0 35px;}\n.xxim_setonline span:hover{background-color:#F2F4F8;}\n.xxim_offline .xxim_nowstate, .xxim_setoffline i{color:#999;}\n.xxim_mymsg i{left:18px; width:14px; height:14px;font-size: 14px;}\n.xxim_mymsg a{position:absolute; left:0; top:0; width:50px; height:32px;}\n.xxim_seter i{left:18px; width:14px; height:14px;font-size: 14px;}\n.xxim_hide i{left:18px; width:14px; height:14px;font-size: 14px;}\n.xxim_show i{}\n.xxim_bottom .xxim_on{position:absolute; left:-17px; top:50%; width:16px;text-align: center;color:#999;line-height: 97px; height:97px; margin-top:-49px;border:solid 1px #BEBEBE;border-right: none; background:#F2F4F8;}\n.xxim_bottom .xxim_off{}\n\n/* 聊天窗口 */\n.layim_chatbox{width:620px; border:1px solid #BEBEBE; background-color:#fff; font-size:12px; box-shadow: 0 0 10px rgba(0,0,0,.2);}\n.layim_chatbox h6{position:relative; height:40px; border-bottom:1px solid #D9D9D9; background-color:#FCFDFA}\n.layim_move{position:absolute; height:40px; width: 620px; z-index:0;}\n.layim_face{position:absolute; bottom:-1px; left:10px; width:64px; height:64px;padding:1px;background: #fff; border:1px solid #ccc;}\n.layim_face img{width:60px; height:60px;}\n.layim_names{position:absolute; left:90px; max-width:300px; line-height:40px; color:#000; overflow:hidden; text-overflow: ellipsis; white-space:nowrap; font-size:14px;}\n.layim_rightbtn{position:absolute; right:15px; top:12px; font-size:20px;}\n.layim_rightbtn i{position:relative; width:16px; height:16px; display:inline-block; *display:inline; *zoom:1; vertical-align:top; cursor:pointer; transition: all .3s;text-align: center;line-height: 16px;}\n.layim_rightbtn .layim_close{background: #FFA00A;color:#fff;}\n.layim_rightbtn .layim_close:hover{-webkit-transform: rotate(180deg); -moz-transform: rotate(180deg);}\n.layim_rightbtn .layer_setmin{margin-right:5px;color:#999;font-size:14px;font-weight: 700;}\n.layim_chat, .layim_chatmore,.layim_groups{height:450px; overflow:hidden;}\n.layim_chatmore{display:none; float:left; width:135px; border-right:1px solid #BEBEBE; background-color:#F2F2F2}\n.layim_chatlist li, .layim_groups li{position:relative; height:30px; line-height:30px; padding:0 10px; overflow:hidden; text-overflow: ellipsis; white-space:nowrap; cursor:pointer;}\n.layim_chatlist li{padding:0 20px 0 10px;}\n.layim_chatlist li:hover{background-color:#E3E3E3;}\n.layim_chatlist li span{display:inline-block; *display:inline; *zoom:1; vertical-align:top; width:90px; overflow:hidden; text-overflow: ellipsis; white-space:nowrap;}\n.layim_chatlist li em{display:none; position:absolute; top:6px; right:10px; height:18px; line-height:18px;width:18px;text-align: center;font-size:14px;font-weight:900; border-radius:3px;}\n.layim_chatlist li em:hover{background-color: #FCBE00; color:#fff;}\n.layim_chatlist .layim_chatnow,.layim_chatlist .layim_chatnow:hover{/*border-top:1px solid #D9D9D9; border-bottom:1px solid #D9D9D9;*/ background-color:#fff;}\n.layim_chat{}\n.layim_chatarea{height:280px;}\n.layim_chatview{display:none; height:280px; overflow:hidden;}\n.layim_chatmore:hover, .layim_groups:hover, .layim_chatview:hover{overflow-y:auto;}\n.layim_chatview li{margin-bottom:10px; clear:both; *zoom:1;}\n.layim_chatview li:after{content:'\\20'; clear:both; *zoom:1; display:block; height:0;}\n\n.layim_chatthis{display:block;}\n.layim_chatuser{float:left; padding:15px; font-size:0;}\n.layim_chatuser *{display:inline-block; *display:inline; *zoom:1; vertical-align:top; line-height:30px; font-size:12px; padding-right:10px;}\n.layim_chatuser img{width:30px; height:30px;padding-right: 0;margin-right: 15px;}\n.layim_chatuser .layim_chatname{max-width:230px; overflow:hidden; text-overflow: ellipsis; white-space:nowrap;}\n.layim_chatuser .layim_chattime{color:#999; padding-left:10px;}\n.layim_chatsay{position:relative; float:left; margin:0 15px; padding:10px; line-height:20px; background-color:#F3F3F3; border-radius:3px; clear:both;}\n.layim_chatsay .layim_zero{left:5px; top:-8px; border-width:8px; border-right-style:solid; border-right-color:#F3F3F3;}\n.layim_chateme .layim_chatuser{float:right;}\n.layim_chateme .layim_chatuser *{padding-right:0; padding-left:10px;}\n.layim_chateme .layim_chatuser img{margin-left:15px;padding-left: 0;}\n.layim_chateme .layim_chatsay .layim_zero{left:auto; right:10px;}\n.layim_chateme .layim_chatuser .layim_chattime{padding-left:0; padding-right:10px;}\n.layim_chateme .layim_chatsay{float:right; background-color:#EBFBE3}\n.layim_chateme .layim_zero{border-right-color:#EBFBE3;}\n.layim_groups{display:none; float:right; width:130px; border-left:1px solid #D9D9D9; background-color:#fff;}\n.layim_groups ul{display:none;}\n.layim_groups ul.layim_groupthis{display:block;}\n.layim_groups li *{display:inline-block; *display:inline; *zoom:1; vertical-align:top; margin-right:10px;}\n.layim_groups li img{width:20px; height:20px; margin-top:5px;}\n.layim_groups li span{max-width:80px; overflow:hidden; text-overflow: ellipsis; white-space:nowrap;}\n.layim_groups li:hover{background-color:#F3F3F3;}\n.layim_groups .layim_errors{text-align:center; color:#999;}\n.layim_tool{position:relative; height:35px; line-height:35px; padding-left:10px; background-color:#F3F3F3;}\n.layim_tool i{position:relative; top:10px; display:inline-block; *display:inline; *zoom:1; vertical-align:top; width:16px; height:16px; margin-right:10px; cursor:pointer;font-size:16px;color:#999;font-weight: 700;}\n.layim_tool i:hover{color:#FFA00A;}\n.layim_tool .layim_seechatlog{position:absolute; right:15px;}\n.layim_tool .layim_seechatlog i{}\n.layim_write{display:block; border:none; width:98%; height:90px; line-height:20px; margin:5px auto 0;}\n.layim_send{position:relative; height:40px; background-color:#F3F3F3;}\n.layim_sendbtn{position:absolute; height:26px; line-height:26px; right:10px; top:8px; padding:0 40px 0 20px; background-color:#FFA00A; color:#fff; border-radius:3px; cursor:pointer;}\n.layim_enter{position:absolute; right:0; border-left:1px solid #FFB94F; width:24px; height:26px;}\n.layim_enter:hover{background-color:#E68A00; border-radius:0 3px 3px 0;}\n.layim_enter .layim_zero{left:7px; top:11px; border-width:5px; border-top-style:solid; border-top-color:#FFE0B3;}\n.layim_sendtype{display:none; position:absolute; right:10px; bottom:37px; border:1px solid #D9D9D9; background-color:#fff; text-align:left;}\n.layim_sendtype span{display:block; line-height:24px; padding:0 10px 0 25px; cursor:pointer;}\n.layim_sendtype span:hover{background-color:#F3F3F3;}\n.layim_sendtype span i{left:5px;}\n\n.layim_min{display:none; position:absolute; left:-190px; bottom:-1px; width:160px; height:32px; line-height:32px; padding:0 10px; overflow:hidden; text-overflow: ellipsis; white-space:nowrap; border:1px solid #ccc; box-shadow: 0 0 5px rgba(0,0,75,.2); background-color:#FCFDFA; cursor:pointer;}\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/layim/layim.js",
    "content": "/*\n\n @Name: layui WebIM 1.0.0\n @Author：贤心\n @Date: 2014-04-25\n @Blog: http://sentsin.com\n\n */\n\n;!function(win, undefined){\n\nvar config = {\n    msgurl: 'mailbox.html?msg=',\n    chatlogurl: 'mailbox.html?user=',\n    aniTime: 200,\n    right: -232,\n    api: {\n        friend: 'js/plugins/layer/layim/data/friend.json', //好友列表接口\n        group: 'js/plugins/layer/layim/data/group.json', //群组列表接口\n        chatlog: 'js/plugins/layer/layim/data/chatlog.json', //聊天记录接口\n        groups: 'js/plugins/layer/layim/data/groups.json', //群组成员接口\n        sendurl: '' //发送消息接口\n    },\n    user: { //当前用户信息\n        name: '游客',\n        face: 'img/a1.jpg'\n    },\n\n    //自动回复内置文案，也可动态读取数据库配置\n    autoReplay: [\n        '您好，我现在有事不在，一会再和您联系。',\n        '你没发错吧？',\n        '洗澡中，请勿打扰，偷窥请购票，个体四十，团体八折，订票电话：一般人我不告诉他！',\n        '你好，我是主人的美女秘书，有什么事就跟我说吧，等他回来我会转告他的。',\n        '我正在拉磨，没法招呼您，因为我们家毛驴去动物保护协会把我告了，说我剥夺它休产假的权利。',\n        '<（@￣︶￣@）>',\n        '你要和我说话？你真的要和我说话？你确定自己想说吗？你一定非说不可吗？那你说吧，这是自动回复。',\n        '主人正在开机自检，键盘鼠标看好机会出去凉快去了，我是他的电冰箱，我打字比较慢，你慢慢说，别急……',\n        '(*^__^*) 嘻嘻，是贤心吗？'\n    ],\n\n\n    chating: {},\n    hosts: (function(){\n        var dk = location.href.match(/\\:\\d+/);\n        dk = dk ? dk[0] : '';\n        return 'http://' + document.domain + dk + '/';\n    })(),\n    json: function(url, data, callback, error){\n        return $.ajax({\n            type: 'POST',\n            url: url,\n            data: data,\n            dataType: 'json',\n            success: callback,\n            error: error\n        });\n    },\n    stopMP: function(e){\n        e ? e.stopPropagation() : e.cancelBubble = true;\n    }\n}, dom = [$(window), $(document), $('html'), $('body')], xxim = {};\n\n//主界面tab\nxxim.tabs = function(index){\n    var node = xxim.node;\n    node.tabs.eq(index).addClass('xxim_tabnow').siblings().removeClass('xxim_tabnow');\n    node.list.eq(index).show().siblings('.xxim_list').hide();\n    if(node.list.eq(index).find('li').length === 0){\n        xxim.getDates(index);\n    }\n};\n\n//节点\nxxim.renode = function(){\n    var node = xxim.node = {\n        tabs: $('#xxim_tabs>span'),\n        list: $('.xxim_list'),\n        online: $('.xxim_online'),\n        setonline: $('.xxim_setonline'),\n        onlinetex: $('#xxim_onlinetex'),\n        xximon: $('#xxim_on'),\n        layimFooter: $('#xxim_bottom'),\n        xximHide: $('#xxim_hide'),\n        xximSearch: $('#xxim_searchkey'),\n        searchMian: $('#xxim_searchmain'),\n        closeSearch: $('#xxim_closesearch'),\n        layimMin: $('#layim_min')\n    };\n};\n\n//主界面缩放\nxxim.expend = function(){\n    var node = xxim.node;\n    if(xxim.layimNode.attr('state') !== '1'){\n        xxim.layimNode.stop().animate({right: config.right}, config.aniTime, function(){\n            node.xximon.addClass('xxim_off');\n            try{\n                localStorage.layimState = 1;\n            }catch(e){}\n            xxim.layimNode.attr({state: 1});\n            node.layimFooter.addClass('xxim_expend').stop().animate({marginLeft: config.right}, config.aniTime/2);\n            node.xximHide.addClass('xxim_show');\n        });\n    } else {\n        xxim.layimNode.stop().animate({right: 1}, config.aniTime, function(){\n            node.xximon.removeClass('xxim_off');\n            try{\n                localStorage.layimState = 2;\n            }catch(e){}\n            xxim.layimNode.removeAttr('state');\n            node.layimFooter.removeClass('xxim_expend');\n            node.xximHide.removeClass('xxim_show');\n        });\n        node.layimFooter.stop().animate({marginLeft: 0}, config.aniTime);\n    }\n};\n\n//初始化窗口格局\nxxim.layinit = function(){\n    var node = xxim.node;\n\n    //主界面\n    try{\n        /*\n        if(!localStorage.layimState){\n            config.aniTime = 0;\n            localStorage.layimState = 1;\n        }\n        */\n        if(localStorage.layimState === '1'){\n            xxim.layimNode.attr({state: 1}).css({right: config.right});\n            node.xximon.addClass('xxim_off');\n            node.layimFooter.addClass('xxim_expend').css({marginLeft: config.right});\n            node.xximHide.addClass('xxim_show');\n        }\n    }catch(e){\n        //layer.msg(e.message, 5, -1);\n    }\n};\n\n//聊天窗口\nxxim.popchat = function(param){\n    var node = xxim.node, log = {};\n\n    log.success = function(layero){\n        layer.setMove();\n\n        xxim.chatbox = layero.find('#layim_chatbox');\n        log.chatlist = xxim.chatbox.find('.layim_chatmore>ul');\n\n        log.chatlist.html('<li data-id=\"'+ param.id +'\" type=\"'+ param.type +'\"  id=\"layim_user'+ param.type + param.id +'\"><span>'+ param.name +'</span><em>×</em></li>')\n        xxim.tabchat(param, xxim.chatbox);\n\n        //最小化聊天窗\n        xxim.chatbox.find('.layer_setmin').on('click', function(){\n            var indexs = layero.attr('times');\n            layero.hide();\n            node.layimMin.text(xxim.nowchat.name).show();\n        });\n\n        //关闭窗口\n        xxim.chatbox.find('.layim_close').on('click', function(){\n            var indexs = layero.attr('times');\n            layer.close(indexs);\n            xxim.chatbox = null;\n            config.chating = {};\n            config.chatings = 0;\n        });\n\n        //关闭某个聊天\n        log.chatlist.on('mouseenter', 'li', function(){\n            $(this).find('em').show();\n        }).on('mouseleave', 'li', function(){\n            $(this).find('em').hide();\n        });\n        log.chatlist.on('click', 'li em', function(e){\n            var parents = $(this).parent(), dataType = parents.attr('type');\n            var dataId = parents.attr('data-id'), index = parents.index();\n            var chatlist = log.chatlist.find('li'), indexs;\n\n            config.stopMP(e);\n\n            delete config.chating[dataType + dataId];\n            config.chatings--;\n\n            parents.remove();\n            $('#layim_area'+ dataType + dataId).remove();\n            if(dataType === 'group'){\n                $('#layim_group'+ dataType + dataId).remove();\n            }\n\n            if(parents.hasClass('layim_chatnow')){\n                if(index === config.chatings){\n                    indexs = index - 1;\n                } else {\n                    indexs = index + 1;\n                }\n                xxim.tabchat(config.chating[chatlist.eq(indexs).attr('type') + chatlist.eq(indexs).attr('data-id')]);\n            }\n\n            if(log.chatlist.find('li').length === 1){\n                log.chatlist.parent().hide();\n            }\n        });\n\n        //聊天选项卡\n        log.chatlist.on('click', 'li', function(){\n            var othis = $(this), dataType = othis.attr('type'), dataId = othis.attr('data-id');\n            xxim.tabchat(config.chating[dataType + dataId]);\n        });\n\n        //发送热键切换\n        log.sendType = $('#layim_sendtype'), log.sendTypes = log.sendType.find('span');\n        $('#layim_enter').on('click', function(e){\n            config.stopMP(e);\n            log.sendType.show();\n        });\n        log.sendTypes.on('click', function(){\n            log.sendTypes.find('i').text('')\n            $(this).find('i').text('√');\n        });\n\n        xxim.transmit();\n    };\n\n    log.html = '<div class=\"layim_chatbox\" id=\"layim_chatbox\">'\n            +'<h6>'\n            +'<span class=\"layim_move\"></span>'\n            +'    <a href=\"'+ param.url +'\" class=\"layim_face\" target=\"_blank\"><img src=\"'+ param.face +'\" ></a>'\n            +'    <a href=\"'+ param.url +'\" class=\"layim_names\" target=\"_blank\">'+ param.name +'</a>'\n            +'    <span class=\"layim_rightbtn\">'\n            +'        <i class=\"layer_setmin\">—</i>'\n            +'        <i class=\"layim_close\">&times;</i>'\n            +'    </span>'\n            +'</h6>'\n            +'<div class=\"layim_chatmore\" id=\"layim_chatmore\">'\n            +'    <ul class=\"layim_chatlist\"></ul>'\n            +'</div>'\n            +'<div class=\"layim_groups\" id=\"layim_groups\"></div>'\n            +'<div class=\"layim_chat\">'\n            +'    <div class=\"layim_chatarea\" id=\"layim_chatarea\">'\n            +'        <ul class=\"layim_chatview layim_chatthis\"  id=\"layim_area'+ param.type + param.id +'\"></ul>'\n            +'    </div>'\n            +'    <div class=\"layim_tool\">'\n            +'        <i class=\"layim_addface fa fa-meh-o\" title=\"发送表情\"></i>'\n            +'        <a href=\"javascript:;\"><i class=\"layim_addimage fa fa-picture-o\" title=\"上传图片\"></i></a>'\n            +'        <a href=\"javascript:;\"><i class=\"layim_addfile fa fa-paperclip\" title=\"上传附件\"></i></a>'\n            +'        <a href=\"\" target=\"_blank\" class=\"layim_seechatlog\"><i class=\"fa fa-comment-o\"></i>聊天记录</a>'\n            +'    </div>'\n            +'    <textarea class=\"layim_write\" id=\"layim_write\"></textarea>'\n            +'    <div class=\"layim_send\">'\n            +'        <div class=\"layim_sendbtn\" id=\"layim_sendbtn\">发送<span class=\"layim_enter\" id=\"layim_enter\"><em class=\"layim_zero\"></em></span></div>'\n            +'        <div class=\"layim_sendtype\" id=\"layim_sendtype\">'\n            +'            <span><i>√</i>按Enter键发送</span>'\n            +'            <span><i></i>按Ctrl+Enter键发送</span>'\n            +'        </div>'\n            +'    </div>'\n            +'</div>'\n            +'</div>';\n\n    if(config.chatings < 1){\n        $.layer({\n            type: 1,\n            border: [0],\n            title: false,\n            shade: [0],\n            area: ['620px', '493px'],\n            move: '.layim_chatbox .layim_move',\n            moveType: 1,\n            closeBtn: false,\n            offset: [(($(window).height() - 493)/2)+'px', ''],\n            page: {\n                html: log.html\n            }, success: function(layero){\n                log.success(layero);\n            }\n        })\n    } else {\n        log.chatmore = xxim.chatbox.find('#layim_chatmore');\n        log.chatarea = xxim.chatbox.find('#layim_chatarea');\n\n        log.chatmore.show();\n\n        log.chatmore.find('ul>li').removeClass('layim_chatnow');\n        log.chatmore.find('ul').append('<li data-id=\"'+ param.id +'\" type=\"'+ param.type +'\" id=\"layim_user'+ param.type + param.id +'\" class=\"layim_chatnow\"><span>'+ param.name +'</span><em>×</em></li>');\n\n        log.chatarea.find('.layim_chatview').removeClass('layim_chatthis');\n        log.chatarea.append('<ul class=\"layim_chatview layim_chatthis\" id=\"layim_area'+ param.type + param.id +'\"></ul>');\n\n        xxim.tabchat(param);\n    }\n\n    //群组\n    log.chatgroup = xxim.chatbox.find('#layim_groups');\n    if(param.type === 'group'){\n        log.chatgroup.find('ul').removeClass('layim_groupthis');\n        log.chatgroup.append('<ul class=\"layim_groupthis\" id=\"layim_group'+ param.type + param.id +'\"></ul>');\n        xxim.getGroups(param);\n    }\n    //点击群员切换聊天窗\n    log.chatgroup.on('click', 'ul>li', function(){\n        xxim.popchatbox($(this));\n    });\n};\n\n//定位到某个聊天队列\nxxim.tabchat = function(param){\n    var node = xxim.node, log = {}, keys = param.type + param.id;\n    xxim.nowchat = param;\n\n    xxim.chatbox.find('#layim_user'+ keys).addClass('layim_chatnow').siblings().removeClass('layim_chatnow');\n    xxim.chatbox.find('#layim_area'+ keys).addClass('layim_chatthis').siblings().removeClass('layim_chatthis');\n    xxim.chatbox.find('#layim_group'+ keys).addClass('layim_groupthis').siblings().removeClass('layim_groupthis');\n\n    xxim.chatbox.find('.layim_face>img').attr('src', param.face);\n    xxim.chatbox.find('.layim_face, .layim_names').attr('href', param.href);\n    xxim.chatbox.find('.layim_names').text(param.name);\n\n    xxim.chatbox.find('.layim_seechatlog').attr('href', config.chatlogurl + param.id);\n\n    log.groups = xxim.chatbox.find('.layim_groups');\n    if(param.type === 'group'){\n        log.groups.show();\n    } else {\n        log.groups.hide();\n    }\n\n    $('#layim_write').focus();\n\n};\n\n//弹出聊天窗\nxxim.popchatbox = function(othis){\n    var node = xxim.node, dataId = othis.attr('data-id'), param = {\n        id: dataId, //用户ID\n        type: othis.attr('type'),\n        name: othis.find('.xxim_onename').text(),  //用户名\n        face: othis.find('.xxim_oneface').attr('src'),  //用户头像\n        href: 'profile.html?user=' + dataId //用户主页\n    }, key = param.type + dataId;\n    if(!config.chating[key]){\n        xxim.popchat(param);\n        config.chatings++;\n    } else {\n        xxim.tabchat(param);\n    }\n    config.chating[key] = param;\n\n    var chatbox = $('#layim_chatbox');\n    if(chatbox[0]){\n        node.layimMin.hide();\n        chatbox.parents('.xubox_layer').show();\n    }\n};\n\n//请求群员\nxxim.getGroups = function(param){\n    var keys = param.type + param.id, str = '',\n    groupss = xxim.chatbox.find('#layim_group'+ keys);\n    groupss.addClass('loading');\n    config.json(config.api.groups, {}, function(datas){\n        if(datas.status === 1){\n            var ii = 0, lens = datas.data.length;\n            if(lens > 0){\n                for(; ii < lens; ii++){\n                    str += '<li data-id=\"'+ datas.data[ii].id +'\" type=\"one\"><img src=\"'+ datas.data[ii].face +'\" class=\"xxim_oneface\"><span class=\"xxim_onename\">'+ datas.data[ii].name +'</span></li>';\n                }\n            } else {\n                str = '<li class=\"layim_errors\">没有群员</li>';\n            }\n\n        } else {\n            str = '<li class=\"layim_errors\">'+ datas.msg +'</li>';\n        }\n        groupss.removeClass('loading');\n        groupss.html(str);\n    }, function(){\n        groupss.removeClass('loading');\n        groupss.html('<li class=\"layim_errors\">请求异常</li>');\n    });\n};\n\n//消息传输\nxxim.transmit = function(){\n    var node = xxim.node, log = {};\n    node.sendbtn = $('#layim_sendbtn');\n    node.imwrite = $('#layim_write');\n\n    //发送\n    log.send = function(){\n        var data = {\n            content: node.imwrite.val(),\n            id: xxim.nowchat.id,\n            sign_key: '', //密匙\n            _: +new Date\n        };\n\n        if(data.content.replace(/\\s/g, '') === ''){\n            layer.tips('说点啥呗！', '#layim_write', 2);\n            node.imwrite.focus();\n        } else {\n            //此处皆为模拟\n            var keys = xxim.nowchat.type + xxim.nowchat.id;\n\n            //聊天模版\n            log.html = function(param, type){\n                return '<li class=\"'+ (type === 'me' ? 'layim_chateme' : '') +'\">'\n                    +'<div class=\"layim_chatuser\">'\n                        + function(){\n                            if(type === 'me'){\n                                return '<span class=\"layim_chattime\">'+ param.time +'</span>'\n                                       +'<span class=\"layim_chatname\">'+ param.name +'</span>'\n                                       +'<img src=\"'+ param.face +'\" >';\n                            } else {\n                                return '<img src=\"'+ param.face +'\" >'\n                                       +'<span class=\"layim_chatname\">'+ param.name +'</span>'\n                                       +'<span class=\"layim_chattime\">'+ param.time +'</span>';\n                            }\n                        }()\n                    +'</div>'\n                    +'<div class=\"layim_chatsay\">'+ param.content +'<em class=\"layim_zero\"></em></div>'\n                +'</li>';\n            };\n\n            log.imarea = xxim.chatbox.find('#layim_area'+ keys);\n\n            log.imarea.append(log.html({\n                time: '2014-04-26 0:37',\n                name: config.user.name,\n                face: config.user.face,\n                content: data.content\n            }, 'me'));\n            node.imwrite.val('').focus();\n            log.imarea.scrollTop(log.imarea[0].scrollHeight);\n\n            setTimeout(function(){\n                log.imarea.append(log.html({\n                    time: '2014-04-26 0:38',\n                    name: xxim.nowchat.name,\n                    face: xxim.nowchat.face,\n                    content: config.autoReplay[(Math.random()*config.autoReplay.length) | 0]\n                }));\n                log.imarea.scrollTop(log.imarea[0].scrollHeight);\n            }, 500);\n\n            /*\n            that.json(config.api.sendurl, data, function(datas){\n\n            });\n            */\n        }\n\n    };\n    node.sendbtn.on('click', log.send);\n\n    node.imwrite.keyup(function(e){\n        if(e.keyCode === 13){\n            log.send();\n        }\n    });\n};\n\n//事件\nxxim.event = function(){\n    var node = xxim.node;\n\n    //主界面tab\n    node.tabs.eq(0).addClass('xxim_tabnow');\n    node.tabs.on('click', function(){\n        var othis = $(this), index = othis.index();\n        xxim.tabs(index);\n    });\n\n    //列表展收\n    node.list.on('click', 'h5', function(){\n        var othis = $(this), chat = othis.siblings('.xxim_chatlist'), parentss = othis.find(\"i\");\n        if(parentss.hasClass('fa-caret-down')){\n            chat.hide();\n            parentss.attr('class','fa fa-caret-right');\n        } else {\n            chat.show();\n            parentss.attr('class','fa fa-caret-down');\n        }\n    });\n\n    //设置在线隐身\n    node.online.on('click', function(e){\n        config.stopMP(e);\n        node.setonline.show();\n    });\n    node.setonline.find('span').on('click', function(e){\n        var index = $(this).index();\n        config.stopMP(e);\n        if(index === 0){\n            node.onlinetex.html('在线');\n            node.online.removeClass('xxim_offline');\n        } else if(index === 1) {\n            node.onlinetex.html('隐身');\n            node.online.addClass('xxim_offline');\n        }\n        node.setonline.hide();\n    });\n\n    node.xximon.on('click', xxim.expend);\n    node.xximHide.on('click', xxim.expend);\n\n    //搜索\n    node.xximSearch.keyup(function(){\n        var val = $(this).val().replace(/\\s/g, '');\n        if(val !== ''){\n            node.searchMian.show();\n            node.closeSearch.show();\n            //此处的搜索ajax参考xxim.getDates\n            node.list.eq(3).html('<li class=\"xxim_errormsg\">没有符合条件的结果</li>');\n        } else {\n            node.searchMian.hide();\n            node.closeSearch.hide();\n        }\n    });\n    node.closeSearch.on('click', function(){\n        $(this).hide();\n        node.searchMian.hide();\n        node.xximSearch.val('').focus();\n    });\n\n    //弹出聊天窗\n    config.chatings = 0;\n    node.list.on('click', '.xxim_childnode', function(){\n        var othis = $(this);\n        xxim.popchatbox(othis);\n    });\n\n    //点击最小化栏\n    node.layimMin.on('click', function(){\n        $(this).hide();\n        $('#layim_chatbox').parents('.xubox_layer').show();\n    });\n\n\n    //document事件\n    dom[1].on('click', function(){\n        node.setonline.hide();\n        $('#layim_sendtype').hide();\n    });\n};\n\n//请求列表数据\nxxim.getDates = function(index){\n    var api = [config.api.friend, config.api.group, config.api.chatlog],\n        node = xxim.node, myf = node.list.eq(index);\n    myf.addClass('loading');\n    config.json(api[index], {}, function(datas){\n        if(datas.status === 1){\n            var i = 0, myflen = datas.data.length, str = '', item;\n            if(myflen > 1){\n                if(index !== 2){\n                    for(; i < myflen; i++){\n                        str += '<li data-id=\"'+ datas.data[i].id +'\" class=\"xxim_parentnode\">'\n                            +'<h5><i class=\"fa fa-caret-right\"></i><span class=\"xxim_parentname\">'+ datas.data[i].name +'</span><em class=\"xxim_nums\">（'+ datas.data[i].nums +'）</em></h5>'\n                            +'<ul class=\"xxim_chatlist\">';\n                        item = datas.data[i].item;\n                        for(var j = 0; j < item.length; j++){\n                            str += '<li data-id=\"'+ item[j].id +'\" class=\"xxim_childnode\" type=\"'+ (index === 0 ? 'one' : 'group') +'\"><img src=\"'+ item[j].face +'\" class=\"xxim_oneface\"><span class=\"xxim_onename\">'+ item[j].name +'</span></li>';\n                        }\n                        str += '</ul></li>';\n                    }\n                } else {\n                    str += '<li class=\"xxim_liston\">'\n                        +'<ul class=\"xxim_chatlist\">';\n                    for(; i < myflen; i++){\n                        str += '<li data-id=\"'+ datas.data[i].id +'\" class=\"xxim_childnode\" type=\"one\"><img src=\"'+ datas.data[i].face +'\"  class=\"xxim_oneface\"><span  class=\"xxim_onename\">'+ datas.data[i].name +'</span><em class=\"xxim_time\">'+ datas.data[i].time +'</em></li>';\n                    }\n                    str += '</ul></li>';\n                }\n                myf.html(str);\n            } else {\n                myf.html('<li class=\"xxim_errormsg\">没有任何数据</li>');\n            }\n            myf.removeClass('loading');\n        } else {\n            myf.html('<li class=\"xxim_errormsg\">'+ datas.msg +'</li>');\n        }\n    }, function(){\n        myf.html('<li class=\"xxim_errormsg\">请求失败</li>');\n        myf.removeClass('loading');\n    });\n};\n\n//渲染骨架\nxxim.view = (function(){\n    var xximNode = xxim.layimNode = $('<div id=\"xximmm\" class=\"xxim_main\">'\n            +'<div class=\"xxim_top\" id=\"xxim_top\">'\n            +'  <div class=\"xxim_search\"><i class=\"fa fa-search\"></i><input id=\"xxim_searchkey\" /><span id=\"xxim_closesearch\">×</span></div>'\n            +'  <div class=\"xxim_tabs\" id=\"xxim_tabs\"><span class=\"xxim_tabfriend\" title=\"好友\"><i class=\"fa fa-user\"></i></span><span class=\"xxim_tabgroup\" title=\"群组\"><i class=\"fa fa-users\"></i></span><span class=\"xxim_latechat\"  title=\"最近聊天\"><i class=\"fa fa-clock-o\"></i></span></div>'\n            +'  <ul class=\"xxim_list\" style=\"display:block\"></ul>'\n            +'  <ul class=\"xxim_list\"></ul>'\n            +'  <ul class=\"xxim_list\"></ul>'\n            +'  <ul class=\"xxim_list xxim_searchmain\" id=\"xxim_searchmain\"></ul>'\n            +'</div>'\n            +'<ul class=\"xxim_bottom\" id=\"xxim_bottom\">'\n            +'<li class=\"xxim_online\" id=\"xxim_online\">'\n                +'<i class=\"xxim_nowstate fa fa-check-circle\"></i><span id=\"xxim_onlinetex\">在线</span>'\n                +'<div class=\"xxim_setonline\">'\n                    +'<span><i class=\"fa fa-check-circle\"></i>在线</span>'\n                    +'<span class=\"xxim_setoffline\"><i class=\"fa fa-check-circle\"></i>隐身</span>'\n                +'</div>'\n            +'</li>'\n            +'<li class=\"xxim_mymsg\" id=\"xxim_mymsg\" title=\"我的私信\"><i class=\"fa fa-comment\"></i><a href=\"'+ config.msgurl +'\" target=\"_blank\"></a></li>'\n            +'<li class=\"xxim_seter\" id=\"xxim_seter\" title=\"设置\">'\n                +'<i class=\"fa fa-gear\"></i>'\n                +'<div>'\n\n                +'</div>'\n            +'</li>'\n            +'<li class=\"xxim_hide\" id=\"xxim_hide\"><i class=\"fa fa-exchange\"></i></li>'\n            +'<li id=\"xxim_on\" class=\"xxim_icon xxim_on fa fa-ellipsis-v\"></li>'\n            +'<div class=\"layim_min\" id=\"layim_min\"></div>'\n        +'</ul>'\n    +'</div>');\n    dom[3].append(xximNode);\n\n    xxim.renode();\n    xxim.getDates(0);\n    xxim.event();\n    xxim.layinit();\n}());\n\n}(window);\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/mobile/layer.js",
    "content": "/*! layer mobile-v2.0.0 Web弹层组件 MIT License  http://layer.layui.com/mobile  By 贤心 */\n ;!function(e){\"use strict\";var t=document,n=\"querySelectorAll\",i=\"getElementsByClassName\",a=function(e){return t[n](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 n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener(\"click\",function(e){t.call(this,e)},!1)};var r=0,o=[\"layui-m-layer\"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement(\"div\");e.id=s.id=o[0]+r,s.setAttribute(\"class\",o[0]+\" \"+o[0]+(n.type||0)),s.setAttribute(\"index\",r);var l=function(){var e=\"object\"==typeof n.title;return n.title?'<h3 style=\"'+(e?n.title[1]:\"\")+'\">'+(e?n.title[0]:n.title)+\"</h3>\":\"\"}(),c=function(){\"string\"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e='<span yes type=\"1\">'+n.btn[0]+\"</span>\",2===t&&(e='<span no type=\"0\">'+n.btn[1]+\"</span>\"+e),'<div class=\"layui-m-layerbtn\">'+e+\"</div>\"):\"\"}();if(n.fixed||(n.top=n.hasOwnProperty(\"top\")?n.top:100,n.style=n.style||\"\",n.style+=\" top:\"+(t.body.scrollTop+n.top)+\"px\"),2===n.type&&(n.content='<i></i><i class=\"layui-m-layerload\"></i><i></i><p>'+(n.content||\"\")+\"</p>\"),n.skin&&(n.anim=\"up\"),\"msg\"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?\"<div \"+(\"string\"==typeof n.shade?'style=\"'+n.shade+'\"':\"\")+' class=\"layui-m-layershade\"></div>':\"\")+'<div class=\"layui-m-layermain\" '+(n.fixed?\"\":'style=\"position:static;\"')+'><div class=\"layui-m-layersection\"><div class=\"layui-m-layerchild '+(n.skin?\"layui-m-layer-\"+n.skin+\" \":\"\")+(n.className?n.className:\"\")+\" \"+(n.anim?\"layui-m-anim-\"+n.anim:\"\")+'\" '+(n.style?'style=\"'+n.style+'\"':\"\")+\">\"+l+'<div class=\"layui-m-layercont\">'+n.content+\"</div>\"+c+\"</div></div></div>\",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute(\"index\"))}document.body.appendChild(s);var u=e.elem=a(\"#\"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute(\"type\");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i](\"layui-m-layerbtn\")[0].children,r=s.length,o=0;o<r;o++)l.touch(s[o],a);if(e.shade&&e.shadeClose){var c=t[i](\"layui-m-layershade\")[0];l.touch(c,function(){layer.close(n.index,e.end)})}e.end&&(l.end[n.index]=e.end)},e.layer={v:\"2.0\",index:r,open:function(e){var t=new c(e||{});return t.index},close:function(e){var n=a(\"#\"+o[0]+e)[0];n&&(n.innerHTML=\"\",t.body.removeChild(n),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[i](o[0]),n=0,a=e.length;n<a;n++)layer.close(0|e[0].getAttribute(\"index\"))}},\"function\"==typeof define?define(function(){return layer}):function(){var e=document.scripts,n=e[e.length-1],i=n.src,a=i.substring(0,i.lastIndexOf(\"/\")+1);n.getAttribute(\"merge\")||document.head.appendChild(function(){var e=t.createElement(\"link\");return e.href=a+\"need/layer.css?2.0\",e.type=\"text/css\",e.rel=\"styleSheet\",e.id=\"layermcss\",e}())}()}(window);"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/mobile/need/layer.css",
    "content": ".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}@-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}.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": "material-manage/src/main/webapp/static/js/plugins/layer/skin/layer.css",
    "content": "/*!\n\n @Name: layer's style\n @Author: 贤心\n @Blog： sentsin.com\n\n */*html{background-image:url(about:blank);background-attachment:fixed}html #layui_layer_skinlayercss{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{top:150px;left:50%;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;box-shadow:1px 1px 50px rgba(0,0,0,.3);border-radius:2px;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.3);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-moves{position:absolute;border:3px solid #666;border:3px solid rgba(0,0,0,.5);cursor:move;background-color:#fff;background-color:rgba(255,255,255,.3);filter:alpha(opacity=50)}.layui-layer-load{background:url(default/loading-0.gif) center center no-repeat #fff}.layui-layer-ico{background:url(default/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}@-webkit-keyframes bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes 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)}}.layui-anim{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.03);transform:scale(1.03)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.03);-ms-transform:scale(1.03);transform:scale(1.03)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layui-anim-close{-webkit-animation-name:bounceOut;animation-name:bounceOut;-webkit-animation-duration:.2s;animation-duration:.2s}@-webkit-keyframes 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 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}}.layui-anim-01{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes 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)}}.layui-anim-02{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes 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 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}}.layui-anim-03{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes 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 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)}}.layui-anim-04{-webkit-animation-name:rollIn;animation-name:rollIn}@keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-anim-05{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes 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 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)}}.layui-anim-06{-webkit-animation-name:shake;animation-name: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;text-overflow:ellipsis;white-space:nowrap;background-color:#F8F8F8}.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:0 -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:-150px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-181px -31px}.layui-layer-btn{text-align:right;padding:0 10px 12px;pointer-events:auto}.layui-layer-btn a{height:28px;line-height:28px;margin:0 6px;padding:0 15px;border:1px solid #dedede;background-color:#f1f1f1;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:.7}.layui-layer-btn .layui-layer-btn0{border-color:#4898d5;background-color:#2e8ded;color:#fff}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;font-size:14px;overflow: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 .layui-layer-content{overflow:hidden}.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(default/loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(default/loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(default/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:5px 10px;font-size:12px;_float:left;border-radius:3px;box-shadow:1px 1px 3px rgba(0,0,0,.3);background-color:#F90;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:#F90}.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:1px;border-bottom-style:solid;border-bottom-color:#F90}.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-lan .layui-layer-btn{padding:10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#BBB5B5;border:none}.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}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/skin/layer.ext.css",
    "content": "/*!\n\n @Name: layer拓展样式\n @Date: 2012.12.13\n @Author: 贤心\n @blog: sentsin.com\n\n */.layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span{text-overflow:ellipsis;white-space:nowrap}.layui-layer-iconext{background:url(default/icon-ext.png) no-repeat}html #layui_layer_skinlayerextcss{display:none;position:absolute;width:1989px}.layui-layer-prompt .layui-layer-input{display:block;width:220px;height:30px;margin:0 auto;line-height:30px;padding:0 5px;border:1px solid #ccc;box-shadow:1px 1px 5px rgba(0,0,0,.1) inset;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;border-bottom:1px solid #ccc;background-color:#eee;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;cursor:default;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px;border-left:1px solid #ccc;border-right:1px solid #ccc;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.xubox_tab_layer{display:block}.xubox_tabclose{position:absolute;right:10px;top:5px;cursor:pointer}.layui-layer-photos{-webkit-animation-duration:1s;animation-duration:1s;background:url(default/xubox_loading1.gif) center center no-repeat #000}.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}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/layer/theme/default/layer.css",
    "content": ".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": "material-manage/src/main/webapp/static/js/plugins/validate/zh_CN.js",
    "content": "(function ($) {\n    /**\n     * Simplified Chinese language package\n     * Translated by @shamiao\n     */\n    $.fn.bootstrapValidator.i18n = $.extend(true, $.fn.bootstrapValidator.i18n, {\n        base64: {\n            'default': '请输入有效的Base64编码'\n        },\n        between: {\n            'default': '请输入在 %s 和 %s 之间的数值',\n            notInclusive: '请输入在 %s 和 %s 之间(不含两端)的数值'\n        },\n        callback: {\n            'default': '请输入有效的值'\n        },\n        choice: {\n            'default': '请输入有效的值',\n            less: '请至少选中 %s 个选项',\n            more: '最多只能选中 %s 个选项',\n            between: '请选择 %s 至 %s 个选项'\n        },\n        color: {\n            'default': '请输入有效的颜色值'\n        },\n        creditCard: {\n            'default': '请输入有效的信用卡号码'\n        },\n        cusip: {\n            'default': '请输入有效的美国CUSIP代码'\n        },\n        cvv: {\n            'default': '请输入有效的CVV代码'\n        },\n        date: {\n            'default': '请输入有效的日期', \n            min: '请输入 %s 或之后的日期',\n            max: '请输入 %s 或以前的日期',\n            range: '请输入 %s 和 %s 之间的日期'\n        },\n        different: {\n            'default': '请输入不同的值'\n        },\n        digits: {\n            'default': '请输入有效的数字'\n        },\n        ean: {\n            'default': '请输入有效的EAN商品编码'\n        },\n        emailAddress: {\n            'default': '请输入有效的邮件地址'\n        },\n        file: {\n            'default': '请选择有效的文件'\n        },\n        greaterThan: {\n            'default': '请输入大于等于 %s 的数值',\n            notInclusive: '请输入大于 %s 的数值'\n        },\n        grid: {\n            'default': '请输入有效的GRId编码'\n        },\n        hex: {\n            'default': '请输入有效的16进制数'\n        },\n        hexColor: {\n            'default': '请输入有效的16进制颜色值'\n        },\n        iban: {\n            'default': '请输入有效的IBAN(国际银行账户)号码',\n            countryNotSupported: '不支持 %s 国家或地区',\n            country: '请输入有效的 %s 国家或地区的IBAN(国际银行账户)号码',\n            countries: {\n                AD: '安道​​尔',\n                AE: '阿联酋',\n                AL: '阿尔巴尼亚',\n                AO: '安哥拉',\n                AT: '奥地利',\n                AZ: '阿塞拜疆',\n                BA: '波斯尼亚和黑塞哥维那',\n                BE: '比利时',\n                BF: '布基纳法索',\n                BG: '保加利亚',\n                BH: '巴林',\n                BI: '布隆迪',\n                BJ: '贝宁',\n                BR: '巴西',\n                CH: '瑞士',\n                CI: '科特迪瓦',\n                CM: '喀麦隆',\n                CR: '哥斯达黎加',\n                CV: '佛得角',\n                CY: '塞浦路斯',\n                CZ: '捷克共和国',\n                DE: '德国',\n                DK: '丹麦',\n                DO: '多米尼加共和国',\n                DZ: '阿尔及利亚',\n                EE: '爱沙尼亚',\n                ES: '西班牙',\n                FI: '芬兰',\n                FO: '法罗群岛',\n                FR: '法国',\n                GB: '英国',\n                GE: '格鲁吉亚',\n                GI: '直布罗陀',\n                GL: '格陵兰岛',\n                GR: '希腊',\n                GT: '危地马拉',\n                HR: '克罗地亚',\n                HU: '匈牙利',\n                IE: '爱尔兰',\n                IL: '以色列',\n                IR: '伊朗',\n                IS: '冰岛',\n                IT: '意大利',\n                JO: '约旦',\n                KW: '科威特',\n                KZ: '哈萨克斯坦',\n                LB: '黎巴嫩',\n                LI: '列支敦士登',\n                LT: '立陶宛',\n                LU: '卢森堡',\n                LV: '拉脱维亚',\n                MC: '摩纳哥',\n                MD: '摩尔多瓦',\n                ME: '黑山',\n                MG: '马达加斯加',\n                MK: '马其顿',\n                ML: '马里',\n                MR: '毛里塔尼亚',\n                MT: '马耳他',\n                MU: '毛里求斯',\n                MZ: '莫桑比克',\n                NL: '荷兰',\n                NO: '挪威',\n                PK: '巴基斯坦',\n                PL: '波兰',\n                PS: '巴勒斯坦',\n                PT: '葡萄牙',\n                QA: '卡塔尔',\n                RO: '罗马尼亚',\n                RS: '塞尔维亚',\n                SA: '沙特阿拉伯',\n                SE: '瑞典',\n                SI: '斯洛文尼亚',\n                SK: '斯洛伐克',\n                SM: '圣马力诺',\n                SN: '塞内加尔',\n                TN: '突尼斯',\n                TR: '土耳其',\n                VG: '英属维尔京群岛'\n            }\n        },\n        id: {\n            'default': '请输入有效的身份证件号码',\n            countryNotSupported: '不支持 %s 国家或地区',\n            country: '请输入有效的 %s 国家或地区的身份证件号码',\n            countries: {\n                BA: '波黑',\n                BG: '保加利亚',\n                BR: '巴西',\n                CH: '瑞士',\n                CL: '智利',\n                CN: '中国',\n                CZ: '捷克共和国',\n                DK: '丹麦',\n                EE: '爱沙尼亚',\n                ES: '西班牙',\n                FI: '芬兰',\n                HR: '克罗地亚',\n                IE: '爱尔兰',\n                IS: '冰岛',\n                LT: '立陶宛',\n                LV: '拉脱维亚',\n                ME: '黑山',\n                MK: '马其顿',\n                NL: '荷兰',\n                RO: '罗马尼亚',\n                RS: '塞尔维亚',\n                SE: '瑞典',\n                SI: '斯洛文尼亚',\n                SK: '斯洛伐克',\n                SM: '圣马力诺',\n                TH: '泰国',\n                ZA: '南非'\n            }\n        },\n        identical: {\n            'default': '请输入相同的值'\n        },\n        imei: {\n            'default': '请输入有效的IMEI(手机串号)'\n        },\n        imo: {\n            'default': '请输入有效的国际海事组织(IMO)号码'\n        },\n        integer: {\n            'default': '请输入有效的整数值'\n        },\n        ip: {\n            'default': '请输入有效的IP地址',\n            ipv4: '请输入有效的IPv4地址',\n            ipv6: '请输入有效的IPv6地址'\n        },\n        isbn: {\n            'default': '请输入有效的ISBN(国际标准书号)'\n        },\n        isin: {\n            'default': '请输入有效的ISIN(国际证券编码)'\n        },\n        ismn: {\n            'default': '请输入有效的ISMN(印刷音乐作品编码)'\n        },\n        issn: {\n            'default': '请输入有效的ISSN(国际标准杂志书号)'\n        },\n        lessThan: {\n            'default': '请输入小于等于 %s 的数值',\n            notInclusive: '请输入小于 %s 的数值'\n        },\n        mac: {\n            'default': '请输入有效的MAC物理地址'\n        },\n        meid: {\n            'default': '请输入有效的MEID(移动设备识别码)'\n        },\n        notEmpty: {\n            'default': '请填写必填项目'\n        },\n        numeric: {\n            'default': '请输入有效的数值，允许小数'\n        },\n        phone: {\n            'default': '请输入有效的电话号码',\n            countryNotSupported: '不支持 %s 国家或地区',\n            country: '请输入有效的 %s 国家或地区的电话号码',\n            countries: {\n                BR: '巴西',\n                CN: '中国',\n                CZ: '捷克共和国',\n                DE: '德国',\n                DK: '丹麦',\n                ES: '西班牙',\n                FR: '法国',\n                GB: '英国',\n                MA: '摩洛哥',\n                PK: '巴基斯坦',\n                RO: '罗马尼亚',\n                RU: '俄罗斯',\n                SK: '斯洛伐克',\n                TH: '泰国',\n                US: '美国',\n                VE: '委内瑞拉'\n            }\n        },\n        regexp: {\n            'default': '请输入符合正则表达式限制的值'\n        },\n        remote: {\n            'default': '请输入有效的值'\n        },\n        rtn: {\n            'default': '请输入有效的RTN号码'\n        },\n        sedol: {\n            'default': '请输入有效的SEDOL代码'\n        },\n        siren: {\n            'default': '请输入有效的SIREN号码'\n        },\n        siret: {\n            'default': '请输入有效的SIRET号码'\n        },\n        step: {\n            'default': '请输入在基础值上，增加 %s 的整数倍的数值'\n        },\n        stringCase: {\n            'default': '只能输入小写字母',\n            upper: '只能输入大写字母'\n        },\n        stringLength: {\n            'default': '请输入符合长度限制的值',\n            less: '最多只能输入 %s 个字符',\n            more: '需要输入至少 %s 个字符',\n            between: '请输入 %s 至 %s 个字符'\n        },\n        uri: {\n            'default': '请输入一个有效的URL地址'\n        },\n        uuid: {\n            'default': '请输入有效的UUID',\n            version: '请输入版本 %s 的UUID'\n        },\n        vat: {\n            'default': '请输入有效的VAT(税号)',\n            countryNotSupported: '不支持 %s 国家或地区',\n            country: '请输入有效的 %s 国家或地区的VAT(税号)',\n            countries: {\n                AT: '奥地利',\n                BE: '比利时',\n                BG: '保加利亚',\n                BR: '巴西',\n                CH: '瑞士',\n                CY: '塞浦路斯',\n                CZ: '捷克共和国',\n                DE: '德国',\n                DK: '丹麦',\n                EE: '爱沙尼亚',\n                ES: '西班牙',\n                FI: '芬兰',\n                FR: '法语',\n                GB: '英国',\n                GR: '希腊',\n                EL: '希腊',\n                HU: '匈牙利',\n                HR: '克罗地亚',\n                IE: '爱尔兰',\n                IS: '冰岛',\n                IT: '意大利',\n                LT: '立陶宛',\n                LU: '卢森堡',\n                LV: '拉脱维亚',\n                MT: '马耳他',\n                NL: '荷兰',\n                NO: '挪威',\n                PL: '波兰',\n                PT: '葡萄牙',\n                RO: '罗马尼亚',\n                RU: '俄罗斯',\n                RS: '塞尔维亚',\n                SE: '瑞典',\n                SI: '斯洛文尼亚',\n                SK: '斯洛伐克',\n                VE: '委内瑞拉',\n                ZA: '南非'\n            }\n        },\n        vin: {\n            'default': '请输入有效的VIN(美国车辆识别号码)'\n        },\n        zipCode: {\n            'default': '请输入有效的邮政编码',\n            countryNotSupported: '不支持 %s 国家或地区',\n            country: '请输入有效的 %s 国家或地区的邮政编码',\n            countries: {\n                AT: '奥地利',\n                BR: '巴西',\n                CA: '加拿大',\n                CH: '瑞士',\n                CZ: '捷克共和国',\n                DE: '德国',\n                DK: '丹麦',\n                FR: '法国',\n                GB: '英国',\n                IE: '爱尔兰',\n                IT: '意大利',\n                MA: '摩洛哥',\n                NL: '荷兰',\n                PT: '葡萄牙',\n                RO: '罗马尼亚',\n                RU: '俄罗斯',\n                SE: '瑞典',\n                SG: '新加坡',\n                SK: '斯洛伐克',\n                US: '美国'\n            }\n        }\n    });\n}(window.jQuery));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/README.md",
    "content": "目录说明\n========================\n\n```bash\n├── Uploader.swf                      # SWF文件，当使用Flash运行时需要引入。\n├\n├── webuploader.js                    # 完全版本。\n├── webuploader.min.js                # min版本\n├\n├── webuploader.flashonly.js          # 只有Flash实现的版本。\n├── webuploader.flashonly.min.js      # min版本\n├\n├── webuploader.html5only.js          # 只有Html5实现的版本。\n├── webuploader.html5only.min.js      # min版本\n├\n├── webuploader.noimage.js            # 去除图片处理的版本，包括HTML5和FLASH.\n├── webuploader.noimage.min.js        # min版本\n├\n├── webuploader.custom.js             # 自定义打包方案，请查看 Gruntfile.js，满足移动端使用。\n└── webuploader.custom.min.js         # min版本\n```\n\n## 示例\n\n请把整个 Git 包下载下来放在 php 服务器下，因为默认提供的文件接受是用 php 编写的，打开 examples 页面便能查看示例效果。"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.css",
    "content": ".webuploader-container {\n\tposition: relative;\n}\n.webuploader-element-invisible {\n\tposition: absolute !important;\n\tclip: rect(1px 1px 1px 1px); /* IE6, IE7 */\n    clip: rect(1px,1px,1px,1px);\n}\n.webuploader-pick {\n\tposition: relative;\n\tdisplay: inline-block;\n\tcursor: pointer;\n\tbackground: #00b7ee;\n\tpadding: 10px 15px;\n\tcolor: #fff;\n\ttext-align: center;\n\tborder-radius: 3px;\n\toverflow: hidden;\n}\n.webuploader-pick-hover {\n\tbackground: #00a2d4;\n}\n\n.webuploader-pick-disable {\n\topacity: 0.6;\n\tpointer-events:none;\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.custom.js",
    "content": "/*! WebUploader 0.1.5 */\n\n\n/**\n * @fileOverview 让内部各个部件的代码可以用[amd](https://github.com/amdjs/amdjs-api/wiki/AMD)模块定义方式组织起来。\n *\n * AMD API 内部的简单不完全实现，请忽略。只有当WebUploader被合并成一个文件的时候才会引入。\n */\n(function( root, factory ) {\n    var modules = {},\n\n        // 内部require, 简单不完全实现。\n        // https://github.com/amdjs/amdjs-api/wiki/require\n        _require = function( deps, callback ) {\n            var args, len, i;\n\n            // 如果deps不是数组，则直接返回指定module\n            if ( typeof deps === 'string' ) {\n                return getModule( deps );\n            } else {\n                args = [];\n                for( len = deps.length, i = 0; i < len; i++ ) {\n                    args.push( getModule( deps[ i ] ) );\n                }\n\n                return callback.apply( null, args );\n            }\n        },\n\n        // 内部define，暂时不支持不指定id.\n        _define = function( id, deps, factory ) {\n            if ( arguments.length === 2 ) {\n                factory = deps;\n                deps = null;\n            }\n\n            _require( deps || [], function() {\n                setModule( id, factory, arguments );\n            });\n        },\n\n        // 设置module, 兼容CommonJs写法。\n        setModule = function( id, factory, args ) {\n            var module = {\n                    exports: factory\n                },\n                returned;\n\n            if ( typeof factory === 'function' ) {\n                args.length || (args = [ _require, module.exports, module ]);\n                returned = factory.apply( null, args );\n                returned !== undefined && (module.exports = returned);\n            }\n\n            modules[ id ] = module.exports;\n        },\n\n        // 根据id获取module\n        getModule = function( id ) {\n            var module = modules[ id ] || root[ id ];\n\n            if ( !module ) {\n                throw new Error( '`' + id + '` is undefined' );\n            }\n\n            return module;\n        },\n\n        // 将所有modules，将路径ids装换成对象。\n        exportsTo = function( obj ) {\n            var key, host, parts, part, last, ucFirst;\n\n            // make the first character upper case.\n            ucFirst = function( str ) {\n                return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 ));\n            };\n\n            for ( key in modules ) {\n                host = obj;\n\n                if ( !modules.hasOwnProperty( key ) ) {\n                    continue;\n                }\n\n                parts = key.split('/');\n                last = ucFirst( parts.pop() );\n\n                while( (part = ucFirst( parts.shift() )) ) {\n                    host[ part ] = host[ part ] || {};\n                    host = host[ part ];\n                }\n\n                host[ last ] = modules[ key ];\n            }\n\n            return obj;\n        },\n\n        makeExport = function( dollar ) {\n            root.__dollar = dollar;\n\n            // exports every module.\n            return exportsTo( factory( root, _define, _require ) );\n        },\n\n        origin;\n\n    if ( typeof module === 'object' && typeof module.exports === 'object' ) {\n\n        // For CommonJS and CommonJS-like environments where a proper window is present,\n        module.exports = makeExport();\n    } else if ( typeof define === 'function' && define.amd ) {\n\n        // Allow using this built library as an AMD module\n        // in another project. That other project will only\n        // see this AMD call, not the internal modules in\n        // the closure below.\n        define([ 'jquery' ], makeExport );\n    } else {\n\n        // Browser globals case. Just assign the\n        // result to a property on the global.\n        origin = root.WebUploader;\n        root.WebUploader = makeExport();\n        root.WebUploader.noConflict = function() {\n            root.WebUploader = origin;\n        };\n    }\n})( window, function( window, define, require ) {\n\n\n    /**\n     * @fileOverview jQuery or Zepto\n     */\n    define('dollar-third',[],function() {\n        var $ = window.__dollar || window.jQuery || window.Zepto;\n\n        if ( !$ ) {\n            throw new Error('jQuery or Zepto not found!');\n        }\n\n        return $;\n    });\n    /**\n     * @fileOverview Dom 操作相关\n     */\n    define('dollar',[\n        'dollar-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * 直接来源于jquery的代码。\n     * @fileOverview Promise/A+\n     * @beta\n     */\n    define('promise-builtin',[\n        'dollar'\n    ], function( $ ) {\n\n        var api;\n\n        // 简单版Callbacks, 默认memory，可选once.\n        function Callbacks( once ) {\n            var list = [],\n                stack = !once && [],\n                fire = function( data ) {\n                    memory = data;\n                    fired = true;\n                    firingIndex = firingStart || 0;\n                    firingStart = 0;\n                    firingLength = list.length;\n                    firing = true;\n\n                    for ( ; list && firingIndex < firingLength; firingIndex++ ) {\n                        list[ firingIndex ].apply( data[ 0 ], data[ 1 ] );\n                    }\n                    firing = false;\n\n                    if ( list ) {\n                        if ( stack ) {\n                            stack.length && fire( stack.shift() );\n                        }  else {\n                            list = [];\n                        }\n                    }\n                },\n                self = {\n                    add: function() {\n                        if ( list ) {\n                            var start = list.length;\n                            (function add ( args ) {\n                                $.each( args, function( _, arg ) {\n                                    var type = $.type( arg );\n                                    if ( type === 'function' ) {\n                                        list.push( arg );\n                                    } else if ( arg && arg.length &&\n                                            type !== 'string' ) {\n\n                                        add( arg );\n                                    }\n                                });\n                            })( arguments );\n\n                            if ( firing ) {\n                                firingLength = list.length;\n                            } else if ( memory ) {\n                                firingStart = start;\n                                fire( memory );\n                            }\n                        }\n                        return this;\n                    },\n\n                    disable: function() {\n                        list = stack = memory = undefined;\n                        return this;\n                    },\n\n                    // Lock the list in its current state\n                    lock: function() {\n                        stack = undefined;\n                        if ( !memory ) {\n                            self.disable();\n                        }\n                        return this;\n                    },\n\n                    fireWith: function( context, args ) {\n                        if ( list && (!fired || stack) ) {\n                            args = args || [];\n                            args = [ context, args.slice ? args.slice() : args ];\n                            if ( firing ) {\n                                stack.push( args );\n                            } else {\n                                fire( args );\n                            }\n                        }\n                        return this;\n                    },\n\n                    fire: function() {\n                        self.fireWith( this, arguments );\n                        return this;\n                    }\n                },\n\n                fired, firing, firingStart, firingLength, firingIndex, memory;\n\n            return self;\n        }\n\n        function Deferred( func ) {\n            var tuples = [\n                    // action, add listener, listener list, final state\n                    [ 'resolve', 'done', Callbacks( true ), 'resolved' ],\n                    [ 'reject', 'fail', Callbacks( true ), 'rejected' ],\n                    [ 'notify', 'progress', Callbacks() ]\n                ],\n                state = 'pending',\n                promise = {\n                    state: function() {\n                        return state;\n                    },\n                    always: function() {\n                        deferred.done( arguments ).fail( arguments );\n                        return this;\n                    },\n                    then: function( /* fnDone, fnFail, fnProgress */ ) {\n                        var fns = arguments;\n                        return Deferred(function( newDefer ) {\n                            $.each( tuples, function( i, tuple ) {\n                                var action = tuple[ 0 ],\n                                    fn = $.isFunction( fns[ i ] ) && fns[ i ];\n\n                                // deferred[ done | fail | progress ] for\n                                // forwarding actions to newDefer\n                                deferred[ tuple[ 1 ] ](function() {\n                                    var returned;\n\n                                    returned = fn && fn.apply( this, arguments );\n\n                                    if ( returned &&\n                                            $.isFunction( returned.promise ) ) {\n\n                                        returned.promise()\n                                                .done( newDefer.resolve )\n                                                .fail( newDefer.reject )\n                                                .progress( newDefer.notify );\n                                    } else {\n                                        newDefer[ action + 'With' ](\n                                                this === promise ?\n                                                newDefer.promise() :\n                                                this,\n                                                fn ? [ returned ] : arguments );\n                                    }\n                                });\n                            });\n                            fns = null;\n                        }).promise();\n                    },\n\n                    // Get a promise for this deferred\n                    // If obj is provided, the promise aspect is added to the object\n                    promise: function( obj ) {\n\n                        return obj != null ? $.extend( obj, promise ) : promise;\n                    }\n                },\n                deferred = {};\n\n            // Keep pipe for back-compat\n            promise.pipe = promise.then;\n\n            // Add list-specific methods\n            $.each( tuples, function( i, tuple ) {\n                var list = tuple[ 2 ],\n                    stateString = tuple[ 3 ];\n\n                // promise[ done | fail | progress ] = list.add\n                promise[ tuple[ 1 ] ] = list.add;\n\n                // Handle state\n                if ( stateString ) {\n                    list.add(function() {\n                        // state = [ resolved | rejected ]\n                        state = stateString;\n\n                    // [ reject_list | resolve_list ].disable; progress_list.lock\n                    }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n                }\n\n                // deferred[ resolve | reject | notify ]\n                deferred[ tuple[ 0 ] ] = function() {\n                    deferred[ tuple[ 0 ] + 'With' ]( this === deferred ? promise :\n                            this, arguments );\n                    return this;\n                };\n                deferred[ tuple[ 0 ] + 'With' ] = list.fireWith;\n            });\n\n            // Make the deferred a promise\n            promise.promise( deferred );\n\n            // Call given func if any\n            if ( func ) {\n                func.call( deferred, deferred );\n            }\n\n            // All done!\n            return deferred;\n        }\n\n        api = {\n            /**\n             * 创建一个[Deferred](http://api.jquery.com/category/deferred-object/)对象。\n             * 详细的Deferred用法说明，请参照jQuery的API文档。\n             *\n             * Deferred对象在钩子回掉函数中经常要用到，用来处理需要等待的异步操作。\n             *\n             * @for  Base\n             * @method Deferred\n             * @grammar Base.Deferred() => Deferred\n             * @example\n             * // 在文件开始发送前做些异步操作。\n             * // WebUploader会等待此异步操作完成后，开始发送文件。\n             * Uploader.register({\n             *     'before-send-file': 'doSomthingAsync'\n             * }, {\n             *\n             *     doSomthingAsync: function() {\n             *         var deferred = Base.Deferred();\n             *\n             *         // 模拟一次异步操作。\n             *         setTimeout(deferred.resolve, 2000);\n             *\n             *         return deferred.promise();\n             *     }\n             * });\n             */\n            Deferred: Deferred,\n\n            /**\n             * 判断传入的参数是否为一个promise对象。\n             * @method isPromise\n             * @grammar Base.isPromise( anything ) => Boolean\n             * @param  {*}  anything 检测对象。\n             * @return {Boolean}\n             * @for  Base\n             * @example\n             * console.log( Base.isPromise() );    // => false\n             * console.log( Base.isPromise({ key: '123' }) );    // => false\n             * console.log( Base.isPromise( Base.Deferred().promise() ) );    // => true\n             *\n             * // Deferred也是一个Promise\n             * console.log( Base.isPromise( Base.Deferred() ) );    // => true\n             */\n            isPromise: function( anything ) {\n                return anything && typeof anything.then === 'function';\n            },\n\n            /**\n             * 返回一个promise，此promise在所有传入的promise都完成了后完成。\n             * 详细请查看[这里](http://api.jquery.com/jQuery.when/)。\n             *\n             * @method when\n             * @for  Base\n             * @grammar Base.when( promise1[, promise2[, promise3...]] ) => Promise\n             */\n            when: function( subordinate /* , ..., subordinateN */ ) {\n                var i = 0,\n                    slice = [].slice,\n                    resolveValues = slice.call( arguments ),\n                    length = resolveValues.length,\n\n                    // the count of uncompleted subordinates\n                    remaining = length !== 1 || (subordinate &&\n                        $.isFunction( subordinate.promise )) ? length : 0,\n\n                    // the master Deferred. If resolveValues consist of\n                    // only a single Deferred, just use that.\n                    deferred = remaining === 1 ? subordinate : Deferred(),\n\n                    // Update function for both resolve and progress values\n                    updateFunc = function( i, contexts, values ) {\n                        return function( value ) {\n                            contexts[ i ] = this;\n                            values[ i ] = arguments.length > 1 ?\n                                    slice.call( arguments ) : value;\n\n                            if ( values === progressValues ) {\n                                deferred.notifyWith( contexts, values );\n                            } else if ( !(--remaining) ) {\n                                deferred.resolveWith( contexts, values );\n                            }\n                        };\n                    },\n\n                    progressValues, progressContexts, resolveContexts;\n\n                // add listeners to Deferred subordinates; treat others as resolved\n                if ( length > 1 ) {\n                    progressValues = new Array( length );\n                    progressContexts = new Array( length );\n                    resolveContexts = new Array( length );\n                    for ( ; i < length; i++ ) {\n                        if ( resolveValues[ i ] &&\n                                $.isFunction( resolveValues[ i ].promise ) ) {\n\n                            resolveValues[ i ].promise()\n                                    .done( updateFunc( i, resolveContexts,\n                                            resolveValues ) )\n                                    .fail( deferred.reject )\n                                    .progress( updateFunc( i, progressContexts,\n                                            progressValues ) );\n                        } else {\n                            --remaining;\n                        }\n                    }\n                }\n\n                // if we're not waiting on anything, resolve the master\n                if ( !remaining ) {\n                    deferred.resolveWith( resolveContexts, resolveValues );\n                }\n\n                return deferred.promise();\n            }\n        };\n\n        return api;\n    });\n    define('promise',[\n        'promise-builtin'\n    ], function( $ ) {\n        return $;\n    });\n    /**\n     * @fileOverview 基础类方法。\n     */\n\n    /**\n     * Web Uploader内部类的详细说明，以下提及的功能类，都可以在`WebUploader`这个变量中访问到。\n     *\n     * As you know, Web Uploader的每个文件都是用过[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)规范中的`define`组织起来的, 每个Module都会有个module id.\n     * 默认module id为该文件的路径，而此路径将会转化成名字空间存放在WebUploader中。如：\n     *\n     * * module `base`：WebUploader.Base\n     * * module `file`: WebUploader.File\n     * * module `lib/dnd`: WebUploader.Lib.Dnd\n     * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd\n     *\n     *\n     * 以下文档中对类的使用可能省略掉了`WebUploader`前缀。\n     * @module WebUploader\n     * @title WebUploader API文档\n     */\n    define('base',[\n        'dollar',\n        'promise'\n    ], function( $, promise ) {\n\n        var noop = function() {},\n            call = Function.call;\n\n        // http://jsperf.com/uncurrythis\n        // 反科里化\n        function uncurryThis( fn ) {\n            return function() {\n                return call.apply( fn, arguments );\n            };\n        }\n\n        function bindFn( fn, context ) {\n            return function() {\n                return fn.apply( context, arguments );\n            };\n        }\n\n        function createObject( proto ) {\n            var f;\n\n            if ( Object.create ) {\n                return Object.create( proto );\n            } else {\n                f = function() {};\n                f.prototype = proto;\n                return new f();\n            }\n        }\n\n\n        /**\n         * 基础类，提供一些简单常用的方法。\n         * @class Base\n         */\n        return {\n\n            /**\n             * @property {String} version 当前版本号。\n             */\n            version: '0.1.5',\n\n            /**\n             * @property {jQuery|Zepto} $ 引用依赖的jQuery或者Zepto对象。\n             */\n            $: $,\n\n            Deferred: promise.Deferred,\n\n            isPromise: promise.isPromise,\n\n            when: promise.when,\n\n            /**\n             * @description  简单的浏览器检查结果。\n             *\n             * * `webkit`  webkit版本号，如果浏览器为非webkit内核，此属性为`undefined`。\n             * * `chrome`  chrome浏览器版本号，如果浏览器为chrome，此属性为`undefined`。\n             * * `ie`  ie浏览器版本号，如果浏览器为非ie，此属性为`undefined`。**暂不支持ie10+**\n             * * `firefox`  firefox浏览器版本号，如果浏览器为非firefox，此属性为`undefined`。\n             * * `safari`  safari浏览器版本号，如果浏览器为非safari，此属性为`undefined`。\n             * * `opera`  opera浏览器版本号，如果浏览器为非opera，此属性为`undefined`。\n             *\n             * @property {Object} [browser]\n             */\n            browser: (function( ua ) {\n                var ret = {},\n                    webkit = ua.match( /WebKit\\/([\\d.]+)/ ),\n                    chrome = ua.match( /Chrome\\/([\\d.]+)/ ) ||\n                        ua.match( /CriOS\\/([\\d.]+)/ ),\n\n                    ie = ua.match( /MSIE\\s([\\d\\.]+)/ ) ||\n                        ua.match( /(?:trident)(?:.*rv:([\\w.]+))?/i ),\n                    firefox = ua.match( /Firefox\\/([\\d.]+)/ ),\n                    safari = ua.match( /Safari\\/([\\d.]+)/ ),\n                    opera = ua.match( /OPR\\/([\\d.]+)/ );\n\n                webkit && (ret.webkit = parseFloat( webkit[ 1 ] ));\n                chrome && (ret.chrome = parseFloat( chrome[ 1 ] ));\n                ie && (ret.ie = parseFloat( ie[ 1 ] ));\n                firefox && (ret.firefox = parseFloat( firefox[ 1 ] ));\n                safari && (ret.safari = parseFloat( safari[ 1 ] ));\n                opera && (ret.opera = parseFloat( opera[ 1 ] ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * @description  操作系统检查结果。\n             *\n             * * `android`  如果在android浏览器环境下，此值为对应的android版本号，否则为`undefined`。\n             * * `ios` 如果在ios浏览器环境下，此值为对应的ios版本号，否则为`undefined`。\n             * @property {Object} [os]\n             */\n            os: (function( ua ) {\n                var ret = {},\n\n                    // osx = !!ua.match( /\\(Macintosh\\; Intel / ),\n                    android = ua.match( /(?:Android);?[\\s\\/]+([\\d.]+)?/ ),\n                    ios = ua.match( /(?:iPad|iPod|iPhone).*OS\\s([\\d_]+)/ );\n\n                // osx && (ret.osx = true);\n                android && (ret.android = parseFloat( android[ 1 ] ));\n                ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * 实现类与类之间的继承。\n             * @method inherits\n             * @grammar Base.inherits( super ) => child\n             * @grammar Base.inherits( super, protos ) => child\n             * @grammar Base.inherits( super, protos, statics ) => child\n             * @param  {Class} super 父类\n             * @param  {Object | Function} [protos] 子类或者对象。如果对象中包含constructor，子类将是用此属性值。\n             * @param  {Function} [protos.constructor] 子类构造器，不指定的话将创建个临时的直接执行父类构造器的方法。\n             * @param  {Object} [statics] 静态属性或方法。\n             * @return {Class} 返回子类。\n             * @example\n             * function Person() {\n             *     console.log( 'Super' );\n             * }\n             * Person.prototype.hello = function() {\n             *     console.log( 'hello' );\n             * };\n             *\n             * var Manager = Base.inherits( Person, {\n             *     world: function() {\n             *         console.log( 'World' );\n             *     }\n             * });\n             *\n             * // 因为没有指定构造器，父类的构造器将会执行。\n             * var instance = new Manager();    // => Super\n             *\n             * // 继承子父类的方法\n             * instance.hello();    // => hello\n             * instance.world();    // => World\n             *\n             * // 子类的__super__属性指向父类\n             * console.log( Manager.__super__ === Person );    // => true\n             */\n            inherits: function( Super, protos, staticProtos ) {\n                var child;\n\n                if ( typeof protos === 'function' ) {\n                    child = protos;\n                    protos = null;\n                } else if ( protos && protos.hasOwnProperty('constructor') ) {\n                    child = protos.constructor;\n                } else {\n                    child = function() {\n                        return Super.apply( this, arguments );\n                    };\n                }\n\n                // 复制静态方法\n                $.extend( true, child, Super, staticProtos || {} );\n\n                /* jshint camelcase: false */\n\n                // 让子类的__super__属性指向父类。\n                child.__super__ = Super.prototype;\n\n                // 构建原型，添加原型方法或属性。\n                // 暂时用Object.create实现。\n                child.prototype = createObject( Super.prototype );\n                protos && $.extend( true, child.prototype, protos );\n\n                return child;\n            },\n\n            /**\n             * 一个不做任何事情的方法。可以用来赋值给默认的callback.\n             * @method noop\n             */\n            noop: noop,\n\n            /**\n             * 返回一个新的方法，此方法将已指定的`context`来执行。\n             * @grammar Base.bindFn( fn, context ) => Function\n             * @method bindFn\n             * @example\n             * var doSomething = function() {\n             *         console.log( this.name );\n             *     },\n             *     obj = {\n             *         name: 'Object Name'\n             *     },\n             *     aliasFn = Base.bind( doSomething, obj );\n             *\n             *  aliasFn();    // => Object Name\n             *\n             */\n            bindFn: bindFn,\n\n            /**\n             * 引用Console.log如果存在的话，否则引用一个[空函数noop](#WebUploader:Base.noop)。\n             * @grammar Base.log( args... ) => undefined\n             * @method log\n             */\n            log: (function() {\n                if ( window.console ) {\n                    return bindFn( console.log, console );\n                }\n                return noop;\n            })(),\n\n            nextTick: (function() {\n\n                return function( cb ) {\n                    setTimeout( cb, 1 );\n                };\n\n                // @bug 当浏览器不在当前窗口时就停了。\n                // var next = window.requestAnimationFrame ||\n                //     window.webkitRequestAnimationFrame ||\n                //     window.mozRequestAnimationFrame ||\n                //     function( cb ) {\n                //         window.setTimeout( cb, 1000 / 60 );\n                //     };\n\n                // // fix: Uncaught TypeError: Illegal invocation\n                // return bindFn( next, window );\n            })(),\n\n            /**\n             * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的数组slice方法。\n             * 将用来将非数组对象转化成数组对象。\n             * @grammar Base.slice( target, start[, end] ) => Array\n             * @method slice\n             * @example\n             * function doSomthing() {\n             *     var args = Base.slice( arguments, 1 );\n             *     console.log( args );\n             * }\n             *\n             * doSomthing( 'ignored', 'arg2', 'arg3' );    // => Array [\"arg2\", \"arg3\"]\n             */\n            slice: uncurryThis( [].slice ),\n\n            /**\n             * 生成唯一的ID\n             * @method guid\n             * @grammar Base.guid() => String\n             * @grammar Base.guid( prefx ) => String\n             */\n            guid: (function() {\n                var counter = 0;\n\n                return function( prefix ) {\n                    var guid = (+new Date()).toString( 32 ),\n                        i = 0;\n\n                    for ( ; i < 5; i++ ) {\n                        guid += Math.floor( Math.random() * 65535 ).toString( 32 );\n                    }\n\n                    return (prefix || 'wu_') + guid + (counter++).toString( 32 );\n                };\n            })(),\n\n            /**\n             * 格式化文件大小, 输出成带单位的字符串\n             * @method formatSize\n             * @grammar Base.formatSize( size ) => String\n             * @grammar Base.formatSize( size, pointLength ) => String\n             * @grammar Base.formatSize( size, pointLength, units ) => String\n             * @param {Number} size 文件大小\n             * @param {Number} [pointLength=2] 精确到的小数点数。\n             * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 单位数组。从字节，到千字节，一直往上指定。如果单位数组里面只指定了到了K(千字节)，同时文件大小大于M, 此方法的输出将还是显示成多少K.\n             * @example\n             * console.log( Base.formatSize( 100 ) );    // => 100B\n             * console.log( Base.formatSize( 1024 ) );    // => 1.00K\n             * console.log( Base.formatSize( 1024, 0 ) );    // => 1K\n             * console.log( Base.formatSize( 1024 * 1024 ) );    // => 1.00M\n             * console.log( Base.formatSize( 1024 * 1024 * 1024 ) );    // => 1.00G\n             * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) );    // => 1024MB\n             */\n            formatSize: function( size, pointLength, units ) {\n                var unit;\n\n                units = units || [ 'B', 'K', 'M', 'G', 'TB' ];\n\n                while ( (unit = units.shift()) && size > 1024 ) {\n                    size = size / 1024;\n                }\n\n                return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) +\n                        unit;\n            }\n        };\n    });\n    /**\n     * 事件处理类，可以独立使用，也可以扩展给对象使用。\n     * @fileOverview Mediator\n     */\n    define('mediator',[\n        'base'\n    ], function( Base ) {\n        var $ = Base.$,\n            slice = [].slice,\n            separator = /\\s+/,\n            protos;\n\n        // 根据条件过滤出事件handlers.\n        function findHandlers( arr, name, callback, context ) {\n            return $.grep( arr, function( handler ) {\n                return handler &&\n                        (!name || handler.e === name) &&\n                        (!callback || handler.cb === callback ||\n                        handler.cb._cb === callback) &&\n                        (!context || handler.ctx === context);\n            });\n        }\n\n        function eachEvent( events, callback, iterator ) {\n            // 不支持对象，只支持多个event用空格隔开\n            $.each( (events || '').split( separator ), function( _, key ) {\n                iterator( key, callback );\n            });\n        }\n\n        function triggerHanders( events, args ) {\n            var stoped = false,\n                i = -1,\n                len = events.length,\n                handler;\n\n            while ( ++i < len ) {\n                handler = events[ i ];\n\n                if ( handler.cb.apply( handler.ctx2, args ) === false ) {\n                    stoped = true;\n                    break;\n                }\n            }\n\n            return !stoped;\n        }\n\n        protos = {\n\n            /**\n             * 绑定事件。\n             *\n             * `callback`方法在执行时，arguments将会来源于trigger的时候携带的参数。如\n             * ```javascript\n             * var obj = {};\n             *\n             * // 使得obj有事件行为\n             * Mediator.installTo( obj );\n             *\n             * obj.on( 'testa', function( arg1, arg2 ) {\n             *     console.log( arg1, arg2 ); // => 'arg1', 'arg2'\n             * });\n             *\n             * obj.trigger( 'testa', 'arg1', 'arg2' );\n             * ```\n             *\n             * 如果`callback`中，某一个方法`return false`了，则后续的其他`callback`都不会被执行到。\n             * 切会影响到`trigger`方法的返回值，为`false`。\n             *\n             * `on`还可以用来添加一个特殊事件`all`, 这样所有的事件触发都会响应到。同时此类`callback`中的arguments有一个不同处，\n             * 就是第一个参数为`type`，记录当前是什么事件在触发。此类`callback`的优先级比脚低，会再正常`callback`执行完后触发。\n             * ```javascript\n             * obj.on( 'all', function( type, arg1, arg2 ) {\n             *     console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2'\n             * });\n             * ```\n             *\n             * @method on\n             * @grammar on( name, callback[, context] ) => self\n             * @param  {String}   name     事件名，支持多个事件用空格隔开\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             * @class Mediator\n             */\n            on: function( name, callback, context ) {\n                var me = this,\n                    set;\n\n                if ( !callback ) {\n                    return this;\n                }\n\n                set = this._events || (this._events = []);\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var handler = { e: name };\n\n                    handler.cb = callback;\n                    handler.ctx = context;\n                    handler.ctx2 = context || me;\n                    handler.id = set.length;\n\n                    set.push( handler );\n                });\n\n                return this;\n            },\n\n            /**\n             * 绑定事件，且当handler执行完后，自动解除绑定。\n             * @method once\n             * @grammar once( name, callback[, context] ) => self\n             * @param  {String}   name     事件名\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            once: function( name, callback, context ) {\n                var me = this;\n\n                if ( !callback ) {\n                    return me;\n                }\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var once = function() {\n                            me.off( name, once );\n                            return callback.apply( context || me, arguments );\n                        };\n\n                    once._cb = callback;\n                    me.on( name, once, context );\n                });\n\n                return me;\n            },\n\n            /**\n             * 解除事件绑定\n             * @method off\n             * @grammar off( [name[, callback[, context] ] ] ) => self\n             * @param  {String}   [name]     事件名\n             * @param  {Function} [callback] 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            off: function( name, cb, ctx ) {\n                var events = this._events;\n\n                if ( !events ) {\n                    return this;\n                }\n\n                if ( !name && !cb && !ctx ) {\n                    this._events = [];\n                    return this;\n                }\n\n                eachEvent( name, cb, function( name, cb ) {\n                    $.each( findHandlers( events, name, cb, ctx ), function() {\n                        delete events[ this.id ];\n                    });\n                });\n\n                return this;\n            },\n\n            /**\n             * 触发事件\n             * @method trigger\n             * @grammar trigger( name[, args...] ) => self\n             * @param  {String}   type     事件名\n             * @param  {*} [...] 任意参数\n             * @return {Boolean} 如果handler中return false了，则返回false, 否则返回true\n             */\n            trigger: function( type ) {\n                var args, events, allEvents;\n\n                if ( !this._events || !type ) {\n                    return this;\n                }\n\n                args = slice.call( arguments, 1 );\n                events = findHandlers( this._events, type );\n                allEvents = findHandlers( this._events, 'all' );\n\n                return triggerHanders( events, args ) &&\n                        triggerHanders( allEvents, arguments );\n            }\n        };\n\n        /**\n         * 中介者，它本身是个单例，但可以通过[installTo](#WebUploader:Mediator:installTo)方法，使任何对象具备事件行为。\n         * 主要目的是负责模块与模块之间的合作，降低耦合度。\n         *\n         * @class Mediator\n         */\n        return $.extend({\n\n            /**\n             * 可以通过这个接口，使任何对象具备事件功能。\n             * @method installTo\n             * @param  {Object} obj 需要具备事件行为的对象。\n             * @return {Object} 返回obj.\n             */\n            installTo: function( obj ) {\n                return $.extend( obj, protos );\n            }\n\n        }, protos );\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('uploader',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$;\n\n        /**\n         * 上传入口类。\n         * @class Uploader\n         * @constructor\n         * @grammar new Uploader( opts ) => Uploader\n         * @example\n         * var uploader = WebUploader.Uploader({\n         *     swf: 'path_of_swf/Uploader.swf',\n         *\n         *     // 开起分片上传。\n         *     chunked: true\n         * });\n         */\n        function Uploader( opts ) {\n            this.options = $.extend( true, {}, Uploader.options, opts );\n            this._init( this.options );\n        }\n\n        // default Options\n        // widgets中有相应扩展\n        Uploader.options = {};\n        Mediator.installTo( Uploader.prototype );\n\n        // 批量添加纯命令式方法。\n        $.each({\n            upload: 'start-upload',\n            stop: 'stop-upload',\n            getFile: 'get-file',\n            getFiles: 'get-files',\n            addFile: 'add-file',\n            addFiles: 'add-file',\n            sort: 'sort-files',\n            removeFile: 'remove-file',\n            cancelFile: 'cancel-file',\n            skipFile: 'skip-file',\n            retry: 'retry',\n            isInProgress: 'is-in-progress',\n            makeThumb: 'make-thumb',\n            md5File: 'md5-file',\n            getDimension: 'get-dimension',\n            addButton: 'add-btn',\n            predictRuntimeType: 'predict-runtime-type',\n            refresh: 'refresh',\n            disable: 'disable',\n            enable: 'enable',\n            reset: 'reset'\n        }, function( fn, command ) {\n            Uploader.prototype[ fn ] = function() {\n                return this.request( command, arguments );\n            };\n        });\n\n        $.extend( Uploader.prototype, {\n            state: 'pending',\n\n            _init: function( opts ) {\n                var me = this;\n\n                me.request( 'init', opts, function() {\n                    me.state = 'ready';\n                    me.trigger('ready');\n                });\n            },\n\n            /**\n             * 获取或者设置Uploader配置项。\n             * @method option\n             * @grammar option( key ) => *\n             * @grammar option( key, val ) => self\n             * @example\n             *\n             * // 初始状态图片上传前不会压缩\n             * var uploader = new WebUploader.Uploader({\n             *     compress: null;\n             * });\n             *\n             * // 修改后图片上传前，尝试将图片压缩到1600 * 1600\n             * uploader.option( 'compress', {\n             *     width: 1600,\n             *     height: 1600\n             * });\n             */\n            option: function( key, val ) {\n                var opts = this.options;\n\n                // setter\n                if ( arguments.length > 1 ) {\n\n                    if ( $.isPlainObject( val ) &&\n                            $.isPlainObject( opts[ key ] ) ) {\n                        $.extend( opts[ key ], val );\n                    } else {\n                        opts[ key ] = val;\n                    }\n\n                } else {    // getter\n                    return key ? opts[ key ] : opts;\n                }\n            },\n\n            /**\n             * 获取文件统计信息。返回一个包含一下信息的对象。\n             * * `successNum` 上传成功的文件数\n             * * `progressNum` 上传中的文件数\n             * * `cancelNum` 被删除的文件数\n             * * `invalidNum` 无效的文件数\n             * * `uploadFailNum` 上传失败的文件数\n             * * `queueNum` 还在队列中的文件数\n             * * `interruptNum` 被暂停的文件数\n             * @method getStats\n             * @grammar getStats() => Object\n             */\n            getStats: function() {\n                // return this._mgr.getStats.apply( this._mgr, arguments );\n                var stats = this.request('get-stats');\n\n                return stats ? {\n                    successNum: stats.numOfSuccess,\n                    progressNum: stats.numOfProgress,\n\n                    // who care?\n                    // queueFailNum: 0,\n                    cancelNum: stats.numOfCancel,\n                    invalidNum: stats.numOfInvalid,\n                    uploadFailNum: stats.numOfUploadFailed,\n                    queueNum: stats.numOfQueue,\n                    interruptNum: stats.numofInterrupt\n                } : {};\n            },\n\n            // 需要重写此方法来来支持opts.onEvent和instance.onEvent的处理器\n            trigger: function( type/*, args...*/ ) {\n                var args = [].slice.call( arguments, 1 ),\n                    opts = this.options,\n                    name = 'on' + type.substring( 0, 1 ).toUpperCase() +\n                        type.substring( 1 );\n\n                if (\n                        // 调用通过on方法注册的handler.\n                        Mediator.trigger.apply( this, arguments ) === false ||\n\n                        // 调用opts.onEvent\n                        $.isFunction( opts[ name ] ) &&\n                        opts[ name ].apply( this, args ) === false ||\n\n                        // 调用this.onEvent\n                        $.isFunction( this[ name ] ) &&\n                        this[ name ].apply( this, args ) === false ||\n\n                        // 广播所有uploader的事件。\n                        Mediator.trigger.apply( Mediator,\n                        [ this, type ].concat( args ) ) === false ) {\n\n                    return false;\n                }\n\n                return true;\n            },\n\n            /**\n             * 销毁 webuploader 实例\n             * @method destroy\n             * @grammar destroy() => undefined\n             */\n            destroy: function() {\n                this.request( 'destroy', arguments );\n                this.off();\n            },\n\n            // widgets/widget.js将补充此方法的详细文档。\n            request: Base.noop\n        });\n\n        /**\n         * 创建Uploader实例，等同于new Uploader( opts );\n         * @method create\n         * @class Base\n         * @static\n         * @grammar Base.create( opts ) => Uploader\n         */\n        Base.create = Uploader.create = function( opts ) {\n            return new Uploader( opts );\n        };\n\n        // 暴露Uploader，可以通过它来扩展业务逻辑。\n        Base.Uploader = Uploader;\n\n        return Uploader;\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/runtime',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            factories = {},\n\n            // 获取对象的第一个key\n            getFirstKey = function( obj ) {\n                for ( var key in obj ) {\n                    if ( obj.hasOwnProperty( key ) ) {\n                        return key;\n                    }\n                }\n                return null;\n            };\n\n        // 接口类。\n        function Runtime( options ) {\n            this.options = $.extend({\n                container: document.body\n            }, options );\n            this.uid = Base.guid('rt_');\n        }\n\n        $.extend( Runtime.prototype, {\n\n            getContainer: function() {\n                var opts = this.options,\n                    parent, container;\n\n                if ( this._container ) {\n                    return this._container;\n                }\n\n                parent = $( opts.container || document.body );\n                container = $( document.createElement('div') );\n\n                container.attr( 'id', 'rt_' + this.uid );\n                container.css({\n                    position: 'absolute',\n                    top: '0px',\n                    left: '0px',\n                    width: '1px',\n                    height: '1px',\n                    overflow: 'hidden'\n                });\n\n                parent.append( container );\n                parent.addClass('webuploader-container');\n                this._container = container;\n                this._parent = parent;\n                return container;\n            },\n\n            init: Base.noop,\n            exec: Base.noop,\n\n            destroy: function() {\n                this._container && this._container.remove();\n                this._parent && this._parent.removeClass('webuploader-container');\n                this.off();\n            }\n        });\n\n        Runtime.orders = 'html5,flash';\n\n\n        /**\n         * 添加Runtime实现。\n         * @param {String} type    类型\n         * @param {Runtime} factory 具体Runtime实现。\n         */\n        Runtime.addRuntime = function( type, factory ) {\n            factories[ type ] = factory;\n        };\n\n        Runtime.hasRuntime = function( type ) {\n            return !!(type ? factories[ type ] : getFirstKey( factories ));\n        };\n\n        Runtime.create = function( opts, orders ) {\n            var type, runtime;\n\n            orders = orders || Runtime.orders;\n            $.each( orders.split( /\\s*,\\s*/g ), function() {\n                if ( factories[ this ] ) {\n                    type = this;\n                    return false;\n                }\n            });\n\n            type = type || getFirstKey( factories );\n\n            if ( !type ) {\n                throw new Error('Runtime Error');\n            }\n\n            runtime = new factories[ type ]( opts );\n            return runtime;\n        };\n\n        Mediator.installTo( Runtime.prototype );\n        return Runtime;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/client',[\n        'base',\n        'mediator',\n        'runtime/runtime'\n    ], function( Base, Mediator, Runtime ) {\n\n        var cache;\n\n        cache = (function() {\n            var obj = {};\n\n            return {\n                add: function( runtime ) {\n                    obj[ runtime.uid ] = runtime;\n                },\n\n                get: function( ruid, standalone ) {\n                    var i;\n\n                    if ( ruid ) {\n                        return obj[ ruid ];\n                    }\n\n                    for ( i in obj ) {\n                        // 有些类型不能重用，比如filepicker.\n                        if ( standalone && obj[ i ].__standalone ) {\n                            continue;\n                        }\n\n                        return obj[ i ];\n                    }\n\n                    return null;\n                },\n\n                remove: function( runtime ) {\n                    delete obj[ runtime.uid ];\n                }\n            };\n        })();\n\n        function RuntimeClient( component, standalone ) {\n            var deferred = Base.Deferred(),\n                runtime;\n\n            this.uid = Base.guid('client_');\n\n            // 允许runtime没有初始化之前，注册一些方法在初始化后执行。\n            this.runtimeReady = function( cb ) {\n                return deferred.done( cb );\n            };\n\n            this.connectRuntime = function( opts, cb ) {\n\n                // already connected.\n                if ( runtime ) {\n                    throw new Error('already connected!');\n                }\n\n                deferred.done( cb );\n\n                if ( typeof opts === 'string' && cache.get( opts ) ) {\n                    runtime = cache.get( opts );\n                }\n\n                // 像filePicker只能独立存在，不能公用。\n                runtime = runtime || cache.get( null, standalone );\n\n                // 需要创建\n                if ( !runtime ) {\n                    runtime = Runtime.create( opts, opts.runtimeOrder );\n                    runtime.__promise = deferred.promise();\n                    runtime.once( 'ready', deferred.resolve );\n                    runtime.init();\n                    cache.add( runtime );\n                    runtime.__client = 1;\n                } else {\n                    // 来自cache\n                    Base.$.extend( runtime.options, opts );\n                    runtime.__promise.then( deferred.resolve );\n                    runtime.__client++;\n                }\n\n                standalone && (runtime.__standalone = standalone);\n                return runtime;\n            };\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.disconnectRuntime = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                runtime.__client--;\n\n                if ( runtime.__client <= 0 ) {\n                    cache.remove( runtime );\n                    delete runtime.__promise;\n                    runtime.destroy();\n                }\n\n                runtime = null;\n            };\n\n            this.exec = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                var args = Base.slice( arguments );\n                component && args.unshift( component );\n\n                return runtime.exec.apply( this, args );\n            };\n\n            this.getRuid = function() {\n                return runtime && runtime.uid;\n            };\n\n            this.destroy = (function( destroy ) {\n                return function() {\n                    destroy && destroy.apply( this, arguments );\n                    this.trigger('destroy');\n                    this.off();\n                    this.exec('destroy');\n                    this.disconnectRuntime();\n                };\n            })( this.destroy );\n        }\n\n        Mediator.installTo( RuntimeClient.prototype );\n        return RuntimeClient;\n    });\n    /**\n     * @fileOverview Blob\n     */\n    define('lib/blob',[\n        'base',\n        'runtime/client'\n    ], function( Base, RuntimeClient ) {\n\n        function Blob( ruid, source ) {\n            var me = this;\n\n            me.source = source;\n            me.ruid = ruid;\n            this.size = source.size || 0;\n\n            // 如果没有指定 mimetype, 但是知道文件后缀。\n            if ( !source.type && this.ext &&\n                    ~'jpg,jpeg,png,gif,bmp'.indexOf( this.ext ) ) {\n                this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);\n            } else {\n                this.type = source.type || 'application/octet-stream';\n            }\n\n            RuntimeClient.call( me, 'Blob' );\n            this.uid = source.uid || this.uid;\n\n            if ( ruid ) {\n                me.connectRuntime( ruid );\n            }\n        }\n\n        Base.inherits( RuntimeClient, {\n            constructor: Blob,\n\n            slice: function( start, end ) {\n                return this.exec( 'slice', start, end );\n            },\n\n            getSource: function() {\n                return this.source;\n            }\n        });\n\n        return Blob;\n    });\n    /**\n     * 为了统一化Flash的File和HTML5的File而存在。\n     * 以至于要调用Flash里面的File，也可以像调用HTML5版本的File一下。\n     * @fileOverview File\n     */\n    define('lib/file',[\n        'base',\n        'lib/blob'\n    ], function( Base, Blob ) {\n\n        var uid = 1,\n            rExt = /\\.([^.]+)$/;\n\n        function File( ruid, file ) {\n            var ext;\n\n            this.name = file.name || ('untitled' + uid++);\n            ext = rExt.exec( file.name ) ? RegExp.$1.toLowerCase() : '';\n\n            // todo 支持其他类型文件的转换。\n            // 如果有 mimetype, 但是文件名里面没有找出后缀规律\n            if ( !ext && file.type ) {\n                ext = /\\/(jpg|jpeg|png|gif|bmp)$/i.exec( file.type ) ?\n                        RegExp.$1.toLowerCase() : '';\n                this.name += '.' + ext;\n            }\n\n            this.ext = ext;\n            this.lastModifiedDate = file.lastModifiedDate ||\n                    (new Date()).toLocaleString();\n\n            Blob.apply( this, arguments );\n        }\n\n        return Base.inherits( Blob, File );\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepicker',[\n        'base',\n        'runtime/client',\n        'lib/file'\n    ], function( Base, RuntimeClent, File ) {\n\n        var $ = Base.$;\n\n        function FilePicker( opts ) {\n            opts = this.options = $.extend({}, FilePicker.options, opts );\n\n            opts.container = $( opts.id );\n\n            if ( !opts.container.length ) {\n                throw new Error('按钮指定错误');\n            }\n\n            opts.innerHTML = opts.innerHTML || opts.label ||\n                    opts.container.html() || '';\n\n            opts.button = $( opts.button || document.createElement('div') );\n            opts.button.html( opts.innerHTML );\n            opts.container.html( opts.button );\n\n            RuntimeClent.call( this, 'FilePicker', true );\n        }\n\n        FilePicker.options = {\n            button: null,\n            container: null,\n            label: null,\n            innerHTML: null,\n            multiple: true,\n            accept: null,\n            name: 'file'\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePicker,\n\n            init: function() {\n                var me = this,\n                    opts = me.options,\n                    button = opts.button;\n\n                button.addClass('webuploader-pick');\n\n                me.on( 'all', function( type ) {\n                    var files;\n\n                    switch ( type ) {\n                        case 'mouseenter':\n                            button.addClass('webuploader-pick-hover');\n                            break;\n\n                        case 'mouseleave':\n                            button.removeClass('webuploader-pick-hover');\n                            break;\n\n                        case 'change':\n                            files = me.exec('getFiles');\n                            me.trigger( 'select', $.map( files, function( file ) {\n                                file = new File( me.getRuid(), file );\n\n                                // 记录来源。\n                                file._refer = opts.container;\n                                return file;\n                            }), opts.container );\n                            break;\n                    }\n                });\n\n                me.connectRuntime( opts, function() {\n                    me.refresh();\n                    me.exec( 'init', opts );\n                    me.trigger('ready');\n                });\n\n                this._resizeHandler = Base.bindFn( this.refresh, this );\n                $( window ).on( 'resize', this._resizeHandler );\n            },\n\n            refresh: function() {\n                var shimContainer = this.getRuntime().getContainer(),\n                    button = this.options.button,\n                    width = button.outerWidth ?\n                            button.outerWidth() : button.width(),\n\n                    height = button.outerHeight ?\n                            button.outerHeight() : button.height(),\n\n                    pos = button.offset();\n\n                width && height && shimContainer.css({\n                    bottom: 'auto',\n                    right: 'auto',\n                    width: width + 'px',\n                    height: height + 'px'\n                }).offset( pos );\n            },\n\n            enable: function() {\n                var btn = this.options.button;\n\n                btn.removeClass('webuploader-pick-disable');\n                this.refresh();\n            },\n\n            disable: function() {\n                var btn = this.options.button;\n\n                this.getRuntime().getContainer().css({\n                    top: '-99999px'\n                });\n\n                btn.addClass('webuploader-pick-disable');\n            },\n\n            destroy: function() {\n                var btn = this.options.button;\n                $( window ).off( 'resize', this._resizeHandler );\n                btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +\n                    'webuploader-pick');\n            }\n        });\n\n        return FilePicker;\n    });\n\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/widget',[\n        'base',\n        'uploader'\n    ], function( Base, Uploader ) {\n\n        var $ = Base.$,\n            _init = Uploader.prototype._init,\n            _destroy = Uploader.prototype.destroy,\n            IGNORE = {},\n            widgetClass = [];\n\n        function isArrayLike( obj ) {\n            if ( !obj ) {\n                return false;\n            }\n\n            var length = obj.length,\n                type = $.type( obj );\n\n            if ( obj.nodeType === 1 && length ) {\n                return true;\n            }\n\n            return type === 'array' || type !== 'function' && type !== 'string' &&\n                    (length === 0 || typeof length === 'number' && length > 0 &&\n                    (length - 1) in obj);\n        }\n\n        function Widget( uploader ) {\n            this.owner = uploader;\n            this.options = uploader.options;\n        }\n\n        $.extend( Widget.prototype, {\n\n            init: Base.noop,\n\n            // 类Backbone的事件监听声明，监听uploader实例上的事件\n            // widget直接无法监听事件，事件只能通过uploader来传递\n            invoke: function( apiName, args ) {\n\n                /*\n                    {\n                        'make-thumb': 'makeThumb'\n                    }\n                 */\n                var map = this.responseMap;\n\n                // 如果无API响应声明则忽略\n                if ( !map || !(apiName in map) || !(map[ apiName ] in this) ||\n                        !$.isFunction( this[ map[ apiName ] ] ) ) {\n\n                    return IGNORE;\n                }\n\n                return this[ map[ apiName ] ].apply( this, args );\n\n            },\n\n            /**\n             * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。\n             * @method request\n             * @grammar request( command, args ) => * | Promise\n             * @grammar request( command, args, callback ) => Promise\n             * @for  Uploader\n             */\n            request: function() {\n                return this.owner.request.apply( this.owner, arguments );\n            }\n        });\n\n        // 扩展Uploader.\n        $.extend( Uploader.prototype, {\n\n            /**\n             * @property {String | Array} [disableWidgets=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。\n             */\n\n            // 覆写_init用来初始化widgets\n            _init: function() {\n                var me = this,\n                    widgets = me._widgets = [],\n                    deactives = me.options.disableWidgets || '';\n\n                $.each( widgetClass, function( _, klass ) {\n                    (!deactives || !~deactives.indexOf( klass._name )) &&\n                        widgets.push( new klass( me ) );\n                });\n\n                return _init.apply( me, arguments );\n            },\n\n            request: function( apiName, args, callback ) {\n                var i = 0,\n                    widgets = this._widgets,\n                    len = widgets && widgets.length,\n                    rlts = [],\n                    dfds = [],\n                    widget, rlt, promise, key;\n\n                args = isArrayLike( args ) ? args : [ args ];\n\n                for ( ; i < len; i++ ) {\n                    widget = widgets[ i ];\n                    rlt = widget.invoke( apiName, args );\n\n                    if ( rlt !== IGNORE ) {\n\n                        // Deferred对象\n                        if ( Base.isPromise( rlt ) ) {\n                            dfds.push( rlt );\n                        } else {\n                            rlts.push( rlt );\n                        }\n                    }\n                }\n\n                // 如果有callback，则用异步方式。\n                if ( callback || dfds.length ) {\n                    promise = Base.when.apply( Base, dfds );\n                    key = promise.pipe ? 'pipe' : 'then';\n\n                    // 很重要不能删除。删除了会死循环。\n                    // 保证执行顺序。让callback总是在下一个 tick 中执行。\n                    return promise[ key ](function() {\n                                var deferred = Base.Deferred(),\n                                    args = arguments;\n\n                                if ( args.length === 1 ) {\n                                    args = args[ 0 ];\n                                }\n\n                                setTimeout(function() {\n                                    deferred.resolve( args );\n                                }, 1 );\n\n                                return deferred.promise();\n                            })[ callback ? key : 'done' ]( callback || Base.noop );\n                } else {\n                    return rlts[ 0 ];\n                }\n            },\n\n            destroy: function() {\n                _destroy.apply( this, arguments );\n                this._widgets = null;\n            }\n        });\n\n        /**\n         * 添加组件\n         * @grammar Uploader.register(proto);\n         * @grammar Uploader.register(map, proto);\n         * @param  {object} responseMap API 名称与函数实现的映射\n         * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义\n         * @method Uploader.register\n         * @for Uploader\n         * @example\n         * Uploader.register({\n         *     'make-thumb': 'makeThumb'\n         * }, {\n         *     init: function( options ) {},\n         *     makeThumb: function() {}\n         * });\n         *\n         * Uploader.register({\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         */\n        Uploader.register = Widget.register = function( responseMap, widgetProto ) {\n            var map = { init: 'init', destroy: 'destroy', name: 'anonymous' },\n                klass;\n\n            if ( arguments.length === 1 ) {\n                widgetProto = responseMap;\n\n                // 自动生成 map 表。\n                $.each(widgetProto, function(key) {\n                    if ( key[0] === '_' || key === 'name' ) {\n                        key === 'name' && (map.name = widgetProto.name);\n                        return;\n                    }\n\n                    map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;\n                });\n\n            } else {\n                map = $.extend( map, responseMap );\n            }\n\n            widgetProto.responseMap = map;\n            klass = Base.inherits( Widget, widgetProto );\n            klass._name = map.name;\n            widgetClass.push( klass );\n\n            return klass;\n        };\n\n        /**\n         * 删除插件，只有在注册时指定了名字的才能被删除。\n         * @grammar Uploader.unRegister(name);\n         * @param  {string} name 组件名字\n         * @method Uploader.unRegister\n         * @for Uploader\n         * @example\n         *\n         * Uploader.register({\n         *     name: 'custom',\n         *\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         *\n         * Uploader.unRegister('custom');\n         */\n        Uploader.unRegister = Widget.unRegister = function( name ) {\n            if ( !name || name === 'anonymous' ) {\n                return;\n            }\n\n            // 删除指定的插件。\n            for ( var i = widgetClass.length; i--; ) {\n                if ( widgetClass[i]._name === name ) {\n                    widgetClass.splice(i, 1)\n                }\n            }\n        };\n\n        return Widget;\n    });\n    /**\n     * @fileOverview 文件选择相关\n     */\n    define('widgets/filepicker',[\n        'base',\n        'uploader',\n        'lib/filepicker',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePicker ) {\n        var $ = Base.$;\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Selector | Object} [pick=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 指定选择文件的按钮容器，不指定则不创建按钮。\n             *\n             * * `id` {Seletor|dom} 指定选择文件的按钮容器，不指定则不创建按钮。**注意** 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。\n             * * `label` {String} 请采用 `innerHTML` 代替\n             * * `innerHTML` {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。\n             * * `multiple` {Boolean} 是否开起同时选择多个文件能力。\n             */\n            pick: null,\n\n            /**\n             * @property {Arroy} [accept=null]\n             * @namespace options\n             * @for Uploader\n             * @description 指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。\n             *\n             * * `title` {String} 文字描述\n             * * `extensions` {String} 允许的文件后缀，不带点，多个用逗号分割。\n             * * `mimeTypes` {String} 多个用逗号分割。\n             *\n             * 如：\n             *\n             * ```\n             * {\n             *     title: 'Images',\n             *     extensions: 'gif,jpg,jpeg,bmp,png',\n             *     mimeTypes: 'image/*'\n             * }\n             * ```\n             */\n            accept: null/*{\n                title: 'Images',\n                extensions: 'gif,jpg,jpeg,bmp,png',\n                mimeTypes: 'image/*'\n            }*/\n        });\n\n        return Uploader.register({\n            name: 'picker',\n\n            init: function( opts ) {\n                this.pickers = [];\n                return opts.pick && this.addBtn( opts.pick );\n            },\n\n            refresh: function() {\n                $.each( this.pickers, function() {\n                    this.refresh();\n                });\n            },\n\n            /**\n             * @method addButton\n             * @for Uploader\n             * @grammar addButton( pick ) => Promise\n             * @description\n             * 添加文件选择按钮，如果一个按钮不够，需要调用此方法来添加。参数跟[options.pick](#WebUploader:Uploader:options)一致。\n             * @example\n             * uploader.addButton({\n             *     id: '#btnContainer',\n             *     innerHTML: '选择文件'\n             * });\n             */\n            addBtn: function( pick ) {\n                var me = this,\n                    opts = me.options,\n                    accept = opts.accept,\n                    promises = [];\n\n                if ( !pick ) {\n                    return;\n                }\n\n                $.isPlainObject( pick ) || (pick = {\n                    id: pick\n                });\n\n                $( pick.id ).each(function() {\n                    var options, picker, deferred;\n\n                    deferred = Base.Deferred();\n\n                    options = $.extend({}, pick, {\n                        accept: $.isPlainObject( accept ) ? [ accept ] : accept,\n                        swf: opts.swf,\n                        runtimeOrder: opts.runtimeOrder,\n                        id: this\n                    });\n\n                    picker = new FilePicker( options );\n\n                    picker.once( 'ready', deferred.resolve );\n                    picker.on( 'select', function( files ) {\n                        me.owner.request( 'add-file', [ files ]);\n                    });\n                    picker.init();\n\n                    me.pickers.push( picker );\n\n                    promises.push( deferred.promise() );\n                });\n\n                return Base.when.apply( Base, promises );\n            },\n\n            disable: function() {\n                $.each( this.pickers, function() {\n                    this.disable();\n                });\n            },\n\n            enable: function() {\n                $.each( this.pickers, function() {\n                    this.enable();\n                });\n            },\n\n            destroy: function() {\n                $.each( this.pickers, function() {\n                    this.destroy();\n                });\n                this.pickers = null;\n            }\n        });\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('lib/image',[\n        'base',\n        'runtime/client',\n        'lib/blob'\n    ], function( Base, RuntimeClient, Blob ) {\n        var $ = Base.$;\n\n        // 构造器。\n        function Image( opts ) {\n            this.options = $.extend({}, Image.options, opts );\n            RuntimeClient.call( this, 'Image' );\n\n            this.on( 'load', function() {\n                this._info = this.exec('info');\n                this._meta = this.exec('meta');\n            });\n        }\n\n        // 默认选项。\n        Image.options = {\n\n            // 默认的图片处理质量\n            quality: 90,\n\n            // 是否裁剪\n            crop: false,\n\n            // 是否保留头部信息\n            preserveHeaders: false,\n\n            // 是否允许放大。\n            allowMagnify: false\n        };\n\n        // 继承RuntimeClient.\n        Base.inherits( RuntimeClient, {\n            constructor: Image,\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    ruid = blob.getRuid();\n\n                this.connectRuntime( ruid, function() {\n                    me.exec( 'init', me.options );\n                    me.exec( 'loadFromBlob', blob );\n                });\n            },\n\n            resize: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'resize' ].concat( args ) );\n            },\n\n            crop: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'crop' ].concat( args ) );\n            },\n\n            getAsDataUrl: function( type ) {\n                return this.exec( 'getAsDataUrl', type );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this.exec( 'getAsBlob', type );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n\n        return Image;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/image',[\n        'base',\n        'uploader',\n        'lib/image',\n        'widgets/widget'\n    ], function( Base, Uploader, Image ) {\n\n        var $ = Base.$,\n            throttle;\n\n        // 根据要处理的文件大小来节流，一次不能处理太多，会卡。\n        throttle = (function( max ) {\n            var occupied = 0,\n                waiting = [],\n                tick = function() {\n                    var item;\n\n                    while ( waiting.length && occupied < max ) {\n                        item = waiting.shift();\n                        occupied += item[ 0 ];\n                        item[ 1 ]();\n                    }\n                };\n\n            return function( emiter, size, cb ) {\n                waiting.push([ size, cb ]);\n                emiter.once( 'destroy', function() {\n                    occupied -= size;\n                    setTimeout( tick, 1 );\n                });\n                setTimeout( tick, 1 );\n            };\n        })( 5 * 1024 * 1024 );\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Object} [thumb]\n             * @namespace options\n             * @for Uploader\n             * @description 配置生成缩略图的选项。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 110,\n             *     height: 110,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 70,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: true,\n             *\n             *     // 是否允许裁剪。\n             *     crop: true,\n             *\n             *     // 为空的话则保留原有图片格式。\n             *     // 否则强制转换成指定的类型。\n             *     type: 'image/jpeg'\n             * }\n             * ```\n             */\n            thumb: {\n                width: 110,\n                height: 110,\n                quality: 70,\n                allowMagnify: true,\n                crop: true,\n                preserveHeaders: false,\n\n                // 为空的话则保留原有图片格式。\n                // 否则强制转换成指定的类型。\n                // IE 8下面 base64 大小不能超过 32K 否则预览失败，而非 jpeg 编码的图片很可\n                // 能会超过 32k, 所以这里设置成预览的时候都是 image/jpeg\n                type: 'image/jpeg'\n            },\n\n            /**\n             * @property {Object} [compress]\n             * @namespace options\n             * @for Uploader\n             * @description 配置压缩的图片的选项。如果此选项为`false`, 则图片在上传前不进行压缩。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 1600,\n             *     height: 1600,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 90,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: false,\n             *\n             *     // 是否允许裁剪。\n             *     crop: false,\n             *\n             *     // 是否保留头部meta信息。\n             *     preserveHeaders: true,\n             *\n             *     // 如果发现压缩后文件大小比原来还大，则使用原来图片\n             *     // 此属性可能会影响图片自动纠正功能\n             *     noCompressIfLarger: false,\n             *\n             *     // 单位字节，如果图片大小小于此值，不会采用压缩。\n             *     compressSize: 0\n             * }\n             * ```\n             */\n            compress: {\n                width: 1600,\n                height: 1600,\n                quality: 90,\n                allowMagnify: false,\n                crop: false,\n                preserveHeaders: true\n            }\n        });\n\n        return Uploader.register({\n\n            name: 'image',\n\n\n            /**\n             * 生成缩略图，此过程为异步，所以需要传入`callback`。\n             * 通常情况在图片加入队里后调用此方法来生成预览图以增强交互效果。\n             *\n             * 当 width 或者 height 的值介于 0 - 1 时，被当成百分比使用。\n             *\n             * `callback`中可以接收到两个参数。\n             * * 第一个为error，如果生成缩略图有错误，此error将为真。\n             * * 第二个为ret, 缩略图的Data URL值。\n             *\n             * **注意**\n             * Date URL在IE6/7中不支持，所以不用调用此方法了，直接显示一张暂不支持预览图片好了。\n             * 也可以借助服务端，将 base64 数据传给服务端，生成一个临时文件供预览。\n             *\n             * @method makeThumb\n             * @grammar makeThumb( file, callback ) => undefined\n             * @grammar makeThumb( file, callback, width, height ) => undefined\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.makeThumb( file, function( error, ret ) {\n             *         if ( error ) {\n             *             $li.text('预览错误');\n             *         } else {\n             *             $li.append('<img alt=\"\" src=\"' + ret + '\" />');\n             *         }\n             *     });\n             *\n             * });\n             */\n            makeThumb: function( file, cb, width, height ) {\n                var opts, image;\n\n                file = this.request( 'get-file', file );\n\n                // 只预览图片格式。\n                if ( !file.type.match( /^image/ ) ) {\n                    cb( true );\n                    return;\n                }\n\n                opts = $.extend({}, this.options.thumb );\n\n                // 如果传入的是object.\n                if ( $.isPlainObject( width ) ) {\n                    opts = $.extend( opts, width );\n                    width = null;\n                }\n\n                width = width || opts.width;\n                height = height || opts.height;\n\n                image = new Image( opts );\n\n                image.once( 'load', function() {\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                // 当 resize 完后\n                image.once( 'complete', function() {\n                    cb( false, image.getAsDataUrl( opts.type ) );\n                    image.destroy();\n                });\n\n                image.once( 'error', function( reason ) {\n                    cb( reason || true );\n                    image.destroy();\n                });\n\n                throttle( image, file.source.size, function() {\n                    file._info && image.info( file._info );\n                    file._meta && image.meta( file._meta );\n                    image.loadFromBlob( file.source );\n                });\n            },\n\n            beforeSendFile: function( file ) {\n                var opts = this.options.compress || this.options.resize,\n                    compressSize = opts && opts.compressSize || 0,\n                    noCompressIfLarger = opts && opts.noCompressIfLarger || false,\n                    image, deferred;\n\n                file = this.request( 'get-file', file );\n\n                // 只压缩 jpeg 图片格式。\n                // gif 可能会丢失针\n                // bmp png 基本上尺寸都不大，且压缩比比较小。\n                if ( !opts || !~'image/jpeg,image/jpg'.indexOf( file.type ) ||\n                        file.size < compressSize ||\n                        file._compressed ) {\n                    return;\n                }\n\n                opts = $.extend({}, opts );\n                deferred = Base.Deferred();\n\n                image = new Image( opts );\n\n                deferred.always(function() {\n                    image.destroy();\n                    image = null;\n                });\n                image.once( 'error', deferred.reject );\n                image.once( 'load', function() {\n                    var width = opts.width,\n                        height = opts.height;\n\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                image.once( 'complete', function() {\n                    var blob, size;\n\n                    // 移动端 UC / qq 浏览器的无图模式下\n                    // ctx.getImageData 处理大图的时候会报 Exception\n                    // INDEX_SIZE_ERR: DOM Exception 1\n                    try {\n                        blob = image.getAsBlob( opts.type );\n\n                        size = file.size;\n\n                        // 如果压缩后，比原来还大则不用压缩后的。\n                        if ( !noCompressIfLarger || blob.size < size ) {\n                            // file.source.destroy && file.source.destroy();\n                            file.source = blob;\n                            file.size = blob.size;\n\n                            file.trigger( 'resize', blob.size, size );\n                        }\n\n                        // 标记，避免重复压缩。\n                        file._compressed = true;\n                        deferred.resolve();\n                    } catch ( e ) {\n                        // 出错了直接继续，让其上传原始图片\n                        deferred.resolve();\n                    }\n                });\n\n                file._info && image.info( file._info );\n                file._meta && image.meta( file._meta );\n\n                image.loadFromBlob( file.source );\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview 文件属性封装\n     */\n    define('file',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            idPrefix = 'WU_FILE_',\n            idSuffix = 0,\n            rExt = /\\.([^.]+)$/,\n            statusMap = {};\n\n        function gid() {\n            return idPrefix + idSuffix++;\n        }\n\n        /**\n         * 文件类\n         * @class File\n         * @constructor 构造函数\n         * @grammar new File( source ) => File\n         * @param {Lib.File} source [lib.File](#Lib.File)实例, 此source对象是带有Runtime信息的。\n         */\n        function WUFile( source ) {\n\n            /**\n             * 文件名，包括扩展名（后缀）\n             * @property name\n             * @type {string}\n             */\n            this.name = source.name || 'Untitled';\n\n            /**\n             * 文件体积（字节）\n             * @property size\n             * @type {uint}\n             * @default 0\n             */\n            this.size = source.size || 0;\n\n            /**\n             * 文件MIMETYPE类型，与文件类型的对应关系请参考[http://t.cn/z8ZnFny](http://t.cn/z8ZnFny)\n             * @property type\n             * @type {string}\n             * @default 'application/octet-stream'\n             */\n            this.type = source.type || 'application/octet-stream';\n\n            /**\n             * 文件最后修改日期\n             * @property lastModifiedDate\n             * @type {int}\n             * @default 当前时间戳\n             */\n            this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);\n\n            /**\n             * 文件ID，每个对象具有唯一ID，与文件名无关\n             * @property id\n             * @type {string}\n             */\n            this.id = gid();\n\n            /**\n             * 文件扩展名，通过文件名获取，例如test.png的扩展名为png\n             * @property ext\n             * @type {string}\n             */\n            this.ext = rExt.exec( this.name ) ? RegExp.$1 : '';\n\n\n            /**\n             * 状态文字说明。在不同的status语境下有不同的用途。\n             * @property statusText\n             * @type {string}\n             */\n            this.statusText = '';\n\n            // 存储文件状态，防止通过属性直接修改\n            statusMap[ this.id ] = WUFile.Status.INITED;\n\n            this.source = source;\n            this.loaded = 0;\n\n            this.on( 'error', function( msg ) {\n                this.setStatus( WUFile.Status.ERROR, msg );\n            });\n        }\n\n        $.extend( WUFile.prototype, {\n\n            /**\n             * 设置状态，状态变化时会触发`change`事件。\n             * @method setStatus\n             * @grammar setStatus( status[, statusText] );\n             * @param {File.Status|String} status [文件状态值](#WebUploader:File:File.Status)\n             * @param {String} [statusText=''] 状态说明，常在error时使用，用http, abort,server等来标记是由于什么原因导致文件错误。\n             */\n            setStatus: function( status, text ) {\n\n                var prevStatus = statusMap[ this.id ];\n\n                typeof text !== 'undefined' && (this.statusText = text);\n\n                if ( status !== prevStatus ) {\n                    statusMap[ this.id ] = status;\n                    /**\n                     * 文件状态变化\n                     * @event statuschange\n                     */\n                    this.trigger( 'statuschange', status, prevStatus );\n                }\n\n            },\n\n            /**\n             * 获取文件状态\n             * @return {File.Status}\n             * @example\n                     文件状态具体包括以下几种类型：\n                     {\n                         // 初始化\n                        INITED:     0,\n                        // 已入队列\n                        QUEUED:     1,\n                        // 正在上传\n                        PROGRESS:     2,\n                        // 上传出错\n                        ERROR:         3,\n                        // 上传成功\n                        COMPLETE:     4,\n                        // 上传取消\n                        CANCELLED:     5\n                    }\n             */\n            getStatus: function() {\n                return statusMap[ this.id ];\n            },\n\n            /**\n             * 获取文件原始信息。\n             * @return {*}\n             */\n            getSource: function() {\n                return this.source;\n            },\n\n            destroy: function() {\n                this.off();\n                delete statusMap[ this.id ];\n            }\n        });\n\n        Mediator.installTo( WUFile.prototype );\n\n        /**\n         * 文件状态值，具体包括以下几种类型：\n         * * `inited` 初始状态\n         * * `queued` 已经进入队列, 等待上传\n         * * `progress` 上传中\n         * * `complete` 上传完成。\n         * * `error` 上传出错，可重试\n         * * `interrupt` 上传中断，可续传。\n         * * `invalid` 文件不合格，不能重试上传。会自动从队列中移除。\n         * * `cancelled` 文件被移除。\n         * @property {Object} Status\n         * @namespace File\n         * @class File\n         * @static\n         */\n        WUFile.Status = {\n            INITED:     'inited',    // 初始状态\n            QUEUED:     'queued',    // 已经进入队列, 等待上传\n            PROGRESS:   'progress',    // 上传中\n            ERROR:      'error',    // 上传出错，可重试\n            COMPLETE:   'complete',    // 上传完成。\n            CANCELLED:  'cancelled',    // 上传取消。\n            INTERRUPT:  'interrupt',    // 上传中断，可续传。\n            INVALID:    'invalid'    // 文件不合格，不能重试上传。\n        };\n\n        return WUFile;\n    });\n\n    /**\n     * @fileOverview 文件队列\n     */\n    define('queue',[\n        'base',\n        'mediator',\n        'file'\n    ], function( Base, Mediator, WUFile ) {\n\n        var $ = Base.$,\n            STATUS = WUFile.Status;\n\n        /**\n         * 文件队列, 用来存储各个状态中的文件。\n         * @class Queue\n         * @extends Mediator\n         */\n        function Queue() {\n\n            /**\n             * 统计文件数。\n             * * `numOfQueue` 队列中的文件数。\n             * * `numOfSuccess` 上传成功的文件数\n             * * `numOfCancel` 被取消的文件数\n             * * `numOfProgress` 正在上传中的文件数\n             * * `numOfUploadFailed` 上传错误的文件数。\n             * * `numOfInvalid` 无效的文件数。\n             * * `numofDeleted` 被移除的文件数。\n             * @property {Object} stats\n             */\n            this.stats = {\n                numOfQueue: 0,\n                numOfSuccess: 0,\n                numOfCancel: 0,\n                numOfProgress: 0,\n                numOfUploadFailed: 0,\n                numOfInvalid: 0,\n                numofDeleted: 0,\n                numofInterrupt: 0\n            };\n\n            // 上传队列，仅包括等待上传的文件\n            this._queue = [];\n\n            // 存储所有文件\n            this._map = {};\n        }\n\n        $.extend( Queue.prototype, {\n\n            /**\n             * 将新文件加入对队列尾部\n             *\n             * @method append\n             * @param  {File} file   文件对象\n             */\n            append: function( file ) {\n                this._queue.push( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 将新文件加入对队列头部\n             *\n             * @method prepend\n             * @param  {File} file   文件对象\n             */\n            prepend: function( file ) {\n                this._queue.unshift( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 获取文件对象\n             *\n             * @method getFile\n             * @param  {String} fileId   文件ID\n             * @return {File}\n             */\n            getFile: function( fileId ) {\n                if ( typeof fileId !== 'string' ) {\n                    return fileId;\n                }\n                return this._map[ fileId ];\n            },\n\n            /**\n             * 从队列中取出一个指定状态的文件。\n             * @grammar fetch( status ) => File\n             * @method fetch\n             * @param {String} status [文件状态值](#WebUploader:File:File.Status)\n             * @return {File} [File](#WebUploader:File)\n             */\n            fetch: function( status ) {\n                var len = this._queue.length,\n                    i, file;\n\n                status = status || STATUS.QUEUED;\n\n                for ( i = 0; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( status === file.getStatus() ) {\n                        return file;\n                    }\n                }\n\n                return null;\n            },\n\n            /**\n             * 对队列进行排序，能够控制文件上传顺序。\n             * @grammar sort( fn ) => undefined\n             * @method sort\n             * @param {Function} fn 排序方法\n             */\n            sort: function( fn ) {\n                if ( typeof fn === 'function' ) {\n                    this._queue.sort( fn );\n                }\n            },\n\n            /**\n             * 获取指定类型的文件列表, 列表中每一个成员为[File](#WebUploader:File)对象。\n             * @grammar getFiles( [status1[, status2 ...]] ) => Array\n             * @method getFiles\n             * @param {String} [status] [文件状态值](#WebUploader:File:File.Status)\n             */\n            getFiles: function() {\n                var sts = [].slice.call( arguments, 0 ),\n                    ret = [],\n                    i = 0,\n                    len = this._queue.length,\n                    file;\n\n                for ( ; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( sts.length && !~$.inArray( file.getStatus(), sts ) ) {\n                        continue;\n                    }\n\n                    ret.push( file );\n                }\n\n                return ret;\n            },\n\n            /**\n             * 在队列中删除文件。\n             * @grammar removeFile( file ) => Array\n             * @method removeFile\n             * @param {File} 文件对象。\n             */\n            removeFile: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( existing ) {\n                    delete this._map[ file.id ];\n                    file.destroy();\n                    this.stats.numofDeleted++;\n                }\n            },\n\n            _fileAdded: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( !existing ) {\n                    this._map[ file.id ] = file;\n\n                    file.on( 'statuschange', function( cur, pre ) {\n                        me._onFileStatusChange( cur, pre );\n                    });\n                }\n            },\n\n            _onFileStatusChange: function( curStatus, preStatus ) {\n                var stats = this.stats;\n\n                switch ( preStatus ) {\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress--;\n                        break;\n\n                    case STATUS.QUEUED:\n                        stats.numOfQueue --;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed--;\n                        break;\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid--;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt--;\n                        break;\n                }\n\n                switch ( curStatus ) {\n                    case STATUS.QUEUED:\n                        stats.numOfQueue++;\n                        break;\n\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress++;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed++;\n                        break;\n\n                    case STATUS.COMPLETE:\n                        stats.numOfSuccess++;\n                        break;\n\n                    case STATUS.CANCELLED:\n                        stats.numOfCancel++;\n                        break;\n\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid++;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt++;\n                        break;\n                }\n            }\n\n        });\n\n        Mediator.installTo( Queue.prototype );\n\n        return Queue;\n    });\n    /**\n     * @fileOverview 队列\n     */\n    define('widgets/queue',[\n        'base',\n        'uploader',\n        'queue',\n        'file',\n        'lib/file',\n        'runtime/client',\n        'widgets/widget'\n    ], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {\n\n        var $ = Base.$,\n            rExt = /\\.\\w+$/,\n            Status = WUFile.Status;\n\n        return Uploader.register({\n            name: 'queue',\n\n            init: function( opts ) {\n                var me = this,\n                    deferred, len, i, item, arr, accept, runtime;\n\n                if ( $.isPlainObject( opts.accept ) ) {\n                    opts.accept = [ opts.accept ];\n                }\n\n                // accept中的中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].extensions;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = '\\\\.' + arr.join(',')\n                                .replace( /,/g, '$|\\\\.' )\n                                .replace( /\\*/g, '.*' ) + '$';\n                    }\n\n                    me.accept = new RegExp( accept, 'i' );\n                }\n\n                me.queue = new Queue();\n                me.stats = me.queue.stats;\n\n                // 如果当前不是html5运行时，那就算了。\n                // 不执行后续操作\n                if ( this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                // 创建一个 html5 运行时的 placeholder\n                // 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。\n                deferred = Base.Deferred();\n                this.placeholder = runtime = new RuntimeClient('Placeholder');\n                runtime.connectRuntime({\n                    runtimeOrder: 'html5'\n                }, function() {\n                    me._ruid = runtime.getRuid();\n                    deferred.resolve();\n                });\n                return deferred.promise();\n            },\n\n\n            // 为了支持外部直接添加一个原生File对象。\n            _wrapFile: function( file ) {\n                if ( !(file instanceof WUFile) ) {\n\n                    if ( !(file instanceof File) ) {\n                        if ( !this._ruid ) {\n                            throw new Error('Can\\'t add external files.');\n                        }\n                        file = new File( this._ruid, file );\n                    }\n\n                    file = new WUFile( file );\n                }\n\n                return file;\n            },\n\n            // 判断文件是否可以被加入队列\n            acceptFile: function( file ) {\n                var invalid = !file || !file.size || this.accept &&\n\n                        // 如果名字中有后缀，才做后缀白名单处理。\n                        rExt.exec( file.name ) && !this.accept.test( file.name );\n\n                return !invalid;\n            },\n\n\n            /**\n             * @event beforeFileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列之前触发，此事件的handler返回值为`false`，则此文件不会被添加进入队列。\n             * @for  Uploader\n             */\n\n            /**\n             * @event fileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列以后触发。\n             * @for  Uploader\n             */\n\n            _addFile: function( file ) {\n                var me = this;\n\n                file = me._wrapFile( file );\n\n                // 不过类型判断允许不允许，先派送 `beforeFileQueued`\n                if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {\n                    return;\n                }\n\n                // 类型不匹配，则派送错误事件，并返回。\n                if ( !me.acceptFile( file ) ) {\n                    me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );\n                    return;\n                }\n\n                me.queue.append( file );\n                me.owner.trigger( 'fileQueued', file );\n                return file;\n            },\n\n            getFile: function( fileId ) {\n                return this.queue.getFile( fileId );\n            },\n\n            /**\n             * @event filesQueued\n             * @param {File} files 数组，内容为原始File(lib/File）对象。\n             * @description 当一批文件添加进队列以后触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @property {Boolean} [auto=false]\n             * @namespace options\n             * @for Uploader\n             * @description 设置为 true 后，不需要手动调用上传，有文件选择即开始上传。\n             *\n             */\n\n            /**\n             * @method addFiles\n             * @grammar addFiles( file ) => undefined\n             * @grammar addFiles( [file1, file2 ...] ) => undefined\n             * @param {Array of File or File} [files] Files 对象 数组\n             * @description 添加文件到队列\n             * @for  Uploader\n             */\n            addFile: function( files ) {\n                var me = this;\n\n                if ( !files.length ) {\n                    files = [ files ];\n                }\n\n                files = $.map( files, function( file ) {\n                    return me._addFile( file );\n                });\n\n                me.owner.trigger( 'filesQueued', files );\n\n                if ( me.options.auto ) {\n                    setTimeout(function() {\n                        me.request('start-upload');\n                    }, 20 );\n                }\n            },\n\n            getStats: function() {\n                return this.stats;\n            },\n\n            /**\n             * @event fileDequeued\n             * @param {File} file File对象\n             * @description 当文件被移除队列后触发。\n             * @for  Uploader\n             */\n\n             /**\n             * @method removeFile\n             * @grammar removeFile( file ) => undefined\n             * @grammar removeFile( id ) => undefined\n             * @grammar removeFile( file, true ) => undefined\n             * @grammar removeFile( id, true ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 移除某一文件, 默认只会标记文件状态为已取消，如果第二个参数为 `true` 则会从 queue 中移除。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.removeFile( file );\n             * })\n             */\n            removeFile: function( file, remove ) {\n                var me = this;\n\n                file = file.id ? file : me.queue.getFile( file );\n\n                this.request( 'cancel-file', file );\n\n                if ( remove ) {\n                    this.queue.removeFile( file );\n                }\n            },\n\n            /**\n             * @method getFiles\n             * @grammar getFiles() => Array\n             * @grammar getFiles( status1, status2, status... ) => Array\n             * @description 返回指定状态的文件集合，不传参数将返回所有状态的文件。\n             * @for  Uploader\n             * @example\n             * console.log( uploader.getFiles() );    // => all files\n             * console.log( uploader.getFiles('error') )    // => all error files.\n             */\n            getFiles: function() {\n                return this.queue.getFiles.apply( this.queue, arguments );\n            },\n\n            fetchFile: function() {\n                return this.queue.fetch.apply( this.queue, arguments );\n            },\n\n            /**\n             * @method retry\n             * @grammar retry() => undefined\n             * @grammar retry( file ) => undefined\n             * @description 重试上传，重试指定文件，或者从出错的文件开始重新上传。\n             * @for  Uploader\n             * @example\n             * function retry() {\n             *     uploader.retry();\n             * }\n             */\n            retry: function( file, noForceStart ) {\n                var me = this,\n                    files, i, len;\n\n                if ( file ) {\n                    file = file.id ? file : me.queue.getFile( file );\n                    file.setStatus( Status.QUEUED );\n                    noForceStart || me.request('start-upload');\n                    return;\n                }\n\n                files = me.queue.getFiles( Status.ERROR );\n                i = 0;\n                len = files.length;\n\n                for ( ; i < len; i++ ) {\n                    file = files[ i ];\n                    file.setStatus( Status.QUEUED );\n                }\n\n                me.request('start-upload');\n            },\n\n            /**\n             * @method sort\n             * @grammar sort( fn ) => undefined\n             * @description 排序队列中的文件，在上传之前调整可以控制上传顺序。\n             * @for  Uploader\n             */\n            sortFiles: function() {\n                return this.queue.sort.apply( this.queue, arguments );\n            },\n\n            /**\n             * @event reset\n             * @description 当 uploader 被重置的时候触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @method reset\n             * @grammar reset() => undefined\n             * @description 重置uploader。目前只重置了队列。\n             * @for  Uploader\n             * @example\n             * uploader.reset();\n             */\n            reset: function() {\n                this.owner.trigger('reset');\n                this.queue = new Queue();\n                this.stats = this.queue.stats;\n            },\n\n            destroy: function() {\n                this.reset();\n                this.placeholder && this.placeholder.destroy();\n            }\n        });\n\n    });\n    /**\n     * @fileOverview 添加获取Runtime相关信息的方法。\n     */\n    define('widgets/runtime',[\n        'uploader',\n        'runtime/runtime',\n        'widgets/widget'\n    ], function( Uploader, Runtime ) {\n\n        Uploader.support = function() {\n            return Runtime.hasRuntime.apply( Runtime, arguments );\n        };\n\n        /**\n         * @property {Object} [runtimeOrder=html5,flash]\n         * @namespace options\n         * @for Uploader\n         * @description 指定运行时启动顺序。默认会想尝试 html5 是否支持，如果支持则使用 html5, 否则则使用 flash.\n         *\n         * 可以将此值设置成 `flash`，来强制使用 flash 运行时。\n         */\n\n        return Uploader.register({\n            name: 'runtime',\n\n            init: function() {\n                if ( !this.predictRuntimeType() ) {\n                    throw Error('Runtime Error');\n                }\n            },\n\n            /**\n             * 预测Uploader将采用哪个`Runtime`\n             * @grammar predictRuntimeType() => String\n             * @method predictRuntimeType\n             * @for  Uploader\n             */\n            predictRuntimeType: function() {\n                var orders = this.options.runtimeOrder || Runtime.orders,\n                    type = this.type,\n                    i, len;\n\n                if ( !type ) {\n                    orders = orders.split( /\\s*,\\s*/g );\n\n                    for ( i = 0, len = orders.length; i < len; i++ ) {\n                        if ( Runtime.hasRuntime( orders[ i ] ) ) {\n                            this.type = type = orders[ i ];\n                            break;\n                        }\n                    }\n                }\n\n                return type;\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     */\n    define('lib/transport',[\n        'base',\n        'runtime/client',\n        'mediator'\n    ], function( Base, RuntimeClient, Mediator ) {\n\n        var $ = Base.$;\n\n        function Transport( opts ) {\n            var me = this;\n\n            opts = me.options = $.extend( true, {}, Transport.options, opts || {} );\n            RuntimeClient.call( this, 'Transport' );\n\n            this._blob = null;\n            this._formData = opts.formData || {};\n            this._headers = opts.headers || {};\n\n            this.on( 'progress', this._timeout );\n            this.on( 'load error', function() {\n                me.trigger( 'progress', 1 );\n                clearTimeout( me._timer );\n            });\n        }\n\n        Transport.options = {\n            server: '',\n            method: 'POST',\n\n            // 跨域时，是否允许携带cookie, 只有html5 runtime才有效\n            withCredentials: false,\n            fileVal: 'file',\n            timeout: 2 * 60 * 1000,    // 2分钟\n            formData: {},\n            headers: {},\n            sendAsBinary: false\n        };\n\n        $.extend( Transport.prototype, {\n\n            // 添加Blob, 只能添加一次，最后一次有效。\n            appendBlob: function( key, blob, filename ) {\n                var me = this,\n                    opts = me.options;\n\n                if ( me.getRuid() ) {\n                    me.disconnectRuntime();\n                }\n\n                // 连接到blob归属的同一个runtime.\n                me.connectRuntime( blob.ruid, function() {\n                    me.exec('init');\n                });\n\n                me._blob = blob;\n                opts.fileVal = key || opts.fileVal;\n                opts.filename = filename || opts.filename;\n            },\n\n            // 添加其他字段\n            append: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._formData, key );\n                } else {\n                    this._formData[ key ] = value;\n                }\n            },\n\n            setRequestHeader: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._headers, key );\n                } else {\n                    this._headers[ key ] = value;\n                }\n            },\n\n            send: function( method ) {\n                this.exec( 'send', method );\n                this._timeout();\n            },\n\n            abort: function() {\n                clearTimeout( this._timer );\n                return this.exec('abort');\n            },\n\n            destroy: function() {\n                this.trigger('destroy');\n                this.off();\n                this.exec('destroy');\n                this.disconnectRuntime();\n            },\n\n            getResponse: function() {\n                return this.exec('getResponse');\n            },\n\n            getResponseAsJson: function() {\n                return this.exec('getResponseAsJson');\n            },\n\n            getStatus: function() {\n                return this.exec('getStatus');\n            },\n\n            _timeout: function() {\n                var me = this,\n                    duration = me.options.timeout;\n\n                if ( !duration ) {\n                    return;\n                }\n\n                clearTimeout( me._timer );\n                me._timer = setTimeout(function() {\n                    me.abort();\n                    me.trigger( 'error', 'timeout' );\n                }, duration );\n            }\n\n        });\n\n        // 让Transport具备事件功能。\n        Mediator.installTo( Transport.prototype );\n\n        return Transport;\n    });\n    /**\n     * @fileOverview 负责文件上传相关。\n     */\n    define('widgets/upload',[\n        'base',\n        'uploader',\n        'file',\n        'lib/transport',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile, Transport ) {\n\n        var $ = Base.$,\n            isPromise = Base.isPromise,\n            Status = WUFile.Status;\n\n        // 添加默认配置项\n        $.extend( Uploader.options, {\n\n\n            /**\n             * @property {Boolean} [prepareNextFile=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否允许在文件传输时提前把下一个文件准备好。\n             * 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。\n             * 如果能提前在当前文件传输期处理，可以节省总体耗时。\n             */\n            prepareNextFile: false,\n\n            /**\n             * @property {Boolean} [chunked=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否要分片处理大文件上传。\n             */\n            chunked: false,\n\n            /**\n             * @property {Boolean} [chunkSize=5242880]\n             * @namespace options\n             * @for Uploader\n             * @description 如果要分片，分多大一片？ 默认大小为5M.\n             */\n            chunkSize: 5 * 1024 * 1024,\n\n            /**\n             * @property {Boolean} [chunkRetry=2]\n             * @namespace options\n             * @for Uploader\n             * @description 如果某个分片由于网络问题出错，允许自动重传多少次？\n             */\n            chunkRetry: 2,\n\n            /**\n             * @property {Boolean} [threads=3]\n             * @namespace options\n             * @for Uploader\n             * @description 上传并发数。允许同时最大上传进程数。\n             */\n            threads: 3,\n\n\n            /**\n             * @property {Object} [formData={}]\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传请求的参数表，每次发送都会发送此对象中的参数。\n             */\n            formData: {}\n\n            /**\n             * @property {Object} [fileVal='file']\n             * @namespace options\n             * @for Uploader\n             * @description 设置文件上传域的name。\n             */\n\n            /**\n             * @property {Object} [method='POST']\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传方式，`POST`或者`GET`。\n             */\n\n            /**\n             * @property {Object} [sendAsBinary=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否已二进制的流的方式发送文件，这样整个上传内容`php://input`都为文件内容，\n             * 其他参数在$_GET数组中。\n             */\n        });\n\n        // 负责将文件切片。\n        function CuteFile( file, chunkSize ) {\n            var pending = [],\n                blob = file.source,\n                total = blob.size,\n                chunks = chunkSize ? Math.ceil( total / chunkSize ) : 1,\n                start = 0,\n                index = 0,\n                len, api;\n\n            api = {\n                file: file,\n\n                has: function() {\n                    return !!pending.length;\n                },\n\n                shift: function() {\n                    return pending.shift();\n                },\n\n                unshift: function( block ) {\n                    pending.unshift( block );\n                }\n            };\n\n            while ( index < chunks ) {\n                len = Math.min( chunkSize, total - start );\n\n                pending.push({\n                    file: file,\n                    start: start,\n                    end: chunkSize ? (start + len) : total,\n                    total: total,\n                    chunks: chunks,\n                    chunk: index++,\n                    cuted: api\n                });\n                start += len;\n            }\n\n            file.blocks = pending.concat();\n            file.remaning = pending.length;\n\n            return api;\n        }\n\n        Uploader.register({\n            name: 'upload',\n\n            init: function() {\n                var owner = this.owner,\n                    me = this;\n\n                this.runing = false;\n                this.progress = false;\n\n                owner\n                    .on( 'startUpload', function() {\n                        me.progress = true;\n                    })\n                    .on( 'uploadFinished', function() {\n                        me.progress = false;\n                    });\n\n                // 记录当前正在传的数据，跟threads相关\n                this.pool = [];\n\n                // 缓存分好片的文件。\n                this.stack = [];\n\n                // 缓存即将上传的文件。\n                this.pending = [];\n\n                // 跟踪还有多少分片在上传中但是没有完成上传。\n                this.remaning = 0;\n                this.__tick = Base.bindFn( this._tick, this );\n\n                owner.on( 'uploadComplete', function( file ) {\n\n                    // 把其他块取消了。\n                    file.blocks && $.each( file.blocks, function( _, v ) {\n                        v.transport && (v.transport.abort(), v.transport.destroy());\n                        delete v.transport;\n                    });\n\n                    delete file.blocks;\n                    delete file.remaning;\n                });\n            },\n\n            reset: function() {\n                this.request( 'stop-upload', true );\n                this.runing = false;\n                this.pool = [];\n                this.stack = [];\n                this.pending = [];\n                this.remaning = 0;\n                this._trigged = false;\n                this._promise = null;\n            },\n\n            /**\n             * @event startUpload\n             * @description 当开始上传流程时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 开始上传。此方法可以从初始状态调用开始上传流程，也可以从暂停状态调用，继续上传流程。\n             *\n             * 可以指定开始某一个文件。\n             * @grammar upload() => undefined\n             * @grammar upload( file | fileId) => undefined\n             * @method upload\n             * @for  Uploader\n             */\n            startUpload: function(file) {\n                var me = this;\n\n                // 移出invalid的文件\n                $.each( me.request( 'get-files', Status.INVALID ), function() {\n                    me.request( 'remove-file', this );\n                });\n\n                // 如果指定了开始某个文件，则只开始指定文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        $.each( me.pool, function( _, v ) {\n\n                            // 之前暂停过。\n                            if (v.file !== file) {\n                                return;\n                            }\n\n                            v.transport && v.transport.send();\n                        });\n\n                        file.setStatus( Status.QUEUED );\n                    } else if (file.getStatus() === Status.PROGRESS) {\n                        return;\n                    } else {\n                        file.setStatus( Status.QUEUED );\n                    }\n                } else {\n                    $.each( me.request( 'get-files', [ Status.INITED ] ), function() {\n                        this.setStatus( Status.QUEUED );\n                    });\n                }\n\n                if ( me.runing ) {\n                    return;\n                }\n\n                me.runing = true;\n\n                var files = [];\n\n                // 如果有暂停的，则续传\n                $.each( me.pool, function( _, v ) {\n                    var file = v.file;\n\n                    if ( file.getStatus() === Status.INTERRUPT ) {\n                        files.push(file);\n                        me._trigged = false;\n                        v.transport && v.transport.send();\n                    }\n                });\n\n                var file;\n                while ( (file = files.shift()) ) {\n                    file.setStatus( Status.PROGRESS );\n                }\n\n                file || $.each( me.request( 'get-files',\n                        Status.INTERRUPT ), function() {\n                    this.setStatus( Status.PROGRESS );\n                });\n\n                me._trigged = false;\n                Base.nextTick( me.__tick );\n                me.owner.trigger('startUpload');\n            },\n\n            /**\n             * @event stopUpload\n             * @description 当开始上传流程暂停时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 暂停上传。第一个参数为是否中断上传当前正在上传的文件。\n             *\n             * 如果第一个参数是文件，则只暂停指定文件。\n             * @grammar stop() => undefined\n             * @grammar stop( true ) => undefined\n             * @grammar stop( file ) => undefined\n             * @method stop\n             * @for  Uploader\n             */\n            stopUpload: function( file, interrupt ) {\n                var me = this;\n\n                if (file === true) {\n                    interrupt = file;\n                    file = null;\n                }\n\n                if ( me.runing === false ) {\n                    return;\n                }\n\n                // 如果只是暂停某个文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if ( file.getStatus() !== Status.PROGRESS &&\n                            file.getStatus() !== Status.QUEUED ) {\n                        return;\n                    }\n\n                    file.setStatus( Status.INTERRUPT );\n                    $.each( me.pool, function( _, v ) {\n\n                        // 只 abort 指定的文件。\n                        if (v.file !== file) {\n                            return;\n                        }\n\n                        v.transport && v.transport.abort();\n                        me._putback(v);\n                        me._popBlock(v);\n                    });\n\n                    return Base.nextTick( me.__tick );\n                }\n\n                me.runing = false;\n\n                if (this._promise && this._promise.file) {\n                    this._promise.file.setStatus( Status.INTERRUPT );\n                }\n\n                interrupt && $.each( me.pool, function( _, v ) {\n                    v.transport && v.transport.abort();\n                    v.file.setStatus( Status.INTERRUPT );\n                });\n\n                me.owner.trigger('stopUpload');\n            },\n\n            /**\n             * @method cancelFile\n             * @grammar cancelFile( file ) => undefined\n             * @grammar cancelFile( id ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 标记文件状态为已取消, 同时将中断文件传输。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.cancelFile( file );\n             * })\n             */\n            cancelFile: function( file ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                file.setStatus( Status.CANCELLED );\n                this.owner.trigger( 'fileDequeued', file );\n            },\n\n            /**\n             * 判断`Uplaode`r是否正在上传中。\n             * @grammar isInProgress() => Boolean\n             * @method isInProgress\n             * @for  Uploader\n             */\n            isInProgress: function() {\n                return !!this.progress;\n            },\n\n            _getStats: function() {\n                return this.request('get-stats');\n            },\n\n            /**\n             * 掉过一个文件上传，直接标记指定文件为已上传状态。\n             * @grammar skipFile( file ) => undefined\n             * @method skipFile\n             * @for  Uploader\n             */\n            skipFile: function( file, status ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                file.setStatus( status || Status.COMPLETE );\n                file.skipped = true;\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                this.owner.trigger( 'uploadSkip', file );\n            },\n\n            /**\n             * @event uploadFinished\n             * @description 当所有文件上传结束时触发。\n             * @for  Uploader\n             */\n            _tick: function() {\n                var me = this,\n                    opts = me.options,\n                    fn, val;\n\n                // 上一个promise还没有结束，则等待完成后再执行。\n                if ( me._promise ) {\n                    return me._promise.always( me.__tick );\n                }\n\n                // 还有位置，且还有文件要处理的话。\n                if ( me.pool.length < opts.threads && (val = me._nextBlock()) ) {\n                    me._trigged = false;\n\n                    fn = function( val ) {\n                        me._promise = null;\n\n                        // 有可能是reject过来的，所以要检测val的类型。\n                        val && val.file && me._startSend( val );\n                        Base.nextTick( me.__tick );\n                    };\n\n                    me._promise = isPromise( val ) ? val.always( fn ) : fn( val );\n\n                // 没有要上传的了，且没有正在传输的了。\n                } else if ( !me.remaning && !me._getStats().numOfQueue &&\n                    !me._getStats().numofInterrupt ) {\n                    me.runing = false;\n\n                    me._trigged || Base.nextTick(function() {\n                        me.owner.trigger('uploadFinished');\n                    });\n                    me._trigged = true;\n                }\n            },\n\n            _putback: function(block) {\n                var idx;\n\n                block.cuted.unshift(block);\n                idx = this.stack.indexOf(block.cuted);\n\n                if (!~idx) {\n                    this.stack.unshift(block.cuted);\n                }\n            },\n\n            _getStack: function() {\n                var i = 0,\n                    act;\n\n                while ( (act = this.stack[ i++ ]) ) {\n                    if ( act.has() && act.file.getStatus() === Status.PROGRESS ) {\n                        return act;\n                    } else if (!act.has() ||\n                            act.file.getStatus() !== Status.PROGRESS &&\n                            act.file.getStatus() !== Status.INTERRUPT ) {\n\n                        // 把已经处理完了的，或者，状态为非 progress（上传中）、\n                        // interupt（暂停中） 的移除。\n                        this.stack.splice( --i, 1 );\n                    }\n                }\n\n                return null;\n            },\n\n            _nextBlock: function() {\n                var me = this,\n                    opts = me.options,\n                    act, next, done, preparing;\n\n                // 如果当前文件还有没有需要传输的，则直接返回剩下的。\n                if ( (act = this._getStack()) ) {\n\n                    // 是否提前准备下一个文件\n                    if ( opts.prepareNextFile && !me.pending.length ) {\n                        me._prepareNextFile();\n                    }\n\n                    return act.shift();\n\n                // 否则，如果正在运行，则准备下一个文件，并等待完成后返回下个分片。\n                } else if ( me.runing ) {\n\n                    // 如果缓存中有，则直接在缓存中取，没有则去queue中取。\n                    if ( !me.pending.length && me._getStats().numOfQueue ) {\n                        me._prepareNextFile();\n                    }\n\n                    next = me.pending.shift();\n                    done = function( file ) {\n                        if ( !file ) {\n                            return null;\n                        }\n\n                        act = CuteFile( file, opts.chunked ? opts.chunkSize : 0 );\n                        me.stack.push(act);\n                        return act.shift();\n                    };\n\n                    // 文件可能还在prepare中，也有可能已经完全准备好了。\n                    if ( isPromise( next) ) {\n                        preparing = next.file;\n                        next = next[ next.pipe ? 'pipe' : 'then' ]( done );\n                        next.file = preparing;\n                        return next;\n                    }\n\n                    return done( next );\n                }\n            },\n\n\n            /**\n             * @event uploadStart\n             * @param {File} file File对象\n             * @description 某个文件开始上传前触发，一个文件只会触发一次。\n             * @for  Uploader\n             */\n            _prepareNextFile: function() {\n                var me = this,\n                    file = me.request('fetch-file'),\n                    pending = me.pending,\n                    promise;\n\n                if ( file ) {\n                    promise = me.request( 'before-send-file', file, function() {\n\n                        // 有可能文件被skip掉了。文件被skip掉后，状态坑定不是Queued.\n                        if ( file.getStatus() === Status.PROGRESS ||\n                            file.getStatus() === Status.INTERRUPT ) {\n                            return file;\n                        }\n\n                        return me._finishFile( file );\n                    });\n\n                    me.owner.trigger( 'uploadStart', file );\n                    file.setStatus( Status.PROGRESS );\n\n                    promise.file = file;\n\n                    // 如果还在pending中，则替换成文件本身。\n                    promise.done(function() {\n                        var idx = $.inArray( promise, pending );\n\n                        ~idx && pending.splice( idx, 1, file );\n                    });\n\n                    // befeore-send-file的钩子就有错误发生。\n                    promise.fail(function( reason ) {\n                        file.setStatus( Status.ERROR, reason );\n                        me.owner.trigger( 'uploadError', file, reason );\n                        me.owner.trigger( 'uploadComplete', file );\n                    });\n\n                    pending.push( promise );\n                }\n            },\n\n            // 让出位置了，可以让其他分片开始上传\n            _popBlock: function( block ) {\n                var idx = $.inArray( block, this.pool );\n\n                this.pool.splice( idx, 1 );\n                block.file.remaning--;\n                this.remaning--;\n            },\n\n            // 开始上传，可以被掉过。如果promise被reject了，则表示跳过此分片。\n            _startSend: function( block ) {\n                var me = this,\n                    file = block.file,\n                    promise;\n\n                // 有可能在 before-send-file 的 promise 期间改变了文件状态。\n                // 如：暂停，取消\n                // 我们不能中断 promise, 但是可以在 promise 完后，不做上传操作。\n                if ( file.getStatus() !== Status.PROGRESS ) {\n\n                    // 如果是中断，则还需要放回去。\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        me._putback(block);\n                    }\n\n                    return;\n                }\n\n                me.pool.push( block );\n                me.remaning++;\n\n                // 如果没有分片，则直接使用原始的。\n                // 不会丢失content-type信息。\n                block.blob = block.chunks === 1 ? file.source :\n                        file.source.slice( block.start, block.end );\n\n                // hook, 每个分片发送之前可能要做些异步的事情。\n                promise = me.request( 'before-send', block, function() {\n\n                    // 有可能文件已经上传出错了，所以不需要再传输了。\n                    if ( file.getStatus() === Status.PROGRESS ) {\n                        me._doSend( block );\n                    } else {\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n\n                // 如果为fail了，则跳过此分片。\n                promise.fail(function() {\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file ).always(function() {\n                            block.percentage = 1;\n                            me._popBlock( block );\n                            me.owner.trigger( 'uploadComplete', file );\n                            Base.nextTick( me.__tick );\n                        });\n                    } else {\n                        block.percentage = 1;\n                        me.updateFileProgress( file );\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n            },\n\n\n            /**\n             * @event uploadBeforeSend\n             * @param {Object} object\n             * @param {Object} data 默认的上传参数，可以扩展此对象来控制上传参数。\n             * @param {Object} headers 可以扩展此对象来控制上传头部。\n             * @description 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadAccept\n             * @param {Object} object\n             * @param {Object} ret 服务端的返回数据，json格式，如果服务端不是json格式，从ret._raw中取数据，自行解析。\n             * @description 当某个文件上传到服务端响应后，会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为`false`, 则此文件将派送`server`类型的`uploadError`事件。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadProgress\n             * @param {File} file File对象\n             * @param {Number} percentage 上传进度\n             * @description 上传过程中触发，携带上传进度。\n             * @for  Uploader\n             */\n\n\n            /**\n             * @event uploadError\n             * @param {File} file File对象\n             * @param {String} reason 出错的code\n             * @description 当文件上传出错时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadSuccess\n             * @param {File} file File对象\n             * @param {Object} response 服务端返回的数据\n             * @description 当文件上传成功时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadComplete\n             * @param {File} [file] File对象\n             * @description 不管成功或者失败，文件上传完成时触发。\n             * @for  Uploader\n             */\n\n            // 做上传操作。\n            _doSend: function( block ) {\n                var me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    file = block.file,\n                    tr = new Transport( opts ),\n                    data = $.extend({}, opts.formData ),\n                    headers = $.extend({}, opts.headers ),\n                    requestAccept, ret;\n\n                block.transport = tr;\n\n                tr.on( 'destroy', function() {\n                    delete block.transport;\n                    me._popBlock( block );\n                    Base.nextTick( me.__tick );\n                });\n\n                // 广播上传进度。以文件为单位。\n                tr.on( 'progress', function( percentage ) {\n                    block.percentage = percentage;\n                    me.updateFileProgress( file );\n                });\n\n                // 用来询问，是否返回的结果是有错误的。\n                requestAccept = function( reject ) {\n                    var fn;\n\n                    ret = tr.getResponseAsJson() || {};\n                    ret._raw = tr.getResponse();\n                    fn = function( value ) {\n                        reject = value;\n                    };\n\n                    // 服务端响应了，不代表成功了，询问是否响应正确。\n                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {\n                        reject = reject || 'server';\n                    }\n\n                    return reject;\n                };\n\n                // 尝试重试，然后广播文件上传出错。\n                tr.on( 'error', function( type, flag ) {\n                    block.retried = block.retried || 0;\n\n                    // 自动重试\n                    if ( block.chunks > 1 && ~'http,abort'.indexOf( type ) &&\n                            block.retried < opts.chunkRetry ) {\n\n                        block.retried++;\n                        tr.send();\n\n                    } else {\n\n                        // http status 500 ~ 600\n                        if ( !flag && type === 'server' ) {\n                            type = requestAccept( type );\n                        }\n\n                        file.setStatus( Status.ERROR, type );\n                        owner.trigger( 'uploadError', file, type );\n                        owner.trigger( 'uploadComplete', file );\n                    }\n                });\n\n                // 上传成功\n                tr.on( 'load', function() {\n                    var reason;\n\n                    // 如果非预期，转向上传出错。\n                    if ( (reason = requestAccept()) ) {\n                        tr.trigger( 'error', reason, true );\n                        return;\n                    }\n\n                    // 全部上传完成。\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file, ret );\n                    } else {\n                        tr.destroy();\n                    }\n                });\n\n                // 配置默认的上传字段。\n                data = $.extend( data, {\n                    id: file.id,\n                    name: file.name,\n                    type: file.type,\n                    lastModifiedDate: file.lastModifiedDate,\n                    size: file.size\n                });\n\n                block.chunks > 1 && $.extend( data, {\n                    chunks: block.chunks,\n                    chunk: block.chunk\n                });\n\n                // 在发送之间可以添加字段什么的。。。\n                // 如果默认的字段不够使用，可以通过监听此事件来扩展\n                owner.trigger( 'uploadBeforeSend', block, data, headers );\n\n                // 开始发送。\n                tr.appendBlob( opts.fileVal, block.blob, file.name );\n                tr.append( data );\n                tr.setRequestHeader( headers );\n                tr.send();\n            },\n\n            // 完成上传。\n            _finishFile: function( file, ret, hds ) {\n                var owner = this.owner;\n\n                return owner\n                        .request( 'after-send-file', arguments, function() {\n                            file.setStatus( Status.COMPLETE );\n                            owner.trigger( 'uploadSuccess', file, ret, hds );\n                        })\n                        .fail(function( reason ) {\n\n                            // 如果外部已经标记为invalid什么的，不再改状态。\n                            if ( file.getStatus() === Status.PROGRESS ) {\n                                file.setStatus( Status.ERROR, reason );\n                            }\n\n                            owner.trigger( 'uploadError', file, reason );\n                        })\n                        .always(function() {\n                            owner.trigger( 'uploadComplete', file );\n                        });\n            },\n\n            updateFileProgress: function(file) {\n                var totalPercent = 0,\n                    uploaded = 0;\n\n                if (!file.blocks) {\n                    return;\n                }\n\n                $.each( file.blocks, function( _, v ) {\n                    uploaded += (v.percentage || 0) * (v.end - v.start);\n                });\n\n                totalPercent = uploaded / file.size;\n                this.owner.trigger( 'uploadProgress', file, totalPercent || 0 );\n            }\n\n        });\n    });\n    /**\n     * @fileOverview 日志组件，主要用来收集错误信息，可以帮助 webuploader 更好的定位问题和发展。\n     *\n     * 如果您不想要启用此功能，请在打包的时候去掉 log 模块。\n     *\n     * 或者可以在初始化的时候通过 options.disableWidgets 属性禁用。\n     *\n     * 如：\n     * WebUploader.create({\n     *     ...\n     *\n     *     disableWidgets: 'log',\n     *\n     *     ...\n     * })\n     */\n    define('widgets/log',[\n        'base',\n        'uploader',\n        'widgets/widget'\n    ], function( Base, Uploader ) {\n        var $ = Base.$,\n            logUrl = ' http://static.tieba.baidu.com/tb/pms/img/st.gif??',\n            product = (location.hostname || location.host || 'protected').toLowerCase(),\n\n            // 只针对 baidu 内部产品用户做统计功能。\n            enable = product && /baidu/i.exec(product),\n            base;\n\n        if (!enable) {\n            return;\n        }\n\n        base = {\n            dv: 3,\n            master: 'webuploader',\n            online: /test/.exec(product) ? 0 : 1,\n            module: '',\n            product: product,\n            type: 0\n        };\n\n        function send(data) {\n            var obj = $.extend({}, base, data),\n                url = logUrl.replace(/^(.*)\\?/, '$1' + $.param( obj )),\n                image = new Image();\n\n            image.src = url;\n        }\n\n        return Uploader.register({\n            name: 'log',\n\n            init: function() {\n                var owner = this.owner,\n                    count = 0,\n                    size = 0;\n\n                owner\n                    .on('error', function(code) {\n                        send({\n                            type: 2,\n                            c_error_code: code\n                        });\n                    })\n                    .on('uploadError', function(file, reason) {\n                        send({\n                            type: 2,\n                            c_error_code: 'UPLOAD_ERROR',\n                            c_reason: '' + reason\n                        });\n                    })\n                    .on('uploadComplete', function(file) {\n                        count++;\n                        size += file.size;\n                    }).\n                    on('uploadFinished', function() {\n                        send({\n                            c_count: count,\n                            c_size: size\n                        });\n                        count = size = 0;\n                    });\n\n                send({\n                    c_usage: 1\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/compbase',[],function() {\n\n        function CompBase( owner, runtime ) {\n\n            this.owner = owner;\n            this.options = owner.options;\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.getRuid = function() {\n                return runtime.uid;\n            };\n\n            this.trigger = function() {\n                return owner.trigger.apply( owner, arguments );\n            };\n        }\n\n        return CompBase;\n    });\n    /**\n     * @fileOverview Html5Runtime\n     */\n    define('runtime/html5/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var type = 'html5',\n            components = {};\n\n        function Html5Runtime() {\n            var pool = {},\n                me = this,\n                destroy = this.destroy;\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                if ( components[ comp ] ) {\n                    instance = pool[ uid ] = pool[ uid ] ||\n                            new components[ comp ]( client, me );\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n            };\n\n            me.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n        }\n\n        Base.inherits( Runtime, {\n            constructor: Html5Runtime,\n\n            // 不需要连接其他程序，直接执行callback\n            init: function() {\n                var me = this;\n                setTimeout(function() {\n                    me.trigger('ready');\n                }, 1 );\n            }\n\n        });\n\n        // 注册Components\n        Html5Runtime.register = function( name, component ) {\n            var klass = components[ name ] = Base.inherits( CompBase, component );\n            return klass;\n        };\n\n        // 注册html5运行时。\n        // 只有在支持的前提下注册。\n        if ( window.Blob && window.FileReader && window.DataView ) {\n            Runtime.addRuntime( type, Html5Runtime );\n        }\n\n        return Html5Runtime;\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/html5/blob',[\n        'runtime/html5/runtime',\n        'lib/blob'\n    ], function( Html5Runtime, Blob ) {\n\n        return Html5Runtime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.owner.source,\n                    slice = blob.slice || blob.webkitSlice || blob.mozSlice;\n\n                blob = slice.call( blob, start, end );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/html5/filepicker',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var $ = Base.$;\n\n        return Html5Runtime.register( 'FilePicker', {\n            init: function() {\n                var container = this.getRuntime().getContainer(),\n                    me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    label = this.label = $( document.createElement('label') ),\n                    input =  this.input = $( document.createElement('input') ),\n                    arr, i, len, mouseHandler;\n\n                input.attr( 'type', 'file' );\n                input.attr( 'name', opts.name );\n                input.addClass('webuploader-element-invisible');\n\n                label.on( 'click', function() {\n                    input.trigger('click');\n                });\n\n                label.css({\n                    opacity: 0,\n                    width: '100%',\n                    height: '100%',\n                    display: 'block',\n                    cursor: 'pointer',\n                    background: '#ffffff'\n                });\n\n                if ( opts.multiple ) {\n                    input.attr( 'multiple', 'multiple' );\n                }\n\n                // @todo Firefox不支持单独指定后缀\n                if ( opts.accept && opts.accept.length > 0 ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        arr.push( opts.accept[ i ].mimeTypes );\n                    }\n\n                    input.attr( 'accept', arr.join(',') );\n                }\n\n                container.append( input );\n                container.append( label );\n\n                mouseHandler = function( e ) {\n                    owner.trigger( e.type );\n                };\n\n                input.on( 'change', function( e ) {\n                    var fn = arguments.callee,\n                        clone;\n\n                    me.files = e.target.files;\n\n                    // reset input\n                    clone = this.cloneNode( true );\n                    clone.value = null;\n                    this.parentNode.replaceChild( clone, this );\n\n                    input.off();\n                    input = $( clone ).on( 'change', fn )\n                            .on( 'mouseenter mouseleave', mouseHandler );\n\n                    owner.trigger('change');\n                });\n\n                label.on( 'mouseenter mouseleave', mouseHandler );\n\n            },\n\n\n            getFiles: function() {\n                return this.files;\n            },\n\n            destroy: function() {\n                this.input.off();\n                this.label.off();\n            }\n        });\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/util',[\n        'base'\n    ], function( Base ) {\n\n        var urlAPI = window.createObjectURL && window ||\n                window.URL && URL.revokeObjectURL && URL ||\n                window.webkitURL,\n            createObjectURL = Base.noop,\n            revokeObjectURL = createObjectURL;\n\n        if ( urlAPI ) {\n\n            // 更安全的方式调用，比如android里面就能把context改成其他的对象。\n            createObjectURL = function() {\n                return urlAPI.createObjectURL.apply( urlAPI, arguments );\n            };\n\n            revokeObjectURL = function() {\n                return urlAPI.revokeObjectURL.apply( urlAPI, arguments );\n            };\n        }\n\n        return {\n            createObjectURL: createObjectURL,\n            revokeObjectURL: revokeObjectURL,\n\n            dataURL2Blob: function( dataURI ) {\n                var byteStr, intArray, ab, i, mimetype, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                ab = new ArrayBuffer( byteStr.length );\n                intArray = new Uint8Array( ab );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                mimetype = parts[ 0 ].split(':')[ 1 ].split(';')[ 0 ];\n\n                return this.arrayBufferToBlob( ab, mimetype );\n            },\n\n            dataURL2ArrayBuffer: function( dataURI ) {\n                var byteStr, intArray, i, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                intArray = new Uint8Array( byteStr.length );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                return intArray.buffer;\n            },\n\n            arrayBufferToBlob: function( buffer, type ) {\n                var builder = window.BlobBuilder || window.WebKitBlobBuilder,\n                    bb;\n\n                // android不支持直接new Blob, 只能借助blobbuilder.\n                if ( builder ) {\n                    bb = new builder();\n                    bb.append( buffer );\n                    return bb.getBlob( type );\n                }\n\n                return new Blob([ buffer ], type ? { type: type } : {} );\n            },\n\n            // 抽出来主要是为了解决android下面canvas.toDataUrl不支持jpeg.\n            // 你得到的结果是png.\n            canvasToDataUrl: function( canvas, type, quality ) {\n                return canvas.toDataURL( type, quality / 100 );\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            parseMeta: function( blob, callback ) {\n                callback( false, {});\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            updateImageHead: function( data ) {\n                return data;\n            }\n        };\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/imagemeta',[\n        'runtime/html5/util'\n    ], function( Util ) {\n\n        var api;\n\n        api = {\n            parsers: {\n                0xffe1: []\n            },\n\n            maxMetaDataSize: 262144,\n\n            parse: function( blob, cb ) {\n                var me = this,\n                    fr = new FileReader();\n\n                fr.onload = function() {\n                    cb( false, me._parse( this.result ) );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                fr.onerror = function( e ) {\n                    cb( e.message );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                blob = blob.slice( 0, me.maxMetaDataSize );\n                fr.readAsArrayBuffer( blob.getSource() );\n            },\n\n            _parse: function( buffer, noParse ) {\n                if ( buffer.byteLength < 6 ) {\n                    return;\n                }\n\n                var dataview = new DataView( buffer ),\n                    offset = 2,\n                    maxOffset = dataview.byteLength - 4,\n                    headLength = offset,\n                    ret = {},\n                    markerBytes, markerLength, parsers, i;\n\n                if ( dataview.getUint16( 0 ) === 0xffd8 ) {\n\n                    while ( offset < maxOffset ) {\n                        markerBytes = dataview.getUint16( offset );\n\n                        if ( markerBytes >= 0xffe0 && markerBytes <= 0xffef ||\n                                markerBytes === 0xfffe ) {\n\n                            markerLength = dataview.getUint16( offset + 2 ) + 2;\n\n                            if ( offset + markerLength > dataview.byteLength ) {\n                                break;\n                            }\n\n                            parsers = api.parsers[ markerBytes ];\n\n                            if ( !noParse && parsers ) {\n                                for ( i = 0; i < parsers.length; i += 1 ) {\n                                    parsers[ i ].call( api, dataview, offset,\n                                            markerLength, ret );\n                                }\n                            }\n\n                            offset += markerLength;\n                            headLength = offset;\n                        } else {\n                            break;\n                        }\n                    }\n\n                    if ( headLength > 6 ) {\n                        if ( buffer.slice ) {\n                            ret.imageHead = buffer.slice( 2, headLength );\n                        } else {\n                            // Workaround for IE10, which does not yet\n                            // support ArrayBuffer.slice:\n                            ret.imageHead = new Uint8Array( buffer )\n                                    .subarray( 2, headLength );\n                        }\n                    }\n                }\n\n                return ret;\n            },\n\n            updateImageHead: function( buffer, head ) {\n                var data = this._parse( buffer, true ),\n                    buf1, buf2, bodyoffset;\n\n\n                bodyoffset = 2;\n                if ( data.imageHead ) {\n                    bodyoffset = 2 + data.imageHead.byteLength;\n                }\n\n                if ( buffer.slice ) {\n                    buf2 = buffer.slice( bodyoffset );\n                } else {\n                    buf2 = new Uint8Array( buffer ).subarray( bodyoffset );\n                }\n\n                buf1 = new Uint8Array( head.byteLength + 2 + buf2.byteLength );\n\n                buf1[ 0 ] = 0xFF;\n                buf1[ 1 ] = 0xD8;\n                buf1.set( new Uint8Array( head ), 2 );\n                buf1.set( new Uint8Array( buf2 ), head.byteLength + 2 );\n\n                return buf1.buffer;\n            }\n        };\n\n        Util.parseMeta = function() {\n            return api.parse.apply( api, arguments );\n        };\n\n        Util.updateImageHead = function() {\n            return api.updateImageHead.apply( api, arguments );\n        };\n\n        return api;\n    });\n    /**\n     * 代码来自于：https://github.com/blueimp/JavaScript-Load-Image\n     * 暂时项目中只用了orientation.\n     *\n     * 去除了 Exif Sub IFD Pointer, GPS Info IFD Pointer, Exif Thumbnail.\n     * @fileOverview EXIF解析\n     */\n\n    // Sample\n    // ====================================\n    // Make : Apple\n    // Model : iPhone 4S\n    // Orientation : 1\n    // XResolution : 72 [72/1]\n    // YResolution : 72 [72/1]\n    // ResolutionUnit : 2\n    // Software : QuickTime 7.7.1\n    // DateTime : 2013:09:01 22:53:55\n    // ExifIFDPointer : 190\n    // ExposureTime : 0.058823529411764705 [1/17]\n    // FNumber : 2.4 [12/5]\n    // ExposureProgram : Normal program\n    // ISOSpeedRatings : 800\n    // ExifVersion : 0220\n    // DateTimeOriginal : 2013:09:01 22:52:51\n    // DateTimeDigitized : 2013:09:01 22:52:51\n    // ComponentsConfiguration : YCbCr\n    // ShutterSpeedValue : 4.058893515764426\n    // ApertureValue : 2.5260688216892597 [4845/1918]\n    // BrightnessValue : -0.3126686601998395\n    // MeteringMode : Pattern\n    // Flash : Flash did not fire, compulsory flash mode\n    // FocalLength : 4.28 [107/25]\n    // SubjectArea : [4 values]\n    // FlashpixVersion : 0100\n    // ColorSpace : 1\n    // PixelXDimension : 2448\n    // PixelYDimension : 3264\n    // SensingMethod : One-chip color area sensor\n    // ExposureMode : 0\n    // WhiteBalance : Auto white balance\n    // FocalLengthIn35mmFilm : 35\n    // SceneCaptureType : Standard\n    define('runtime/html5/imagemeta/exif',[\n        'base',\n        'runtime/html5/imagemeta'\n    ], function( Base, ImageMeta ) {\n\n        var EXIF = {};\n\n        EXIF.ExifMap = function() {\n            return this;\n        };\n\n        EXIF.ExifMap.prototype.map = {\n            'Orientation': 0x0112\n        };\n\n        EXIF.ExifMap.prototype.get = function( id ) {\n            return this[ id ] || this[ this.map[ id ] ];\n        };\n\n        EXIF.exifTagTypes = {\n            // byte, 8-bit unsigned int:\n            1: {\n                getValue: function( dataView, dataOffset ) {\n                    return dataView.getUint8( dataOffset );\n                },\n                size: 1\n            },\n\n            // ascii, 8-bit byte:\n            2: {\n                getValue: function( dataView, dataOffset ) {\n                    return String.fromCharCode( dataView.getUint8( dataOffset ) );\n                },\n                size: 1,\n                ascii: true\n            },\n\n            // short, 16 bit int:\n            3: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint16( dataOffset, littleEndian );\n                },\n                size: 2\n            },\n\n            // long, 32 bit int:\n            4: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // rational = two long values,\n            // first is numerator, second is denominator:\n            5: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian ) /\n                        dataView.getUint32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            },\n\n            // slong, 32 bit signed int:\n            9: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // srational, two slongs, first is numerator, second is denominator:\n            10: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian ) /\n                        dataView.getInt32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            }\n        };\n\n        // undefined, 8-bit byte, value depending on field:\n        EXIF.exifTagTypes[ 7 ] = EXIF.exifTagTypes[ 1 ];\n\n        EXIF.getExifValue = function( dataView, tiffOffset, offset, type, length,\n                littleEndian ) {\n\n            var tagType = EXIF.exifTagTypes[ type ],\n                tagSize, dataOffset, values, i, str, c;\n\n            if ( !tagType ) {\n                Base.log('Invalid Exif data: Invalid tag type.');\n                return;\n            }\n\n            tagSize = tagType.size * length;\n\n            // Determine if the value is contained in the dataOffset bytes,\n            // or if the value at the dataOffset is a pointer to the actual data:\n            dataOffset = tagSize > 4 ? tiffOffset + dataView.getUint32( offset + 8,\n                    littleEndian ) : (offset + 8);\n\n            if ( dataOffset + tagSize > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid data offset.');\n                return;\n            }\n\n            if ( length === 1 ) {\n                return tagType.getValue( dataView, dataOffset, littleEndian );\n            }\n\n            values = [];\n\n            for ( i = 0; i < length; i += 1 ) {\n                values[ i ] = tagType.getValue( dataView,\n                        dataOffset + i * tagType.size, littleEndian );\n            }\n\n            if ( tagType.ascii ) {\n                str = '';\n\n                // Concatenate the chars:\n                for ( i = 0; i < values.length; i += 1 ) {\n                    c = values[ i ];\n\n                    // Ignore the terminating NULL byte(s):\n                    if ( c === '\\u0000' ) {\n                        break;\n                    }\n                    str += c;\n                }\n\n                return str;\n            }\n            return values;\n        };\n\n        EXIF.parseExifTag = function( dataView, tiffOffset, offset, littleEndian,\n                data ) {\n\n            var tag = dataView.getUint16( offset, littleEndian );\n            data.exif[ tag ] = EXIF.getExifValue( dataView, tiffOffset, offset,\n                    dataView.getUint16( offset + 2, littleEndian ),    // tag type\n                    dataView.getUint32( offset + 4, littleEndian ),    // tag length\n                    littleEndian );\n        };\n\n        EXIF.parseExifTags = function( dataView, tiffOffset, dirOffset,\n                littleEndian, data ) {\n\n            var tagsNumber, dirEndOffset, i;\n\n            if ( dirOffset + 6 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory offset.');\n                return;\n            }\n\n            tagsNumber = dataView.getUint16( dirOffset, littleEndian );\n            dirEndOffset = dirOffset + 2 + 12 * tagsNumber;\n\n            if ( dirEndOffset + 4 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory size.');\n                return;\n            }\n\n            for ( i = 0; i < tagsNumber; i += 1 ) {\n                this.parseExifTag( dataView, tiffOffset,\n                        dirOffset + 2 + 12 * i,    // tag offset\n                        littleEndian, data );\n            }\n\n            // Return the offset to the next directory:\n            return dataView.getUint32( dirEndOffset, littleEndian );\n        };\n\n        // EXIF.getExifThumbnail = function(dataView, offset, length) {\n        //     var hexData,\n        //         i,\n        //         b;\n        //     if (!length || offset + length > dataView.byteLength) {\n        //         Base.log('Invalid Exif data: Invalid thumbnail data.');\n        //         return;\n        //     }\n        //     hexData = [];\n        //     for (i = 0; i < length; i += 1) {\n        //         b = dataView.getUint8(offset + i);\n        //         hexData.push((b < 16 ? '0' : '') + b.toString(16));\n        //     }\n        //     return 'data:image/jpeg,%' + hexData.join('%');\n        // };\n\n        EXIF.parseExifData = function( dataView, offset, length, data ) {\n\n            var tiffOffset = offset + 10,\n                littleEndian, dirOffset;\n\n            // Check for the ASCII code for \"Exif\" (0x45786966):\n            if ( dataView.getUint32( offset + 4 ) !== 0x45786966 ) {\n                // No Exif data, might be XMP data instead\n                return;\n            }\n            if ( tiffOffset + 8 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid segment size.');\n                return;\n            }\n\n            // Check for the two null bytes:\n            if ( dataView.getUint16( offset + 8 ) !== 0x0000 ) {\n                Base.log('Invalid Exif data: Missing byte alignment offset.');\n                return;\n            }\n\n            // Check the byte alignment:\n            switch ( dataView.getUint16( tiffOffset ) ) {\n                case 0x4949:\n                    littleEndian = true;\n                    break;\n\n                case 0x4D4D:\n                    littleEndian = false;\n                    break;\n\n                default:\n                    Base.log('Invalid Exif data: Invalid byte alignment marker.');\n                    return;\n            }\n\n            // Check for the TIFF tag marker (0x002A):\n            if ( dataView.getUint16( tiffOffset + 2, littleEndian ) !== 0x002A ) {\n                Base.log('Invalid Exif data: Missing TIFF marker.');\n                return;\n            }\n\n            // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:\n            dirOffset = dataView.getUint32( tiffOffset + 4, littleEndian );\n            // Create the exif object to store the tags:\n            data.exif = new EXIF.ExifMap();\n            // Parse the tags of the main image directory and retrieve the\n            // offset to the next directory, usually the thumbnail directory:\n            dirOffset = EXIF.parseExifTags( dataView, tiffOffset,\n                    tiffOffset + dirOffset, littleEndian, data );\n\n            // 尝试读取缩略图\n            // if ( dirOffset ) {\n            //     thumbnailData = {exif: {}};\n            //     dirOffset = EXIF.parseExifTags(\n            //         dataView,\n            //         tiffOffset,\n            //         tiffOffset + dirOffset,\n            //         littleEndian,\n            //         thumbnailData\n            //     );\n\n            //     // Check for JPEG Thumbnail offset:\n            //     if (thumbnailData.exif[0x0201]) {\n            //         data.exif.Thumbnail = EXIF.getExifThumbnail(\n            //             dataView,\n            //             tiffOffset + thumbnailData.exif[0x0201],\n            //             thumbnailData.exif[0x0202] // Thumbnail data length\n            //         );\n            //     }\n            // }\n        };\n\n        ImageMeta.parsers[ 0xffe1 ].push( EXIF.parseExifData );\n        return EXIF;\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('runtime/html5/image',[\n        'base',\n        'runtime/html5/runtime',\n        'runtime/html5/util'\n    ], function( Base, Html5Runtime, Util ) {\n\n        var BLANK = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D';\n\n        return Html5Runtime.register( 'Image', {\n\n            // flag: 标记是否被修改过。\n            modified: false,\n\n            init: function() {\n                var me = this,\n                    img = new Image();\n\n                img.onload = function() {\n\n                    me._info = {\n                        type: me.type,\n                        width: this.width,\n                        height: this.height\n                    };\n\n                    // 读取meta信息。\n                    if ( !me._metas && 'image/jpeg' === me.type ) {\n                        Util.parseMeta( me._blob, function( error, ret ) {\n                            me._metas = ret;\n                            me.owner.trigger('load');\n                        });\n                    } else {\n                        me.owner.trigger('load');\n                    }\n                };\n\n                img.onerror = function() {\n                    me.owner.trigger('error');\n                };\n\n                me._img = img;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    img = me._img;\n\n                me._blob = blob;\n                me.type = blob.type;\n                img.src = Util.createObjectURL( blob.getSource() );\n                me.owner.once( 'load', function() {\n                    Util.revokeObjectURL( img.src );\n                });\n            },\n\n            resize: function( width, height ) {\n                var canvas = this._canvas ||\n                        (this._canvas = document.createElement('canvas'));\n\n                this._resize( this._img, canvas, width, height );\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'resize' );\n            },\n\n            crop: function( x, y, w, h, s ) {\n                var cvs = this._canvas ||\n                        (this._canvas = document.createElement('canvas')),\n                    opts = this.options,\n                    img = this._img,\n                    iw = img.naturalWidth,\n                    ih = img.naturalHeight,\n                    orientation = this.getOrientation();\n\n                s = s || 1;\n\n                // todo 解决 orientation 的问题。\n                // values that require 90 degree rotation\n                // if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                //     switch ( orientation ) {\n                //         case 6:\n                //             tmp = x;\n                //             x = y;\n                //             y = iw * s - tmp - w;\n                //             console.log(ih * s, tmp, w)\n                //             break;\n                //     }\n\n                //     (w ^= h, h ^= w, w ^= h);\n                // }\n\n                cvs.width = w;\n                cvs.height = h;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n                this._renderImageToCanvas( cvs, img, -x, -y, iw * s, ih * s );\n\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'crop' );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this._blob,\n                    opts = this.options,\n                    canvas;\n\n                type = type || this.type;\n\n                // blob需要重新生成。\n                if ( this.modified || this.type !== type ) {\n                    canvas = this._canvas;\n\n                    if ( type === 'image/jpeg' ) {\n\n                        blob = Util.canvasToDataUrl( canvas, type, opts.quality );\n\n                        if ( opts.preserveHeaders && this._metas &&\n                                this._metas.imageHead ) {\n\n                            blob = Util.dataURL2ArrayBuffer( blob );\n                            blob = Util.updateImageHead( blob,\n                                    this._metas.imageHead );\n                            blob = Util.arrayBufferToBlob( blob, type );\n                            return blob;\n                        }\n                    } else {\n                        blob = Util.canvasToDataUrl( canvas, type );\n                    }\n\n                    blob = Util.dataURL2Blob( blob );\n                }\n\n                return blob;\n            },\n\n            getAsDataUrl: function( type ) {\n                var opts = this.options;\n\n                type = type || this.type;\n\n                if ( type === 'image/jpeg' ) {\n                    return Util.canvasToDataUrl( this._canvas, type, opts.quality );\n                } else {\n                    return this._canvas.toDataURL( type );\n                }\n            },\n\n            getOrientation: function() {\n                return this._metas && this._metas.exif &&\n                        this._metas.exif.get('Orientation') || 1;\n            },\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            destroy: function() {\n                var canvas = this._canvas;\n                this._img.onload = null;\n\n                if ( canvas ) {\n                    canvas.getContext('2d')\n                            .clearRect( 0, 0, canvas.width, canvas.height );\n                    canvas.width = canvas.height = 0;\n                    this._canvas = null;\n                }\n\n                // 释放内存。非常重要，否则释放不了image的内存。\n                this._img.src = BLANK;\n                this._img = this._blob = null;\n            },\n\n            _resize: function( img, cvs, width, height ) {\n                var opts = this.options,\n                    naturalWidth = img.width,\n                    naturalHeight = img.height,\n                    orientation = this.getOrientation(),\n                    scale, w, h, x, y;\n\n                // values that require 90 degree rotation\n                if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                    // 交换width, height的值。\n                    width ^= height;\n                    height ^= width;\n                    width ^= height;\n                }\n\n                scale = Math[ opts.crop ? 'max' : 'min' ]( width / naturalWidth,\n                        height / naturalHeight );\n\n                // 不允许放大。\n                opts.allowMagnify || (scale = Math.min( 1, scale ));\n\n                w = naturalWidth * scale;\n                h = naturalHeight * scale;\n\n                if ( opts.crop ) {\n                    cvs.width = width;\n                    cvs.height = height;\n                } else {\n                    cvs.width = w;\n                    cvs.height = h;\n                }\n\n                x = (cvs.width - w) / 2;\n                y = (cvs.height - h) / 2;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n\n                this._renderImageToCanvas( cvs, img, x, y, w, h );\n            },\n\n            _rotate2Orientaion: function( canvas, orientation ) {\n                var width = canvas.width,\n                    height = canvas.height,\n                    ctx = canvas.getContext('2d');\n\n                switch ( orientation ) {\n                    case 5:\n                    case 6:\n                    case 7:\n                    case 8:\n                        canvas.width = height;\n                        canvas.height = width;\n                        break;\n                }\n\n                switch ( orientation ) {\n                    case 2:    // horizontal flip\n                        ctx.translate( width, 0 );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 3:    // 180 rotate left\n                        ctx.translate( width, height );\n                        ctx.rotate( Math.PI );\n                        break;\n\n                    case 4:    // vertical flip\n                        ctx.translate( 0, height );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 5:    // vertical flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 6:    // 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( 0, -height );\n                        break;\n\n                    case 7:    // horizontal flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( width, -height );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 8:    // 90 rotate left\n                        ctx.rotate( -0.5 * Math.PI );\n                        ctx.translate( -width, 0 );\n                        break;\n                }\n            },\n\n            // https://github.com/stomita/ios-imagefile-megapixel/\n            // blob/master/src/megapix-image.js\n            _renderImageToCanvas: (function() {\n\n                // 如果不是ios, 不需要这么复杂！\n                if ( !Base.os.ios ) {\n                    return function( canvas ) {\n                        var args = Base.slice( arguments, 1 ),\n                            ctx = canvas.getContext('2d');\n\n                        ctx.drawImage.apply( ctx, args );\n                    };\n                }\n\n                /**\n                 * Detecting vertical squash in loaded image.\n                 * Fixes a bug which squash image vertically while drawing into\n                 * canvas for some images.\n                 */\n                function detectVerticalSquash( img, iw, ih ) {\n                    var canvas = document.createElement('canvas'),\n                        ctx = canvas.getContext('2d'),\n                        sy = 0,\n                        ey = ih,\n                        py = ih,\n                        data, alpha, ratio;\n\n\n                    canvas.width = 1;\n                    canvas.height = ih;\n                    ctx.drawImage( img, 0, 0 );\n                    data = ctx.getImageData( 0, 0, 1, ih ).data;\n\n                    // search image edge pixel position in case\n                    // it is squashed vertically.\n                    while ( py > sy ) {\n                        alpha = data[ (py - 1) * 4 + 3 ];\n\n                        if ( alpha === 0 ) {\n                            ey = py;\n                        } else {\n                            sy = py;\n                        }\n\n                        py = (ey + sy) >> 1;\n                    }\n\n                    ratio = (py / ih);\n                    return (ratio === 0) ? 1 : ratio;\n                }\n\n                // fix ie7 bug\n                // http://stackoverflow.com/questions/11929099/\n                // html5-canvas-drawimage-ratio-bug-ios\n                if ( Base.os.ios >= 7 ) {\n                    return function( canvas, img, x, y, w, h ) {\n                        var iw = img.naturalWidth,\n                            ih = img.naturalHeight,\n                            vertSquashRatio = detectVerticalSquash( img, iw, ih );\n\n                        return canvas.getContext('2d').drawImage( img, 0, 0,\n                                iw * vertSquashRatio, ih * vertSquashRatio,\n                                x, y, w, h );\n                    };\n                }\n\n                /**\n                 * Detect subsampling in loaded image.\n                 * In iOS, larger images than 2M pixels may be\n                 * subsampled in rendering.\n                 */\n                function detectSubsampling( img ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        canvas, ctx;\n\n                    // subsampling may happen overmegapixel image\n                    if ( iw * ih > 1024 * 1024 ) {\n                        canvas = document.createElement('canvas');\n                        canvas.width = canvas.height = 1;\n                        ctx = canvas.getContext('2d');\n                        ctx.drawImage( img, -iw + 1, 0 );\n\n                        // subsampled image becomes half smaller in rendering size.\n                        // check alpha channel value to confirm image is covering\n                        // edge pixel or not. if alpha value is 0\n                        // image is not covering, hence subsampled.\n                        return ctx.getImageData( 0, 0, 1, 1 ).data[ 3 ] === 0;\n                    } else {\n                        return false;\n                    }\n                }\n\n\n                return function( canvas, img, x, y, width, height ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        ctx = canvas.getContext('2d'),\n                        subsampled = detectSubsampling( img ),\n                        doSquash = this.type === 'image/jpeg',\n                        d = 1024,\n                        sy = 0,\n                        dy = 0,\n                        tmpCanvas, tmpCtx, vertSquashRatio, dw, dh, sx, dx;\n\n                    if ( subsampled ) {\n                        iw /= 2;\n                        ih /= 2;\n                    }\n\n                    ctx.save();\n                    tmpCanvas = document.createElement('canvas');\n                    tmpCanvas.width = tmpCanvas.height = d;\n\n                    tmpCtx = tmpCanvas.getContext('2d');\n                    vertSquashRatio = doSquash ?\n                            detectVerticalSquash( img, iw, ih ) : 1;\n\n                    dw = Math.ceil( d * width / iw );\n                    dh = Math.ceil( d * height / ih / vertSquashRatio );\n\n                    while ( sy < ih ) {\n                        sx = 0;\n                        dx = 0;\n                        while ( sx < iw ) {\n                            tmpCtx.clearRect( 0, 0, d, d );\n                            tmpCtx.drawImage( img, -sx, -sy );\n                            ctx.drawImage( tmpCanvas, 0, 0, d, d,\n                                    x + dx, y + dy, dw, dh );\n                            sx += d;\n                            dx += dw;\n                        }\n                        sy += d;\n                        dy += dh;\n                    }\n                    ctx.restore();\n                    tmpCanvas = tmpCtx = null;\n                };\n            })()\n        });\n    });\n    /**\n     * 这个方式性能不行，但是可以解决android里面的toDataUrl的bug\n     * android里面toDataUrl('image/jpege')得到的结果却是png.\n     *\n     * 所以这里没辙，只能借助这个工具\n     * @fileOverview jpeg encoder\n     */\n    define('runtime/html5/jpegencoder',[], function( require, exports, module ) {\n\n        /*\n          Copyright (c) 2008, Adobe Systems Incorporated\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\n          met:\n\n          * Redistributions of source code must retain the above copyright notice,\n            this list of conditions and the following disclaimer.\n\n          * Redistributions in binary form must reproduce the above copyright\n            notice, this list of conditions and the following disclaimer in the\n            documentation and/or other materials provided with the distribution.\n\n          * Neither the name of Adobe Systems Incorporated nor the names of its\n            contributors may be used to endorse or promote products derived from\n            this software without specific prior written permission.\n\n          THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n          IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n          THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n          PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n          CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n          EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n          PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n          PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n          LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n          NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n          SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n        */\n        /*\n        JPEG encoder ported to JavaScript and optimized by Andreas Ritter, www.bytestrom.eu, 11/2009\n\n        Basic GUI blocking jpeg encoder\n        */\n\n        function JPEGEncoder(quality) {\n          var self = this;\n            var fround = Math.round;\n            var ffloor = Math.floor;\n            var YTable = new Array(64);\n            var UVTable = new Array(64);\n            var fdtbl_Y = new Array(64);\n            var fdtbl_UV = new Array(64);\n            var YDC_HT;\n            var UVDC_HT;\n            var YAC_HT;\n            var UVAC_HT;\n\n            var bitcode = new Array(65535);\n            var category = new Array(65535);\n            var outputfDCTQuant = new Array(64);\n            var DU = new Array(64);\n            var byteout = [];\n            var bytenew = 0;\n            var bytepos = 7;\n\n            var YDU = new Array(64);\n            var UDU = new Array(64);\n            var VDU = new Array(64);\n            var clt = new Array(256);\n            var RGB_YUV_TABLE = new Array(2048);\n            var currentQuality;\n\n            var ZigZag = [\n                     0, 1, 5, 6,14,15,27,28,\n                     2, 4, 7,13,16,26,29,42,\n                     3, 8,12,17,25,30,41,43,\n                     9,11,18,24,31,40,44,53,\n                    10,19,23,32,39,45,52,54,\n                    20,22,33,38,46,51,55,60,\n                    21,34,37,47,50,56,59,61,\n                    35,36,48,49,57,58,62,63\n                ];\n\n            var std_dc_luminance_nrcodes = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];\n            var std_dc_luminance_values = [0,1,2,3,4,5,6,7,8,9,10,11];\n            var std_ac_luminance_nrcodes = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];\n            var std_ac_luminance_values = [\n                    0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,\n                    0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,\n                    0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\n                    0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,\n                    0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,\n                    0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\n                    0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,\n                    0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,\n                    0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\n                    0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,\n                    0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,\n                    0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\n                    0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,\n                    0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,\n                    0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\n                    0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,\n                    0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,\n                    0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\n                    0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,\n                    0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\n                    0xf9,0xfa\n                ];\n\n            var std_dc_chrominance_nrcodes = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];\n            var std_dc_chrominance_values = [0,1,2,3,4,5,6,7,8,9,10,11];\n            var std_ac_chrominance_nrcodes = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];\n            var std_ac_chrominance_values = [\n                    0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,\n                    0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,\n                    0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\n                    0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,\n                    0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,\n                    0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\n                    0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,\n                    0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,\n                    0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\n                    0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,\n                    0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,\n                    0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\n                    0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,\n                    0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,\n                    0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\n                    0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,\n                    0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,\n                    0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\n                    0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,\n                    0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\n                    0xf9,0xfa\n                ];\n\n            function initQuantTables(sf){\n                    var YQT = [\n                        16, 11, 10, 16, 24, 40, 51, 61,\n                        12, 12, 14, 19, 26, 58, 60, 55,\n                        14, 13, 16, 24, 40, 57, 69, 56,\n                        14, 17, 22, 29, 51, 87, 80, 62,\n                        18, 22, 37, 56, 68,109,103, 77,\n                        24, 35, 55, 64, 81,104,113, 92,\n                        49, 64, 78, 87,103,121,120,101,\n                        72, 92, 95, 98,112,100,103, 99\n                    ];\n\n                    for (var i = 0; i < 64; i++) {\n                        var t = ffloor((YQT[i]*sf+50)/100);\n                        if (t < 1) {\n                            t = 1;\n                        } else if (t > 255) {\n                            t = 255;\n                        }\n                        YTable[ZigZag[i]] = t;\n                    }\n                    var UVQT = [\n                        17, 18, 24, 47, 99, 99, 99, 99,\n                        18, 21, 26, 66, 99, 99, 99, 99,\n                        24, 26, 56, 99, 99, 99, 99, 99,\n                        47, 66, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99\n                    ];\n                    for (var j = 0; j < 64; j++) {\n                        var u = ffloor((UVQT[j]*sf+50)/100);\n                        if (u < 1) {\n                            u = 1;\n                        } else if (u > 255) {\n                            u = 255;\n                        }\n                        UVTable[ZigZag[j]] = u;\n                    }\n                    var aasf = [\n                        1.0, 1.387039845, 1.306562965, 1.175875602,\n                        1.0, 0.785694958, 0.541196100, 0.275899379\n                    ];\n                    var k = 0;\n                    for (var row = 0; row < 8; row++)\n                    {\n                        for (var col = 0; col < 8; col++)\n                        {\n                            fdtbl_Y[k]  = (1.0 / (YTable [ZigZag[k]] * aasf[row] * aasf[col] * 8.0));\n                            fdtbl_UV[k] = (1.0 / (UVTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0));\n                            k++;\n                        }\n                    }\n                }\n\n                function computeHuffmanTbl(nrcodes, std_table){\n                    var codevalue = 0;\n                    var pos_in_table = 0;\n                    var HT = new Array();\n                    for (var k = 1; k <= 16; k++) {\n                        for (var j = 1; j <= nrcodes[k]; j++) {\n                            HT[std_table[pos_in_table]] = [];\n                            HT[std_table[pos_in_table]][0] = codevalue;\n                            HT[std_table[pos_in_table]][1] = k;\n                            pos_in_table++;\n                            codevalue++;\n                        }\n                        codevalue*=2;\n                    }\n                    return HT;\n                }\n\n                function initHuffmanTbl()\n                {\n                    YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);\n                    UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);\n                    YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);\n                    UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);\n                }\n\n                function initCategoryNumber()\n                {\n                    var nrlower = 1;\n                    var nrupper = 2;\n                    for (var cat = 1; cat <= 15; cat++) {\n                        //Positive numbers\n                        for (var nr = nrlower; nr<nrupper; nr++) {\n                            category[32767+nr] = cat;\n                            bitcode[32767+nr] = [];\n                            bitcode[32767+nr][1] = cat;\n                            bitcode[32767+nr][0] = nr;\n                        }\n                        //Negative numbers\n                        for (var nrneg =-(nrupper-1); nrneg<=-nrlower; nrneg++) {\n                            category[32767+nrneg] = cat;\n                            bitcode[32767+nrneg] = [];\n                            bitcode[32767+nrneg][1] = cat;\n                            bitcode[32767+nrneg][0] = nrupper-1+nrneg;\n                        }\n                        nrlower <<= 1;\n                        nrupper <<= 1;\n                    }\n                }\n\n                function initRGBYUVTable() {\n                    for(var i = 0; i < 256;i++) {\n                        RGB_YUV_TABLE[i]            =  19595 * i;\n                        RGB_YUV_TABLE[(i+ 256)>>0]  =  38470 * i;\n                        RGB_YUV_TABLE[(i+ 512)>>0]  =   7471 * i + 0x8000;\n                        RGB_YUV_TABLE[(i+ 768)>>0]  = -11059 * i;\n                        RGB_YUV_TABLE[(i+1024)>>0]  = -21709 * i;\n                        RGB_YUV_TABLE[(i+1280)>>0]  =  32768 * i + 0x807FFF;\n                        RGB_YUV_TABLE[(i+1536)>>0]  = -27439 * i;\n                        RGB_YUV_TABLE[(i+1792)>>0]  = - 5329 * i;\n                    }\n                }\n\n                // IO functions\n                function writeBits(bs)\n                {\n                    var value = bs[0];\n                    var posval = bs[1]-1;\n                    while ( posval >= 0 ) {\n                        if (value & (1 << posval) ) {\n                            bytenew |= (1 << bytepos);\n                        }\n                        posval--;\n                        bytepos--;\n                        if (bytepos < 0) {\n                            if (bytenew == 0xFF) {\n                                writeByte(0xFF);\n                                writeByte(0);\n                            }\n                            else {\n                                writeByte(bytenew);\n                            }\n                            bytepos=7;\n                            bytenew=0;\n                        }\n                    }\n                }\n\n                function writeByte(value)\n                {\n                    byteout.push(clt[value]); // write char directly instead of converting later\n                }\n\n                function writeWord(value)\n                {\n                    writeByte((value>>8)&0xFF);\n                    writeByte((value   )&0xFF);\n                }\n\n                // DCT & quantization core\n                function fDCTQuant(data, fdtbl)\n                {\n                    var d0, d1, d2, d3, d4, d5, d6, d7;\n                    /* Pass 1: process rows. */\n                    var dataOff=0;\n                    var i;\n                    var I8 = 8;\n                    var I64 = 64;\n                    for (i=0; i<I8; ++i)\n                    {\n                        d0 = data[dataOff];\n                        d1 = data[dataOff+1];\n                        d2 = data[dataOff+2];\n                        d3 = data[dataOff+3];\n                        d4 = data[dataOff+4];\n                        d5 = data[dataOff+5];\n                        d6 = data[dataOff+6];\n                        d7 = data[dataOff+7];\n\n                        var tmp0 = d0 + d7;\n                        var tmp7 = d0 - d7;\n                        var tmp1 = d1 + d6;\n                        var tmp6 = d1 - d6;\n                        var tmp2 = d2 + d5;\n                        var tmp5 = d2 - d5;\n                        var tmp3 = d3 + d4;\n                        var tmp4 = d3 - d4;\n\n                        /* Even part */\n                        var tmp10 = tmp0 + tmp3;    /* phase 2 */\n                        var tmp13 = tmp0 - tmp3;\n                        var tmp11 = tmp1 + tmp2;\n                        var tmp12 = tmp1 - tmp2;\n\n                        data[dataOff] = tmp10 + tmp11; /* phase 3 */\n                        data[dataOff+4] = tmp10 - tmp11;\n\n                        var z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */\n                        data[dataOff+2] = tmp13 + z1; /* phase 5 */\n                        data[dataOff+6] = tmp13 - z1;\n\n                        /* Odd part */\n                        tmp10 = tmp4 + tmp5; /* phase 2 */\n                        tmp11 = tmp5 + tmp6;\n                        tmp12 = tmp6 + tmp7;\n\n                        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n                        var z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */\n                        var z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */\n                        var z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */\n                        var z3 = tmp11 * 0.707106781; /* c4 */\n\n                        var z11 = tmp7 + z3;    /* phase 5 */\n                        var z13 = tmp7 - z3;\n\n                        data[dataOff+5] = z13 + z2; /* phase 6 */\n                        data[dataOff+3] = z13 - z2;\n                        data[dataOff+1] = z11 + z4;\n                        data[dataOff+7] = z11 - z4;\n\n                        dataOff += 8; /* advance pointer to next row */\n                    }\n\n                    /* Pass 2: process columns. */\n                    dataOff = 0;\n                    for (i=0; i<I8; ++i)\n                    {\n                        d0 = data[dataOff];\n                        d1 = data[dataOff + 8];\n                        d2 = data[dataOff + 16];\n                        d3 = data[dataOff + 24];\n                        d4 = data[dataOff + 32];\n                        d5 = data[dataOff + 40];\n                        d6 = data[dataOff + 48];\n                        d7 = data[dataOff + 56];\n\n                        var tmp0p2 = d0 + d7;\n                        var tmp7p2 = d0 - d7;\n                        var tmp1p2 = d1 + d6;\n                        var tmp6p2 = d1 - d6;\n                        var tmp2p2 = d2 + d5;\n                        var tmp5p2 = d2 - d5;\n                        var tmp3p2 = d3 + d4;\n                        var tmp4p2 = d3 - d4;\n\n                        /* Even part */\n                        var tmp10p2 = tmp0p2 + tmp3p2;  /* phase 2 */\n                        var tmp13p2 = tmp0p2 - tmp3p2;\n                        var tmp11p2 = tmp1p2 + tmp2p2;\n                        var tmp12p2 = tmp1p2 - tmp2p2;\n\n                        data[dataOff] = tmp10p2 + tmp11p2; /* phase 3 */\n                        data[dataOff+32] = tmp10p2 - tmp11p2;\n\n                        var z1p2 = (tmp12p2 + tmp13p2) * 0.707106781; /* c4 */\n                        data[dataOff+16] = tmp13p2 + z1p2; /* phase 5 */\n                        data[dataOff+48] = tmp13p2 - z1p2;\n\n                        /* Odd part */\n                        tmp10p2 = tmp4p2 + tmp5p2; /* phase 2 */\n                        tmp11p2 = tmp5p2 + tmp6p2;\n                        tmp12p2 = tmp6p2 + tmp7p2;\n\n                        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n                        var z5p2 = (tmp10p2 - tmp12p2) * 0.382683433; /* c6 */\n                        var z2p2 = 0.541196100 * tmp10p2 + z5p2; /* c2-c6 */\n                        var z4p2 = 1.306562965 * tmp12p2 + z5p2; /* c2+c6 */\n                        var z3p2 = tmp11p2 * 0.707106781; /* c4 */\n\n                        var z11p2 = tmp7p2 + z3p2;  /* phase 5 */\n                        var z13p2 = tmp7p2 - z3p2;\n\n                        data[dataOff+40] = z13p2 + z2p2; /* phase 6 */\n                        data[dataOff+24] = z13p2 - z2p2;\n                        data[dataOff+ 8] = z11p2 + z4p2;\n                        data[dataOff+56] = z11p2 - z4p2;\n\n                        dataOff++; /* advance pointer to next column */\n                    }\n\n                    // Quantize/descale the coefficients\n                    var fDCTQuant;\n                    for (i=0; i<I64; ++i)\n                    {\n                        // Apply the quantization and scaling factor & Round to nearest integer\n                        fDCTQuant = data[i]*fdtbl[i];\n                        outputfDCTQuant[i] = (fDCTQuant > 0.0) ? ((fDCTQuant + 0.5)|0) : ((fDCTQuant - 0.5)|0);\n                        //outputfDCTQuant[i] = fround(fDCTQuant);\n\n                    }\n                    return outputfDCTQuant;\n                }\n\n                function writeAPP0()\n                {\n                    writeWord(0xFFE0); // marker\n                    writeWord(16); // length\n                    writeByte(0x4A); // J\n                    writeByte(0x46); // F\n                    writeByte(0x49); // I\n                    writeByte(0x46); // F\n                    writeByte(0); // = \"JFIF\",'\\0'\n                    writeByte(1); // versionhi\n                    writeByte(1); // versionlo\n                    writeByte(0); // xyunits\n                    writeWord(1); // xdensity\n                    writeWord(1); // ydensity\n                    writeByte(0); // thumbnwidth\n                    writeByte(0); // thumbnheight\n                }\n\n                function writeSOF0(width, height)\n                {\n                    writeWord(0xFFC0); // marker\n                    writeWord(17);   // length, truecolor YUV JPG\n                    writeByte(8);    // precision\n                    writeWord(height);\n                    writeWord(width);\n                    writeByte(3);    // nrofcomponents\n                    writeByte(1);    // IdY\n                    writeByte(0x11); // HVY\n                    writeByte(0);    // QTY\n                    writeByte(2);    // IdU\n                    writeByte(0x11); // HVU\n                    writeByte(1);    // QTU\n                    writeByte(3);    // IdV\n                    writeByte(0x11); // HVV\n                    writeByte(1);    // QTV\n                }\n\n                function writeDQT()\n                {\n                    writeWord(0xFFDB); // marker\n                    writeWord(132);    // length\n                    writeByte(0);\n                    for (var i=0; i<64; i++) {\n                        writeByte(YTable[i]);\n                    }\n                    writeByte(1);\n                    for (var j=0; j<64; j++) {\n                        writeByte(UVTable[j]);\n                    }\n                }\n\n                function writeDHT()\n                {\n                    writeWord(0xFFC4); // marker\n                    writeWord(0x01A2); // length\n\n                    writeByte(0); // HTYDCinfo\n                    for (var i=0; i<16; i++) {\n                        writeByte(std_dc_luminance_nrcodes[i+1]);\n                    }\n                    for (var j=0; j<=11; j++) {\n                        writeByte(std_dc_luminance_values[j]);\n                    }\n\n                    writeByte(0x10); // HTYACinfo\n                    for (var k=0; k<16; k++) {\n                        writeByte(std_ac_luminance_nrcodes[k+1]);\n                    }\n                    for (var l=0; l<=161; l++) {\n                        writeByte(std_ac_luminance_values[l]);\n                    }\n\n                    writeByte(1); // HTUDCinfo\n                    for (var m=0; m<16; m++) {\n                        writeByte(std_dc_chrominance_nrcodes[m+1]);\n                    }\n                    for (var n=0; n<=11; n++) {\n                        writeByte(std_dc_chrominance_values[n]);\n                    }\n\n                    writeByte(0x11); // HTUACinfo\n                    for (var o=0; o<16; o++) {\n                        writeByte(std_ac_chrominance_nrcodes[o+1]);\n                    }\n                    for (var p=0; p<=161; p++) {\n                        writeByte(std_ac_chrominance_values[p]);\n                    }\n                }\n\n                function writeSOS()\n                {\n                    writeWord(0xFFDA); // marker\n                    writeWord(12); // length\n                    writeByte(3); // nrofcomponents\n                    writeByte(1); // IdY\n                    writeByte(0); // HTY\n                    writeByte(2); // IdU\n                    writeByte(0x11); // HTU\n                    writeByte(3); // IdV\n                    writeByte(0x11); // HTV\n                    writeByte(0); // Ss\n                    writeByte(0x3f); // Se\n                    writeByte(0); // Bf\n                }\n\n                function processDU(CDU, fdtbl, DC, HTDC, HTAC){\n                    var EOB = HTAC[0x00];\n                    var M16zeroes = HTAC[0xF0];\n                    var pos;\n                    var I16 = 16;\n                    var I63 = 63;\n                    var I64 = 64;\n                    var DU_DCT = fDCTQuant(CDU, fdtbl);\n                    //ZigZag reorder\n                    for (var j=0;j<I64;++j) {\n                        DU[ZigZag[j]]=DU_DCT[j];\n                    }\n                    var Diff = DU[0] - DC; DC = DU[0];\n                    //Encode DC\n                    if (Diff==0) {\n                        writeBits(HTDC[0]); // Diff might be 0\n                    } else {\n                        pos = 32767+Diff;\n                        writeBits(HTDC[category[pos]]);\n                        writeBits(bitcode[pos]);\n                    }\n                    //Encode ACs\n                    var end0pos = 63; // was const... which is crazy\n                    for (; (end0pos>0)&&(DU[end0pos]==0); end0pos--) {};\n                    //end0pos = first element in reverse order !=0\n                    if ( end0pos == 0) {\n                        writeBits(EOB);\n                        return DC;\n                    }\n                    var i = 1;\n                    var lng;\n                    while ( i <= end0pos ) {\n                        var startpos = i;\n                        for (; (DU[i]==0) && (i<=end0pos); ++i) {}\n                        var nrzeroes = i-startpos;\n                        if ( nrzeroes >= I16 ) {\n                            lng = nrzeroes>>4;\n                            for (var nrmarker=1; nrmarker <= lng; ++nrmarker)\n                                writeBits(M16zeroes);\n                            nrzeroes = nrzeroes&0xF;\n                        }\n                        pos = 32767+DU[i];\n                        writeBits(HTAC[(nrzeroes<<4)+category[pos]]);\n                        writeBits(bitcode[pos]);\n                        i++;\n                    }\n                    if ( end0pos != I63 ) {\n                        writeBits(EOB);\n                    }\n                    return DC;\n                }\n\n                function initCharLookupTable(){\n                    var sfcc = String.fromCharCode;\n                    for(var i=0; i < 256; i++){ ///// ACHTUNG // 255\n                        clt[i] = sfcc(i);\n                    }\n                }\n\n                this.encode = function(image,quality) // image data object\n                {\n                    // var time_start = new Date().getTime();\n\n                    if(quality) setQuality(quality);\n\n                    // Initialize bit writer\n                    byteout = new Array();\n                    bytenew=0;\n                    bytepos=7;\n\n                    // Add JPEG headers\n                    writeWord(0xFFD8); // SOI\n                    writeAPP0();\n                    writeDQT();\n                    writeSOF0(image.width,image.height);\n                    writeDHT();\n                    writeSOS();\n\n\n                    // Encode 8x8 macroblocks\n                    var DCY=0;\n                    var DCU=0;\n                    var DCV=0;\n\n                    bytenew=0;\n                    bytepos=7;\n\n\n                    this.encode.displayName = \"_encode_\";\n\n                    var imageData = image.data;\n                    var width = image.width;\n                    var height = image.height;\n\n                    var quadWidth = width*4;\n                    var tripleWidth = width*3;\n\n                    var x, y = 0;\n                    var r, g, b;\n                    var start,p, col,row,pos;\n                    while(y < height){\n                        x = 0;\n                        while(x < quadWidth){\n                        start = quadWidth * y + x;\n                        p = start;\n                        col = -1;\n                        row = 0;\n\n                        for(pos=0; pos < 64; pos++){\n                            row = pos >> 3;// /8\n                            col = ( pos & 7 ) * 4; // %8\n                            p = start + ( row * quadWidth ) + col;\n\n                            if(y+row >= height){ // padding bottom\n                                p-= (quadWidth*(y+1+row-height));\n                            }\n\n                            if(x+col >= quadWidth){ // padding right\n                                p-= ((x+col) - quadWidth +4)\n                            }\n\n                            r = imageData[ p++ ];\n                            g = imageData[ p++ ];\n                            b = imageData[ p++ ];\n\n\n                            /* // calculate YUV values dynamically\n                            YDU[pos]=((( 0.29900)*r+( 0.58700)*g+( 0.11400)*b))-128; //-0x80\n                            UDU[pos]=(((-0.16874)*r+(-0.33126)*g+( 0.50000)*b));\n                            VDU[pos]=((( 0.50000)*r+(-0.41869)*g+(-0.08131)*b));\n                            */\n\n                            // use lookup table (slightly faster)\n                            YDU[pos] = ((RGB_YUV_TABLE[r]             + RGB_YUV_TABLE[(g +  256)>>0] + RGB_YUV_TABLE[(b +  512)>>0]) >> 16)-128;\n                            UDU[pos] = ((RGB_YUV_TABLE[(r +  768)>>0] + RGB_YUV_TABLE[(g + 1024)>>0] + RGB_YUV_TABLE[(b + 1280)>>0]) >> 16)-128;\n                            VDU[pos] = ((RGB_YUV_TABLE[(r + 1280)>>0] + RGB_YUV_TABLE[(g + 1536)>>0] + RGB_YUV_TABLE[(b + 1792)>>0]) >> 16)-128;\n\n                        }\n\n                        DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n                        DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n                        DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n                        x+=32;\n                        }\n                        y+=8;\n                    }\n\n\n                    ////////////////////////////////////////////////////////////////\n\n                    // Do the bit alignment of the EOI marker\n                    if ( bytepos >= 0 ) {\n                        var fillbits = [];\n                        fillbits[1] = bytepos+1;\n                        fillbits[0] = (1<<(bytepos+1))-1;\n                        writeBits(fillbits);\n                    }\n\n                    writeWord(0xFFD9); //EOI\n\n                    var jpegDataUri = 'data:image/jpeg;base64,' + btoa(byteout.join(''));\n\n                    byteout = [];\n\n                    // benchmarking\n                    // var duration = new Date().getTime() - time_start;\n                    // console.log('Encoding time: '+ currentQuality + 'ms');\n                    //\n\n                    return jpegDataUri\n            }\n\n            function setQuality(quality){\n                if (quality <= 0) {\n                    quality = 1;\n                }\n                if (quality > 100) {\n                    quality = 100;\n                }\n\n                if(currentQuality == quality) return // don't recalc if unchanged\n\n                var sf = 0;\n                if (quality < 50) {\n                    sf = Math.floor(5000 / quality);\n                } else {\n                    sf = Math.floor(200 - quality*2);\n                }\n\n                initQuantTables(sf);\n                currentQuality = quality;\n                // console.log('Quality set to: '+quality +'%');\n            }\n\n            function init(){\n                // var time_start = new Date().getTime();\n                if(!quality) quality = 50;\n                // Create tables\n                initCharLookupTable()\n                initHuffmanTbl();\n                initCategoryNumber();\n                initRGBYUVTable();\n\n                setQuality(quality);\n                // var duration = new Date().getTime() - time_start;\n                // console.log('Initialization '+ duration + 'ms');\n            }\n\n            init();\n\n        };\n\n        JPEGEncoder.encode = function( data, quality ) {\n            var encoder = new JPEGEncoder( quality );\n\n            return encoder.encode( data );\n        }\n\n        return JPEGEncoder;\n    });\n    /**\n     * @fileOverview Fix android canvas.toDataUrl bug.\n     */\n    define('runtime/html5/androidpatch',[\n        'runtime/html5/util',\n        'runtime/html5/jpegencoder',\n        'base'\n    ], function( Util, encoder, Base ) {\n        var origin = Util.canvasToDataUrl,\n            supportJpeg;\n\n        Util.canvasToDataUrl = function( canvas, type, quality ) {\n            var ctx, w, h, fragement, parts;\n\n            // 非android手机直接跳过。\n            if ( !Base.os.android ) {\n                return origin.apply( null, arguments );\n            }\n\n            // 检测是否canvas支持jpeg导出，根据数据格式来判断。\n            // JPEG 前两位分别是：255, 216\n            if ( type === 'image/jpeg' && typeof supportJpeg === 'undefined' ) {\n                fragement = origin.apply( null, arguments );\n\n                parts = fragement.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    fragement = atob( parts[ 1 ] );\n                } else {\n                    fragement = decodeURIComponent( parts[ 1 ] );\n                }\n\n                fragement = fragement.substring( 0, 2 );\n\n                supportJpeg = fragement.charCodeAt( 0 ) === 255 &&\n                        fragement.charCodeAt( 1 ) === 216;\n            }\n\n            // 只有在android环境下才修复\n            if ( type === 'image/jpeg' && !supportJpeg ) {\n                w = canvas.width;\n                h = canvas.height;\n                ctx = canvas.getContext('2d');\n\n                return encoder.encode( ctx.getImageData( 0, 0, w, h ), quality );\n            }\n\n            return origin.apply( null, arguments );\n        };\n    });\n    /**\n     * @fileOverview Transport\n     * @todo 支持chunked传输，优势：\n     * 可以将大文件分成小块，挨个传输，可以提高大文件成功率，当失败的时候，也只需要重传那小部分，\n     * 而不需要重头再传一次。另外断点续传也需要用chunked方式。\n     */\n    define('runtime/html5/transport',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var noop = Base.noop,\n            $ = Base.$;\n\n        return Html5Runtime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    formData, binary, fr;\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.getSource();\n                } else {\n                    formData = new FormData();\n                    $.each( owner._formData, function( k, v ) {\n                        formData.append( k, v );\n                    });\n\n                    formData.append( opts.fileVal, blob.getSource(),\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                if ( opts.withCredentials && 'withCredentials' in xhr ) {\n                    xhr.open( opts.method, server, true );\n                    xhr.withCredentials = true;\n                } else {\n                    xhr.open( opts.method, server );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n\n                if ( binary ) {\n                    // 强制设置成 content-type 为文件流。\n                    xhr.overrideMimeType &&\n                            xhr.overrideMimeType('application/octet-stream');\n\n                    // android直接发送blob会导致服务端接收到的是空文件。\n                    // bug详情。\n                    // https://code.google.com/p/android/issues/detail?id=39882\n                    // 所以先用fileReader读取出来再通过arraybuffer的方式发送。\n                    if ( Base.os.android ) {\n                        fr = new FileReader();\n\n                        fr.onload = function() {\n                            xhr.send( this.result );\n                            fr = fr.onload = null;\n                        };\n\n                        fr.readAsArrayBuffer( binary );\n                    } else {\n                        xhr.send( binary );\n                    }\n                } else {\n                    xhr.send( formData );\n                }\n            },\n\n            getResponse: function() {\n                return this._response;\n            },\n\n            getResponseAsJson: function() {\n                return this._parseJson( this._response );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    xhr.abort();\n\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new XMLHttpRequest(),\n                    opts = this.options;\n\n                if ( opts.withCredentials && !('withCredentials' in xhr) &&\n                        typeof XDomainRequest !== 'undefined' ) {\n                    xhr = new XDomainRequest();\n                }\n\n                xhr.upload.onprogress = function( e ) {\n                    var percentage = 0;\n\n                    if ( e.lengthComputable ) {\n                        percentage = e.loaded / e.total;\n                    }\n\n                    return me.trigger( 'progress', percentage );\n                };\n\n                xhr.onreadystatechange = function() {\n\n                    if ( xhr.readyState !== 4 ) {\n                        return;\n                    }\n\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    me._xhr = null;\n                    me._status = xhr.status;\n\n                    if ( xhr.status >= 200 && xhr.status < 300 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger('load');\n                    } else if ( xhr.status >= 500 && xhr.status < 600 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger( 'error', 'server' );\n                    }\n\n\n                    return me.trigger( 'error', me._status ? 'http' : 'abort' );\n                };\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.setRequestHeader( key, val );\n                });\n            },\n\n            _parseJson: function( str ) {\n                var json;\n\n                try {\n                    json = JSON.parse( str );\n                } catch ( ex ) {\n                    json = {};\n                }\n\n                return json;\n            }\n        });\n    });\n    define('webuploader',[\n        'base',\n        'widgets/filepicker',\n        'widgets/image',\n        'widgets/queue',\n        'widgets/runtime',\n        'widgets/upload',\n        'widgets/log',\n        'runtime/html5/blob',\n        'runtime/html5/filepicker',\n        'runtime/html5/imagemeta/exif',\n        'runtime/html5/image',\n        'runtime/html5/androidpatch',\n        'runtime/html5/transport'\n    ], function( Base ) {\n        return Base;\n    });\n    return require('webuploader');\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.fis.js",
    "content": "/*! WebUploader 0.1.5 */\n\n\nvar jQuery = require('example:widget/ui/jquery/jquery.js')\n\nreturn (function( root, factory ) {\n    var modules = {},\n\n        // 内部require, 简单不完全实现。\n        // https://github.com/amdjs/amdjs-api/wiki/require\n        _require = function( deps, callback ) {\n            var args, len, i;\n\n            // 如果deps不是数组，则直接返回指定module\n            if ( typeof deps === 'string' ) {\n                return getModule( deps );\n            } else {\n                args = [];\n                for( len = deps.length, i = 0; i < len; i++ ) {\n                    args.push( getModule( deps[ i ] ) );\n                }\n\n                return callback.apply( null, args );\n            }\n        },\n\n        // 内部define，暂时不支持不指定id.\n        _define = function( id, deps, factory ) {\n            if ( arguments.length === 2 ) {\n                factory = deps;\n                deps = null;\n            }\n\n            _require( deps || [], function() {\n                setModule( id, factory, arguments );\n            });\n        },\n\n        // 设置module, 兼容CommonJs写法。\n        setModule = function( id, factory, args ) {\n            var module = {\n                    exports: factory\n                },\n                returned;\n\n            if ( typeof factory === 'function' ) {\n                args.length || (args = [ _require, module.exports, module ]);\n                returned = factory.apply( null, args );\n                returned !== undefined && (module.exports = returned);\n            }\n\n            modules[ id ] = module.exports;\n        },\n\n        // 根据id获取module\n        getModule = function( id ) {\n            var module = modules[ id ] || root[ id ];\n\n            if ( !module ) {\n                throw new Error( '`' + id + '` is undefined' );\n            }\n\n            return module;\n        },\n\n        // 将所有modules，将路径ids装换成对象。\n        exportsTo = function( obj ) {\n            var key, host, parts, part, last, ucFirst;\n\n            // make the first character upper case.\n            ucFirst = function( str ) {\n                return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 ));\n            };\n\n            for ( key in modules ) {\n                host = obj;\n\n                if ( !modules.hasOwnProperty( key ) ) {\n                    continue;\n                }\n\n                parts = key.split('/');\n                last = ucFirst( parts.pop() );\n\n                while( (part = ucFirst( parts.shift() )) ) {\n                    host[ part ] = host[ part ] || {};\n                    host = host[ part ];\n                }\n\n                host[ last ] = modules[ key ];\n            }\n\n            return obj;\n        },\n\n        makeExport = function( dollar ) {\n            root.__dollar = dollar;\n\n            // exports every module.\n            return exportsTo( factory( root, _define, _require ) );\n        };\n\n    return makeExport( jQuery );\n})( window, function( window, define, require ) {\n\n\n    /**\n     * @fileOverview jQuery or Zepto\n     */\n    define('dollar-third',[],function() {\n        var $ = window.__dollar || window.jQuery || window.Zepto;\n\n        if ( !$ ) {\n            throw new Error('jQuery or Zepto not found!');\n        }\n\n        return $;\n    });\n    /**\n     * @fileOverview Dom 操作相关\n     */\n    define('dollar',[\n        'dollar-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 使用jQuery的Promise\n     */\n    define('promise-third',[\n        'dollar'\n    ], function( $ ) {\n        return {\n            Deferred: $.Deferred,\n            when: $.when,\n\n            isPromise: function( anything ) {\n                return anything && typeof anything.then === 'function';\n            }\n        };\n    });\n    /**\n     * @fileOverview Promise/A+\n     */\n    define('promise',[\n        'promise-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 基础类方法。\n     */\n\n    /**\n     * Web Uploader内部类的详细说明，以下提及的功能类，都可以在`WebUploader`这个变量中访问到。\n     *\n     * As you know, Web Uploader的每个文件都是用过[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)规范中的`define`组织起来的, 每个Module都会有个module id.\n     * 默认module id为该文件的路径，而此路径将会转化成名字空间存放在WebUploader中。如：\n     *\n     * * module `base`：WebUploader.Base\n     * * module `file`: WebUploader.File\n     * * module `lib/dnd`: WebUploader.Lib.Dnd\n     * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd\n     *\n     *\n     * 以下文档中对类的使用可能省略掉了`WebUploader`前缀。\n     * @module WebUploader\n     * @title WebUploader API文档\n     */\n    define('base',[\n        'dollar',\n        'promise'\n    ], function( $, promise ) {\n\n        var noop = function() {},\n            call = Function.call;\n\n        // http://jsperf.com/uncurrythis\n        // 反科里化\n        function uncurryThis( fn ) {\n            return function() {\n                return call.apply( fn, arguments );\n            };\n        }\n\n        function bindFn( fn, context ) {\n            return function() {\n                return fn.apply( context, arguments );\n            };\n        }\n\n        function createObject( proto ) {\n            var f;\n\n            if ( Object.create ) {\n                return Object.create( proto );\n            } else {\n                f = function() {};\n                f.prototype = proto;\n                return new f();\n            }\n        }\n\n\n        /**\n         * 基础类，提供一些简单常用的方法。\n         * @class Base\n         */\n        return {\n\n            /**\n             * @property {String} version 当前版本号。\n             */\n            version: '0.1.5',\n\n            /**\n             * @property {jQuery|Zepto} $ 引用依赖的jQuery或者Zepto对象。\n             */\n            $: $,\n\n            Deferred: promise.Deferred,\n\n            isPromise: promise.isPromise,\n\n            when: promise.when,\n\n            /**\n             * @description  简单的浏览器检查结果。\n             *\n             * * `webkit`  webkit版本号，如果浏览器为非webkit内核，此属性为`undefined`。\n             * * `chrome`  chrome浏览器版本号，如果浏览器为chrome，此属性为`undefined`。\n             * * `ie`  ie浏览器版本号，如果浏览器为非ie，此属性为`undefined`。**暂不支持ie10+**\n             * * `firefox`  firefox浏览器版本号，如果浏览器为非firefox，此属性为`undefined`。\n             * * `safari`  safari浏览器版本号，如果浏览器为非safari，此属性为`undefined`。\n             * * `opera`  opera浏览器版本号，如果浏览器为非opera，此属性为`undefined`。\n             *\n             * @property {Object} [browser]\n             */\n            browser: (function( ua ) {\n                var ret = {},\n                    webkit = ua.match( /WebKit\\/([\\d.]+)/ ),\n                    chrome = ua.match( /Chrome\\/([\\d.]+)/ ) ||\n                        ua.match( /CriOS\\/([\\d.]+)/ ),\n\n                    ie = ua.match( /MSIE\\s([\\d\\.]+)/ ) ||\n                        ua.match( /(?:trident)(?:.*rv:([\\w.]+))?/i ),\n                    firefox = ua.match( /Firefox\\/([\\d.]+)/ ),\n                    safari = ua.match( /Safari\\/([\\d.]+)/ ),\n                    opera = ua.match( /OPR\\/([\\d.]+)/ );\n\n                webkit && (ret.webkit = parseFloat( webkit[ 1 ] ));\n                chrome && (ret.chrome = parseFloat( chrome[ 1 ] ));\n                ie && (ret.ie = parseFloat( ie[ 1 ] ));\n                firefox && (ret.firefox = parseFloat( firefox[ 1 ] ));\n                safari && (ret.safari = parseFloat( safari[ 1 ] ));\n                opera && (ret.opera = parseFloat( opera[ 1 ] ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * @description  操作系统检查结果。\n             *\n             * * `android`  如果在android浏览器环境下，此值为对应的android版本号，否则为`undefined`。\n             * * `ios` 如果在ios浏览器环境下，此值为对应的ios版本号，否则为`undefined`。\n             * @property {Object} [os]\n             */\n            os: (function( ua ) {\n                var ret = {},\n\n                    // osx = !!ua.match( /\\(Macintosh\\; Intel / ),\n                    android = ua.match( /(?:Android);?[\\s\\/]+([\\d.]+)?/ ),\n                    ios = ua.match( /(?:iPad|iPod|iPhone).*OS\\s([\\d_]+)/ );\n\n                // osx && (ret.osx = true);\n                android && (ret.android = parseFloat( android[ 1 ] ));\n                ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * 实现类与类之间的继承。\n             * @method inherits\n             * @grammar Base.inherits( super ) => child\n             * @grammar Base.inherits( super, protos ) => child\n             * @grammar Base.inherits( super, protos, statics ) => child\n             * @param  {Class} super 父类\n             * @param  {Object | Function} [protos] 子类或者对象。如果对象中包含constructor，子类将是用此属性值。\n             * @param  {Function} [protos.constructor] 子类构造器，不指定的话将创建个临时的直接执行父类构造器的方法。\n             * @param  {Object} [statics] 静态属性或方法。\n             * @return {Class} 返回子类。\n             * @example\n             * function Person() {\n             *     console.log( 'Super' );\n             * }\n             * Person.prototype.hello = function() {\n             *     console.log( 'hello' );\n             * };\n             *\n             * var Manager = Base.inherits( Person, {\n             *     world: function() {\n             *         console.log( 'World' );\n             *     }\n             * });\n             *\n             * // 因为没有指定构造器，父类的构造器将会执行。\n             * var instance = new Manager();    // => Super\n             *\n             * // 继承子父类的方法\n             * instance.hello();    // => hello\n             * instance.world();    // => World\n             *\n             * // 子类的__super__属性指向父类\n             * console.log( Manager.__super__ === Person );    // => true\n             */\n            inherits: function( Super, protos, staticProtos ) {\n                var child;\n\n                if ( typeof protos === 'function' ) {\n                    child = protos;\n                    protos = null;\n                } else if ( protos && protos.hasOwnProperty('constructor') ) {\n                    child = protos.constructor;\n                } else {\n                    child = function() {\n                        return Super.apply( this, arguments );\n                    };\n                }\n\n                // 复制静态方法\n                $.extend( true, child, Super, staticProtos || {} );\n\n                /* jshint camelcase: false */\n\n                // 让子类的__super__属性指向父类。\n                child.__super__ = Super.prototype;\n\n                // 构建原型，添加原型方法或属性。\n                // 暂时用Object.create实现。\n                child.prototype = createObject( Super.prototype );\n                protos && $.extend( true, child.prototype, protos );\n\n                return child;\n            },\n\n            /**\n             * 一个不做任何事情的方法。可以用来赋值给默认的callback.\n             * @method noop\n             */\n            noop: noop,\n\n            /**\n             * 返回一个新的方法，此方法将已指定的`context`来执行。\n             * @grammar Base.bindFn( fn, context ) => Function\n             * @method bindFn\n             * @example\n             * var doSomething = function() {\n             *         console.log( this.name );\n             *     },\n             *     obj = {\n             *         name: 'Object Name'\n             *     },\n             *     aliasFn = Base.bind( doSomething, obj );\n             *\n             *  aliasFn();    // => Object Name\n             *\n             */\n            bindFn: bindFn,\n\n            /**\n             * 引用Console.log如果存在的话，否则引用一个[空函数noop](#WebUploader:Base.noop)。\n             * @grammar Base.log( args... ) => undefined\n             * @method log\n             */\n            log: (function() {\n                if ( window.console ) {\n                    return bindFn( console.log, console );\n                }\n                return noop;\n            })(),\n\n            nextTick: (function() {\n\n                return function( cb ) {\n                    setTimeout( cb, 1 );\n                };\n\n                // @bug 当浏览器不在当前窗口时就停了。\n                // var next = window.requestAnimationFrame ||\n                //     window.webkitRequestAnimationFrame ||\n                //     window.mozRequestAnimationFrame ||\n                //     function( cb ) {\n                //         window.setTimeout( cb, 1000 / 60 );\n                //     };\n\n                // // fix: Uncaught TypeError: Illegal invocation\n                // return bindFn( next, window );\n            })(),\n\n            /**\n             * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的数组slice方法。\n             * 将用来将非数组对象转化成数组对象。\n             * @grammar Base.slice( target, start[, end] ) => Array\n             * @method slice\n             * @example\n             * function doSomthing() {\n             *     var args = Base.slice( arguments, 1 );\n             *     console.log( args );\n             * }\n             *\n             * doSomthing( 'ignored', 'arg2', 'arg3' );    // => Array [\"arg2\", \"arg3\"]\n             */\n            slice: uncurryThis( [].slice ),\n\n            /**\n             * 生成唯一的ID\n             * @method guid\n             * @grammar Base.guid() => String\n             * @grammar Base.guid( prefx ) => String\n             */\n            guid: (function() {\n                var counter = 0;\n\n                return function( prefix ) {\n                    var guid = (+new Date()).toString( 32 ),\n                        i = 0;\n\n                    for ( ; i < 5; i++ ) {\n                        guid += Math.floor( Math.random() * 65535 ).toString( 32 );\n                    }\n\n                    return (prefix || 'wu_') + guid + (counter++).toString( 32 );\n                };\n            })(),\n\n            /**\n             * 格式化文件大小, 输出成带单位的字符串\n             * @method formatSize\n             * @grammar Base.formatSize( size ) => String\n             * @grammar Base.formatSize( size, pointLength ) => String\n             * @grammar Base.formatSize( size, pointLength, units ) => String\n             * @param {Number} size 文件大小\n             * @param {Number} [pointLength=2] 精确到的小数点数。\n             * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 单位数组。从字节，到千字节，一直往上指定。如果单位数组里面只指定了到了K(千字节)，同时文件大小大于M, 此方法的输出将还是显示成多少K.\n             * @example\n             * console.log( Base.formatSize( 100 ) );    // => 100B\n             * console.log( Base.formatSize( 1024 ) );    // => 1.00K\n             * console.log( Base.formatSize( 1024, 0 ) );    // => 1K\n             * console.log( Base.formatSize( 1024 * 1024 ) );    // => 1.00M\n             * console.log( Base.formatSize( 1024 * 1024 * 1024 ) );    // => 1.00G\n             * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) );    // => 1024MB\n             */\n            formatSize: function( size, pointLength, units ) {\n                var unit;\n\n                units = units || [ 'B', 'K', 'M', 'G', 'TB' ];\n\n                while ( (unit = units.shift()) && size > 1024 ) {\n                    size = size / 1024;\n                }\n\n                return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) +\n                        unit;\n            }\n        };\n    });\n    /**\n     * 事件处理类，可以独立使用，也可以扩展给对象使用。\n     * @fileOverview Mediator\n     */\n    define('mediator',[\n        'base'\n    ], function( Base ) {\n        var $ = Base.$,\n            slice = [].slice,\n            separator = /\\s+/,\n            protos;\n\n        // 根据条件过滤出事件handlers.\n        function findHandlers( arr, name, callback, context ) {\n            return $.grep( arr, function( handler ) {\n                return handler &&\n                        (!name || handler.e === name) &&\n                        (!callback || handler.cb === callback ||\n                        handler.cb._cb === callback) &&\n                        (!context || handler.ctx === context);\n            });\n        }\n\n        function eachEvent( events, callback, iterator ) {\n            // 不支持对象，只支持多个event用空格隔开\n            $.each( (events || '').split( separator ), function( _, key ) {\n                iterator( key, callback );\n            });\n        }\n\n        function triggerHanders( events, args ) {\n            var stoped = false,\n                i = -1,\n                len = events.length,\n                handler;\n\n            while ( ++i < len ) {\n                handler = events[ i ];\n\n                if ( handler.cb.apply( handler.ctx2, args ) === false ) {\n                    stoped = true;\n                    break;\n                }\n            }\n\n            return !stoped;\n        }\n\n        protos = {\n\n            /**\n             * 绑定事件。\n             *\n             * `callback`方法在执行时，arguments将会来源于trigger的时候携带的参数。如\n             * ```javascript\n             * var obj = {};\n             *\n             * // 使得obj有事件行为\n             * Mediator.installTo( obj );\n             *\n             * obj.on( 'testa', function( arg1, arg2 ) {\n             *     console.log( arg1, arg2 ); // => 'arg1', 'arg2'\n             * });\n             *\n             * obj.trigger( 'testa', 'arg1', 'arg2' );\n             * ```\n             *\n             * 如果`callback`中，某一个方法`return false`了，则后续的其他`callback`都不会被执行到。\n             * 切会影响到`trigger`方法的返回值，为`false`。\n             *\n             * `on`还可以用来添加一个特殊事件`all`, 这样所有的事件触发都会响应到。同时此类`callback`中的arguments有一个不同处，\n             * 就是第一个参数为`type`，记录当前是什么事件在触发。此类`callback`的优先级比脚低，会再正常`callback`执行完后触发。\n             * ```javascript\n             * obj.on( 'all', function( type, arg1, arg2 ) {\n             *     console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2'\n             * });\n             * ```\n             *\n             * @method on\n             * @grammar on( name, callback[, context] ) => self\n             * @param  {String}   name     事件名，支持多个事件用空格隔开\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             * @class Mediator\n             */\n            on: function( name, callback, context ) {\n                var me = this,\n                    set;\n\n                if ( !callback ) {\n                    return this;\n                }\n\n                set = this._events || (this._events = []);\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var handler = { e: name };\n\n                    handler.cb = callback;\n                    handler.ctx = context;\n                    handler.ctx2 = context || me;\n                    handler.id = set.length;\n\n                    set.push( handler );\n                });\n\n                return this;\n            },\n\n            /**\n             * 绑定事件，且当handler执行完后，自动解除绑定。\n             * @method once\n             * @grammar once( name, callback[, context] ) => self\n             * @param  {String}   name     事件名\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            once: function( name, callback, context ) {\n                var me = this;\n\n                if ( !callback ) {\n                    return me;\n                }\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var once = function() {\n                            me.off( name, once );\n                            return callback.apply( context || me, arguments );\n                        };\n\n                    once._cb = callback;\n                    me.on( name, once, context );\n                });\n\n                return me;\n            },\n\n            /**\n             * 解除事件绑定\n             * @method off\n             * @grammar off( [name[, callback[, context] ] ] ) => self\n             * @param  {String}   [name]     事件名\n             * @param  {Function} [callback] 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            off: function( name, cb, ctx ) {\n                var events = this._events;\n\n                if ( !events ) {\n                    return this;\n                }\n\n                if ( !name && !cb && !ctx ) {\n                    this._events = [];\n                    return this;\n                }\n\n                eachEvent( name, cb, function( name, cb ) {\n                    $.each( findHandlers( events, name, cb, ctx ), function() {\n                        delete events[ this.id ];\n                    });\n                });\n\n                return this;\n            },\n\n            /**\n             * 触发事件\n             * @method trigger\n             * @grammar trigger( name[, args...] ) => self\n             * @param  {String}   type     事件名\n             * @param  {*} [...] 任意参数\n             * @return {Boolean} 如果handler中return false了，则返回false, 否则返回true\n             */\n            trigger: function( type ) {\n                var args, events, allEvents;\n\n                if ( !this._events || !type ) {\n                    return this;\n                }\n\n                args = slice.call( arguments, 1 );\n                events = findHandlers( this._events, type );\n                allEvents = findHandlers( this._events, 'all' );\n\n                return triggerHanders( events, args ) &&\n                        triggerHanders( allEvents, arguments );\n            }\n        };\n\n        /**\n         * 中介者，它本身是个单例，但可以通过[installTo](#WebUploader:Mediator:installTo)方法，使任何对象具备事件行为。\n         * 主要目的是负责模块与模块之间的合作，降低耦合度。\n         *\n         * @class Mediator\n         */\n        return $.extend({\n\n            /**\n             * 可以通过这个接口，使任何对象具备事件功能。\n             * @method installTo\n             * @param  {Object} obj 需要具备事件行为的对象。\n             * @return {Object} 返回obj.\n             */\n            installTo: function( obj ) {\n                return $.extend( obj, protos );\n            }\n\n        }, protos );\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('uploader',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$;\n\n        /**\n         * 上传入口类。\n         * @class Uploader\n         * @constructor\n         * @grammar new Uploader( opts ) => Uploader\n         * @example\n         * var uploader = WebUploader.Uploader({\n         *     swf: 'path_of_swf/Uploader.swf',\n         *\n         *     // 开起分片上传。\n         *     chunked: true\n         * });\n         */\n        function Uploader( opts ) {\n            this.options = $.extend( true, {}, Uploader.options, opts );\n            this._init( this.options );\n        }\n\n        // default Options\n        // widgets中有相应扩展\n        Uploader.options = {};\n        Mediator.installTo( Uploader.prototype );\n\n        // 批量添加纯命令式方法。\n        $.each({\n            upload: 'start-upload',\n            stop: 'stop-upload',\n            getFile: 'get-file',\n            getFiles: 'get-files',\n            addFile: 'add-file',\n            addFiles: 'add-file',\n            sort: 'sort-files',\n            removeFile: 'remove-file',\n            cancelFile: 'cancel-file',\n            skipFile: 'skip-file',\n            retry: 'retry',\n            isInProgress: 'is-in-progress',\n            makeThumb: 'make-thumb',\n            md5File: 'md5-file',\n            getDimension: 'get-dimension',\n            addButton: 'add-btn',\n            predictRuntimeType: 'predict-runtime-type',\n            refresh: 'refresh',\n            disable: 'disable',\n            enable: 'enable',\n            reset: 'reset'\n        }, function( fn, command ) {\n            Uploader.prototype[ fn ] = function() {\n                return this.request( command, arguments );\n            };\n        });\n\n        $.extend( Uploader.prototype, {\n            state: 'pending',\n\n            _init: function( opts ) {\n                var me = this;\n\n                me.request( 'init', opts, function() {\n                    me.state = 'ready';\n                    me.trigger('ready');\n                });\n            },\n\n            /**\n             * 获取或者设置Uploader配置项。\n             * @method option\n             * @grammar option( key ) => *\n             * @grammar option( key, val ) => self\n             * @example\n             *\n             * // 初始状态图片上传前不会压缩\n             * var uploader = new WebUploader.Uploader({\n             *     compress: null;\n             * });\n             *\n             * // 修改后图片上传前，尝试将图片压缩到1600 * 1600\n             * uploader.option( 'compress', {\n             *     width: 1600,\n             *     height: 1600\n             * });\n             */\n            option: function( key, val ) {\n                var opts = this.options;\n\n                // setter\n                if ( arguments.length > 1 ) {\n\n                    if ( $.isPlainObject( val ) &&\n                            $.isPlainObject( opts[ key ] ) ) {\n                        $.extend( opts[ key ], val );\n                    } else {\n                        opts[ key ] = val;\n                    }\n\n                } else {    // getter\n                    return key ? opts[ key ] : opts;\n                }\n            },\n\n            /**\n             * 获取文件统计信息。返回一个包含一下信息的对象。\n             * * `successNum` 上传成功的文件数\n             * * `progressNum` 上传中的文件数\n             * * `cancelNum` 被删除的文件数\n             * * `invalidNum` 无效的文件数\n             * * `uploadFailNum` 上传失败的文件数\n             * * `queueNum` 还在队列中的文件数\n             * * `interruptNum` 被暂停的文件数\n             * @method getStats\n             * @grammar getStats() => Object\n             */\n            getStats: function() {\n                // return this._mgr.getStats.apply( this._mgr, arguments );\n                var stats = this.request('get-stats');\n\n                return stats ? {\n                    successNum: stats.numOfSuccess,\n                    progressNum: stats.numOfProgress,\n\n                    // who care?\n                    // queueFailNum: 0,\n                    cancelNum: stats.numOfCancel,\n                    invalidNum: stats.numOfInvalid,\n                    uploadFailNum: stats.numOfUploadFailed,\n                    queueNum: stats.numOfQueue,\n                    interruptNum: stats.numofInterrupt\n                } : {};\n            },\n\n            // 需要重写此方法来来支持opts.onEvent和instance.onEvent的处理器\n            trigger: function( type/*, args...*/ ) {\n                var args = [].slice.call( arguments, 1 ),\n                    opts = this.options,\n                    name = 'on' + type.substring( 0, 1 ).toUpperCase() +\n                        type.substring( 1 );\n\n                if (\n                        // 调用通过on方法注册的handler.\n                        Mediator.trigger.apply( this, arguments ) === false ||\n\n                        // 调用opts.onEvent\n                        $.isFunction( opts[ name ] ) &&\n                        opts[ name ].apply( this, args ) === false ||\n\n                        // 调用this.onEvent\n                        $.isFunction( this[ name ] ) &&\n                        this[ name ].apply( this, args ) === false ||\n\n                        // 广播所有uploader的事件。\n                        Mediator.trigger.apply( Mediator,\n                        [ this, type ].concat( args ) ) === false ) {\n\n                    return false;\n                }\n\n                return true;\n            },\n\n            /**\n             * 销毁 webuploader 实例\n             * @method destroy\n             * @grammar destroy() => undefined\n             */\n            destroy: function() {\n                this.request( 'destroy', arguments );\n                this.off();\n            },\n\n            // widgets/widget.js将补充此方法的详细文档。\n            request: Base.noop\n        });\n\n        /**\n         * 创建Uploader实例，等同于new Uploader( opts );\n         * @method create\n         * @class Base\n         * @static\n         * @grammar Base.create( opts ) => Uploader\n         */\n        Base.create = Uploader.create = function( opts ) {\n            return new Uploader( opts );\n        };\n\n        // 暴露Uploader，可以通过它来扩展业务逻辑。\n        Base.Uploader = Uploader;\n\n        return Uploader;\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/runtime',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            factories = {},\n\n            // 获取对象的第一个key\n            getFirstKey = function( obj ) {\n                for ( var key in obj ) {\n                    if ( obj.hasOwnProperty( key ) ) {\n                        return key;\n                    }\n                }\n                return null;\n            };\n\n        // 接口类。\n        function Runtime( options ) {\n            this.options = $.extend({\n                container: document.body\n            }, options );\n            this.uid = Base.guid('rt_');\n        }\n\n        $.extend( Runtime.prototype, {\n\n            getContainer: function() {\n                var opts = this.options,\n                    parent, container;\n\n                if ( this._container ) {\n                    return this._container;\n                }\n\n                parent = $( opts.container || document.body );\n                container = $( document.createElement('div') );\n\n                container.attr( 'id', 'rt_' + this.uid );\n                container.css({\n                    position: 'absolute',\n                    top: '0px',\n                    left: '0px',\n                    width: '1px',\n                    height: '1px',\n                    overflow: 'hidden'\n                });\n\n                parent.append( container );\n                parent.addClass('webuploader-container');\n                this._container = container;\n                this._parent = parent;\n                return container;\n            },\n\n            init: Base.noop,\n            exec: Base.noop,\n\n            destroy: function() {\n                this._container && this._container.remove();\n                this._parent && this._parent.removeClass('webuploader-container');\n                this.off();\n            }\n        });\n\n        Runtime.orders = 'html5,flash';\n\n\n        /**\n         * 添加Runtime实现。\n         * @param {String} type    类型\n         * @param {Runtime} factory 具体Runtime实现。\n         */\n        Runtime.addRuntime = function( type, factory ) {\n            factories[ type ] = factory;\n        };\n\n        Runtime.hasRuntime = function( type ) {\n            return !!(type ? factories[ type ] : getFirstKey( factories ));\n        };\n\n        Runtime.create = function( opts, orders ) {\n            var type, runtime;\n\n            orders = orders || Runtime.orders;\n            $.each( orders.split( /\\s*,\\s*/g ), function() {\n                if ( factories[ this ] ) {\n                    type = this;\n                    return false;\n                }\n            });\n\n            type = type || getFirstKey( factories );\n\n            if ( !type ) {\n                throw new Error('Runtime Error');\n            }\n\n            runtime = new factories[ type ]( opts );\n            return runtime;\n        };\n\n        Mediator.installTo( Runtime.prototype );\n        return Runtime;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/client',[\n        'base',\n        'mediator',\n        'runtime/runtime'\n    ], function( Base, Mediator, Runtime ) {\n\n        var cache;\n\n        cache = (function() {\n            var obj = {};\n\n            return {\n                add: function( runtime ) {\n                    obj[ runtime.uid ] = runtime;\n                },\n\n                get: function( ruid, standalone ) {\n                    var i;\n\n                    if ( ruid ) {\n                        return obj[ ruid ];\n                    }\n\n                    for ( i in obj ) {\n                        // 有些类型不能重用，比如filepicker.\n                        if ( standalone && obj[ i ].__standalone ) {\n                            continue;\n                        }\n\n                        return obj[ i ];\n                    }\n\n                    return null;\n                },\n\n                remove: function( runtime ) {\n                    delete obj[ runtime.uid ];\n                }\n            };\n        })();\n\n        function RuntimeClient( component, standalone ) {\n            var deferred = Base.Deferred(),\n                runtime;\n\n            this.uid = Base.guid('client_');\n\n            // 允许runtime没有初始化之前，注册一些方法在初始化后执行。\n            this.runtimeReady = function( cb ) {\n                return deferred.done( cb );\n            };\n\n            this.connectRuntime = function( opts, cb ) {\n\n                // already connected.\n                if ( runtime ) {\n                    throw new Error('already connected!');\n                }\n\n                deferred.done( cb );\n\n                if ( typeof opts === 'string' && cache.get( opts ) ) {\n                    runtime = cache.get( opts );\n                }\n\n                // 像filePicker只能独立存在，不能公用。\n                runtime = runtime || cache.get( null, standalone );\n\n                // 需要创建\n                if ( !runtime ) {\n                    runtime = Runtime.create( opts, opts.runtimeOrder );\n                    runtime.__promise = deferred.promise();\n                    runtime.once( 'ready', deferred.resolve );\n                    runtime.init();\n                    cache.add( runtime );\n                    runtime.__client = 1;\n                } else {\n                    // 来自cache\n                    Base.$.extend( runtime.options, opts );\n                    runtime.__promise.then( deferred.resolve );\n                    runtime.__client++;\n                }\n\n                standalone && (runtime.__standalone = standalone);\n                return runtime;\n            };\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.disconnectRuntime = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                runtime.__client--;\n\n                if ( runtime.__client <= 0 ) {\n                    cache.remove( runtime );\n                    delete runtime.__promise;\n                    runtime.destroy();\n                }\n\n                runtime = null;\n            };\n\n            this.exec = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                var args = Base.slice( arguments );\n                component && args.unshift( component );\n\n                return runtime.exec.apply( this, args );\n            };\n\n            this.getRuid = function() {\n                return runtime && runtime.uid;\n            };\n\n            this.destroy = (function( destroy ) {\n                return function() {\n                    destroy && destroy.apply( this, arguments );\n                    this.trigger('destroy');\n                    this.off();\n                    this.exec('destroy');\n                    this.disconnectRuntime();\n                };\n            })( this.destroy );\n        }\n\n        Mediator.installTo( RuntimeClient.prototype );\n        return RuntimeClient;\n    });\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/dnd',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function DragAndDrop( opts ) {\n            opts = this.options = $.extend({}, DragAndDrop.options, opts );\n\n            opts.container = $( opts.container );\n\n            if ( !opts.container.length ) {\n                return;\n            }\n\n            RuntimeClent.call( this, 'DragAndDrop' );\n        }\n\n        DragAndDrop.options = {\n            accept: null,\n            disableGlobalDnd: false\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: DragAndDrop,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( DragAndDrop.prototype );\n\n        return DragAndDrop;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/widget',[\n        'base',\n        'uploader'\n    ], function( Base, Uploader ) {\n\n        var $ = Base.$,\n            _init = Uploader.prototype._init,\n            _destroy = Uploader.prototype.destroy,\n            IGNORE = {},\n            widgetClass = [];\n\n        function isArrayLike( obj ) {\n            if ( !obj ) {\n                return false;\n            }\n\n            var length = obj.length,\n                type = $.type( obj );\n\n            if ( obj.nodeType === 1 && length ) {\n                return true;\n            }\n\n            return type === 'array' || type !== 'function' && type !== 'string' &&\n                    (length === 0 || typeof length === 'number' && length > 0 &&\n                    (length - 1) in obj);\n        }\n\n        function Widget( uploader ) {\n            this.owner = uploader;\n            this.options = uploader.options;\n        }\n\n        $.extend( Widget.prototype, {\n\n            init: Base.noop,\n\n            // 类Backbone的事件监听声明，监听uploader实例上的事件\n            // widget直接无法监听事件，事件只能通过uploader来传递\n            invoke: function( apiName, args ) {\n\n                /*\n                    {\n                        'make-thumb': 'makeThumb'\n                    }\n                 */\n                var map = this.responseMap;\n\n                // 如果无API响应声明则忽略\n                if ( !map || !(apiName in map) || !(map[ apiName ] in this) ||\n                        !$.isFunction( this[ map[ apiName ] ] ) ) {\n\n                    return IGNORE;\n                }\n\n                return this[ map[ apiName ] ].apply( this, args );\n\n            },\n\n            /**\n             * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。\n             * @method request\n             * @grammar request( command, args ) => * | Promise\n             * @grammar request( command, args, callback ) => Promise\n             * @for  Uploader\n             */\n            request: function() {\n                return this.owner.request.apply( this.owner, arguments );\n            }\n        });\n\n        // 扩展Uploader.\n        $.extend( Uploader.prototype, {\n\n            /**\n             * @property {String | Array} [disableWidgets=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。\n             */\n\n            // 覆写_init用来初始化widgets\n            _init: function() {\n                var me = this,\n                    widgets = me._widgets = [],\n                    deactives = me.options.disableWidgets || '';\n\n                $.each( widgetClass, function( _, klass ) {\n                    (!deactives || !~deactives.indexOf( klass._name )) &&\n                        widgets.push( new klass( me ) );\n                });\n\n                return _init.apply( me, arguments );\n            },\n\n            request: function( apiName, args, callback ) {\n                var i = 0,\n                    widgets = this._widgets,\n                    len = widgets && widgets.length,\n                    rlts = [],\n                    dfds = [],\n                    widget, rlt, promise, key;\n\n                args = isArrayLike( args ) ? args : [ args ];\n\n                for ( ; i < len; i++ ) {\n                    widget = widgets[ i ];\n                    rlt = widget.invoke( apiName, args );\n\n                    if ( rlt !== IGNORE ) {\n\n                        // Deferred对象\n                        if ( Base.isPromise( rlt ) ) {\n                            dfds.push( rlt );\n                        } else {\n                            rlts.push( rlt );\n                        }\n                    }\n                }\n\n                // 如果有callback，则用异步方式。\n                if ( callback || dfds.length ) {\n                    promise = Base.when.apply( Base, dfds );\n                    key = promise.pipe ? 'pipe' : 'then';\n\n                    // 很重要不能删除。删除了会死循环。\n                    // 保证执行顺序。让callback总是在下一个 tick 中执行。\n                    return promise[ key ](function() {\n                                var deferred = Base.Deferred(),\n                                    args = arguments;\n\n                                if ( args.length === 1 ) {\n                                    args = args[ 0 ];\n                                }\n\n                                setTimeout(function() {\n                                    deferred.resolve( args );\n                                }, 1 );\n\n                                return deferred.promise();\n                            })[ callback ? key : 'done' ]( callback || Base.noop );\n                } else {\n                    return rlts[ 0 ];\n                }\n            },\n\n            destroy: function() {\n                _destroy.apply( this, arguments );\n                this._widgets = null;\n            }\n        });\n\n        /**\n         * 添加组件\n         * @grammar Uploader.register(proto);\n         * @grammar Uploader.register(map, proto);\n         * @param  {object} responseMap API 名称与函数实现的映射\n         * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义\n         * @method Uploader.register\n         * @for Uploader\n         * @example\n         * Uploader.register({\n         *     'make-thumb': 'makeThumb'\n         * }, {\n         *     init: function( options ) {},\n         *     makeThumb: function() {}\n         * });\n         *\n         * Uploader.register({\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         */\n        Uploader.register = Widget.register = function( responseMap, widgetProto ) {\n            var map = { init: 'init', destroy: 'destroy', name: 'anonymous' },\n                klass;\n\n            if ( arguments.length === 1 ) {\n                widgetProto = responseMap;\n\n                // 自动生成 map 表。\n                $.each(widgetProto, function(key) {\n                    if ( key[0] === '_' || key === 'name' ) {\n                        key === 'name' && (map.name = widgetProto.name);\n                        return;\n                    }\n\n                    map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;\n                });\n\n            } else {\n                map = $.extend( map, responseMap );\n            }\n\n            widgetProto.responseMap = map;\n            klass = Base.inherits( Widget, widgetProto );\n            klass._name = map.name;\n            widgetClass.push( klass );\n\n            return klass;\n        };\n\n        /**\n         * 删除插件，只有在注册时指定了名字的才能被删除。\n         * @grammar Uploader.unRegister(name);\n         * @param  {string} name 组件名字\n         * @method Uploader.unRegister\n         * @for Uploader\n         * @example\n         *\n         * Uploader.register({\n         *     name: 'custom',\n         *\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         *\n         * Uploader.unRegister('custom');\n         */\n        Uploader.unRegister = Widget.unRegister = function( name ) {\n            if ( !name || name === 'anonymous' ) {\n                return;\n            }\n\n            // 删除指定的插件。\n            for ( var i = widgetClass.length; i--; ) {\n                if ( widgetClass[i]._name === name ) {\n                    widgetClass.splice(i, 1)\n                }\n            }\n        };\n\n        return Widget;\n    });\n    /**\n     * @fileOverview DragAndDrop Widget。\n     */\n    define('widgets/filednd',[\n        'base',\n        'uploader',\n        'lib/dnd',\n        'widgets/widget'\n    ], function( Base, Uploader, Dnd ) {\n        var $ = Base.$;\n\n        Uploader.options.dnd = '';\n\n        /**\n         * @property {Selector} [dnd=undefined]  指定Drag And Drop拖拽的容器，如果不指定，则不启动。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @property {Selector} [disableGlobalDnd=false]  是否禁掉整个页面的拖拽功能，如果不禁用，图片拖进来的时候会默认被浏览器打开。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @event dndAccept\n         * @param {DataTransferItemList} items DataTransferItem\n         * @description 阻止此事件可以拒绝某些类型的文件拖入进来。目前只有 chrome 提供这样的 API，且只能通过 mime-type 验证。\n         * @for  Uploader\n         */\n        return Uploader.register({\n            name: 'dnd',\n\n            init: function( opts ) {\n\n                if ( !opts.dnd ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        disableGlobalDnd: opts.disableGlobalDnd,\n                        container: opts.dnd,\n                        accept: opts.accept\n                    }),\n                    dnd;\n\n                this.dnd = dnd = new Dnd( options );\n\n                dnd.once( 'ready', deferred.resolve );\n                dnd.on( 'drop', function( files ) {\n                    me.request( 'add-file', [ files ]);\n                });\n\n                // 检测文件是否全部允许添加。\n                dnd.on( 'accept', function( items ) {\n                    return me.owner.trigger( 'dndAccept', items );\n                });\n\n                dnd.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.dnd && this.dnd.destroy();\n            }\n        });\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepaste',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function FilePaste( opts ) {\n            opts = this.options = $.extend({}, opts );\n            opts.container = $( opts.container || document.body );\n            RuntimeClent.call( this, 'FilePaste' );\n        }\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePaste,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( FilePaste.prototype );\n\n        return FilePaste;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/filepaste',[\n        'base',\n        'uploader',\n        'lib/filepaste',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePaste ) {\n        var $ = Base.$;\n\n        /**\n         * @property {Selector} [paste=undefined]  指定监听paste事件的容器，如果不指定，不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为`document.body`.\n         * @namespace options\n         * @for Uploader\n         */\n        return Uploader.register({\n            name: 'paste',\n\n            init: function( opts ) {\n\n                if ( !opts.paste ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        container: opts.paste,\n                        accept: opts.accept\n                    }),\n                    paste;\n\n                this.paste = paste = new FilePaste( options );\n\n                paste.once( 'ready', deferred.resolve );\n                paste.on( 'paste', function( files ) {\n                    me.owner.request( 'add-file', [ files ]);\n                });\n                paste.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.paste && this.paste.destroy();\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob\n     */\n    define('lib/blob',[\n        'base',\n        'runtime/client'\n    ], function( Base, RuntimeClient ) {\n\n        function Blob( ruid, source ) {\n            var me = this;\n\n            me.source = source;\n            me.ruid = ruid;\n            this.size = source.size || 0;\n\n            // 如果没有指定 mimetype, 但是知道文件后缀。\n            if ( !source.type && this.ext &&\n                    ~'jpg,jpeg,png,gif,bmp'.indexOf( this.ext ) ) {\n                this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);\n            } else {\n                this.type = source.type || 'application/octet-stream';\n            }\n\n            RuntimeClient.call( me, 'Blob' );\n            this.uid = source.uid || this.uid;\n\n            if ( ruid ) {\n                me.connectRuntime( ruid );\n            }\n        }\n\n        Base.inherits( RuntimeClient, {\n            constructor: Blob,\n\n            slice: function( start, end ) {\n                return this.exec( 'slice', start, end );\n            },\n\n            getSource: function() {\n                return this.source;\n            }\n        });\n\n        return Blob;\n    });\n    /**\n     * 为了统一化Flash的File和HTML5的File而存在。\n     * 以至于要调用Flash里面的File，也可以像调用HTML5版本的File一下。\n     * @fileOverview File\n     */\n    define('lib/file',[\n        'base',\n        'lib/blob'\n    ], function( Base, Blob ) {\n\n        var uid = 1,\n            rExt = /\\.([^.]+)$/;\n\n        function File( ruid, file ) {\n            var ext;\n\n            this.name = file.name || ('untitled' + uid++);\n            ext = rExt.exec( file.name ) ? RegExp.$1.toLowerCase() : '';\n\n            // todo 支持其他类型文件的转换。\n            // 如果有 mimetype, 但是文件名里面没有找出后缀规律\n            if ( !ext && file.type ) {\n                ext = /\\/(jpg|jpeg|png|gif|bmp)$/i.exec( file.type ) ?\n                        RegExp.$1.toLowerCase() : '';\n                this.name += '.' + ext;\n            }\n\n            this.ext = ext;\n            this.lastModifiedDate = file.lastModifiedDate ||\n                    (new Date()).toLocaleString();\n\n            Blob.apply( this, arguments );\n        }\n\n        return Base.inherits( Blob, File );\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepicker',[\n        'base',\n        'runtime/client',\n        'lib/file'\n    ], function( Base, RuntimeClent, File ) {\n\n        var $ = Base.$;\n\n        function FilePicker( opts ) {\n            opts = this.options = $.extend({}, FilePicker.options, opts );\n\n            opts.container = $( opts.id );\n\n            if ( !opts.container.length ) {\n                throw new Error('按钮指定错误');\n            }\n\n            opts.innerHTML = opts.innerHTML || opts.label ||\n                    opts.container.html() || '';\n\n            opts.button = $( opts.button || document.createElement('div') );\n            opts.button.html( opts.innerHTML );\n            opts.container.html( opts.button );\n\n            RuntimeClent.call( this, 'FilePicker', true );\n        }\n\n        FilePicker.options = {\n            button: null,\n            container: null,\n            label: null,\n            innerHTML: null,\n            multiple: true,\n            accept: null,\n            name: 'file'\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePicker,\n\n            init: function() {\n                var me = this,\n                    opts = me.options,\n                    button = opts.button;\n\n                button.addClass('webuploader-pick');\n\n                me.on( 'all', function( type ) {\n                    var files;\n\n                    switch ( type ) {\n                        case 'mouseenter':\n                            button.addClass('webuploader-pick-hover');\n                            break;\n\n                        case 'mouseleave':\n                            button.removeClass('webuploader-pick-hover');\n                            break;\n\n                        case 'change':\n                            files = me.exec('getFiles');\n                            me.trigger( 'select', $.map( files, function( file ) {\n                                file = new File( me.getRuid(), file );\n\n                                // 记录来源。\n                                file._refer = opts.container;\n                                return file;\n                            }), opts.container );\n                            break;\n                    }\n                });\n\n                me.connectRuntime( opts, function() {\n                    me.refresh();\n                    me.exec( 'init', opts );\n                    me.trigger('ready');\n                });\n\n                this._resizeHandler = Base.bindFn( this.refresh, this );\n                $( window ).on( 'resize', this._resizeHandler );\n            },\n\n            refresh: function() {\n                var shimContainer = this.getRuntime().getContainer(),\n                    button = this.options.button,\n                    width = button.outerWidth ?\n                            button.outerWidth() : button.width(),\n\n                    height = button.outerHeight ?\n                            button.outerHeight() : button.height(),\n\n                    pos = button.offset();\n\n                width && height && shimContainer.css({\n                    bottom: 'auto',\n                    right: 'auto',\n                    width: width + 'px',\n                    height: height + 'px'\n                }).offset( pos );\n            },\n\n            enable: function() {\n                var btn = this.options.button;\n\n                btn.removeClass('webuploader-pick-disable');\n                this.refresh();\n            },\n\n            disable: function() {\n                var btn = this.options.button;\n\n                this.getRuntime().getContainer().css({\n                    top: '-99999px'\n                });\n\n                btn.addClass('webuploader-pick-disable');\n            },\n\n            destroy: function() {\n                var btn = this.options.button;\n                $( window ).off( 'resize', this._resizeHandler );\n                btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +\n                    'webuploader-pick');\n            }\n        });\n\n        return FilePicker;\n    });\n\n    /**\n     * @fileOverview 文件选择相关\n     */\n    define('widgets/filepicker',[\n        'base',\n        'uploader',\n        'lib/filepicker',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePicker ) {\n        var $ = Base.$;\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Selector | Object} [pick=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 指定选择文件的按钮容器，不指定则不创建按钮。\n             *\n             * * `id` {Seletor|dom} 指定选择文件的按钮容器，不指定则不创建按钮。**注意** 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。\n             * * `label` {String} 请采用 `innerHTML` 代替\n             * * `innerHTML` {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。\n             * * `multiple` {Boolean} 是否开起同时选择多个文件能力。\n             */\n            pick: null,\n\n            /**\n             * @property {Arroy} [accept=null]\n             * @namespace options\n             * @for Uploader\n             * @description 指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。\n             *\n             * * `title` {String} 文字描述\n             * * `extensions` {String} 允许的文件后缀，不带点，多个用逗号分割。\n             * * `mimeTypes` {String} 多个用逗号分割。\n             *\n             * 如：\n             *\n             * ```\n             * {\n             *     title: 'Images',\n             *     extensions: 'gif,jpg,jpeg,bmp,png',\n             *     mimeTypes: 'image/*'\n             * }\n             * ```\n             */\n            accept: null/*{\n                title: 'Images',\n                extensions: 'gif,jpg,jpeg,bmp,png',\n                mimeTypes: 'image/*'\n            }*/\n        });\n\n        return Uploader.register({\n            name: 'picker',\n\n            init: function( opts ) {\n                this.pickers = [];\n                return opts.pick && this.addBtn( opts.pick );\n            },\n\n            refresh: function() {\n                $.each( this.pickers, function() {\n                    this.refresh();\n                });\n            },\n\n            /**\n             * @method addButton\n             * @for Uploader\n             * @grammar addButton( pick ) => Promise\n             * @description\n             * 添加文件选择按钮，如果一个按钮不够，需要调用此方法来添加。参数跟[options.pick](#WebUploader:Uploader:options)一致。\n             * @example\n             * uploader.addButton({\n             *     id: '#btnContainer',\n             *     innerHTML: '选择文件'\n             * });\n             */\n            addBtn: function( pick ) {\n                var me = this,\n                    opts = me.options,\n                    accept = opts.accept,\n                    promises = [];\n\n                if ( !pick ) {\n                    return;\n                }\n\n                $.isPlainObject( pick ) || (pick = {\n                    id: pick\n                });\n\n                $( pick.id ).each(function() {\n                    var options, picker, deferred;\n\n                    deferred = Base.Deferred();\n\n                    options = $.extend({}, pick, {\n                        accept: $.isPlainObject( accept ) ? [ accept ] : accept,\n                        swf: opts.swf,\n                        runtimeOrder: opts.runtimeOrder,\n                        id: this\n                    });\n\n                    picker = new FilePicker( options );\n\n                    picker.once( 'ready', deferred.resolve );\n                    picker.on( 'select', function( files ) {\n                        me.owner.request( 'add-file', [ files ]);\n                    });\n                    picker.init();\n\n                    me.pickers.push( picker );\n\n                    promises.push( deferred.promise() );\n                });\n\n                return Base.when.apply( Base, promises );\n            },\n\n            disable: function() {\n                $.each( this.pickers, function() {\n                    this.disable();\n                });\n            },\n\n            enable: function() {\n                $.each( this.pickers, function() {\n                    this.enable();\n                });\n            },\n\n            destroy: function() {\n                $.each( this.pickers, function() {\n                    this.destroy();\n                });\n                this.pickers = null;\n            }\n        });\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('lib/image',[\n        'base',\n        'runtime/client',\n        'lib/blob'\n    ], function( Base, RuntimeClient, Blob ) {\n        var $ = Base.$;\n\n        // 构造器。\n        function Image( opts ) {\n            this.options = $.extend({}, Image.options, opts );\n            RuntimeClient.call( this, 'Image' );\n\n            this.on( 'load', function() {\n                this._info = this.exec('info');\n                this._meta = this.exec('meta');\n            });\n        }\n\n        // 默认选项。\n        Image.options = {\n\n            // 默认的图片处理质量\n            quality: 90,\n\n            // 是否裁剪\n            crop: false,\n\n            // 是否保留头部信息\n            preserveHeaders: false,\n\n            // 是否允许放大。\n            allowMagnify: false\n        };\n\n        // 继承RuntimeClient.\n        Base.inherits( RuntimeClient, {\n            constructor: Image,\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    ruid = blob.getRuid();\n\n                this.connectRuntime( ruid, function() {\n                    me.exec( 'init', me.options );\n                    me.exec( 'loadFromBlob', blob );\n                });\n            },\n\n            resize: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'resize' ].concat( args ) );\n            },\n\n            crop: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'crop' ].concat( args ) );\n            },\n\n            getAsDataUrl: function( type ) {\n                return this.exec( 'getAsDataUrl', type );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this.exec( 'getAsBlob', type );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n\n        return Image;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/image',[\n        'base',\n        'uploader',\n        'lib/image',\n        'widgets/widget'\n    ], function( Base, Uploader, Image ) {\n\n        var $ = Base.$,\n            throttle;\n\n        // 根据要处理的文件大小来节流，一次不能处理太多，会卡。\n        throttle = (function( max ) {\n            var occupied = 0,\n                waiting = [],\n                tick = function() {\n                    var item;\n\n                    while ( waiting.length && occupied < max ) {\n                        item = waiting.shift();\n                        occupied += item[ 0 ];\n                        item[ 1 ]();\n                    }\n                };\n\n            return function( emiter, size, cb ) {\n                waiting.push([ size, cb ]);\n                emiter.once( 'destroy', function() {\n                    occupied -= size;\n                    setTimeout( tick, 1 );\n                });\n                setTimeout( tick, 1 );\n            };\n        })( 5 * 1024 * 1024 );\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Object} [thumb]\n             * @namespace options\n             * @for Uploader\n             * @description 配置生成缩略图的选项。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 110,\n             *     height: 110,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 70,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: true,\n             *\n             *     // 是否允许裁剪。\n             *     crop: true,\n             *\n             *     // 为空的话则保留原有图片格式。\n             *     // 否则强制转换成指定的类型。\n             *     type: 'image/jpeg'\n             * }\n             * ```\n             */\n            thumb: {\n                width: 110,\n                height: 110,\n                quality: 70,\n                allowMagnify: true,\n                crop: true,\n                preserveHeaders: false,\n\n                // 为空的话则保留原有图片格式。\n                // 否则强制转换成指定的类型。\n                // IE 8下面 base64 大小不能超过 32K 否则预览失败，而非 jpeg 编码的图片很可\n                // 能会超过 32k, 所以这里设置成预览的时候都是 image/jpeg\n                type: 'image/jpeg'\n            },\n\n            /**\n             * @property {Object} [compress]\n             * @namespace options\n             * @for Uploader\n             * @description 配置压缩的图片的选项。如果此选项为`false`, 则图片在上传前不进行压缩。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 1600,\n             *     height: 1600,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 90,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: false,\n             *\n             *     // 是否允许裁剪。\n             *     crop: false,\n             *\n             *     // 是否保留头部meta信息。\n             *     preserveHeaders: true,\n             *\n             *     // 如果发现压缩后文件大小比原来还大，则使用原来图片\n             *     // 此属性可能会影响图片自动纠正功能\n             *     noCompressIfLarger: false,\n             *\n             *     // 单位字节，如果图片大小小于此值，不会采用压缩。\n             *     compressSize: 0\n             * }\n             * ```\n             */\n            compress: {\n                width: 1600,\n                height: 1600,\n                quality: 90,\n                allowMagnify: false,\n                crop: false,\n                preserveHeaders: true\n            }\n        });\n\n        return Uploader.register({\n\n            name: 'image',\n\n\n            /**\n             * 生成缩略图，此过程为异步，所以需要传入`callback`。\n             * 通常情况在图片加入队里后调用此方法来生成预览图以增强交互效果。\n             *\n             * 当 width 或者 height 的值介于 0 - 1 时，被当成百分比使用。\n             *\n             * `callback`中可以接收到两个参数。\n             * * 第一个为error，如果生成缩略图有错误，此error将为真。\n             * * 第二个为ret, 缩略图的Data URL值。\n             *\n             * **注意**\n             * Date URL在IE6/7中不支持，所以不用调用此方法了，直接显示一张暂不支持预览图片好了。\n             * 也可以借助服务端，将 base64 数据传给服务端，生成一个临时文件供预览。\n             *\n             * @method makeThumb\n             * @grammar makeThumb( file, callback ) => undefined\n             * @grammar makeThumb( file, callback, width, height ) => undefined\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.makeThumb( file, function( error, ret ) {\n             *         if ( error ) {\n             *             $li.text('预览错误');\n             *         } else {\n             *             $li.append('<img alt=\"\" src=\"' + ret + '\" />');\n             *         }\n             *     });\n             *\n             * });\n             */\n            makeThumb: function( file, cb, width, height ) {\n                var opts, image;\n\n                file = this.request( 'get-file', file );\n\n                // 只预览图片格式。\n                if ( !file.type.match( /^image/ ) ) {\n                    cb( true );\n                    return;\n                }\n\n                opts = $.extend({}, this.options.thumb );\n\n                // 如果传入的是object.\n                if ( $.isPlainObject( width ) ) {\n                    opts = $.extend( opts, width );\n                    width = null;\n                }\n\n                width = width || opts.width;\n                height = height || opts.height;\n\n                image = new Image( opts );\n\n                image.once( 'load', function() {\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                // 当 resize 完后\n                image.once( 'complete', function() {\n                    cb( false, image.getAsDataUrl( opts.type ) );\n                    image.destroy();\n                });\n\n                image.once( 'error', function( reason ) {\n                    cb( reason || true );\n                    image.destroy();\n                });\n\n                throttle( image, file.source.size, function() {\n                    file._info && image.info( file._info );\n                    file._meta && image.meta( file._meta );\n                    image.loadFromBlob( file.source );\n                });\n            },\n\n            beforeSendFile: function( file ) {\n                var opts = this.options.compress || this.options.resize,\n                    compressSize = opts && opts.compressSize || 0,\n                    noCompressIfLarger = opts && opts.noCompressIfLarger || false,\n                    image, deferred;\n\n                file = this.request( 'get-file', file );\n\n                // 只压缩 jpeg 图片格式。\n                // gif 可能会丢失针\n                // bmp png 基本上尺寸都不大，且压缩比比较小。\n                if ( !opts || !~'image/jpeg,image/jpg'.indexOf( file.type ) ||\n                        file.size < compressSize ||\n                        file._compressed ) {\n                    return;\n                }\n\n                opts = $.extend({}, opts );\n                deferred = Base.Deferred();\n\n                image = new Image( opts );\n\n                deferred.always(function() {\n                    image.destroy();\n                    image = null;\n                });\n                image.once( 'error', deferred.reject );\n                image.once( 'load', function() {\n                    var width = opts.width,\n                        height = opts.height;\n\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                image.once( 'complete', function() {\n                    var blob, size;\n\n                    // 移动端 UC / qq 浏览器的无图模式下\n                    // ctx.getImageData 处理大图的时候会报 Exception\n                    // INDEX_SIZE_ERR: DOM Exception 1\n                    try {\n                        blob = image.getAsBlob( opts.type );\n\n                        size = file.size;\n\n                        // 如果压缩后，比原来还大则不用压缩后的。\n                        if ( !noCompressIfLarger || blob.size < size ) {\n                            // file.source.destroy && file.source.destroy();\n                            file.source = blob;\n                            file.size = blob.size;\n\n                            file.trigger( 'resize', blob.size, size );\n                        }\n\n                        // 标记，避免重复压缩。\n                        file._compressed = true;\n                        deferred.resolve();\n                    } catch ( e ) {\n                        // 出错了直接继续，让其上传原始图片\n                        deferred.resolve();\n                    }\n                });\n\n                file._info && image.info( file._info );\n                file._meta && image.meta( file._meta );\n\n                image.loadFromBlob( file.source );\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview 文件属性封装\n     */\n    define('file',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            idPrefix = 'WU_FILE_',\n            idSuffix = 0,\n            rExt = /\\.([^.]+)$/,\n            statusMap = {};\n\n        function gid() {\n            return idPrefix + idSuffix++;\n        }\n\n        /**\n         * 文件类\n         * @class File\n         * @constructor 构造函数\n         * @grammar new File( source ) => File\n         * @param {Lib.File} source [lib.File](#Lib.File)实例, 此source对象是带有Runtime信息的。\n         */\n        function WUFile( source ) {\n\n            /**\n             * 文件名，包括扩展名（后缀）\n             * @property name\n             * @type {string}\n             */\n            this.name = source.name || 'Untitled';\n\n            /**\n             * 文件体积（字节）\n             * @property size\n             * @type {uint}\n             * @default 0\n             */\n            this.size = source.size || 0;\n\n            /**\n             * 文件MIMETYPE类型，与文件类型的对应关系请参考[http://t.cn/z8ZnFny](http://t.cn/z8ZnFny)\n             * @property type\n             * @type {string}\n             * @default 'application/octet-stream'\n             */\n            this.type = source.type || 'application/octet-stream';\n\n            /**\n             * 文件最后修改日期\n             * @property lastModifiedDate\n             * @type {int}\n             * @default 当前时间戳\n             */\n            this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);\n\n            /**\n             * 文件ID，每个对象具有唯一ID，与文件名无关\n             * @property id\n             * @type {string}\n             */\n            this.id = gid();\n\n            /**\n             * 文件扩展名，通过文件名获取，例如test.png的扩展名为png\n             * @property ext\n             * @type {string}\n             */\n            this.ext = rExt.exec( this.name ) ? RegExp.$1 : '';\n\n\n            /**\n             * 状态文字说明。在不同的status语境下有不同的用途。\n             * @property statusText\n             * @type {string}\n             */\n            this.statusText = '';\n\n            // 存储文件状态，防止通过属性直接修改\n            statusMap[ this.id ] = WUFile.Status.INITED;\n\n            this.source = source;\n            this.loaded = 0;\n\n            this.on( 'error', function( msg ) {\n                this.setStatus( WUFile.Status.ERROR, msg );\n            });\n        }\n\n        $.extend( WUFile.prototype, {\n\n            /**\n             * 设置状态，状态变化时会触发`change`事件。\n             * @method setStatus\n             * @grammar setStatus( status[, statusText] );\n             * @param {File.Status|String} status [文件状态值](#WebUploader:File:File.Status)\n             * @param {String} [statusText=''] 状态说明，常在error时使用，用http, abort,server等来标记是由于什么原因导致文件错误。\n             */\n            setStatus: function( status, text ) {\n\n                var prevStatus = statusMap[ this.id ];\n\n                typeof text !== 'undefined' && (this.statusText = text);\n\n                if ( status !== prevStatus ) {\n                    statusMap[ this.id ] = status;\n                    /**\n                     * 文件状态变化\n                     * @event statuschange\n                     */\n                    this.trigger( 'statuschange', status, prevStatus );\n                }\n\n            },\n\n            /**\n             * 获取文件状态\n             * @return {File.Status}\n             * @example\n                     文件状态具体包括以下几种类型：\n                     {\n                         // 初始化\n                        INITED:     0,\n                        // 已入队列\n                        QUEUED:     1,\n                        // 正在上传\n                        PROGRESS:     2,\n                        // 上传出错\n                        ERROR:         3,\n                        // 上传成功\n                        COMPLETE:     4,\n                        // 上传取消\n                        CANCELLED:     5\n                    }\n             */\n            getStatus: function() {\n                return statusMap[ this.id ];\n            },\n\n            /**\n             * 获取文件原始信息。\n             * @return {*}\n             */\n            getSource: function() {\n                return this.source;\n            },\n\n            destroy: function() {\n                this.off();\n                delete statusMap[ this.id ];\n            }\n        });\n\n        Mediator.installTo( WUFile.prototype );\n\n        /**\n         * 文件状态值，具体包括以下几种类型：\n         * * `inited` 初始状态\n         * * `queued` 已经进入队列, 等待上传\n         * * `progress` 上传中\n         * * `complete` 上传完成。\n         * * `error` 上传出错，可重试\n         * * `interrupt` 上传中断，可续传。\n         * * `invalid` 文件不合格，不能重试上传。会自动从队列中移除。\n         * * `cancelled` 文件被移除。\n         * @property {Object} Status\n         * @namespace File\n         * @class File\n         * @static\n         */\n        WUFile.Status = {\n            INITED:     'inited',    // 初始状态\n            QUEUED:     'queued',    // 已经进入队列, 等待上传\n            PROGRESS:   'progress',    // 上传中\n            ERROR:      'error',    // 上传出错，可重试\n            COMPLETE:   'complete',    // 上传完成。\n            CANCELLED:  'cancelled',    // 上传取消。\n            INTERRUPT:  'interrupt',    // 上传中断，可续传。\n            INVALID:    'invalid'    // 文件不合格，不能重试上传。\n        };\n\n        return WUFile;\n    });\n\n    /**\n     * @fileOverview 文件队列\n     */\n    define('queue',[\n        'base',\n        'mediator',\n        'file'\n    ], function( Base, Mediator, WUFile ) {\n\n        var $ = Base.$,\n            STATUS = WUFile.Status;\n\n        /**\n         * 文件队列, 用来存储各个状态中的文件。\n         * @class Queue\n         * @extends Mediator\n         */\n        function Queue() {\n\n            /**\n             * 统计文件数。\n             * * `numOfQueue` 队列中的文件数。\n             * * `numOfSuccess` 上传成功的文件数\n             * * `numOfCancel` 被取消的文件数\n             * * `numOfProgress` 正在上传中的文件数\n             * * `numOfUploadFailed` 上传错误的文件数。\n             * * `numOfInvalid` 无效的文件数。\n             * * `numofDeleted` 被移除的文件数。\n             * @property {Object} stats\n             */\n            this.stats = {\n                numOfQueue: 0,\n                numOfSuccess: 0,\n                numOfCancel: 0,\n                numOfProgress: 0,\n                numOfUploadFailed: 0,\n                numOfInvalid: 0,\n                numofDeleted: 0,\n                numofInterrupt: 0\n            };\n\n            // 上传队列，仅包括等待上传的文件\n            this._queue = [];\n\n            // 存储所有文件\n            this._map = {};\n        }\n\n        $.extend( Queue.prototype, {\n\n            /**\n             * 将新文件加入对队列尾部\n             *\n             * @method append\n             * @param  {File} file   文件对象\n             */\n            append: function( file ) {\n                this._queue.push( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 将新文件加入对队列头部\n             *\n             * @method prepend\n             * @param  {File} file   文件对象\n             */\n            prepend: function( file ) {\n                this._queue.unshift( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 获取文件对象\n             *\n             * @method getFile\n             * @param  {String} fileId   文件ID\n             * @return {File}\n             */\n            getFile: function( fileId ) {\n                if ( typeof fileId !== 'string' ) {\n                    return fileId;\n                }\n                return this._map[ fileId ];\n            },\n\n            /**\n             * 从队列中取出一个指定状态的文件。\n             * @grammar fetch( status ) => File\n             * @method fetch\n             * @param {String} status [文件状态值](#WebUploader:File:File.Status)\n             * @return {File} [File](#WebUploader:File)\n             */\n            fetch: function( status ) {\n                var len = this._queue.length,\n                    i, file;\n\n                status = status || STATUS.QUEUED;\n\n                for ( i = 0; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( status === file.getStatus() ) {\n                        return file;\n                    }\n                }\n\n                return null;\n            },\n\n            /**\n             * 对队列进行排序，能够控制文件上传顺序。\n             * @grammar sort( fn ) => undefined\n             * @method sort\n             * @param {Function} fn 排序方法\n             */\n            sort: function( fn ) {\n                if ( typeof fn === 'function' ) {\n                    this._queue.sort( fn );\n                }\n            },\n\n            /**\n             * 获取指定类型的文件列表, 列表中每一个成员为[File](#WebUploader:File)对象。\n             * @grammar getFiles( [status1[, status2 ...]] ) => Array\n             * @method getFiles\n             * @param {String} [status] [文件状态值](#WebUploader:File:File.Status)\n             */\n            getFiles: function() {\n                var sts = [].slice.call( arguments, 0 ),\n                    ret = [],\n                    i = 0,\n                    len = this._queue.length,\n                    file;\n\n                for ( ; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( sts.length && !~$.inArray( file.getStatus(), sts ) ) {\n                        continue;\n                    }\n\n                    ret.push( file );\n                }\n\n                return ret;\n            },\n\n            /**\n             * 在队列中删除文件。\n             * @grammar removeFile( file ) => Array\n             * @method removeFile\n             * @param {File} 文件对象。\n             */\n            removeFile: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( existing ) {\n                    delete this._map[ file.id ];\n                    file.destroy();\n                    this.stats.numofDeleted++;\n                }\n            },\n\n            _fileAdded: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( !existing ) {\n                    this._map[ file.id ] = file;\n\n                    file.on( 'statuschange', function( cur, pre ) {\n                        me._onFileStatusChange( cur, pre );\n                    });\n                }\n            },\n\n            _onFileStatusChange: function( curStatus, preStatus ) {\n                var stats = this.stats;\n\n                switch ( preStatus ) {\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress--;\n                        break;\n\n                    case STATUS.QUEUED:\n                        stats.numOfQueue --;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed--;\n                        break;\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid--;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt--;\n                        break;\n                }\n\n                switch ( curStatus ) {\n                    case STATUS.QUEUED:\n                        stats.numOfQueue++;\n                        break;\n\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress++;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed++;\n                        break;\n\n                    case STATUS.COMPLETE:\n                        stats.numOfSuccess++;\n                        break;\n\n                    case STATUS.CANCELLED:\n                        stats.numOfCancel++;\n                        break;\n\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid++;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt++;\n                        break;\n                }\n            }\n\n        });\n\n        Mediator.installTo( Queue.prototype );\n\n        return Queue;\n    });\n    /**\n     * @fileOverview 队列\n     */\n    define('widgets/queue',[\n        'base',\n        'uploader',\n        'queue',\n        'file',\n        'lib/file',\n        'runtime/client',\n        'widgets/widget'\n    ], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {\n\n        var $ = Base.$,\n            rExt = /\\.\\w+$/,\n            Status = WUFile.Status;\n\n        return Uploader.register({\n            name: 'queue',\n\n            init: function( opts ) {\n                var me = this,\n                    deferred, len, i, item, arr, accept, runtime;\n\n                if ( $.isPlainObject( opts.accept ) ) {\n                    opts.accept = [ opts.accept ];\n                }\n\n                // accept中的中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].extensions;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = '\\\\.' + arr.join(',')\n                                .replace( /,/g, '$|\\\\.' )\n                                .replace( /\\*/g, '.*' ) + '$';\n                    }\n\n                    me.accept = new RegExp( accept, 'i' );\n                }\n\n                me.queue = new Queue();\n                me.stats = me.queue.stats;\n\n                // 如果当前不是html5运行时，那就算了。\n                // 不执行后续操作\n                if ( this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                // 创建一个 html5 运行时的 placeholder\n                // 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。\n                deferred = Base.Deferred();\n                this.placeholder = runtime = new RuntimeClient('Placeholder');\n                runtime.connectRuntime({\n                    runtimeOrder: 'html5'\n                }, function() {\n                    me._ruid = runtime.getRuid();\n                    deferred.resolve();\n                });\n                return deferred.promise();\n            },\n\n\n            // 为了支持外部直接添加一个原生File对象。\n            _wrapFile: function( file ) {\n                if ( !(file instanceof WUFile) ) {\n\n                    if ( !(file instanceof File) ) {\n                        if ( !this._ruid ) {\n                            throw new Error('Can\\'t add external files.');\n                        }\n                        file = new File( this._ruid, file );\n                    }\n\n                    file = new WUFile( file );\n                }\n\n                return file;\n            },\n\n            // 判断文件是否可以被加入队列\n            acceptFile: function( file ) {\n                var invalid = !file || !file.size || this.accept &&\n\n                        // 如果名字中有后缀，才做后缀白名单处理。\n                        rExt.exec( file.name ) && !this.accept.test( file.name );\n\n                return !invalid;\n            },\n\n\n            /**\n             * @event beforeFileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列之前触发，此事件的handler返回值为`false`，则此文件不会被添加进入队列。\n             * @for  Uploader\n             */\n\n            /**\n             * @event fileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列以后触发。\n             * @for  Uploader\n             */\n\n            _addFile: function( file ) {\n                var me = this;\n\n                file = me._wrapFile( file );\n\n                // 不过类型判断允许不允许，先派送 `beforeFileQueued`\n                if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {\n                    return;\n                }\n\n                // 类型不匹配，则派送错误事件，并返回。\n                if ( !me.acceptFile( file ) ) {\n                    me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );\n                    return;\n                }\n\n                me.queue.append( file );\n                me.owner.trigger( 'fileQueued', file );\n                return file;\n            },\n\n            getFile: function( fileId ) {\n                return this.queue.getFile( fileId );\n            },\n\n            /**\n             * @event filesQueued\n             * @param {File} files 数组，内容为原始File(lib/File）对象。\n             * @description 当一批文件添加进队列以后触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @property {Boolean} [auto=false]\n             * @namespace options\n             * @for Uploader\n             * @description 设置为 true 后，不需要手动调用上传，有文件选择即开始上传。\n             *\n             */\n\n            /**\n             * @method addFiles\n             * @grammar addFiles( file ) => undefined\n             * @grammar addFiles( [file1, file2 ...] ) => undefined\n             * @param {Array of File or File} [files] Files 对象 数组\n             * @description 添加文件到队列\n             * @for  Uploader\n             */\n            addFile: function( files ) {\n                var me = this;\n\n                if ( !files.length ) {\n                    files = [ files ];\n                }\n\n                files = $.map( files, function( file ) {\n                    return me._addFile( file );\n                });\n\n                me.owner.trigger( 'filesQueued', files );\n\n                if ( me.options.auto ) {\n                    setTimeout(function() {\n                        me.request('start-upload');\n                    }, 20 );\n                }\n            },\n\n            getStats: function() {\n                return this.stats;\n            },\n\n            /**\n             * @event fileDequeued\n             * @param {File} file File对象\n             * @description 当文件被移除队列后触发。\n             * @for  Uploader\n             */\n\n             /**\n             * @method removeFile\n             * @grammar removeFile( file ) => undefined\n             * @grammar removeFile( id ) => undefined\n             * @grammar removeFile( file, true ) => undefined\n             * @grammar removeFile( id, true ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 移除某一文件, 默认只会标记文件状态为已取消，如果第二个参数为 `true` 则会从 queue 中移除。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.removeFile( file );\n             * })\n             */\n            removeFile: function( file, remove ) {\n                var me = this;\n\n                file = file.id ? file : me.queue.getFile( file );\n\n                this.request( 'cancel-file', file );\n\n                if ( remove ) {\n                    this.queue.removeFile( file );\n                }\n            },\n\n            /**\n             * @method getFiles\n             * @grammar getFiles() => Array\n             * @grammar getFiles( status1, status2, status... ) => Array\n             * @description 返回指定状态的文件集合，不传参数将返回所有状态的文件。\n             * @for  Uploader\n             * @example\n             * console.log( uploader.getFiles() );    // => all files\n             * console.log( uploader.getFiles('error') )    // => all error files.\n             */\n            getFiles: function() {\n                return this.queue.getFiles.apply( this.queue, arguments );\n            },\n\n            fetchFile: function() {\n                return this.queue.fetch.apply( this.queue, arguments );\n            },\n\n            /**\n             * @method retry\n             * @grammar retry() => undefined\n             * @grammar retry( file ) => undefined\n             * @description 重试上传，重试指定文件，或者从出错的文件开始重新上传。\n             * @for  Uploader\n             * @example\n             * function retry() {\n             *     uploader.retry();\n             * }\n             */\n            retry: function( file, noForceStart ) {\n                var me = this,\n                    files, i, len;\n\n                if ( file ) {\n                    file = file.id ? file : me.queue.getFile( file );\n                    file.setStatus( Status.QUEUED );\n                    noForceStart || me.request('start-upload');\n                    return;\n                }\n\n                files = me.queue.getFiles( Status.ERROR );\n                i = 0;\n                len = files.length;\n\n                for ( ; i < len; i++ ) {\n                    file = files[ i ];\n                    file.setStatus( Status.QUEUED );\n                }\n\n                me.request('start-upload');\n            },\n\n            /**\n             * @method sort\n             * @grammar sort( fn ) => undefined\n             * @description 排序队列中的文件，在上传之前调整可以控制上传顺序。\n             * @for  Uploader\n             */\n            sortFiles: function() {\n                return this.queue.sort.apply( this.queue, arguments );\n            },\n\n            /**\n             * @event reset\n             * @description 当 uploader 被重置的时候触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @method reset\n             * @grammar reset() => undefined\n             * @description 重置uploader。目前只重置了队列。\n             * @for  Uploader\n             * @example\n             * uploader.reset();\n             */\n            reset: function() {\n                this.owner.trigger('reset');\n                this.queue = new Queue();\n                this.stats = this.queue.stats;\n            },\n\n            destroy: function() {\n                this.reset();\n                this.placeholder && this.placeholder.destroy();\n            }\n        });\n\n    });\n    /**\n     * @fileOverview 添加获取Runtime相关信息的方法。\n     */\n    define('widgets/runtime',[\n        'uploader',\n        'runtime/runtime',\n        'widgets/widget'\n    ], function( Uploader, Runtime ) {\n\n        Uploader.support = function() {\n            return Runtime.hasRuntime.apply( Runtime, arguments );\n        };\n\n        /**\n         * @property {Object} [runtimeOrder=html5,flash]\n         * @namespace options\n         * @for Uploader\n         * @description 指定运行时启动顺序。默认会想尝试 html5 是否支持，如果支持则使用 html5, 否则则使用 flash.\n         *\n         * 可以将此值设置成 `flash`，来强制使用 flash 运行时。\n         */\n\n        return Uploader.register({\n            name: 'runtime',\n\n            init: function() {\n                if ( !this.predictRuntimeType() ) {\n                    throw Error('Runtime Error');\n                }\n            },\n\n            /**\n             * 预测Uploader将采用哪个`Runtime`\n             * @grammar predictRuntimeType() => String\n             * @method predictRuntimeType\n             * @for  Uploader\n             */\n            predictRuntimeType: function() {\n                var orders = this.options.runtimeOrder || Runtime.orders,\n                    type = this.type,\n                    i, len;\n\n                if ( !type ) {\n                    orders = orders.split( /\\s*,\\s*/g );\n\n                    for ( i = 0, len = orders.length; i < len; i++ ) {\n                        if ( Runtime.hasRuntime( orders[ i ] ) ) {\n                            this.type = type = orders[ i ];\n                            break;\n                        }\n                    }\n                }\n\n                return type;\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     */\n    define('lib/transport',[\n        'base',\n        'runtime/client',\n        'mediator'\n    ], function( Base, RuntimeClient, Mediator ) {\n\n        var $ = Base.$;\n\n        function Transport( opts ) {\n            var me = this;\n\n            opts = me.options = $.extend( true, {}, Transport.options, opts || {} );\n            RuntimeClient.call( this, 'Transport' );\n\n            this._blob = null;\n            this._formData = opts.formData || {};\n            this._headers = opts.headers || {};\n\n            this.on( 'progress', this._timeout );\n            this.on( 'load error', function() {\n                me.trigger( 'progress', 1 );\n                clearTimeout( me._timer );\n            });\n        }\n\n        Transport.options = {\n            server: '',\n            method: 'POST',\n\n            // 跨域时，是否允许携带cookie, 只有html5 runtime才有效\n            withCredentials: false,\n            fileVal: 'file',\n            timeout: 2 * 60 * 1000,    // 2分钟\n            formData: {},\n            headers: {},\n            sendAsBinary: false\n        };\n\n        $.extend( Transport.prototype, {\n\n            // 添加Blob, 只能添加一次，最后一次有效。\n            appendBlob: function( key, blob, filename ) {\n                var me = this,\n                    opts = me.options;\n\n                if ( me.getRuid() ) {\n                    me.disconnectRuntime();\n                }\n\n                // 连接到blob归属的同一个runtime.\n                me.connectRuntime( blob.ruid, function() {\n                    me.exec('init');\n                });\n\n                me._blob = blob;\n                opts.fileVal = key || opts.fileVal;\n                opts.filename = filename || opts.filename;\n            },\n\n            // 添加其他字段\n            append: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._formData, key );\n                } else {\n                    this._formData[ key ] = value;\n                }\n            },\n\n            setRequestHeader: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._headers, key );\n                } else {\n                    this._headers[ key ] = value;\n                }\n            },\n\n            send: function( method ) {\n                this.exec( 'send', method );\n                this._timeout();\n            },\n\n            abort: function() {\n                clearTimeout( this._timer );\n                return this.exec('abort');\n            },\n\n            destroy: function() {\n                this.trigger('destroy');\n                this.off();\n                this.exec('destroy');\n                this.disconnectRuntime();\n            },\n\n            getResponse: function() {\n                return this.exec('getResponse');\n            },\n\n            getResponseAsJson: function() {\n                return this.exec('getResponseAsJson');\n            },\n\n            getStatus: function() {\n                return this.exec('getStatus');\n            },\n\n            _timeout: function() {\n                var me = this,\n                    duration = me.options.timeout;\n\n                if ( !duration ) {\n                    return;\n                }\n\n                clearTimeout( me._timer );\n                me._timer = setTimeout(function() {\n                    me.abort();\n                    me.trigger( 'error', 'timeout' );\n                }, duration );\n            }\n\n        });\n\n        // 让Transport具备事件功能。\n        Mediator.installTo( Transport.prototype );\n\n        return Transport;\n    });\n    /**\n     * @fileOverview 负责文件上传相关。\n     */\n    define('widgets/upload',[\n        'base',\n        'uploader',\n        'file',\n        'lib/transport',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile, Transport ) {\n\n        var $ = Base.$,\n            isPromise = Base.isPromise,\n            Status = WUFile.Status;\n\n        // 添加默认配置项\n        $.extend( Uploader.options, {\n\n\n            /**\n             * @property {Boolean} [prepareNextFile=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否允许在文件传输时提前把下一个文件准备好。\n             * 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。\n             * 如果能提前在当前文件传输期处理，可以节省总体耗时。\n             */\n            prepareNextFile: false,\n\n            /**\n             * @property {Boolean} [chunked=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否要分片处理大文件上传。\n             */\n            chunked: false,\n\n            /**\n             * @property {Boolean} [chunkSize=5242880]\n             * @namespace options\n             * @for Uploader\n             * @description 如果要分片，分多大一片？ 默认大小为5M.\n             */\n            chunkSize: 5 * 1024 * 1024,\n\n            /**\n             * @property {Boolean} [chunkRetry=2]\n             * @namespace options\n             * @for Uploader\n             * @description 如果某个分片由于网络问题出错，允许自动重传多少次？\n             */\n            chunkRetry: 2,\n\n            /**\n             * @property {Boolean} [threads=3]\n             * @namespace options\n             * @for Uploader\n             * @description 上传并发数。允许同时最大上传进程数。\n             */\n            threads: 3,\n\n\n            /**\n             * @property {Object} [formData={}]\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传请求的参数表，每次发送都会发送此对象中的参数。\n             */\n            formData: {}\n\n            /**\n             * @property {Object} [fileVal='file']\n             * @namespace options\n             * @for Uploader\n             * @description 设置文件上传域的name。\n             */\n\n            /**\n             * @property {Object} [method='POST']\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传方式，`POST`或者`GET`。\n             */\n\n            /**\n             * @property {Object} [sendAsBinary=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否已二进制的流的方式发送文件，这样整个上传内容`php://input`都为文件内容，\n             * 其他参数在$_GET数组中。\n             */\n        });\n\n        // 负责将文件切片。\n        function CuteFile( file, chunkSize ) {\n            var pending = [],\n                blob = file.source,\n                total = blob.size,\n                chunks = chunkSize ? Math.ceil( total / chunkSize ) : 1,\n                start = 0,\n                index = 0,\n                len, api;\n\n            api = {\n                file: file,\n\n                has: function() {\n                    return !!pending.length;\n                },\n\n                shift: function() {\n                    return pending.shift();\n                },\n\n                unshift: function( block ) {\n                    pending.unshift( block );\n                }\n            };\n\n            while ( index < chunks ) {\n                len = Math.min( chunkSize, total - start );\n\n                pending.push({\n                    file: file,\n                    start: start,\n                    end: chunkSize ? (start + len) : total,\n                    total: total,\n                    chunks: chunks,\n                    chunk: index++,\n                    cuted: api\n                });\n                start += len;\n            }\n\n            file.blocks = pending.concat();\n            file.remaning = pending.length;\n\n            return api;\n        }\n\n        Uploader.register({\n            name: 'upload',\n\n            init: function() {\n                var owner = this.owner,\n                    me = this;\n\n                this.runing = false;\n                this.progress = false;\n\n                owner\n                    .on( 'startUpload', function() {\n                        me.progress = true;\n                    })\n                    .on( 'uploadFinished', function() {\n                        me.progress = false;\n                    });\n\n                // 记录当前正在传的数据，跟threads相关\n                this.pool = [];\n\n                // 缓存分好片的文件。\n                this.stack = [];\n\n                // 缓存即将上传的文件。\n                this.pending = [];\n\n                // 跟踪还有多少分片在上传中但是没有完成上传。\n                this.remaning = 0;\n                this.__tick = Base.bindFn( this._tick, this );\n\n                owner.on( 'uploadComplete', function( file ) {\n\n                    // 把其他块取消了。\n                    file.blocks && $.each( file.blocks, function( _, v ) {\n                        v.transport && (v.transport.abort(), v.transport.destroy());\n                        delete v.transport;\n                    });\n\n                    delete file.blocks;\n                    delete file.remaning;\n                });\n            },\n\n            reset: function() {\n                this.request( 'stop-upload', true );\n                this.runing = false;\n                this.pool = [];\n                this.stack = [];\n                this.pending = [];\n                this.remaning = 0;\n                this._trigged = false;\n                this._promise = null;\n            },\n\n            /**\n             * @event startUpload\n             * @description 当开始上传流程时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 开始上传。此方法可以从初始状态调用开始上传流程，也可以从暂停状态调用，继续上传流程。\n             *\n             * 可以指定开始某一个文件。\n             * @grammar upload() => undefined\n             * @grammar upload( file | fileId) => undefined\n             * @method upload\n             * @for  Uploader\n             */\n            startUpload: function(file) {\n                var me = this;\n\n                // 移出invalid的文件\n                $.each( me.request( 'get-files', Status.INVALID ), function() {\n                    me.request( 'remove-file', this );\n                });\n\n                // 如果指定了开始某个文件，则只开始指定文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        $.each( me.pool, function( _, v ) {\n\n                            // 之前暂停过。\n                            if (v.file !== file) {\n                                return;\n                            }\n\n                            v.transport && v.transport.send();\n                        });\n\n                        file.setStatus( Status.QUEUED );\n                    } else if (file.getStatus() === Status.PROGRESS) {\n                        return;\n                    } else {\n                        file.setStatus( Status.QUEUED );\n                    }\n                } else {\n                    $.each( me.request( 'get-files', [ Status.INITED ] ), function() {\n                        this.setStatus( Status.QUEUED );\n                    });\n                }\n\n                if ( me.runing ) {\n                    return;\n                }\n\n                me.runing = true;\n\n                var files = [];\n\n                // 如果有暂停的，则续传\n                $.each( me.pool, function( _, v ) {\n                    var file = v.file;\n\n                    if ( file.getStatus() === Status.INTERRUPT ) {\n                        files.push(file);\n                        me._trigged = false;\n                        v.transport && v.transport.send();\n                    }\n                });\n\n                var file;\n                while ( (file = files.shift()) ) {\n                    file.setStatus( Status.PROGRESS );\n                }\n\n                file || $.each( me.request( 'get-files',\n                        Status.INTERRUPT ), function() {\n                    this.setStatus( Status.PROGRESS );\n                });\n\n                me._trigged = false;\n                Base.nextTick( me.__tick );\n                me.owner.trigger('startUpload');\n            },\n\n            /**\n             * @event stopUpload\n             * @description 当开始上传流程暂停时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 暂停上传。第一个参数为是否中断上传当前正在上传的文件。\n             *\n             * 如果第一个参数是文件，则只暂停指定文件。\n             * @grammar stop() => undefined\n             * @grammar stop( true ) => undefined\n             * @grammar stop( file ) => undefined\n             * @method stop\n             * @for  Uploader\n             */\n            stopUpload: function( file, interrupt ) {\n                var me = this;\n\n                if (file === true) {\n                    interrupt = file;\n                    file = null;\n                }\n\n                if ( me.runing === false ) {\n                    return;\n                }\n\n                // 如果只是暂停某个文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if ( file.getStatus() !== Status.PROGRESS &&\n                            file.getStatus() !== Status.QUEUED ) {\n                        return;\n                    }\n\n                    file.setStatus( Status.INTERRUPT );\n                    $.each( me.pool, function( _, v ) {\n\n                        // 只 abort 指定的文件。\n                        if (v.file !== file) {\n                            return;\n                        }\n\n                        v.transport && v.transport.abort();\n                        me._putback(v);\n                        me._popBlock(v);\n                    });\n\n                    return Base.nextTick( me.__tick );\n                }\n\n                me.runing = false;\n\n                if (this._promise && this._promise.file) {\n                    this._promise.file.setStatus( Status.INTERRUPT );\n                }\n\n                interrupt && $.each( me.pool, function( _, v ) {\n                    v.transport && v.transport.abort();\n                    v.file.setStatus( Status.INTERRUPT );\n                });\n\n                me.owner.trigger('stopUpload');\n            },\n\n            /**\n             * @method cancelFile\n             * @grammar cancelFile( file ) => undefined\n             * @grammar cancelFile( id ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 标记文件状态为已取消, 同时将中断文件传输。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.cancelFile( file );\n             * })\n             */\n            cancelFile: function( file ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                file.setStatus( Status.CANCELLED );\n                this.owner.trigger( 'fileDequeued', file );\n            },\n\n            /**\n             * 判断`Uplaode`r是否正在上传中。\n             * @grammar isInProgress() => Boolean\n             * @method isInProgress\n             * @for  Uploader\n             */\n            isInProgress: function() {\n                return !!this.progress;\n            },\n\n            _getStats: function() {\n                return this.request('get-stats');\n            },\n\n            /**\n             * 掉过一个文件上传，直接标记指定文件为已上传状态。\n             * @grammar skipFile( file ) => undefined\n             * @method skipFile\n             * @for  Uploader\n             */\n            skipFile: function( file, status ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                file.setStatus( status || Status.COMPLETE );\n                file.skipped = true;\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                this.owner.trigger( 'uploadSkip', file );\n            },\n\n            /**\n             * @event uploadFinished\n             * @description 当所有文件上传结束时触发。\n             * @for  Uploader\n             */\n            _tick: function() {\n                var me = this,\n                    opts = me.options,\n                    fn, val;\n\n                // 上一个promise还没有结束，则等待完成后再执行。\n                if ( me._promise ) {\n                    return me._promise.always( me.__tick );\n                }\n\n                // 还有位置，且还有文件要处理的话。\n                if ( me.pool.length < opts.threads && (val = me._nextBlock()) ) {\n                    me._trigged = false;\n\n                    fn = function( val ) {\n                        me._promise = null;\n\n                        // 有可能是reject过来的，所以要检测val的类型。\n                        val && val.file && me._startSend( val );\n                        Base.nextTick( me.__tick );\n                    };\n\n                    me._promise = isPromise( val ) ? val.always( fn ) : fn( val );\n\n                // 没有要上传的了，且没有正在传输的了。\n                } else if ( !me.remaning && !me._getStats().numOfQueue &&\n                    !me._getStats().numofInterrupt ) {\n                    me.runing = false;\n\n                    me._trigged || Base.nextTick(function() {\n                        me.owner.trigger('uploadFinished');\n                    });\n                    me._trigged = true;\n                }\n            },\n\n            _putback: function(block) {\n                var idx;\n\n                block.cuted.unshift(block);\n                idx = this.stack.indexOf(block.cuted);\n\n                if (!~idx) {\n                    this.stack.unshift(block.cuted);\n                }\n            },\n\n            _getStack: function() {\n                var i = 0,\n                    act;\n\n                while ( (act = this.stack[ i++ ]) ) {\n                    if ( act.has() && act.file.getStatus() === Status.PROGRESS ) {\n                        return act;\n                    } else if (!act.has() ||\n                            act.file.getStatus() !== Status.PROGRESS &&\n                            act.file.getStatus() !== Status.INTERRUPT ) {\n\n                        // 把已经处理完了的，或者，状态为非 progress（上传中）、\n                        // interupt（暂停中） 的移除。\n                        this.stack.splice( --i, 1 );\n                    }\n                }\n\n                return null;\n            },\n\n            _nextBlock: function() {\n                var me = this,\n                    opts = me.options,\n                    act, next, done, preparing;\n\n                // 如果当前文件还有没有需要传输的，则直接返回剩下的。\n                if ( (act = this._getStack()) ) {\n\n                    // 是否提前准备下一个文件\n                    if ( opts.prepareNextFile && !me.pending.length ) {\n                        me._prepareNextFile();\n                    }\n\n                    return act.shift();\n\n                // 否则，如果正在运行，则准备下一个文件，并等待完成后返回下个分片。\n                } else if ( me.runing ) {\n\n                    // 如果缓存中有，则直接在缓存中取，没有则去queue中取。\n                    if ( !me.pending.length && me._getStats().numOfQueue ) {\n                        me._prepareNextFile();\n                    }\n\n                    next = me.pending.shift();\n                    done = function( file ) {\n                        if ( !file ) {\n                            return null;\n                        }\n\n                        act = CuteFile( file, opts.chunked ? opts.chunkSize : 0 );\n                        me.stack.push(act);\n                        return act.shift();\n                    };\n\n                    // 文件可能还在prepare中，也有可能已经完全准备好了。\n                    if ( isPromise( next) ) {\n                        preparing = next.file;\n                        next = next[ next.pipe ? 'pipe' : 'then' ]( done );\n                        next.file = preparing;\n                        return next;\n                    }\n\n                    return done( next );\n                }\n            },\n\n\n            /**\n             * @event uploadStart\n             * @param {File} file File对象\n             * @description 某个文件开始上传前触发，一个文件只会触发一次。\n             * @for  Uploader\n             */\n            _prepareNextFile: function() {\n                var me = this,\n                    file = me.request('fetch-file'),\n                    pending = me.pending,\n                    promise;\n\n                if ( file ) {\n                    promise = me.request( 'before-send-file', file, function() {\n\n                        // 有可能文件被skip掉了。文件被skip掉后，状态坑定不是Queued.\n                        if ( file.getStatus() === Status.PROGRESS ||\n                            file.getStatus() === Status.INTERRUPT ) {\n                            return file;\n                        }\n\n                        return me._finishFile( file );\n                    });\n\n                    me.owner.trigger( 'uploadStart', file );\n                    file.setStatus( Status.PROGRESS );\n\n                    promise.file = file;\n\n                    // 如果还在pending中，则替换成文件本身。\n                    promise.done(function() {\n                        var idx = $.inArray( promise, pending );\n\n                        ~idx && pending.splice( idx, 1, file );\n                    });\n\n                    // befeore-send-file的钩子就有错误发生。\n                    promise.fail(function( reason ) {\n                        file.setStatus( Status.ERROR, reason );\n                        me.owner.trigger( 'uploadError', file, reason );\n                        me.owner.trigger( 'uploadComplete', file );\n                    });\n\n                    pending.push( promise );\n                }\n            },\n\n            // 让出位置了，可以让其他分片开始上传\n            _popBlock: function( block ) {\n                var idx = $.inArray( block, this.pool );\n\n                this.pool.splice( idx, 1 );\n                block.file.remaning--;\n                this.remaning--;\n            },\n\n            // 开始上传，可以被掉过。如果promise被reject了，则表示跳过此分片。\n            _startSend: function( block ) {\n                var me = this,\n                    file = block.file,\n                    promise;\n\n                // 有可能在 before-send-file 的 promise 期间改变了文件状态。\n                // 如：暂停，取消\n                // 我们不能中断 promise, 但是可以在 promise 完后，不做上传操作。\n                if ( file.getStatus() !== Status.PROGRESS ) {\n\n                    // 如果是中断，则还需要放回去。\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        me._putback(block);\n                    }\n\n                    return;\n                }\n\n                me.pool.push( block );\n                me.remaning++;\n\n                // 如果没有分片，则直接使用原始的。\n                // 不会丢失content-type信息。\n                block.blob = block.chunks === 1 ? file.source :\n                        file.source.slice( block.start, block.end );\n\n                // hook, 每个分片发送之前可能要做些异步的事情。\n                promise = me.request( 'before-send', block, function() {\n\n                    // 有可能文件已经上传出错了，所以不需要再传输了。\n                    if ( file.getStatus() === Status.PROGRESS ) {\n                        me._doSend( block );\n                    } else {\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n\n                // 如果为fail了，则跳过此分片。\n                promise.fail(function() {\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file ).always(function() {\n                            block.percentage = 1;\n                            me._popBlock( block );\n                            me.owner.trigger( 'uploadComplete', file );\n                            Base.nextTick( me.__tick );\n                        });\n                    } else {\n                        block.percentage = 1;\n                        me.updateFileProgress( file );\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n            },\n\n\n            /**\n             * @event uploadBeforeSend\n             * @param {Object} object\n             * @param {Object} data 默认的上传参数，可以扩展此对象来控制上传参数。\n             * @param {Object} headers 可以扩展此对象来控制上传头部。\n             * @description 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadAccept\n             * @param {Object} object\n             * @param {Object} ret 服务端的返回数据，json格式，如果服务端不是json格式，从ret._raw中取数据，自行解析。\n             * @description 当某个文件上传到服务端响应后，会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为`false`, 则此文件将派送`server`类型的`uploadError`事件。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadProgress\n             * @param {File} file File对象\n             * @param {Number} percentage 上传进度\n             * @description 上传过程中触发，携带上传进度。\n             * @for  Uploader\n             */\n\n\n            /**\n             * @event uploadError\n             * @param {File} file File对象\n             * @param {String} reason 出错的code\n             * @description 当文件上传出错时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadSuccess\n             * @param {File} file File对象\n             * @param {Object} response 服务端返回的数据\n             * @description 当文件上传成功时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadComplete\n             * @param {File} [file] File对象\n             * @description 不管成功或者失败，文件上传完成时触发。\n             * @for  Uploader\n             */\n\n            // 做上传操作。\n            _doSend: function( block ) {\n                var me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    file = block.file,\n                    tr = new Transport( opts ),\n                    data = $.extend({}, opts.formData ),\n                    headers = $.extend({}, opts.headers ),\n                    requestAccept, ret;\n\n                block.transport = tr;\n\n                tr.on( 'destroy', function() {\n                    delete block.transport;\n                    me._popBlock( block );\n                    Base.nextTick( me.__tick );\n                });\n\n                // 广播上传进度。以文件为单位。\n                tr.on( 'progress', function( percentage ) {\n                    block.percentage = percentage;\n                    me.updateFileProgress( file );\n                });\n\n                // 用来询问，是否返回的结果是有错误的。\n                requestAccept = function( reject ) {\n                    var fn;\n\n                    ret = tr.getResponseAsJson() || {};\n                    ret._raw = tr.getResponse();\n                    fn = function( value ) {\n                        reject = value;\n                    };\n\n                    // 服务端响应了，不代表成功了，询问是否响应正确。\n                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {\n                        reject = reject || 'server';\n                    }\n\n                    return reject;\n                };\n\n                // 尝试重试，然后广播文件上传出错。\n                tr.on( 'error', function( type, flag ) {\n                    block.retried = block.retried || 0;\n\n                    // 自动重试\n                    if ( block.chunks > 1 && ~'http,abort'.indexOf( type ) &&\n                            block.retried < opts.chunkRetry ) {\n\n                        block.retried++;\n                        tr.send();\n\n                    } else {\n\n                        // http status 500 ~ 600\n                        if ( !flag && type === 'server' ) {\n                            type = requestAccept( type );\n                        }\n\n                        file.setStatus( Status.ERROR, type );\n                        owner.trigger( 'uploadError', file, type );\n                        owner.trigger( 'uploadComplete', file );\n                    }\n                });\n\n                // 上传成功\n                tr.on( 'load', function() {\n                    var reason;\n\n                    // 如果非预期，转向上传出错。\n                    if ( (reason = requestAccept()) ) {\n                        tr.trigger( 'error', reason, true );\n                        return;\n                    }\n\n                    // 全部上传完成。\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file, ret );\n                    } else {\n                        tr.destroy();\n                    }\n                });\n\n                // 配置默认的上传字段。\n                data = $.extend( data, {\n                    id: file.id,\n                    name: file.name,\n                    type: file.type,\n                    lastModifiedDate: file.lastModifiedDate,\n                    size: file.size\n                });\n\n                block.chunks > 1 && $.extend( data, {\n                    chunks: block.chunks,\n                    chunk: block.chunk\n                });\n\n                // 在发送之间可以添加字段什么的。。。\n                // 如果默认的字段不够使用，可以通过监听此事件来扩展\n                owner.trigger( 'uploadBeforeSend', block, data, headers );\n\n                // 开始发送。\n                tr.appendBlob( opts.fileVal, block.blob, file.name );\n                tr.append( data );\n                tr.setRequestHeader( headers );\n                tr.send();\n            },\n\n            // 完成上传。\n            _finishFile: function( file, ret, hds ) {\n                var owner = this.owner;\n\n                return owner\n                        .request( 'after-send-file', arguments, function() {\n                            file.setStatus( Status.COMPLETE );\n                            owner.trigger( 'uploadSuccess', file, ret, hds );\n                        })\n                        .fail(function( reason ) {\n\n                            // 如果外部已经标记为invalid什么的，不再改状态。\n                            if ( file.getStatus() === Status.PROGRESS ) {\n                                file.setStatus( Status.ERROR, reason );\n                            }\n\n                            owner.trigger( 'uploadError', file, reason );\n                        })\n                        .always(function() {\n                            owner.trigger( 'uploadComplete', file );\n                        });\n            },\n\n            updateFileProgress: function(file) {\n                var totalPercent = 0,\n                    uploaded = 0;\n\n                if (!file.blocks) {\n                    return;\n                }\n\n                $.each( file.blocks, function( _, v ) {\n                    uploaded += (v.percentage || 0) * (v.end - v.start);\n                });\n\n                totalPercent = uploaded / file.size;\n                this.owner.trigger( 'uploadProgress', file, totalPercent || 0 );\n            }\n\n        });\n    });\n    /**\n     * @fileOverview 各种验证，包括文件总大小是否超出、单文件是否超出和文件是否重复。\n     */\n\n    define('widgets/validator',[\n        'base',\n        'uploader',\n        'file',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile ) {\n\n        var $ = Base.$,\n            validators = {},\n            api;\n\n        /**\n         * @event error\n         * @param {String} type 错误类型。\n         * @description 当validate不通过时，会以派送错误事件的形式通知调用者。通过`upload.on('error', handler)`可以捕获到此类错误，目前有以下错误会在特定的情况下派送错来。\n         *\n         * * `Q_EXCEED_NUM_LIMIT` 在设置了`fileNumLimit`且尝试给`uploader`添加的文件数量超出这个值时派送。\n         * * `Q_EXCEED_SIZE_LIMIT` 在设置了`Q_EXCEED_SIZE_LIMIT`且尝试给`uploader`添加的文件总大小超出这个值时派送。\n         * * `Q_TYPE_DENIED` 当文件类型不满足时触发。。\n         * @for  Uploader\n         */\n\n        // 暴露给外面的api\n        api = {\n\n            // 添加验证器\n            addValidator: function( type, cb ) {\n                validators[ type ] = cb;\n            },\n\n            // 移除验证器\n            removeValidator: function( type ) {\n                delete validators[ type ];\n            }\n        };\n\n        // 在Uploader初始化的时候启动Validators的初始化\n        Uploader.register({\n            name: 'validator',\n\n            init: function() {\n                var me = this;\n                Base.nextTick(function() {\n                    $.each( validators, function() {\n                        this.call( me.owner );\n                    });\n                });\n            }\n        });\n\n        /**\n         * @property {int} [fileNumLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总数量, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileNumLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileNumLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( count >= max && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_NUM_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return count >= max ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function() {\n                count++;\n            });\n\n            uploader.on( 'fileDequeued', function() {\n                count--;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n\n        /**\n         * @property {int} [fileSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileSizeLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var invalid = count + file.size > max;\n\n                if ( invalid && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_SIZE_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return invalid ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                count += file.size;\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                count -= file.size;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n        /**\n         * @property {int} [fileSingleSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证单个文件大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSingleSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                max = opts.fileSingleSizeLimit;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( file.size > max ) {\n                    file.setStatus( WUFile.Status.INVALID, 'exceed_size' );\n                    this.trigger( 'error', 'F_EXCEED_SIZE', max, file );\n                    return false;\n                }\n\n            });\n\n        });\n\n        /**\n         * @property {Boolean} [duplicate=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 去重， 根据文件名字、文件大小和最后修改时间来生成hash Key.\n         */\n        api.addValidator( 'duplicate', function() {\n            var uploader = this,\n                opts = uploader.options,\n                mapping = {};\n\n            if ( opts.duplicate ) {\n                return;\n            }\n\n            function hashString( str ) {\n                var hash = 0,\n                    i = 0,\n                    len = str.length,\n                    _char;\n\n                for ( ; i < len; i++ ) {\n                    _char = str.charCodeAt( i );\n                    hash = _char + (hash << 6) + (hash << 16) - hash;\n                }\n\n                return hash;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var hash = file.__hash || (file.__hash = hashString( file.name +\n                        file.size + file.lastModifiedDate ));\n\n                // 已经重复了\n                if ( mapping[ hash ] ) {\n                    this.trigger( 'error', 'F_DUPLICATE', file );\n                    return false;\n                }\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (mapping[ hash ] = true);\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (delete mapping[ hash ]);\n            });\n\n            uploader.on( 'reset', function() {\n                mapping = {};\n            });\n        });\n\n        return api;\n    });\n\n    /**\n     * @fileOverview Md5\n     */\n    define('lib/md5',[\n        'runtime/client',\n        'mediator'\n    ], function( RuntimeClient, Mediator ) {\n\n        function Md5() {\n            RuntimeClient.call( this, 'Md5' );\n        }\n\n        // 让 Md5 具备事件功能。\n        Mediator.installTo( Md5.prototype );\n\n        Md5.prototype.loadFromBlob = function( blob ) {\n            var me = this;\n\n            if ( me.getRuid() ) {\n                me.disconnectRuntime();\n            }\n\n            // 连接到blob归属的同一个runtime.\n            me.connectRuntime( blob.ruid, function() {\n                me.exec('init');\n                me.exec( 'loadFromBlob', blob );\n            });\n        };\n\n        Md5.prototype.getResult = function() {\n            return this.exec('getResult');\n        };\n\n        return Md5;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/md5',[\n        'base',\n        'uploader',\n        'lib/md5',\n        'lib/blob',\n        'widgets/widget'\n    ], function( Base, Uploader, Md5, Blob ) {\n\n        return Uploader.register({\n            name: 'md5',\n\n\n            /**\n             * 计算文件 md5 值，返回一个 promise 对象，可以监听 progress 进度。\n             *\n             *\n             * @method md5File\n             * @grammar md5File( file[, start[, end]] ) => promise\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.md5File( file )\n             *\n             *         // 及时显示进度\n             *         .progress(function(percentage) {\n             *             console.log('Percentage:', percentage);\n             *         })\n             *\n             *         // 完成\n             *         .then(function(val) {\n             *             console.log('md5 result:', val);\n             *         });\n             *\n             * });\n             */\n            md5File: function( file, start, end ) {\n                var md5 = new Md5(),\n                    deferred = Base.Deferred(),\n                    blob = (file instanceof Blob) ? file :\n                        this.request( 'get-file', file ).source;\n\n                md5.on( 'progress load', function( e ) {\n                    e = e || {};\n                    deferred.notify( e.total ? e.loaded / e.total : 1 );\n                });\n\n                md5.on( 'complete', function() {\n                    deferred.resolve( md5.getResult() );\n                });\n\n                md5.on( 'error', function( reason ) {\n                    deferred.reject( reason );\n                });\n\n                if ( arguments.length > 1 ) {\n                    start = start || 0;\n                    end = end || 0;\n                    start < 0 && (start = blob.size + start);\n                    end < 0 && (end = blob.size + end);\n                    end = Math.min( end, blob.size );\n                    blob = blob.slice( start, end );\n                }\n\n                md5.loadFromBlob( blob );\n\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/compbase',[],function() {\n\n        function CompBase( owner, runtime ) {\n\n            this.owner = owner;\n            this.options = owner.options;\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.getRuid = function() {\n                return runtime.uid;\n            };\n\n            this.trigger = function() {\n                return owner.trigger.apply( owner, arguments );\n            };\n        }\n\n        return CompBase;\n    });\n    /**\n     * @fileOverview Html5Runtime\n     */\n    define('runtime/html5/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var type = 'html5',\n            components = {};\n\n        function Html5Runtime() {\n            var pool = {},\n                me = this,\n                destroy = this.destroy;\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                if ( components[ comp ] ) {\n                    instance = pool[ uid ] = pool[ uid ] ||\n                            new components[ comp ]( client, me );\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n            };\n\n            me.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n        }\n\n        Base.inherits( Runtime, {\n            constructor: Html5Runtime,\n\n            // 不需要连接其他程序，直接执行callback\n            init: function() {\n                var me = this;\n                setTimeout(function() {\n                    me.trigger('ready');\n                }, 1 );\n            }\n\n        });\n\n        // 注册Components\n        Html5Runtime.register = function( name, component ) {\n            var klass = components[ name ] = Base.inherits( CompBase, component );\n            return klass;\n        };\n\n        // 注册html5运行时。\n        // 只有在支持的前提下注册。\n        if ( window.Blob && window.FileReader && window.DataView ) {\n            Runtime.addRuntime( type, Html5Runtime );\n        }\n\n        return Html5Runtime;\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/html5/blob',[\n        'runtime/html5/runtime',\n        'lib/blob'\n    ], function( Html5Runtime, Blob ) {\n\n        return Html5Runtime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.owner.source,\n                    slice = blob.slice || blob.webkitSlice || blob.mozSlice;\n\n                blob = slice.call( blob, start, end );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/dnd',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        var $ = Base.$,\n            prefix = 'webuploader-dnd-';\n\n        return Html5Runtime.register( 'DragAndDrop', {\n            init: function() {\n                var elem = this.elem = this.options.container;\n\n                this.dragEnterHandler = Base.bindFn( this._dragEnterHandler, this );\n                this.dragOverHandler = Base.bindFn( this._dragOverHandler, this );\n                this.dragLeaveHandler = Base.bindFn( this._dragLeaveHandler, this );\n                this.dropHandler = Base.bindFn( this._dropHandler, this );\n                this.dndOver = false;\n\n                elem.on( 'dragenter', this.dragEnterHandler );\n                elem.on( 'dragover', this.dragOverHandler );\n                elem.on( 'dragleave', this.dragLeaveHandler );\n                elem.on( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).on( 'dragover', this.dragOverHandler );\n                    $( document ).on( 'drop', this.dropHandler );\n                }\n            },\n\n            _dragEnterHandler: function( e ) {\n                var me = this,\n                    denied = me._denied || false,\n                    items;\n\n                e = e.originalEvent || e;\n\n                if ( !me.dndOver ) {\n                    me.dndOver = true;\n\n                    // 注意只有 chrome 支持。\n                    items = e.dataTransfer.items;\n\n                    if ( items && items.length ) {\n                        me._denied = denied = !me.trigger( 'accept', items );\n                    }\n\n                    me.elem.addClass( prefix + 'over' );\n                    me.elem[ denied ? 'addClass' :\n                            'removeClass' ]( prefix + 'denied' );\n                }\n\n                e.dataTransfer.dropEffect = denied ? 'none' : 'copy';\n\n                return false;\n            },\n\n            _dragOverHandler: function( e ) {\n                // 只处理框内的。\n                var parentElem = this.elem.parent().get( 0 );\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                clearTimeout( this._leaveTimer );\n                this._dragEnterHandler.call( this, e );\n\n                return false;\n            },\n\n            _dragLeaveHandler: function() {\n                var me = this,\n                    handler;\n\n                handler = function() {\n                    me.dndOver = false;\n                    me.elem.removeClass( prefix + 'over ' + prefix + 'denied' );\n                };\n\n                clearTimeout( me._leaveTimer );\n                me._leaveTimer = setTimeout( handler, 100 );\n                return false;\n            },\n\n            _dropHandler: function( e ) {\n                var me = this,\n                    ruid = me.getRuid(),\n                    parentElem = me.elem.parent().get( 0 ),\n                    dataTransfer, data;\n\n                // 只处理框内的。\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                e = e.originalEvent || e;\n                dataTransfer = e.dataTransfer;\n\n                // 如果是页面内拖拽，还不能处理，不阻止事件。\n                // 此处 ie11 下会报参数错误，\n                try {\n                    data = dataTransfer.getData('text/html');\n                } catch( err ) {\n                }\n\n                if ( data ) {\n                    return;\n                }\n\n                me._getTansferFiles( dataTransfer, function( results ) {\n                    me.trigger( 'drop', $.map( results, function( file ) {\n                        return new File( ruid, file );\n                    }) );\n                });\n\n                me.dndOver = false;\n                me.elem.removeClass( prefix + 'over' );\n                return false;\n            },\n\n            // 如果传入 callback 则去查看文件夹，否则只管当前文件夹。\n            _getTansferFiles: function( dataTransfer, callback ) {\n                var results  = [],\n                    promises = [],\n                    items, files, file, item, i, len, canAccessFolder;\n\n                items = dataTransfer.items;\n                files = dataTransfer.files;\n\n                canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);\n\n                for ( i = 0, len = files.length; i < len; i++ ) {\n                    file = files[ i ];\n                    item = items && items[ i ];\n\n                    if ( canAccessFolder && item.webkitGetAsEntry().isDirectory ) {\n\n                        promises.push( this._traverseDirectoryTree(\n                                item.webkitGetAsEntry(), results ) );\n                    } else {\n                        results.push( file );\n                    }\n                }\n\n                Base.when.apply( Base, promises ).done(function() {\n\n                    if ( !results.length ) {\n                        return;\n                    }\n\n                    callback( results );\n                });\n            },\n\n            _traverseDirectoryTree: function( entry, results ) {\n                var deferred = Base.Deferred(),\n                    me = this;\n\n                if ( entry.isFile ) {\n                    entry.file(function( file ) {\n                        results.push( file );\n                        deferred.resolve();\n                    });\n                } else if ( entry.isDirectory ) {\n                    entry.createReader().readEntries(function( entries ) {\n                        var len = entries.length,\n                            promises = [],\n                            arr = [],    // 为了保证顺序。\n                            i;\n\n                        for ( i = 0; i < len; i++ ) {\n                            promises.push( me._traverseDirectoryTree(\n                                    entries[ i ], arr ) );\n                        }\n\n                        Base.when.apply( Base, promises ).then(function() {\n                            results.push.apply( results, arr );\n                            deferred.resolve();\n                        }, deferred.reject );\n                    });\n                }\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                var elem = this.elem;\n\n                // 还没 init 就调用 destroy\n                if (!elem) {\n                    return;\n                }\n\n                elem.off( 'dragenter', this.dragEnterHandler );\n                elem.off( 'dragover', this.dragOverHandler );\n                elem.off( 'dragleave', this.dragLeaveHandler );\n                elem.off( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).off( 'dragover', this.dragOverHandler );\n                    $( document ).off( 'drop', this.dropHandler );\n                }\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/filepaste',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        return Html5Runtime.register( 'FilePaste', {\n            init: function() {\n                var opts = this.options,\n                    elem = this.elem = opts.container,\n                    accept = '.*',\n                    arr, i, len, item;\n\n                // accetp的mimeTypes中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].mimeTypes;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = arr.join(',');\n                        accept = accept.replace( /,/g, '|' ).replace( /\\*/g, '.*' );\n                    }\n                }\n                this.accept = accept = new RegExp( accept, 'i' );\n                this.hander = Base.bindFn( this._pasteHander, this );\n                elem.on( 'paste', this.hander );\n            },\n\n            _pasteHander: function( e ) {\n                var allowed = [],\n                    ruid = this.getRuid(),\n                    items, item, blob, i, len;\n\n                e = e.originalEvent || e;\n                items = e.clipboardData.items;\n\n                for ( i = 0, len = items.length; i < len; i++ ) {\n                    item = items[ i ];\n\n                    if ( item.kind !== 'file' || !(blob = item.getAsFile()) ) {\n                        continue;\n                    }\n\n                    allowed.push( new File( ruid, blob ) );\n                }\n\n                if ( allowed.length ) {\n                    // 不阻止非文件粘贴（文字粘贴）的事件冒泡\n                    e.preventDefault();\n                    e.stopPropagation();\n                    this.trigger( 'paste', allowed );\n                }\n            },\n\n            destroy: function() {\n                this.elem.off( 'paste', this.hander );\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/html5/filepicker',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var $ = Base.$;\n\n        return Html5Runtime.register( 'FilePicker', {\n            init: function() {\n                var container = this.getRuntime().getContainer(),\n                    me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    label = this.label = $( document.createElement('label') ),\n                    input =  this.input = $( document.createElement('input') ),\n                    arr, i, len, mouseHandler;\n\n                input.attr( 'type', 'file' );\n                input.attr( 'name', opts.name );\n                input.addClass('webuploader-element-invisible');\n\n                label.on( 'click', function() {\n                    input.trigger('click');\n                });\n\n                label.css({\n                    opacity: 0,\n                    width: '100%',\n                    height: '100%',\n                    display: 'block',\n                    cursor: 'pointer',\n                    background: '#ffffff'\n                });\n\n                if ( opts.multiple ) {\n                    input.attr( 'multiple', 'multiple' );\n                }\n\n                // @todo Firefox不支持单独指定后缀\n                if ( opts.accept && opts.accept.length > 0 ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        arr.push( opts.accept[ i ].mimeTypes );\n                    }\n\n                    input.attr( 'accept', arr.join(',') );\n                }\n\n                container.append( input );\n                container.append( label );\n\n                mouseHandler = function( e ) {\n                    owner.trigger( e.type );\n                };\n\n                input.on( 'change', function( e ) {\n                    var fn = arguments.callee,\n                        clone;\n\n                    me.files = e.target.files;\n\n                    // reset input\n                    clone = this.cloneNode( true );\n                    clone.value = null;\n                    this.parentNode.replaceChild( clone, this );\n\n                    input.off();\n                    input = $( clone ).on( 'change', fn )\n                            .on( 'mouseenter mouseleave', mouseHandler );\n\n                    owner.trigger('change');\n                });\n\n                label.on( 'mouseenter mouseleave', mouseHandler );\n\n            },\n\n\n            getFiles: function() {\n                return this.files;\n            },\n\n            destroy: function() {\n                this.input.off();\n                this.label.off();\n            }\n        });\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/util',[\n        'base'\n    ], function( Base ) {\n\n        var urlAPI = window.createObjectURL && window ||\n                window.URL && URL.revokeObjectURL && URL ||\n                window.webkitURL,\n            createObjectURL = Base.noop,\n            revokeObjectURL = createObjectURL;\n\n        if ( urlAPI ) {\n\n            // 更安全的方式调用，比如android里面就能把context改成其他的对象。\n            createObjectURL = function() {\n                return urlAPI.createObjectURL.apply( urlAPI, arguments );\n            };\n\n            revokeObjectURL = function() {\n                return urlAPI.revokeObjectURL.apply( urlAPI, arguments );\n            };\n        }\n\n        return {\n            createObjectURL: createObjectURL,\n            revokeObjectURL: revokeObjectURL,\n\n            dataURL2Blob: function( dataURI ) {\n                var byteStr, intArray, ab, i, mimetype, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                ab = new ArrayBuffer( byteStr.length );\n                intArray = new Uint8Array( ab );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                mimetype = parts[ 0 ].split(':')[ 1 ].split(';')[ 0 ];\n\n                return this.arrayBufferToBlob( ab, mimetype );\n            },\n\n            dataURL2ArrayBuffer: function( dataURI ) {\n                var byteStr, intArray, i, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                intArray = new Uint8Array( byteStr.length );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                return intArray.buffer;\n            },\n\n            arrayBufferToBlob: function( buffer, type ) {\n                var builder = window.BlobBuilder || window.WebKitBlobBuilder,\n                    bb;\n\n                // android不支持直接new Blob, 只能借助blobbuilder.\n                if ( builder ) {\n                    bb = new builder();\n                    bb.append( buffer );\n                    return bb.getBlob( type );\n                }\n\n                return new Blob([ buffer ], type ? { type: type } : {} );\n            },\n\n            // 抽出来主要是为了解决android下面canvas.toDataUrl不支持jpeg.\n            // 你得到的结果是png.\n            canvasToDataUrl: function( canvas, type, quality ) {\n                return canvas.toDataURL( type, quality / 100 );\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            parseMeta: function( blob, callback ) {\n                callback( false, {});\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            updateImageHead: function( data ) {\n                return data;\n            }\n        };\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/imagemeta',[\n        'runtime/html5/util'\n    ], function( Util ) {\n\n        var api;\n\n        api = {\n            parsers: {\n                0xffe1: []\n            },\n\n            maxMetaDataSize: 262144,\n\n            parse: function( blob, cb ) {\n                var me = this,\n                    fr = new FileReader();\n\n                fr.onload = function() {\n                    cb( false, me._parse( this.result ) );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                fr.onerror = function( e ) {\n                    cb( e.message );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                blob = blob.slice( 0, me.maxMetaDataSize );\n                fr.readAsArrayBuffer( blob.getSource() );\n            },\n\n            _parse: function( buffer, noParse ) {\n                if ( buffer.byteLength < 6 ) {\n                    return;\n                }\n\n                var dataview = new DataView( buffer ),\n                    offset = 2,\n                    maxOffset = dataview.byteLength - 4,\n                    headLength = offset,\n                    ret = {},\n                    markerBytes, markerLength, parsers, i;\n\n                if ( dataview.getUint16( 0 ) === 0xffd8 ) {\n\n                    while ( offset < maxOffset ) {\n                        markerBytes = dataview.getUint16( offset );\n\n                        if ( markerBytes >= 0xffe0 && markerBytes <= 0xffef ||\n                                markerBytes === 0xfffe ) {\n\n                            markerLength = dataview.getUint16( offset + 2 ) + 2;\n\n                            if ( offset + markerLength > dataview.byteLength ) {\n                                break;\n                            }\n\n                            parsers = api.parsers[ markerBytes ];\n\n                            if ( !noParse && parsers ) {\n                                for ( i = 0; i < parsers.length; i += 1 ) {\n                                    parsers[ i ].call( api, dataview, offset,\n                                            markerLength, ret );\n                                }\n                            }\n\n                            offset += markerLength;\n                            headLength = offset;\n                        } else {\n                            break;\n                        }\n                    }\n\n                    if ( headLength > 6 ) {\n                        if ( buffer.slice ) {\n                            ret.imageHead = buffer.slice( 2, headLength );\n                        } else {\n                            // Workaround for IE10, which does not yet\n                            // support ArrayBuffer.slice:\n                            ret.imageHead = new Uint8Array( buffer )\n                                    .subarray( 2, headLength );\n                        }\n                    }\n                }\n\n                return ret;\n            },\n\n            updateImageHead: function( buffer, head ) {\n                var data = this._parse( buffer, true ),\n                    buf1, buf2, bodyoffset;\n\n\n                bodyoffset = 2;\n                if ( data.imageHead ) {\n                    bodyoffset = 2 + data.imageHead.byteLength;\n                }\n\n                if ( buffer.slice ) {\n                    buf2 = buffer.slice( bodyoffset );\n                } else {\n                    buf2 = new Uint8Array( buffer ).subarray( bodyoffset );\n                }\n\n                buf1 = new Uint8Array( head.byteLength + 2 + buf2.byteLength );\n\n                buf1[ 0 ] = 0xFF;\n                buf1[ 1 ] = 0xD8;\n                buf1.set( new Uint8Array( head ), 2 );\n                buf1.set( new Uint8Array( buf2 ), head.byteLength + 2 );\n\n                return buf1.buffer;\n            }\n        };\n\n        Util.parseMeta = function() {\n            return api.parse.apply( api, arguments );\n        };\n\n        Util.updateImageHead = function() {\n            return api.updateImageHead.apply( api, arguments );\n        };\n\n        return api;\n    });\n    /**\n     * 代码来自于：https://github.com/blueimp/JavaScript-Load-Image\n     * 暂时项目中只用了orientation.\n     *\n     * 去除了 Exif Sub IFD Pointer, GPS Info IFD Pointer, Exif Thumbnail.\n     * @fileOverview EXIF解析\n     */\n\n    // Sample\n    // ====================================\n    // Make : Apple\n    // Model : iPhone 4S\n    // Orientation : 1\n    // XResolution : 72 [72/1]\n    // YResolution : 72 [72/1]\n    // ResolutionUnit : 2\n    // Software : QuickTime 7.7.1\n    // DateTime : 2013:09:01 22:53:55\n    // ExifIFDPointer : 190\n    // ExposureTime : 0.058823529411764705 [1/17]\n    // FNumber : 2.4 [12/5]\n    // ExposureProgram : Normal program\n    // ISOSpeedRatings : 800\n    // ExifVersion : 0220\n    // DateTimeOriginal : 2013:09:01 22:52:51\n    // DateTimeDigitized : 2013:09:01 22:52:51\n    // ComponentsConfiguration : YCbCr\n    // ShutterSpeedValue : 4.058893515764426\n    // ApertureValue : 2.5260688216892597 [4845/1918]\n    // BrightnessValue : -0.3126686601998395\n    // MeteringMode : Pattern\n    // Flash : Flash did not fire, compulsory flash mode\n    // FocalLength : 4.28 [107/25]\n    // SubjectArea : [4 values]\n    // FlashpixVersion : 0100\n    // ColorSpace : 1\n    // PixelXDimension : 2448\n    // PixelYDimension : 3264\n    // SensingMethod : One-chip color area sensor\n    // ExposureMode : 0\n    // WhiteBalance : Auto white balance\n    // FocalLengthIn35mmFilm : 35\n    // SceneCaptureType : Standard\n    define('runtime/html5/imagemeta/exif',[\n        'base',\n        'runtime/html5/imagemeta'\n    ], function( Base, ImageMeta ) {\n\n        var EXIF = {};\n\n        EXIF.ExifMap = function() {\n            return this;\n        };\n\n        EXIF.ExifMap.prototype.map = {\n            'Orientation': 0x0112\n        };\n\n        EXIF.ExifMap.prototype.get = function( id ) {\n            return this[ id ] || this[ this.map[ id ] ];\n        };\n\n        EXIF.exifTagTypes = {\n            // byte, 8-bit unsigned int:\n            1: {\n                getValue: function( dataView, dataOffset ) {\n                    return dataView.getUint8( dataOffset );\n                },\n                size: 1\n            },\n\n            // ascii, 8-bit byte:\n            2: {\n                getValue: function( dataView, dataOffset ) {\n                    return String.fromCharCode( dataView.getUint8( dataOffset ) );\n                },\n                size: 1,\n                ascii: true\n            },\n\n            // short, 16 bit int:\n            3: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint16( dataOffset, littleEndian );\n                },\n                size: 2\n            },\n\n            // long, 32 bit int:\n            4: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // rational = two long values,\n            // first is numerator, second is denominator:\n            5: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian ) /\n                        dataView.getUint32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            },\n\n            // slong, 32 bit signed int:\n            9: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // srational, two slongs, first is numerator, second is denominator:\n            10: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian ) /\n                        dataView.getInt32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            }\n        };\n\n        // undefined, 8-bit byte, value depending on field:\n        EXIF.exifTagTypes[ 7 ] = EXIF.exifTagTypes[ 1 ];\n\n        EXIF.getExifValue = function( dataView, tiffOffset, offset, type, length,\n                littleEndian ) {\n\n            var tagType = EXIF.exifTagTypes[ type ],\n                tagSize, dataOffset, values, i, str, c;\n\n            if ( !tagType ) {\n                Base.log('Invalid Exif data: Invalid tag type.');\n                return;\n            }\n\n            tagSize = tagType.size * length;\n\n            // Determine if the value is contained in the dataOffset bytes,\n            // or if the value at the dataOffset is a pointer to the actual data:\n            dataOffset = tagSize > 4 ? tiffOffset + dataView.getUint32( offset + 8,\n                    littleEndian ) : (offset + 8);\n\n            if ( dataOffset + tagSize > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid data offset.');\n                return;\n            }\n\n            if ( length === 1 ) {\n                return tagType.getValue( dataView, dataOffset, littleEndian );\n            }\n\n            values = [];\n\n            for ( i = 0; i < length; i += 1 ) {\n                values[ i ] = tagType.getValue( dataView,\n                        dataOffset + i * tagType.size, littleEndian );\n            }\n\n            if ( tagType.ascii ) {\n                str = '';\n\n                // Concatenate the chars:\n                for ( i = 0; i < values.length; i += 1 ) {\n                    c = values[ i ];\n\n                    // Ignore the terminating NULL byte(s):\n                    if ( c === '\\u0000' ) {\n                        break;\n                    }\n                    str += c;\n                }\n\n                return str;\n            }\n            return values;\n        };\n\n        EXIF.parseExifTag = function( dataView, tiffOffset, offset, littleEndian,\n                data ) {\n\n            var tag = dataView.getUint16( offset, littleEndian );\n            data.exif[ tag ] = EXIF.getExifValue( dataView, tiffOffset, offset,\n                    dataView.getUint16( offset + 2, littleEndian ),    // tag type\n                    dataView.getUint32( offset + 4, littleEndian ),    // tag length\n                    littleEndian );\n        };\n\n        EXIF.parseExifTags = function( dataView, tiffOffset, dirOffset,\n                littleEndian, data ) {\n\n            var tagsNumber, dirEndOffset, i;\n\n            if ( dirOffset + 6 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory offset.');\n                return;\n            }\n\n            tagsNumber = dataView.getUint16( dirOffset, littleEndian );\n            dirEndOffset = dirOffset + 2 + 12 * tagsNumber;\n\n            if ( dirEndOffset + 4 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory size.');\n                return;\n            }\n\n            for ( i = 0; i < tagsNumber; i += 1 ) {\n                this.parseExifTag( dataView, tiffOffset,\n                        dirOffset + 2 + 12 * i,    // tag offset\n                        littleEndian, data );\n            }\n\n            // Return the offset to the next directory:\n            return dataView.getUint32( dirEndOffset, littleEndian );\n        };\n\n        // EXIF.getExifThumbnail = function(dataView, offset, length) {\n        //     var hexData,\n        //         i,\n        //         b;\n        //     if (!length || offset + length > dataView.byteLength) {\n        //         Base.log('Invalid Exif data: Invalid thumbnail data.');\n        //         return;\n        //     }\n        //     hexData = [];\n        //     for (i = 0; i < length; i += 1) {\n        //         b = dataView.getUint8(offset + i);\n        //         hexData.push((b < 16 ? '0' : '') + b.toString(16));\n        //     }\n        //     return 'data:image/jpeg,%' + hexData.join('%');\n        // };\n\n        EXIF.parseExifData = function( dataView, offset, length, data ) {\n\n            var tiffOffset = offset + 10,\n                littleEndian, dirOffset;\n\n            // Check for the ASCII code for \"Exif\" (0x45786966):\n            if ( dataView.getUint32( offset + 4 ) !== 0x45786966 ) {\n                // No Exif data, might be XMP data instead\n                return;\n            }\n            if ( tiffOffset + 8 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid segment size.');\n                return;\n            }\n\n            // Check for the two null bytes:\n            if ( dataView.getUint16( offset + 8 ) !== 0x0000 ) {\n                Base.log('Invalid Exif data: Missing byte alignment offset.');\n                return;\n            }\n\n            // Check the byte alignment:\n            switch ( dataView.getUint16( tiffOffset ) ) {\n                case 0x4949:\n                    littleEndian = true;\n                    break;\n\n                case 0x4D4D:\n                    littleEndian = false;\n                    break;\n\n                default:\n                    Base.log('Invalid Exif data: Invalid byte alignment marker.');\n                    return;\n            }\n\n            // Check for the TIFF tag marker (0x002A):\n            if ( dataView.getUint16( tiffOffset + 2, littleEndian ) !== 0x002A ) {\n                Base.log('Invalid Exif data: Missing TIFF marker.');\n                return;\n            }\n\n            // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:\n            dirOffset = dataView.getUint32( tiffOffset + 4, littleEndian );\n            // Create the exif object to store the tags:\n            data.exif = new EXIF.ExifMap();\n            // Parse the tags of the main image directory and retrieve the\n            // offset to the next directory, usually the thumbnail directory:\n            dirOffset = EXIF.parseExifTags( dataView, tiffOffset,\n                    tiffOffset + dirOffset, littleEndian, data );\n\n            // 尝试读取缩略图\n            // if ( dirOffset ) {\n            //     thumbnailData = {exif: {}};\n            //     dirOffset = EXIF.parseExifTags(\n            //         dataView,\n            //         tiffOffset,\n            //         tiffOffset + dirOffset,\n            //         littleEndian,\n            //         thumbnailData\n            //     );\n\n            //     // Check for JPEG Thumbnail offset:\n            //     if (thumbnailData.exif[0x0201]) {\n            //         data.exif.Thumbnail = EXIF.getExifThumbnail(\n            //             dataView,\n            //             tiffOffset + thumbnailData.exif[0x0201],\n            //             thumbnailData.exif[0x0202] // Thumbnail data length\n            //         );\n            //     }\n            // }\n        };\n\n        ImageMeta.parsers[ 0xffe1 ].push( EXIF.parseExifData );\n        return EXIF;\n    });\n    /**\n     * 这个方式性能不行，但是可以解决android里面的toDataUrl的bug\n     * android里面toDataUrl('image/jpege')得到的结果却是png.\n     *\n     * 所以这里没辙，只能借助这个工具\n     * @fileOverview jpeg encoder\n     */\n    define('runtime/html5/jpegencoder',[], function( require, exports, module ) {\n\n        /*\n          Copyright (c) 2008, Adobe Systems Incorporated\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\n          met:\n\n          * Redistributions of source code must retain the above copyright notice,\n            this list of conditions and the following disclaimer.\n\n          * Redistributions in binary form must reproduce the above copyright\n            notice, this list of conditions and the following disclaimer in the\n            documentation and/or other materials provided with the distribution.\n\n          * Neither the name of Adobe Systems Incorporated nor the names of its\n            contributors may be used to endorse or promote products derived from\n            this software without specific prior written permission.\n\n          THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n          IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n          THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n          PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n          CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n          EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n          PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n          PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n          LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n          NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n          SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n        */\n        /*\n        JPEG encoder ported to JavaScript and optimized by Andreas Ritter, www.bytestrom.eu, 11/2009\n\n        Basic GUI blocking jpeg encoder\n        */\n\n        function JPEGEncoder(quality) {\n          var self = this;\n            var fround = Math.round;\n            var ffloor = Math.floor;\n            var YTable = new Array(64);\n            var UVTable = new Array(64);\n            var fdtbl_Y = new Array(64);\n            var fdtbl_UV = new Array(64);\n            var YDC_HT;\n            var UVDC_HT;\n            var YAC_HT;\n            var UVAC_HT;\n\n            var bitcode = new Array(65535);\n            var category = new Array(65535);\n            var outputfDCTQuant = new Array(64);\n            var DU = new Array(64);\n            var byteout = [];\n            var bytenew = 0;\n            var bytepos = 7;\n\n            var YDU = new Array(64);\n            var UDU = new Array(64);\n            var VDU = new Array(64);\n            var clt = new Array(256);\n            var RGB_YUV_TABLE = new Array(2048);\n            var currentQuality;\n\n            var ZigZag = [\n                     0, 1, 5, 6,14,15,27,28,\n                     2, 4, 7,13,16,26,29,42,\n                     3, 8,12,17,25,30,41,43,\n                     9,11,18,24,31,40,44,53,\n                    10,19,23,32,39,45,52,54,\n                    20,22,33,38,46,51,55,60,\n                    21,34,37,47,50,56,59,61,\n                    35,36,48,49,57,58,62,63\n                ];\n\n            var std_dc_luminance_nrcodes = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];\n            var std_dc_luminance_values = [0,1,2,3,4,5,6,7,8,9,10,11];\n            var std_ac_luminance_nrcodes = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];\n            var std_ac_luminance_values = [\n                    0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,\n                    0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,\n                    0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\n                    0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,\n                    0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,\n                    0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\n                    0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,\n                    0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,\n                    0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\n                    0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,\n                    0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,\n                    0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\n                    0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,\n                    0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,\n                    0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\n                    0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,\n                    0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,\n                    0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\n                    0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,\n                    0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\n                    0xf9,0xfa\n                ];\n\n            var std_dc_chrominance_nrcodes = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];\n            var std_dc_chrominance_values = [0,1,2,3,4,5,6,7,8,9,10,11];\n            var std_ac_chrominance_nrcodes = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];\n            var std_ac_chrominance_values = [\n                    0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,\n                    0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,\n                    0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\n                    0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,\n                    0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,\n                    0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\n                    0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,\n                    0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,\n                    0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\n                    0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,\n                    0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,\n                    0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\n                    0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,\n                    0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,\n                    0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\n                    0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,\n                    0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,\n                    0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\n                    0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,\n                    0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\n                    0xf9,0xfa\n                ];\n\n            function initQuantTables(sf){\n                    var YQT = [\n                        16, 11, 10, 16, 24, 40, 51, 61,\n                        12, 12, 14, 19, 26, 58, 60, 55,\n                        14, 13, 16, 24, 40, 57, 69, 56,\n                        14, 17, 22, 29, 51, 87, 80, 62,\n                        18, 22, 37, 56, 68,109,103, 77,\n                        24, 35, 55, 64, 81,104,113, 92,\n                        49, 64, 78, 87,103,121,120,101,\n                        72, 92, 95, 98,112,100,103, 99\n                    ];\n\n                    for (var i = 0; i < 64; i++) {\n                        var t = ffloor((YQT[i]*sf+50)/100);\n                        if (t < 1) {\n                            t = 1;\n                        } else if (t > 255) {\n                            t = 255;\n                        }\n                        YTable[ZigZag[i]] = t;\n                    }\n                    var UVQT = [\n                        17, 18, 24, 47, 99, 99, 99, 99,\n                        18, 21, 26, 66, 99, 99, 99, 99,\n                        24, 26, 56, 99, 99, 99, 99, 99,\n                        47, 66, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99\n                    ];\n                    for (var j = 0; j < 64; j++) {\n                        var u = ffloor((UVQT[j]*sf+50)/100);\n                        if (u < 1) {\n                            u = 1;\n                        } else if (u > 255) {\n                            u = 255;\n                        }\n                        UVTable[ZigZag[j]] = u;\n                    }\n                    var aasf = [\n                        1.0, 1.387039845, 1.306562965, 1.175875602,\n                        1.0, 0.785694958, 0.541196100, 0.275899379\n                    ];\n                    var k = 0;\n                    for (var row = 0; row < 8; row++)\n                    {\n                        for (var col = 0; col < 8; col++)\n                        {\n                            fdtbl_Y[k]  = (1.0 / (YTable [ZigZag[k]] * aasf[row] * aasf[col] * 8.0));\n                            fdtbl_UV[k] = (1.0 / (UVTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0));\n                            k++;\n                        }\n                    }\n                }\n\n                function computeHuffmanTbl(nrcodes, std_table){\n                    var codevalue = 0;\n                    var pos_in_table = 0;\n                    var HT = new Array();\n                    for (var k = 1; k <= 16; k++) {\n                        for (var j = 1; j <= nrcodes[k]; j++) {\n                            HT[std_table[pos_in_table]] = [];\n                            HT[std_table[pos_in_table]][0] = codevalue;\n                            HT[std_table[pos_in_table]][1] = k;\n                            pos_in_table++;\n                            codevalue++;\n                        }\n                        codevalue*=2;\n                    }\n                    return HT;\n                }\n\n                function initHuffmanTbl()\n                {\n                    YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);\n                    UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);\n                    YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);\n                    UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);\n                }\n\n                function initCategoryNumber()\n                {\n                    var nrlower = 1;\n                    var nrupper = 2;\n                    for (var cat = 1; cat <= 15; cat++) {\n                        //Positive numbers\n                        for (var nr = nrlower; nr<nrupper; nr++) {\n                            category[32767+nr] = cat;\n                            bitcode[32767+nr] = [];\n                            bitcode[32767+nr][1] = cat;\n                            bitcode[32767+nr][0] = nr;\n                        }\n                        //Negative numbers\n                        for (var nrneg =-(nrupper-1); nrneg<=-nrlower; nrneg++) {\n                            category[32767+nrneg] = cat;\n                            bitcode[32767+nrneg] = [];\n                            bitcode[32767+nrneg][1] = cat;\n                            bitcode[32767+nrneg][0] = nrupper-1+nrneg;\n                        }\n                        nrlower <<= 1;\n                        nrupper <<= 1;\n                    }\n                }\n\n                function initRGBYUVTable() {\n                    for(var i = 0; i < 256;i++) {\n                        RGB_YUV_TABLE[i]            =  19595 * i;\n                        RGB_YUV_TABLE[(i+ 256)>>0]  =  38470 * i;\n                        RGB_YUV_TABLE[(i+ 512)>>0]  =   7471 * i + 0x8000;\n                        RGB_YUV_TABLE[(i+ 768)>>0]  = -11059 * i;\n                        RGB_YUV_TABLE[(i+1024)>>0]  = -21709 * i;\n                        RGB_YUV_TABLE[(i+1280)>>0]  =  32768 * i + 0x807FFF;\n                        RGB_YUV_TABLE[(i+1536)>>0]  = -27439 * i;\n                        RGB_YUV_TABLE[(i+1792)>>0]  = - 5329 * i;\n                    }\n                }\n\n                // IO functions\n                function writeBits(bs)\n                {\n                    var value = bs[0];\n                    var posval = bs[1]-1;\n                    while ( posval >= 0 ) {\n                        if (value & (1 << posval) ) {\n                            bytenew |= (1 << bytepos);\n                        }\n                        posval--;\n                        bytepos--;\n                        if (bytepos < 0) {\n                            if (bytenew == 0xFF) {\n                                writeByte(0xFF);\n                                writeByte(0);\n                            }\n                            else {\n                                writeByte(bytenew);\n                            }\n                            bytepos=7;\n                            bytenew=0;\n                        }\n                    }\n                }\n\n                function writeByte(value)\n                {\n                    byteout.push(clt[value]); // write char directly instead of converting later\n                }\n\n                function writeWord(value)\n                {\n                    writeByte((value>>8)&0xFF);\n                    writeByte((value   )&0xFF);\n                }\n\n                // DCT & quantization core\n                function fDCTQuant(data, fdtbl)\n                {\n                    var d0, d1, d2, d3, d4, d5, d6, d7;\n                    /* Pass 1: process rows. */\n                    var dataOff=0;\n                    var i;\n                    var I8 = 8;\n                    var I64 = 64;\n                    for (i=0; i<I8; ++i)\n                    {\n                        d0 = data[dataOff];\n                        d1 = data[dataOff+1];\n                        d2 = data[dataOff+2];\n                        d3 = data[dataOff+3];\n                        d4 = data[dataOff+4];\n                        d5 = data[dataOff+5];\n                        d6 = data[dataOff+6];\n                        d7 = data[dataOff+7];\n\n                        var tmp0 = d0 + d7;\n                        var tmp7 = d0 - d7;\n                        var tmp1 = d1 + d6;\n                        var tmp6 = d1 - d6;\n                        var tmp2 = d2 + d5;\n                        var tmp5 = d2 - d5;\n                        var tmp3 = d3 + d4;\n                        var tmp4 = d3 - d4;\n\n                        /* Even part */\n                        var tmp10 = tmp0 + tmp3;    /* phase 2 */\n                        var tmp13 = tmp0 - tmp3;\n                        var tmp11 = tmp1 + tmp2;\n                        var tmp12 = tmp1 - tmp2;\n\n                        data[dataOff] = tmp10 + tmp11; /* phase 3 */\n                        data[dataOff+4] = tmp10 - tmp11;\n\n                        var z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */\n                        data[dataOff+2] = tmp13 + z1; /* phase 5 */\n                        data[dataOff+6] = tmp13 - z1;\n\n                        /* Odd part */\n                        tmp10 = tmp4 + tmp5; /* phase 2 */\n                        tmp11 = tmp5 + tmp6;\n                        tmp12 = tmp6 + tmp7;\n\n                        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n                        var z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */\n                        var z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */\n                        var z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */\n                        var z3 = tmp11 * 0.707106781; /* c4 */\n\n                        var z11 = tmp7 + z3;    /* phase 5 */\n                        var z13 = tmp7 - z3;\n\n                        data[dataOff+5] = z13 + z2; /* phase 6 */\n                        data[dataOff+3] = z13 - z2;\n                        data[dataOff+1] = z11 + z4;\n                        data[dataOff+7] = z11 - z4;\n\n                        dataOff += 8; /* advance pointer to next row */\n                    }\n\n                    /* Pass 2: process columns. */\n                    dataOff = 0;\n                    for (i=0; i<I8; ++i)\n                    {\n                        d0 = data[dataOff];\n                        d1 = data[dataOff + 8];\n                        d2 = data[dataOff + 16];\n                        d3 = data[dataOff + 24];\n                        d4 = data[dataOff + 32];\n                        d5 = data[dataOff + 40];\n                        d6 = data[dataOff + 48];\n                        d7 = data[dataOff + 56];\n\n                        var tmp0p2 = d0 + d7;\n                        var tmp7p2 = d0 - d7;\n                        var tmp1p2 = d1 + d6;\n                        var tmp6p2 = d1 - d6;\n                        var tmp2p2 = d2 + d5;\n                        var tmp5p2 = d2 - d5;\n                        var tmp3p2 = d3 + d4;\n                        var tmp4p2 = d3 - d4;\n\n                        /* Even part */\n                        var tmp10p2 = tmp0p2 + tmp3p2;  /* phase 2 */\n                        var tmp13p2 = tmp0p2 - tmp3p2;\n                        var tmp11p2 = tmp1p2 + tmp2p2;\n                        var tmp12p2 = tmp1p2 - tmp2p2;\n\n                        data[dataOff] = tmp10p2 + tmp11p2; /* phase 3 */\n                        data[dataOff+32] = tmp10p2 - tmp11p2;\n\n                        var z1p2 = (tmp12p2 + tmp13p2) * 0.707106781; /* c4 */\n                        data[dataOff+16] = tmp13p2 + z1p2; /* phase 5 */\n                        data[dataOff+48] = tmp13p2 - z1p2;\n\n                        /* Odd part */\n                        tmp10p2 = tmp4p2 + tmp5p2; /* phase 2 */\n                        tmp11p2 = tmp5p2 + tmp6p2;\n                        tmp12p2 = tmp6p2 + tmp7p2;\n\n                        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n                        var z5p2 = (tmp10p2 - tmp12p2) * 0.382683433; /* c6 */\n                        var z2p2 = 0.541196100 * tmp10p2 + z5p2; /* c2-c6 */\n                        var z4p2 = 1.306562965 * tmp12p2 + z5p2; /* c2+c6 */\n                        var z3p2 = tmp11p2 * 0.707106781; /* c4 */\n\n                        var z11p2 = tmp7p2 + z3p2;  /* phase 5 */\n                        var z13p2 = tmp7p2 - z3p2;\n\n                        data[dataOff+40] = z13p2 + z2p2; /* phase 6 */\n                        data[dataOff+24] = z13p2 - z2p2;\n                        data[dataOff+ 8] = z11p2 + z4p2;\n                        data[dataOff+56] = z11p2 - z4p2;\n\n                        dataOff++; /* advance pointer to next column */\n                    }\n\n                    // Quantize/descale the coefficients\n                    var fDCTQuant;\n                    for (i=0; i<I64; ++i)\n                    {\n                        // Apply the quantization and scaling factor & Round to nearest integer\n                        fDCTQuant = data[i]*fdtbl[i];\n                        outputfDCTQuant[i] = (fDCTQuant > 0.0) ? ((fDCTQuant + 0.5)|0) : ((fDCTQuant - 0.5)|0);\n                        //outputfDCTQuant[i] = fround(fDCTQuant);\n\n                    }\n                    return outputfDCTQuant;\n                }\n\n                function writeAPP0()\n                {\n                    writeWord(0xFFE0); // marker\n                    writeWord(16); // length\n                    writeByte(0x4A); // J\n                    writeByte(0x46); // F\n                    writeByte(0x49); // I\n                    writeByte(0x46); // F\n                    writeByte(0); // = \"JFIF\",'\\0'\n                    writeByte(1); // versionhi\n                    writeByte(1); // versionlo\n                    writeByte(0); // xyunits\n                    writeWord(1); // xdensity\n                    writeWord(1); // ydensity\n                    writeByte(0); // thumbnwidth\n                    writeByte(0); // thumbnheight\n                }\n\n                function writeSOF0(width, height)\n                {\n                    writeWord(0xFFC0); // marker\n                    writeWord(17);   // length, truecolor YUV JPG\n                    writeByte(8);    // precision\n                    writeWord(height);\n                    writeWord(width);\n                    writeByte(3);    // nrofcomponents\n                    writeByte(1);    // IdY\n                    writeByte(0x11); // HVY\n                    writeByte(0);    // QTY\n                    writeByte(2);    // IdU\n                    writeByte(0x11); // HVU\n                    writeByte(1);    // QTU\n                    writeByte(3);    // IdV\n                    writeByte(0x11); // HVV\n                    writeByte(1);    // QTV\n                }\n\n                function writeDQT()\n                {\n                    writeWord(0xFFDB); // marker\n                    writeWord(132);    // length\n                    writeByte(0);\n                    for (var i=0; i<64; i++) {\n                        writeByte(YTable[i]);\n                    }\n                    writeByte(1);\n                    for (var j=0; j<64; j++) {\n                        writeByte(UVTable[j]);\n                    }\n                }\n\n                function writeDHT()\n                {\n                    writeWord(0xFFC4); // marker\n                    writeWord(0x01A2); // length\n\n                    writeByte(0); // HTYDCinfo\n                    for (var i=0; i<16; i++) {\n                        writeByte(std_dc_luminance_nrcodes[i+1]);\n                    }\n                    for (var j=0; j<=11; j++) {\n                        writeByte(std_dc_luminance_values[j]);\n                    }\n\n                    writeByte(0x10); // HTYACinfo\n                    for (var k=0; k<16; k++) {\n                        writeByte(std_ac_luminance_nrcodes[k+1]);\n                    }\n                    for (var l=0; l<=161; l++) {\n                        writeByte(std_ac_luminance_values[l]);\n                    }\n\n                    writeByte(1); // HTUDCinfo\n                    for (var m=0; m<16; m++) {\n                        writeByte(std_dc_chrominance_nrcodes[m+1]);\n                    }\n                    for (var n=0; n<=11; n++) {\n                        writeByte(std_dc_chrominance_values[n]);\n                    }\n\n                    writeByte(0x11); // HTUACinfo\n                    for (var o=0; o<16; o++) {\n                        writeByte(std_ac_chrominance_nrcodes[o+1]);\n                    }\n                    for (var p=0; p<=161; p++) {\n                        writeByte(std_ac_chrominance_values[p]);\n                    }\n                }\n\n                function writeSOS()\n                {\n                    writeWord(0xFFDA); // marker\n                    writeWord(12); // length\n                    writeByte(3); // nrofcomponents\n                    writeByte(1); // IdY\n                    writeByte(0); // HTY\n                    writeByte(2); // IdU\n                    writeByte(0x11); // HTU\n                    writeByte(3); // IdV\n                    writeByte(0x11); // HTV\n                    writeByte(0); // Ss\n                    writeByte(0x3f); // Se\n                    writeByte(0); // Bf\n                }\n\n                function processDU(CDU, fdtbl, DC, HTDC, HTAC){\n                    var EOB = HTAC[0x00];\n                    var M16zeroes = HTAC[0xF0];\n                    var pos;\n                    var I16 = 16;\n                    var I63 = 63;\n                    var I64 = 64;\n                    var DU_DCT = fDCTQuant(CDU, fdtbl);\n                    //ZigZag reorder\n                    for (var j=0;j<I64;++j) {\n                        DU[ZigZag[j]]=DU_DCT[j];\n                    }\n                    var Diff = DU[0] - DC; DC = DU[0];\n                    //Encode DC\n                    if (Diff==0) {\n                        writeBits(HTDC[0]); // Diff might be 0\n                    } else {\n                        pos = 32767+Diff;\n                        writeBits(HTDC[category[pos]]);\n                        writeBits(bitcode[pos]);\n                    }\n                    //Encode ACs\n                    var end0pos = 63; // was const... which is crazy\n                    for (; (end0pos>0)&&(DU[end0pos]==0); end0pos--) {};\n                    //end0pos = first element in reverse order !=0\n                    if ( end0pos == 0) {\n                        writeBits(EOB);\n                        return DC;\n                    }\n                    var i = 1;\n                    var lng;\n                    while ( i <= end0pos ) {\n                        var startpos = i;\n                        for (; (DU[i]==0) && (i<=end0pos); ++i) {}\n                        var nrzeroes = i-startpos;\n                        if ( nrzeroes >= I16 ) {\n                            lng = nrzeroes>>4;\n                            for (var nrmarker=1; nrmarker <= lng; ++nrmarker)\n                                writeBits(M16zeroes);\n                            nrzeroes = nrzeroes&0xF;\n                        }\n                        pos = 32767+DU[i];\n                        writeBits(HTAC[(nrzeroes<<4)+category[pos]]);\n                        writeBits(bitcode[pos]);\n                        i++;\n                    }\n                    if ( end0pos != I63 ) {\n                        writeBits(EOB);\n                    }\n                    return DC;\n                }\n\n                function initCharLookupTable(){\n                    var sfcc = String.fromCharCode;\n                    for(var i=0; i < 256; i++){ ///// ACHTUNG // 255\n                        clt[i] = sfcc(i);\n                    }\n                }\n\n                this.encode = function(image,quality) // image data object\n                {\n                    // var time_start = new Date().getTime();\n\n                    if(quality) setQuality(quality);\n\n                    // Initialize bit writer\n                    byteout = new Array();\n                    bytenew=0;\n                    bytepos=7;\n\n                    // Add JPEG headers\n                    writeWord(0xFFD8); // SOI\n                    writeAPP0();\n                    writeDQT();\n                    writeSOF0(image.width,image.height);\n                    writeDHT();\n                    writeSOS();\n\n\n                    // Encode 8x8 macroblocks\n                    var DCY=0;\n                    var DCU=0;\n                    var DCV=0;\n\n                    bytenew=0;\n                    bytepos=7;\n\n\n                    this.encode.displayName = \"_encode_\";\n\n                    var imageData = image.data;\n                    var width = image.width;\n                    var height = image.height;\n\n                    var quadWidth = width*4;\n                    var tripleWidth = width*3;\n\n                    var x, y = 0;\n                    var r, g, b;\n                    var start,p, col,row,pos;\n                    while(y < height){\n                        x = 0;\n                        while(x < quadWidth){\n                        start = quadWidth * y + x;\n                        p = start;\n                        col = -1;\n                        row = 0;\n\n                        for(pos=0; pos < 64; pos++){\n                            row = pos >> 3;// /8\n                            col = ( pos & 7 ) * 4; // %8\n                            p = start + ( row * quadWidth ) + col;\n\n                            if(y+row >= height){ // padding bottom\n                                p-= (quadWidth*(y+1+row-height));\n                            }\n\n                            if(x+col >= quadWidth){ // padding right\n                                p-= ((x+col) - quadWidth +4)\n                            }\n\n                            r = imageData[ p++ ];\n                            g = imageData[ p++ ];\n                            b = imageData[ p++ ];\n\n\n                            /* // calculate YUV values dynamically\n                            YDU[pos]=((( 0.29900)*r+( 0.58700)*g+( 0.11400)*b))-128; //-0x80\n                            UDU[pos]=(((-0.16874)*r+(-0.33126)*g+( 0.50000)*b));\n                            VDU[pos]=((( 0.50000)*r+(-0.41869)*g+(-0.08131)*b));\n                            */\n\n                            // use lookup table (slightly faster)\n                            YDU[pos] = ((RGB_YUV_TABLE[r]             + RGB_YUV_TABLE[(g +  256)>>0] + RGB_YUV_TABLE[(b +  512)>>0]) >> 16)-128;\n                            UDU[pos] = ((RGB_YUV_TABLE[(r +  768)>>0] + RGB_YUV_TABLE[(g + 1024)>>0] + RGB_YUV_TABLE[(b + 1280)>>0]) >> 16)-128;\n                            VDU[pos] = ((RGB_YUV_TABLE[(r + 1280)>>0] + RGB_YUV_TABLE[(g + 1536)>>0] + RGB_YUV_TABLE[(b + 1792)>>0]) >> 16)-128;\n\n                        }\n\n                        DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n                        DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n                        DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n                        x+=32;\n                        }\n                        y+=8;\n                    }\n\n\n                    ////////////////////////////////////////////////////////////////\n\n                    // Do the bit alignment of the EOI marker\n                    if ( bytepos >= 0 ) {\n                        var fillbits = [];\n                        fillbits[1] = bytepos+1;\n                        fillbits[0] = (1<<(bytepos+1))-1;\n                        writeBits(fillbits);\n                    }\n\n                    writeWord(0xFFD9); //EOI\n\n                    var jpegDataUri = 'data:image/jpeg;base64,' + btoa(byteout.join(''));\n\n                    byteout = [];\n\n                    // benchmarking\n                    // var duration = new Date().getTime() - time_start;\n                    // console.log('Encoding time: '+ currentQuality + 'ms');\n                    //\n\n                    return jpegDataUri\n            }\n\n            function setQuality(quality){\n                if (quality <= 0) {\n                    quality = 1;\n                }\n                if (quality > 100) {\n                    quality = 100;\n                }\n\n                if(currentQuality == quality) return // don't recalc if unchanged\n\n                var sf = 0;\n                if (quality < 50) {\n                    sf = Math.floor(5000 / quality);\n                } else {\n                    sf = Math.floor(200 - quality*2);\n                }\n\n                initQuantTables(sf);\n                currentQuality = quality;\n                // console.log('Quality set to: '+quality +'%');\n            }\n\n            function init(){\n                // var time_start = new Date().getTime();\n                if(!quality) quality = 50;\n                // Create tables\n                initCharLookupTable()\n                initHuffmanTbl();\n                initCategoryNumber();\n                initRGBYUVTable();\n\n                setQuality(quality);\n                // var duration = new Date().getTime() - time_start;\n                // console.log('Initialization '+ duration + 'ms');\n            }\n\n            init();\n\n        };\n\n        JPEGEncoder.encode = function( data, quality ) {\n            var encoder = new JPEGEncoder( quality );\n\n            return encoder.encode( data );\n        }\n\n        return JPEGEncoder;\n    });\n    /**\n     * @fileOverview Fix android canvas.toDataUrl bug.\n     */\n    define('runtime/html5/androidpatch',[\n        'runtime/html5/util',\n        'runtime/html5/jpegencoder',\n        'base'\n    ], function( Util, encoder, Base ) {\n        var origin = Util.canvasToDataUrl,\n            supportJpeg;\n\n        Util.canvasToDataUrl = function( canvas, type, quality ) {\n            var ctx, w, h, fragement, parts;\n\n            // 非android手机直接跳过。\n            if ( !Base.os.android ) {\n                return origin.apply( null, arguments );\n            }\n\n            // 检测是否canvas支持jpeg导出，根据数据格式来判断。\n            // JPEG 前两位分别是：255, 216\n            if ( type === 'image/jpeg' && typeof supportJpeg === 'undefined' ) {\n                fragement = origin.apply( null, arguments );\n\n                parts = fragement.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    fragement = atob( parts[ 1 ] );\n                } else {\n                    fragement = decodeURIComponent( parts[ 1 ] );\n                }\n\n                fragement = fragement.substring( 0, 2 );\n\n                supportJpeg = fragement.charCodeAt( 0 ) === 255 &&\n                        fragement.charCodeAt( 1 ) === 216;\n            }\n\n            // 只有在android环境下才修复\n            if ( type === 'image/jpeg' && !supportJpeg ) {\n                w = canvas.width;\n                h = canvas.height;\n                ctx = canvas.getContext('2d');\n\n                return encoder.encode( ctx.getImageData( 0, 0, w, h ), quality );\n            }\n\n            return origin.apply( null, arguments );\n        };\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('runtime/html5/image',[\n        'base',\n        'runtime/html5/runtime',\n        'runtime/html5/util'\n    ], function( Base, Html5Runtime, Util ) {\n\n        var BLANK = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D';\n\n        return Html5Runtime.register( 'Image', {\n\n            // flag: 标记是否被修改过。\n            modified: false,\n\n            init: function() {\n                var me = this,\n                    img = new Image();\n\n                img.onload = function() {\n\n                    me._info = {\n                        type: me.type,\n                        width: this.width,\n                        height: this.height\n                    };\n\n                    // 读取meta信息。\n                    if ( !me._metas && 'image/jpeg' === me.type ) {\n                        Util.parseMeta( me._blob, function( error, ret ) {\n                            me._metas = ret;\n                            me.owner.trigger('load');\n                        });\n                    } else {\n                        me.owner.trigger('load');\n                    }\n                };\n\n                img.onerror = function() {\n                    me.owner.trigger('error');\n                };\n\n                me._img = img;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    img = me._img;\n\n                me._blob = blob;\n                me.type = blob.type;\n                img.src = Util.createObjectURL( blob.getSource() );\n                me.owner.once( 'load', function() {\n                    Util.revokeObjectURL( img.src );\n                });\n            },\n\n            resize: function( width, height ) {\n                var canvas = this._canvas ||\n                        (this._canvas = document.createElement('canvas'));\n\n                this._resize( this._img, canvas, width, height );\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'resize' );\n            },\n\n            crop: function( x, y, w, h, s ) {\n                var cvs = this._canvas ||\n                        (this._canvas = document.createElement('canvas')),\n                    opts = this.options,\n                    img = this._img,\n                    iw = img.naturalWidth,\n                    ih = img.naturalHeight,\n                    orientation = this.getOrientation();\n\n                s = s || 1;\n\n                // todo 解决 orientation 的问题。\n                // values that require 90 degree rotation\n                // if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                //     switch ( orientation ) {\n                //         case 6:\n                //             tmp = x;\n                //             x = y;\n                //             y = iw * s - tmp - w;\n                //             console.log(ih * s, tmp, w)\n                //             break;\n                //     }\n\n                //     (w ^= h, h ^= w, w ^= h);\n                // }\n\n                cvs.width = w;\n                cvs.height = h;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n                this._renderImageToCanvas( cvs, img, -x, -y, iw * s, ih * s );\n\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'crop' );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this._blob,\n                    opts = this.options,\n                    canvas;\n\n                type = type || this.type;\n\n                // blob需要重新生成。\n                if ( this.modified || this.type !== type ) {\n                    canvas = this._canvas;\n\n                    if ( type === 'image/jpeg' ) {\n\n                        blob = Util.canvasToDataUrl( canvas, type, opts.quality );\n\n                        if ( opts.preserveHeaders && this._metas &&\n                                this._metas.imageHead ) {\n\n                            blob = Util.dataURL2ArrayBuffer( blob );\n                            blob = Util.updateImageHead( blob,\n                                    this._metas.imageHead );\n                            blob = Util.arrayBufferToBlob( blob, type );\n                            return blob;\n                        }\n                    } else {\n                        blob = Util.canvasToDataUrl( canvas, type );\n                    }\n\n                    blob = Util.dataURL2Blob( blob );\n                }\n\n                return blob;\n            },\n\n            getAsDataUrl: function( type ) {\n                var opts = this.options;\n\n                type = type || this.type;\n\n                if ( type === 'image/jpeg' ) {\n                    return Util.canvasToDataUrl( this._canvas, type, opts.quality );\n                } else {\n                    return this._canvas.toDataURL( type );\n                }\n            },\n\n            getOrientation: function() {\n                return this._metas && this._metas.exif &&\n                        this._metas.exif.get('Orientation') || 1;\n            },\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            destroy: function() {\n                var canvas = this._canvas;\n                this._img.onload = null;\n\n                if ( canvas ) {\n                    canvas.getContext('2d')\n                            .clearRect( 0, 0, canvas.width, canvas.height );\n                    canvas.width = canvas.height = 0;\n                    this._canvas = null;\n                }\n\n                // 释放内存。非常重要，否则释放不了image的内存。\n                this._img.src = BLANK;\n                this._img = this._blob = null;\n            },\n\n            _resize: function( img, cvs, width, height ) {\n                var opts = this.options,\n                    naturalWidth = img.width,\n                    naturalHeight = img.height,\n                    orientation = this.getOrientation(),\n                    scale, w, h, x, y;\n\n                // values that require 90 degree rotation\n                if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                    // 交换width, height的值。\n                    width ^= height;\n                    height ^= width;\n                    width ^= height;\n                }\n\n                scale = Math[ opts.crop ? 'max' : 'min' ]( width / naturalWidth,\n                        height / naturalHeight );\n\n                // 不允许放大。\n                opts.allowMagnify || (scale = Math.min( 1, scale ));\n\n                w = naturalWidth * scale;\n                h = naturalHeight * scale;\n\n                if ( opts.crop ) {\n                    cvs.width = width;\n                    cvs.height = height;\n                } else {\n                    cvs.width = w;\n                    cvs.height = h;\n                }\n\n                x = (cvs.width - w) / 2;\n                y = (cvs.height - h) / 2;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n\n                this._renderImageToCanvas( cvs, img, x, y, w, h );\n            },\n\n            _rotate2Orientaion: function( canvas, orientation ) {\n                var width = canvas.width,\n                    height = canvas.height,\n                    ctx = canvas.getContext('2d');\n\n                switch ( orientation ) {\n                    case 5:\n                    case 6:\n                    case 7:\n                    case 8:\n                        canvas.width = height;\n                        canvas.height = width;\n                        break;\n                }\n\n                switch ( orientation ) {\n                    case 2:    // horizontal flip\n                        ctx.translate( width, 0 );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 3:    // 180 rotate left\n                        ctx.translate( width, height );\n                        ctx.rotate( Math.PI );\n                        break;\n\n                    case 4:    // vertical flip\n                        ctx.translate( 0, height );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 5:    // vertical flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 6:    // 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( 0, -height );\n                        break;\n\n                    case 7:    // horizontal flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( width, -height );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 8:    // 90 rotate left\n                        ctx.rotate( -0.5 * Math.PI );\n                        ctx.translate( -width, 0 );\n                        break;\n                }\n            },\n\n            // https://github.com/stomita/ios-imagefile-megapixel/\n            // blob/master/src/megapix-image.js\n            _renderImageToCanvas: (function() {\n\n                // 如果不是ios, 不需要这么复杂！\n                if ( !Base.os.ios ) {\n                    return function( canvas ) {\n                        var args = Base.slice( arguments, 1 ),\n                            ctx = canvas.getContext('2d');\n\n                        ctx.drawImage.apply( ctx, args );\n                    };\n                }\n\n                /**\n                 * Detecting vertical squash in loaded image.\n                 * Fixes a bug which squash image vertically while drawing into\n                 * canvas for some images.\n                 */\n                function detectVerticalSquash( img, iw, ih ) {\n                    var canvas = document.createElement('canvas'),\n                        ctx = canvas.getContext('2d'),\n                        sy = 0,\n                        ey = ih,\n                        py = ih,\n                        data, alpha, ratio;\n\n\n                    canvas.width = 1;\n                    canvas.height = ih;\n                    ctx.drawImage( img, 0, 0 );\n                    data = ctx.getImageData( 0, 0, 1, ih ).data;\n\n                    // search image edge pixel position in case\n                    // it is squashed vertically.\n                    while ( py > sy ) {\n                        alpha = data[ (py - 1) * 4 + 3 ];\n\n                        if ( alpha === 0 ) {\n                            ey = py;\n                        } else {\n                            sy = py;\n                        }\n\n                        py = (ey + sy) >> 1;\n                    }\n\n                    ratio = (py / ih);\n                    return (ratio === 0) ? 1 : ratio;\n                }\n\n                // fix ie7 bug\n                // http://stackoverflow.com/questions/11929099/\n                // html5-canvas-drawimage-ratio-bug-ios\n                if ( Base.os.ios >= 7 ) {\n                    return function( canvas, img, x, y, w, h ) {\n                        var iw = img.naturalWidth,\n                            ih = img.naturalHeight,\n                            vertSquashRatio = detectVerticalSquash( img, iw, ih );\n\n                        return canvas.getContext('2d').drawImage( img, 0, 0,\n                                iw * vertSquashRatio, ih * vertSquashRatio,\n                                x, y, w, h );\n                    };\n                }\n\n                /**\n                 * Detect subsampling in loaded image.\n                 * In iOS, larger images than 2M pixels may be\n                 * subsampled in rendering.\n                 */\n                function detectSubsampling( img ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        canvas, ctx;\n\n                    // subsampling may happen overmegapixel image\n                    if ( iw * ih > 1024 * 1024 ) {\n                        canvas = document.createElement('canvas');\n                        canvas.width = canvas.height = 1;\n                        ctx = canvas.getContext('2d');\n                        ctx.drawImage( img, -iw + 1, 0 );\n\n                        // subsampled image becomes half smaller in rendering size.\n                        // check alpha channel value to confirm image is covering\n                        // edge pixel or not. if alpha value is 0\n                        // image is not covering, hence subsampled.\n                        return ctx.getImageData( 0, 0, 1, 1 ).data[ 3 ] === 0;\n                    } else {\n                        return false;\n                    }\n                }\n\n\n                return function( canvas, img, x, y, width, height ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        ctx = canvas.getContext('2d'),\n                        subsampled = detectSubsampling( img ),\n                        doSquash = this.type === 'image/jpeg',\n                        d = 1024,\n                        sy = 0,\n                        dy = 0,\n                        tmpCanvas, tmpCtx, vertSquashRatio, dw, dh, sx, dx;\n\n                    if ( subsampled ) {\n                        iw /= 2;\n                        ih /= 2;\n                    }\n\n                    ctx.save();\n                    tmpCanvas = document.createElement('canvas');\n                    tmpCanvas.width = tmpCanvas.height = d;\n\n                    tmpCtx = tmpCanvas.getContext('2d');\n                    vertSquashRatio = doSquash ?\n                            detectVerticalSquash( img, iw, ih ) : 1;\n\n                    dw = Math.ceil( d * width / iw );\n                    dh = Math.ceil( d * height / ih / vertSquashRatio );\n\n                    while ( sy < ih ) {\n                        sx = 0;\n                        dx = 0;\n                        while ( sx < iw ) {\n                            tmpCtx.clearRect( 0, 0, d, d );\n                            tmpCtx.drawImage( img, -sx, -sy );\n                            ctx.drawImage( tmpCanvas, 0, 0, d, d,\n                                    x + dx, y + dy, dw, dh );\n                            sx += d;\n                            dx += dw;\n                        }\n                        sy += d;\n                        dy += dh;\n                    }\n                    ctx.restore();\n                    tmpCanvas = tmpCtx = null;\n                };\n            })()\n        });\n    });\n    /**\n     * @fileOverview Transport\n     * @todo 支持chunked传输，优势：\n     * 可以将大文件分成小块，挨个传输，可以提高大文件成功率，当失败的时候，也只需要重传那小部分，\n     * 而不需要重头再传一次。另外断点续传也需要用chunked方式。\n     */\n    define('runtime/html5/transport',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var noop = Base.noop,\n            $ = Base.$;\n\n        return Html5Runtime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    formData, binary, fr;\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.getSource();\n                } else {\n                    formData = new FormData();\n                    $.each( owner._formData, function( k, v ) {\n                        formData.append( k, v );\n                    });\n\n                    formData.append( opts.fileVal, blob.getSource(),\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                if ( opts.withCredentials && 'withCredentials' in xhr ) {\n                    xhr.open( opts.method, server, true );\n                    xhr.withCredentials = true;\n                } else {\n                    xhr.open( opts.method, server );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n\n                if ( binary ) {\n                    // 强制设置成 content-type 为文件流。\n                    xhr.overrideMimeType &&\n                            xhr.overrideMimeType('application/octet-stream');\n\n                    // android直接发送blob会导致服务端接收到的是空文件。\n                    // bug详情。\n                    // https://code.google.com/p/android/issues/detail?id=39882\n                    // 所以先用fileReader读取出来再通过arraybuffer的方式发送。\n                    if ( Base.os.android ) {\n                        fr = new FileReader();\n\n                        fr.onload = function() {\n                            xhr.send( this.result );\n                            fr = fr.onload = null;\n                        };\n\n                        fr.readAsArrayBuffer( binary );\n                    } else {\n                        xhr.send( binary );\n                    }\n                } else {\n                    xhr.send( formData );\n                }\n            },\n\n            getResponse: function() {\n                return this._response;\n            },\n\n            getResponseAsJson: function() {\n                return this._parseJson( this._response );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    xhr.abort();\n\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new XMLHttpRequest(),\n                    opts = this.options;\n\n                if ( opts.withCredentials && !('withCredentials' in xhr) &&\n                        typeof XDomainRequest !== 'undefined' ) {\n                    xhr = new XDomainRequest();\n                }\n\n                xhr.upload.onprogress = function( e ) {\n                    var percentage = 0;\n\n                    if ( e.lengthComputable ) {\n                        percentage = e.loaded / e.total;\n                    }\n\n                    return me.trigger( 'progress', percentage );\n                };\n\n                xhr.onreadystatechange = function() {\n\n                    if ( xhr.readyState !== 4 ) {\n                        return;\n                    }\n\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    me._xhr = null;\n                    me._status = xhr.status;\n\n                    if ( xhr.status >= 200 && xhr.status < 300 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger('load');\n                    } else if ( xhr.status >= 500 && xhr.status < 600 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger( 'error', 'server' );\n                    }\n\n\n                    return me.trigger( 'error', me._status ? 'http' : 'abort' );\n                };\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.setRequestHeader( key, val );\n                });\n            },\n\n            _parseJson: function( str ) {\n                var json;\n\n                try {\n                    json = JSON.parse( str );\n                } catch ( ex ) {\n                    json = {};\n                }\n\n                return json;\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/html5/md5',[\n        'runtime/html5/runtime'\n    ], function( FlashRuntime ) {\n\n        /*\n         * Fastest md5 implementation around (JKM md5)\n         * Credits: Joseph Myers\n         *\n         * @see http://www.myersdaily.org/joseph/javascript/md5-text.html\n         * @see http://jsperf.com/md5-shootout/7\n         */\n\n        /* this function is much faster,\n          so if possible we use it. Some IEs\n          are the only ones I know of that\n          need the idiotic second function,\n          generated by an if clause.  */\n        var add32 = function (a, b) {\n            return (a + b) & 0xFFFFFFFF;\n        },\n\n        cmn = function (q, a, b, x, s, t) {\n            a = add32(add32(a, q), add32(x, t));\n            return add32((a << s) | (a >>> (32 - s)), b);\n        },\n\n        ff = function (a, b, c, d, x, s, t) {\n            return cmn((b & c) | ((~b) & d), a, b, x, s, t);\n        },\n\n        gg = function (a, b, c, d, x, s, t) {\n            return cmn((b & d) | (c & (~d)), a, b, x, s, t);\n        },\n\n        hh = function (a, b, c, d, x, s, t) {\n            return cmn(b ^ c ^ d, a, b, x, s, t);\n        },\n\n        ii = function (a, b, c, d, x, s, t) {\n            return cmn(c ^ (b | (~d)), a, b, x, s, t);\n        },\n\n        md5cycle = function (x, k) {\n            var a = x[0],\n                b = x[1],\n                c = x[2],\n                d = x[3];\n\n            a = ff(a, b, c, d, k[0], 7, -680876936);\n            d = ff(d, a, b, c, k[1], 12, -389564586);\n            c = ff(c, d, a, b, k[2], 17, 606105819);\n            b = ff(b, c, d, a, k[3], 22, -1044525330);\n            a = ff(a, b, c, d, k[4], 7, -176418897);\n            d = ff(d, a, b, c, k[5], 12, 1200080426);\n            c = ff(c, d, a, b, k[6], 17, -1473231341);\n            b = ff(b, c, d, a, k[7], 22, -45705983);\n            a = ff(a, b, c, d, k[8], 7, 1770035416);\n            d = ff(d, a, b, c, k[9], 12, -1958414417);\n            c = ff(c, d, a, b, k[10], 17, -42063);\n            b = ff(b, c, d, a, k[11], 22, -1990404162);\n            a = ff(a, b, c, d, k[12], 7, 1804603682);\n            d = ff(d, a, b, c, k[13], 12, -40341101);\n            c = ff(c, d, a, b, k[14], 17, -1502002290);\n            b = ff(b, c, d, a, k[15], 22, 1236535329);\n\n            a = gg(a, b, c, d, k[1], 5, -165796510);\n            d = gg(d, a, b, c, k[6], 9, -1069501632);\n            c = gg(c, d, a, b, k[11], 14, 643717713);\n            b = gg(b, c, d, a, k[0], 20, -373897302);\n            a = gg(a, b, c, d, k[5], 5, -701558691);\n            d = gg(d, a, b, c, k[10], 9, 38016083);\n            c = gg(c, d, a, b, k[15], 14, -660478335);\n            b = gg(b, c, d, a, k[4], 20, -405537848);\n            a = gg(a, b, c, d, k[9], 5, 568446438);\n            d = gg(d, a, b, c, k[14], 9, -1019803690);\n            c = gg(c, d, a, b, k[3], 14, -187363961);\n            b = gg(b, c, d, a, k[8], 20, 1163531501);\n            a = gg(a, b, c, d, k[13], 5, -1444681467);\n            d = gg(d, a, b, c, k[2], 9, -51403784);\n            c = gg(c, d, a, b, k[7], 14, 1735328473);\n            b = gg(b, c, d, a, k[12], 20, -1926607734);\n\n            a = hh(a, b, c, d, k[5], 4, -378558);\n            d = hh(d, a, b, c, k[8], 11, -2022574463);\n            c = hh(c, d, a, b, k[11], 16, 1839030562);\n            b = hh(b, c, d, a, k[14], 23, -35309556);\n            a = hh(a, b, c, d, k[1], 4, -1530992060);\n            d = hh(d, a, b, c, k[4], 11, 1272893353);\n            c = hh(c, d, a, b, k[7], 16, -155497632);\n            b = hh(b, c, d, a, k[10], 23, -1094730640);\n            a = hh(a, b, c, d, k[13], 4, 681279174);\n            d = hh(d, a, b, c, k[0], 11, -358537222);\n            c = hh(c, d, a, b, k[3], 16, -722521979);\n            b = hh(b, c, d, a, k[6], 23, 76029189);\n            a = hh(a, b, c, d, k[9], 4, -640364487);\n            d = hh(d, a, b, c, k[12], 11, -421815835);\n            c = hh(c, d, a, b, k[15], 16, 530742520);\n            b = hh(b, c, d, a, k[2], 23, -995338651);\n\n            a = ii(a, b, c, d, k[0], 6, -198630844);\n            d = ii(d, a, b, c, k[7], 10, 1126891415);\n            c = ii(c, d, a, b, k[14], 15, -1416354905);\n            b = ii(b, c, d, a, k[5], 21, -57434055);\n            a = ii(a, b, c, d, k[12], 6, 1700485571);\n            d = ii(d, a, b, c, k[3], 10, -1894986606);\n            c = ii(c, d, a, b, k[10], 15, -1051523);\n            b = ii(b, c, d, a, k[1], 21, -2054922799);\n            a = ii(a, b, c, d, k[8], 6, 1873313359);\n            d = ii(d, a, b, c, k[15], 10, -30611744);\n            c = ii(c, d, a, b, k[6], 15, -1560198380);\n            b = ii(b, c, d, a, k[13], 21, 1309151649);\n            a = ii(a, b, c, d, k[4], 6, -145523070);\n            d = ii(d, a, b, c, k[11], 10, -1120210379);\n            c = ii(c, d, a, b, k[2], 15, 718787259);\n            b = ii(b, c, d, a, k[9], 21, -343485551);\n\n            x[0] = add32(a, x[0]);\n            x[1] = add32(b, x[1]);\n            x[2] = add32(c, x[2]);\n            x[3] = add32(d, x[3]);\n        },\n\n        /* there needs to be support for Unicode here,\n           * unless we pretend that we can redefine the MD-5\n           * algorithm for multi-byte characters (perhaps\n           * by adding every four 16-bit characters and\n           * shortening the sum to 32 bits). Otherwise\n           * I suggest performing MD-5 as if every character\n           * was two bytes--e.g., 0040 0025 = @%--but then\n           * how will an ordinary MD-5 sum be matched?\n           * There is no way to standardize text to something\n           * like UTF-8 before transformation; speed cost is\n           * utterly prohibitive. The JavaScript standard\n           * itself needs to look at this: it should start\n           * providing access to strings as preformed UTF-8\n           * 8-bit unsigned value arrays.\n           */\n        md5blk = function (s) {\n            var md5blks = [],\n                i; /* Andy King said do it this way. */\n\n            for (i = 0; i < 64; i += 4) {\n                md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);\n            }\n            return md5blks;\n        },\n\n        md5blk_array = function (a) {\n            var md5blks = [],\n                i; /* Andy King said do it this way. */\n\n            for (i = 0; i < 64; i += 4) {\n                md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);\n            }\n            return md5blks;\n        },\n\n        md51 = function (s) {\n            var n = s.length,\n                state = [1732584193, -271733879, -1732584194, 271733878],\n                i,\n                length,\n                tail,\n                tmp,\n                lo,\n                hi;\n\n            for (i = 64; i <= n; i += 64) {\n                md5cycle(state, md5blk(s.substring(i - 64, i)));\n            }\n            s = s.substring(i - 64);\n            length = s.length;\n            tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);\n            }\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Beware that the final length might not fit in 32 bits so we take care of that\n            tmp = n * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n\n            md5cycle(state, tail);\n            return state;\n        },\n\n        md51_array = function (a) {\n            var n = a.length,\n                state = [1732584193, -271733879, -1732584194, 271733878],\n                i,\n                length,\n                tail,\n                tmp,\n                lo,\n                hi;\n\n            for (i = 64; i <= n; i += 64) {\n                md5cycle(state, md5blk_array(a.subarray(i - 64, i)));\n            }\n\n            // Not sure if it is a bug, however IE10 will always produce a sub array of length 1\n            // containing the last element of the parent array if the sub array specified starts\n            // beyond the length of the parent array - weird.\n            // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue\n            a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);\n\n            length = a.length;\n            tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= a[i] << ((i % 4) << 3);\n            }\n\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Beware that the final length might not fit in 32 bits so we take care of that\n            tmp = n * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n\n            md5cycle(state, tail);\n\n            return state;\n        },\n\n        hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'],\n\n        rhex = function (n) {\n            var s = '',\n                j;\n            for (j = 0; j < 4; j += 1) {\n                s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];\n            }\n            return s;\n        },\n\n        hex = function (x) {\n            var i;\n            for (i = 0; i < x.length; i += 1) {\n                x[i] = rhex(x[i]);\n            }\n            return x.join('');\n        },\n\n        md5 = function (s) {\n            return hex(md51(s));\n        },\n\n\n\n        ////////////////////////////////////////////////////////////////////////////\n\n        /**\n         * SparkMD5 OOP implementation.\n         *\n         * Use this class to perform an incremental md5, otherwise use the\n         * static methods instead.\n         */\n        SparkMD5 = function () {\n            // call reset to init the instance\n            this.reset();\n        };\n\n\n        // In some cases the fast add32 function cannot be used..\n        if (md5('hello') !== '5d41402abc4b2a76b9719d911017c592') {\n            add32 = function (x, y) {\n                var lsw = (x & 0xFFFF) + (y & 0xFFFF),\n                    msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n                return (msw << 16) | (lsw & 0xFFFF);\n            };\n        }\n\n\n        /**\n         * Appends a string.\n         * A conversion will be applied if an utf8 string is detected.\n         *\n         * @param {String} str The string to be appended\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.append = function (str) {\n            // converts the string to utf8 bytes if necessary\n            if (/[\\u0080-\\uFFFF]/.test(str)) {\n                str = unescape(encodeURIComponent(str));\n            }\n\n            // then append as binary\n            this.appendBinary(str);\n\n            return this;\n        };\n\n        /**\n         * Appends a binary string.\n         *\n         * @param {String} contents The binary string to be appended\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.appendBinary = function (contents) {\n            this._buff += contents;\n            this._length += contents.length;\n\n            var length = this._buff.length,\n                i;\n\n            for (i = 64; i <= length; i += 64) {\n                md5cycle(this._state, md5blk(this._buff.substring(i - 64, i)));\n            }\n\n            this._buff = this._buff.substr(i - 64);\n\n            return this;\n        };\n\n        /**\n         * Finishes the incremental computation, reseting the internal state and\n         * returning the result.\n         * Use the raw parameter to obtain the raw result instead of the hex one.\n         *\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.prototype.end = function (raw) {\n            var buff = this._buff,\n                length = buff.length,\n                i,\n                tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n                ret;\n\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);\n            }\n\n            this._finish(tail, length);\n            ret = !!raw ? this._state : hex(this._state);\n\n            this.reset();\n\n            return ret;\n        };\n\n        /**\n         * Finish the final calculation based on the tail.\n         *\n         * @param {Array}  tail   The tail (will be modified)\n         * @param {Number} length The length of the remaining buffer\n         */\n        SparkMD5.prototype._finish = function (tail, length) {\n            var i = length,\n                tmp,\n                lo,\n                hi;\n\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(this._state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Do the final computation based on the tail and length\n            // Beware that the final length may not fit in 32 bits so we take care of that\n            tmp = this._length * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n            md5cycle(this._state, tail);\n        };\n\n        /**\n         * Resets the internal state of the computation.\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.reset = function () {\n            this._buff = \"\";\n            this._length = 0;\n            this._state = [1732584193, -271733879, -1732584194, 271733878];\n\n            return this;\n        };\n\n        /**\n         * Releases memory used by the incremental buffer and other aditional\n         * resources. If you plan to use the instance again, use reset instead.\n         */\n        SparkMD5.prototype.destroy = function () {\n            delete this._state;\n            delete this._buff;\n            delete this._length;\n        };\n\n\n        /**\n         * Performs the md5 hash on a string.\n         * A conversion will be applied if utf8 string is detected.\n         *\n         * @param {String}  str The string\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.hash = function (str, raw) {\n            // converts the string to utf8 bytes if necessary\n            if (/[\\u0080-\\uFFFF]/.test(str)) {\n                str = unescape(encodeURIComponent(str));\n            }\n\n            var hash = md51(str);\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        /**\n         * Performs the md5 hash on a binary string.\n         *\n         * @param {String}  content The binary string\n         * @param {Boolean} raw     True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.hashBinary = function (content, raw) {\n            var hash = md51(content);\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        /**\n         * SparkMD5 OOP implementation for array buffers.\n         *\n         * Use this class to perform an incremental md5 ONLY for array buffers.\n         */\n        SparkMD5.ArrayBuffer = function () {\n            // call reset to init the instance\n            this.reset();\n        };\n\n        ////////////////////////////////////////////////////////////////////////////\n\n        /**\n         * Appends an array buffer.\n         *\n         * @param {ArrayBuffer} arr The array to be appended\n         *\n         * @return {SparkMD5.ArrayBuffer} The instance itself\n         */\n        SparkMD5.ArrayBuffer.prototype.append = function (arr) {\n            // TODO: we could avoid the concatenation here but the algorithm would be more complex\n            //       if you find yourself needing extra performance, please make a PR.\n            var buff = this._concatArrayBuffer(this._buff, arr),\n                length = buff.length,\n                i;\n\n            this._length += arr.byteLength;\n\n            for (i = 64; i <= length; i += 64) {\n                md5cycle(this._state, md5blk_array(buff.subarray(i - 64, i)));\n            }\n\n            // Avoids IE10 weirdness (documented above)\n            this._buff = (i - 64) < length ? buff.subarray(i - 64) : new Uint8Array(0);\n\n            return this;\n        };\n\n        /**\n         * Finishes the incremental computation, reseting the internal state and\n         * returning the result.\n         * Use the raw parameter to obtain the raw result instead of the hex one.\n         *\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.ArrayBuffer.prototype.end = function (raw) {\n            var buff = this._buff,\n                length = buff.length,\n                tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n                i,\n                ret;\n\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= buff[i] << ((i % 4) << 3);\n            }\n\n            this._finish(tail, length);\n            ret = !!raw ? this._state : hex(this._state);\n\n            this.reset();\n\n            return ret;\n        };\n\n        SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;\n\n        /**\n         * Resets the internal state of the computation.\n         *\n         * @return {SparkMD5.ArrayBuffer} The instance itself\n         */\n        SparkMD5.ArrayBuffer.prototype.reset = function () {\n            this._buff = new Uint8Array(0);\n            this._length = 0;\n            this._state = [1732584193, -271733879, -1732584194, 271733878];\n\n            return this;\n        };\n\n        /**\n         * Releases memory used by the incremental buffer and other aditional\n         * resources. If you plan to use the instance again, use reset instead.\n         */\n        SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;\n\n        /**\n         * Concats two array buffers, returning a new one.\n         *\n         * @param  {ArrayBuffer} first  The first array buffer\n         * @param  {ArrayBuffer} second The second array buffer\n         *\n         * @return {ArrayBuffer} The new array buffer\n         */\n        SparkMD5.ArrayBuffer.prototype._concatArrayBuffer = function (first, second) {\n            var firstLength = first.length,\n                result = new Uint8Array(firstLength + second.byteLength);\n\n            result.set(first);\n            result.set(new Uint8Array(second), firstLength);\n\n            return result;\n        };\n\n        /**\n         * Performs the md5 hash on an array buffer.\n         *\n         * @param {ArrayBuffer} arr The array buffer\n         * @param {Boolean}     raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.ArrayBuffer.hash = function (arr, raw) {\n            var hash = md51_array(new Uint8Array(arr));\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        return FlashRuntime.register( 'Md5', {\n            init: function() {\n                // do nothing.\n            },\n\n            loadFromBlob: function( file ) {\n                var blob = file.getSource(),\n                    chunkSize = 2 * 1024 * 1024,\n                    chunks = Math.ceil( blob.size / chunkSize ),\n                    chunk = 0,\n                    owner = this.owner,\n                    spark = new SparkMD5.ArrayBuffer(),\n                    me = this,\n                    blobSlice = blob.mozSlice || blob.webkitSlice || blob.slice,\n                    loadNext, fr;\n\n                fr = new FileReader();\n\n                loadNext = function() {\n                    var start, end;\n\n                    start = chunk * chunkSize;\n                    end = Math.min( start + chunkSize, blob.size );\n\n                    fr.onload = function( e ) {\n                        spark.append( e.target.result );\n                        owner.trigger( 'progress', {\n                            total: file.size,\n                            loaded: end\n                        });\n                    };\n\n                    fr.onloadend = function() {\n                        fr.onloadend = fr.onload = null;\n\n                        if ( ++chunk < chunks ) {\n                            setTimeout( loadNext, 1 );\n                        } else {\n                            setTimeout(function(){\n                                owner.trigger('load');\n                                me.result = spark.end();\n                                loadNext = file = blob = spark = null;\n                                owner.trigger('complete');\n                            }, 50 );\n                        }\n                    };\n\n                    fr.readAsArrayBuffer( blobSlice.call( blob, start, end ) );\n                };\n\n                loadNext();\n            },\n\n            getResult: function() {\n                return this.result;\n            }\n        });\n    });\n    /**\n     * @fileOverview FlashRuntime\n     */\n    define('runtime/flash/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var $ = Base.$,\n            type = 'flash',\n            components = {};\n\n\n        function getFlashVersion() {\n            var version;\n\n            try {\n                version = navigator.plugins[ 'Shockwave Flash' ];\n                version = version.description;\n            } catch ( ex ) {\n                try {\n                    version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')\n                            .GetVariable('$version');\n                } catch ( ex2 ) {\n                    version = '0.0';\n                }\n            }\n            version = version.match( /\\d+/g );\n            return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 );\n        }\n\n        function FlashRuntime() {\n            var pool = {},\n                clients = {},\n                destroy = this.destroy,\n                me = this,\n                jsreciver = Base.guid('webuploader_');\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/ ) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                clients[ uid ] = client;\n\n                if ( components[ comp ] ) {\n                    if ( !pool[ uid ] ) {\n                        pool[ uid ] = new components[ comp ]( client, me );\n                    }\n\n                    instance = pool[ uid ];\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n\n                return me.flashExec.apply( client, arguments );\n            };\n\n            function handler( evt, obj ) {\n                var type = evt.type || evt,\n                    parts, uid;\n\n                parts = type.split('::');\n                uid = parts[ 0 ];\n                type = parts[ 1 ];\n\n                // console.log.apply( console, arguments );\n\n                if ( type === 'Ready' && uid === me.uid ) {\n                    me.trigger('ready');\n                } else if ( clients[ uid ] ) {\n                    clients[ uid ].trigger( type.toLowerCase(), evt, obj );\n                }\n\n                // Base.log( evt, obj );\n            }\n\n            // flash的接受器。\n            window[ jsreciver ] = function() {\n                var args = arguments;\n\n                // 为了能捕获得到。\n                setTimeout(function() {\n                    handler.apply( null, args );\n                }, 1 );\n            };\n\n            this.jsreciver = jsreciver;\n\n            this.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n\n            this.flashExec = function( comp, fn ) {\n                var flash = me.getFlash(),\n                    args = Base.slice( arguments, 2 );\n\n                return flash.exec( this.uid, comp, fn, args );\n            };\n\n            // @todo\n        }\n\n        Base.inherits( Runtime, {\n            constructor: FlashRuntime,\n\n            init: function() {\n                var container = this.getContainer(),\n                    opts = this.options,\n                    html;\n\n                // if not the minimal height, shims are not initialized\n                // in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)\n                container.css({\n                    position: 'absolute',\n                    top: '-8px',\n                    left: '-8px',\n                    width: '9px',\n                    height: '9px',\n                    overflow: 'hidden'\n                });\n\n                // insert flash object\n                html = '<object id=\"' + this.uid + '\" type=\"application/' +\n                        'x-shockwave-flash\" data=\"' +  opts.swf + '\" ';\n\n                if ( Base.browser.ie ) {\n                    html += 'classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" ';\n                }\n\n                html += 'width=\"100%\" height=\"100%\" style=\"outline:0\">'  +\n                    '<param name=\"movie\" value=\"' + opts.swf + '\" />' +\n                    '<param name=\"flashvars\" value=\"uid=' + this.uid +\n                    '&jsreciver=' + this.jsreciver + '\" />' +\n                    '<param name=\"wmode\" value=\"transparent\" />' +\n                    '<param name=\"allowscriptaccess\" value=\"always\" />' +\n                '</object>';\n\n                container.html( html );\n            },\n\n            getFlash: function() {\n                if ( this._flash ) {\n                    return this._flash;\n                }\n\n                this._flash = $( '#' + this.uid ).get( 0 );\n                return this._flash;\n            }\n\n        });\n\n        FlashRuntime.register = function( name, component ) {\n            component = components[ name ] = Base.inherits( CompBase, $.extend({\n\n                // @todo fix this later\n                flashExec: function() {\n                    var owner = this.owner,\n                        runtime = this.getRuntime();\n\n                    return runtime.flashExec.apply( owner, arguments );\n                }\n            }, component ) );\n\n            return component;\n        };\n\n        if ( getFlashVersion() >= 11.4 ) {\n            Runtime.addRuntime( type, FlashRuntime );\n        }\n\n        return FlashRuntime;\n    });\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/flash/filepicker',[\n        'base',\n        'runtime/flash/runtime'\n    ], function( Base, FlashRuntime ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'FilePicker', {\n            init: function( opts ) {\n                var copy = $.extend({}, opts ),\n                    len, i;\n\n                // 修复Flash再没有设置title的情况下无法弹出flash文件选择框的bug.\n                len = copy.accept && copy.accept.length;\n                for (  i = 0; i < len; i++ ) {\n                    if ( !copy.accept[ i ].title ) {\n                        copy.accept[ i ].title = 'Files';\n                    }\n                }\n\n                delete copy.button;\n                delete copy.id;\n                delete copy.container;\n\n                this.flashExec( 'FilePicker', 'init', copy );\n            },\n\n            destroy: function() {\n                this.flashExec( 'FilePicker', 'destroy' );\n            }\n        });\n    });\n    /**\n     * @fileOverview 图片压缩\n     */\n    define('runtime/flash/image',[\n        'runtime/flash/runtime'\n    ], function( FlashRuntime ) {\n\n        return FlashRuntime.register( 'Image', {\n            // init: function( options ) {\n            //     var owner = this.owner;\n\n            //     this.flashExec( 'Image', 'init', options );\n            //     owner.on( 'load', function() {\n            //         debugger;\n            //     });\n            // },\n\n            loadFromBlob: function( blob ) {\n                var owner = this.owner;\n\n                owner.info() && this.flashExec( 'Image', 'info', owner.info() );\n                owner.meta() && this.flashExec( 'Image', 'meta', owner.meta() );\n\n                this.flashExec( 'Image', 'loadFromBlob', blob.uid );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/flash/transport',[\n        'base',\n        'runtime/flash/runtime',\n        'runtime/client'\n    ], function( Base, FlashRuntime, RuntimeClient ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n                this._responseJson = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    binary;\n\n                xhr.connectRuntime( blob.ruid );\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.uid;\n                } else {\n                    $.each( owner._formData, function( k, v ) {\n                        xhr.exec( 'append', k, v );\n                    });\n\n                    xhr.exec( 'appendBlob', opts.fileVal, blob.uid,\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n                xhr.exec( 'send', {\n                    method: opts.method,\n                    url: server,\n                    forceURLStream: opts.forceURLStream,\n                    mimeType: 'application/octet-stream'\n                }, binary );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            getResponse: function() {\n                return this._response || '';\n            },\n\n            getResponseAsJson: function() {\n                return this._responseJson;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.exec('abort');\n                    xhr.destroy();\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new RuntimeClient('XMLHttpRequest');\n\n                xhr.on( 'uploadprogress progress', function( e ) {\n                    var percent = e.loaded / e.total;\n                    percent = Math.min( 1, Math.max( 0, percent ) );\n                    return me.trigger( 'progress', percent );\n                });\n\n                xhr.on( 'load', function() {\n                    var status = xhr.exec('getStatus'),\n                        readBody = false,\n                        err = '',\n                        p;\n\n                    xhr.off();\n                    me._xhr = null;\n\n                    if ( status >= 200 && status < 300 ) {\n                        readBody = true;\n                    } else if ( status >= 500 && status < 600 ) {\n                        readBody = true;\n                        err = 'server';\n                    } else {\n                        err = 'http';\n                    }\n\n                    if ( readBody ) {\n                        me._response = xhr.exec('getResponse');\n                        me._response = decodeURIComponent( me._response );\n\n                        // flash 处理可能存在 bug, 没辙只能靠 js 了\n                        // try {\n                        //     me._responseJson = xhr.exec('getResponseAsJson');\n                        // } catch ( error ) {\n\n                        p = window.JSON && window.JSON.parse || function( s ) {\n                            try {\n                                return new Function('return ' + s).call();\n                            } catch ( err ) {\n                                return {};\n                            }\n                        };\n                        me._responseJson  = me._response ? p(me._response) : {};\n\n                        // }\n                    }\n\n                    xhr.destroy();\n                    xhr = null;\n\n                    return err ? me.trigger( 'error', err ) : me.trigger('load');\n                });\n\n                xhr.on( 'error', function() {\n                    xhr.off();\n                    me._xhr = null;\n                    me.trigger( 'error', 'http' );\n                });\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.exec( 'setRequestHeader', key, val );\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/flash/blob',[\n        'runtime/flash/runtime',\n        'lib/blob'\n    ], function( FlashRuntime, Blob ) {\n\n        return FlashRuntime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.flashExec( 'Blob', 'slice', start, end );\n\n                return new Blob( blob.uid, blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Md5 flash实现\n     */\n    define('runtime/flash/md5',[\n        'runtime/flash/runtime'\n    ], function( FlashRuntime ) {\n\n        return FlashRuntime.register( 'Md5', {\n            init: function() {\n                // do nothing.\n            },\n\n            loadFromBlob: function( blob ) {\n                return this.flashExec( 'Md5', 'loadFromBlob', blob.uid );\n            }\n        });\n    });\n    /**\n     * @fileOverview 完全版本。\n     */\n    define('preset/all',[\n        'base',\n\n        // widgets\n        'widgets/filednd',\n        'widgets/filepaste',\n        'widgets/filepicker',\n        'widgets/image',\n        'widgets/queue',\n        'widgets/runtime',\n        'widgets/upload',\n        'widgets/validator',\n        'widgets/md5',\n\n        // runtimes\n        // html5\n        'runtime/html5/blob',\n        'runtime/html5/dnd',\n        'runtime/html5/filepaste',\n        'runtime/html5/filepicker',\n        'runtime/html5/imagemeta/exif',\n        'runtime/html5/androidpatch',\n        'runtime/html5/image',\n        'runtime/html5/transport',\n        'runtime/html5/md5',\n\n        // flash\n        'runtime/flash/filepicker',\n        'runtime/flash/image',\n        'runtime/flash/transport',\n        'runtime/flash/blob',\n        'runtime/flash/md5'\n    ], function( Base ) {\n        return Base;\n    });\n    /**\n     * @fileOverview 日志组件，主要用来收集错误信息，可以帮助 webuploader 更好的定位问题和发展。\n     *\n     * 如果您不想要启用此功能，请在打包的时候去掉 log 模块。\n     *\n     * 或者可以在初始化的时候通过 options.disableWidgets 属性禁用。\n     *\n     * 如：\n     * WebUploader.create({\n     *     ...\n     *\n     *     disableWidgets: 'log',\n     *\n     *     ...\n     * })\n     */\n    define('widgets/log',[\n        'base',\n        'uploader',\n        'widgets/widget'\n    ], function( Base, Uploader ) {\n        var $ = Base.$,\n            logUrl = ' http://static.tieba.baidu.com/tb/pms/img/st.gif??',\n            product = (location.hostname || location.host || 'protected').toLowerCase(),\n\n            // 只针对 baidu 内部产品用户做统计功能。\n            enable = product && /baidu/i.exec(product),\n            base;\n\n        if (!enable) {\n            return;\n        }\n\n        base = {\n            dv: 3,\n            master: 'webuploader',\n            online: /test/.exec(product) ? 0 : 1,\n            module: '',\n            product: product,\n            type: 0\n        };\n\n        function send(data) {\n            var obj = $.extend({}, base, data),\n                url = logUrl.replace(/^(.*)\\?/, '$1' + $.param( obj )),\n                image = new Image();\n\n            image.src = url;\n        }\n\n        return Uploader.register({\n            name: 'log',\n\n            init: function() {\n                var owner = this.owner,\n                    count = 0,\n                    size = 0;\n\n                owner\n                    .on('error', function(code) {\n                        send({\n                            type: 2,\n                            c_error_code: code\n                        });\n                    })\n                    .on('uploadError', function(file, reason) {\n                        send({\n                            type: 2,\n                            c_error_code: 'UPLOAD_ERROR',\n                            c_reason: '' + reason\n                        });\n                    })\n                    .on('uploadComplete', function(file) {\n                        count++;\n                        size += file.size;\n                    }).\n                    on('uploadFinished', function() {\n                        send({\n                            c_count: count,\n                            c_size: size\n                        });\n                        count = size = 0;\n                    });\n\n                send({\n                    c_usage: 1\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('webuploader',[\n        'preset/all',\n        'widgets/log'\n    ], function( preset ) {\n        return preset;\n    });\n\n    var _require = require;\n    return _require('webuploader');\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.flashonly.js",
    "content": "/*! WebUploader 0.1.5 */\n\n\n/**\n * @fileOverview 让内部各个部件的代码可以用[amd](https://github.com/amdjs/amdjs-api/wiki/AMD)模块定义方式组织起来。\n *\n * AMD API 内部的简单不完全实现，请忽略。只有当WebUploader被合并成一个文件的时候才会引入。\n */\n(function( root, factory ) {\n    var modules = {},\n\n        // 内部require, 简单不完全实现。\n        // https://github.com/amdjs/amdjs-api/wiki/require\n        _require = function( deps, callback ) {\n            var args, len, i;\n\n            // 如果deps不是数组，则直接返回指定module\n            if ( typeof deps === 'string' ) {\n                return getModule( deps );\n            } else {\n                args = [];\n                for( len = deps.length, i = 0; i < len; i++ ) {\n                    args.push( getModule( deps[ i ] ) );\n                }\n\n                return callback.apply( null, args );\n            }\n        },\n\n        // 内部define，暂时不支持不指定id.\n        _define = function( id, deps, factory ) {\n            if ( arguments.length === 2 ) {\n                factory = deps;\n                deps = null;\n            }\n\n            _require( deps || [], function() {\n                setModule( id, factory, arguments );\n            });\n        },\n\n        // 设置module, 兼容CommonJs写法。\n        setModule = function( id, factory, args ) {\n            var module = {\n                    exports: factory\n                },\n                returned;\n\n            if ( typeof factory === 'function' ) {\n                args.length || (args = [ _require, module.exports, module ]);\n                returned = factory.apply( null, args );\n                returned !== undefined && (module.exports = returned);\n            }\n\n            modules[ id ] = module.exports;\n        },\n\n        // 根据id获取module\n        getModule = function( id ) {\n            var module = modules[ id ] || root[ id ];\n\n            if ( !module ) {\n                throw new Error( '`' + id + '` is undefined' );\n            }\n\n            return module;\n        },\n\n        // 将所有modules，将路径ids装换成对象。\n        exportsTo = function( obj ) {\n            var key, host, parts, part, last, ucFirst;\n\n            // make the first character upper case.\n            ucFirst = function( str ) {\n                return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 ));\n            };\n\n            for ( key in modules ) {\n                host = obj;\n\n                if ( !modules.hasOwnProperty( key ) ) {\n                    continue;\n                }\n\n                parts = key.split('/');\n                last = ucFirst( parts.pop() );\n\n                while( (part = ucFirst( parts.shift() )) ) {\n                    host[ part ] = host[ part ] || {};\n                    host = host[ part ];\n                }\n\n                host[ last ] = modules[ key ];\n            }\n\n            return obj;\n        },\n\n        makeExport = function( dollar ) {\n            root.__dollar = dollar;\n\n            // exports every module.\n            return exportsTo( factory( root, _define, _require ) );\n        },\n\n        origin;\n\n    if ( typeof module === 'object' && typeof module.exports === 'object' ) {\n\n        // For CommonJS and CommonJS-like environments where a proper window is present,\n        module.exports = makeExport();\n    } else if ( typeof define === 'function' && define.amd ) {\n\n        // Allow using this built library as an AMD module\n        // in another project. That other project will only\n        // see this AMD call, not the internal modules in\n        // the closure below.\n        define([ 'jquery' ], makeExport );\n    } else {\n\n        // Browser globals case. Just assign the\n        // result to a property on the global.\n        origin = root.WebUploader;\n        root.WebUploader = makeExport();\n        root.WebUploader.noConflict = function() {\n            root.WebUploader = origin;\n        };\n    }\n})( window, function( window, define, require ) {\n\n\n    /**\n     * @fileOverview jQuery or Zepto\n     */\n    define('dollar-third',[],function() {\n        var $ = window.__dollar || window.jQuery || window.Zepto;\n\n        if ( !$ ) {\n            throw new Error('jQuery or Zepto not found!');\n        }\n\n        return $;\n    });\n    /**\n     * @fileOverview Dom 操作相关\n     */\n    define('dollar',[\n        'dollar-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 使用jQuery的Promise\n     */\n    define('promise-third',[\n        'dollar'\n    ], function( $ ) {\n        return {\n            Deferred: $.Deferred,\n            when: $.when,\n\n            isPromise: function( anything ) {\n                return anything && typeof anything.then === 'function';\n            }\n        };\n    });\n    /**\n     * @fileOverview Promise/A+\n     */\n    define('promise',[\n        'promise-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 基础类方法。\n     */\n\n    /**\n     * Web Uploader内部类的详细说明，以下提及的功能类，都可以在`WebUploader`这个变量中访问到。\n     *\n     * As you know, Web Uploader的每个文件都是用过[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)规范中的`define`组织起来的, 每个Module都会有个module id.\n     * 默认module id为该文件的路径，而此路径将会转化成名字空间存放在WebUploader中。如：\n     *\n     * * module `base`：WebUploader.Base\n     * * module `file`: WebUploader.File\n     * * module `lib/dnd`: WebUploader.Lib.Dnd\n     * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd\n     *\n     *\n     * 以下文档中对类的使用可能省略掉了`WebUploader`前缀。\n     * @module WebUploader\n     * @title WebUploader API文档\n     */\n    define('base',[\n        'dollar',\n        'promise'\n    ], function( $, promise ) {\n\n        var noop = function() {},\n            call = Function.call;\n\n        // http://jsperf.com/uncurrythis\n        // 反科里化\n        function uncurryThis( fn ) {\n            return function() {\n                return call.apply( fn, arguments );\n            };\n        }\n\n        function bindFn( fn, context ) {\n            return function() {\n                return fn.apply( context, arguments );\n            };\n        }\n\n        function createObject( proto ) {\n            var f;\n\n            if ( Object.create ) {\n                return Object.create( proto );\n            } else {\n                f = function() {};\n                f.prototype = proto;\n                return new f();\n            }\n        }\n\n\n        /**\n         * 基础类，提供一些简单常用的方法。\n         * @class Base\n         */\n        return {\n\n            /**\n             * @property {String} version 当前版本号。\n             */\n            version: '0.1.5',\n\n            /**\n             * @property {jQuery|Zepto} $ 引用依赖的jQuery或者Zepto对象。\n             */\n            $: $,\n\n            Deferred: promise.Deferred,\n\n            isPromise: promise.isPromise,\n\n            when: promise.when,\n\n            /**\n             * @description  简单的浏览器检查结果。\n             *\n             * * `webkit`  webkit版本号，如果浏览器为非webkit内核，此属性为`undefined`。\n             * * `chrome`  chrome浏览器版本号，如果浏览器为chrome，此属性为`undefined`。\n             * * `ie`  ie浏览器版本号，如果浏览器为非ie，此属性为`undefined`。**暂不支持ie10+**\n             * * `firefox`  firefox浏览器版本号，如果浏览器为非firefox，此属性为`undefined`。\n             * * `safari`  safari浏览器版本号，如果浏览器为非safari，此属性为`undefined`。\n             * * `opera`  opera浏览器版本号，如果浏览器为非opera，此属性为`undefined`。\n             *\n             * @property {Object} [browser]\n             */\n            browser: (function( ua ) {\n                var ret = {},\n                    webkit = ua.match( /WebKit\\/([\\d.]+)/ ),\n                    chrome = ua.match( /Chrome\\/([\\d.]+)/ ) ||\n                        ua.match( /CriOS\\/([\\d.]+)/ ),\n\n                    ie = ua.match( /MSIE\\s([\\d\\.]+)/ ) ||\n                        ua.match( /(?:trident)(?:.*rv:([\\w.]+))?/i ),\n                    firefox = ua.match( /Firefox\\/([\\d.]+)/ ),\n                    safari = ua.match( /Safari\\/([\\d.]+)/ ),\n                    opera = ua.match( /OPR\\/([\\d.]+)/ );\n\n                webkit && (ret.webkit = parseFloat( webkit[ 1 ] ));\n                chrome && (ret.chrome = parseFloat( chrome[ 1 ] ));\n                ie && (ret.ie = parseFloat( ie[ 1 ] ));\n                firefox && (ret.firefox = parseFloat( firefox[ 1 ] ));\n                safari && (ret.safari = parseFloat( safari[ 1 ] ));\n                opera && (ret.opera = parseFloat( opera[ 1 ] ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * @description  操作系统检查结果。\n             *\n             * * `android`  如果在android浏览器环境下，此值为对应的android版本号，否则为`undefined`。\n             * * `ios` 如果在ios浏览器环境下，此值为对应的ios版本号，否则为`undefined`。\n             * @property {Object} [os]\n             */\n            os: (function( ua ) {\n                var ret = {},\n\n                    // osx = !!ua.match( /\\(Macintosh\\; Intel / ),\n                    android = ua.match( /(?:Android);?[\\s\\/]+([\\d.]+)?/ ),\n                    ios = ua.match( /(?:iPad|iPod|iPhone).*OS\\s([\\d_]+)/ );\n\n                // osx && (ret.osx = true);\n                android && (ret.android = parseFloat( android[ 1 ] ));\n                ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * 实现类与类之间的继承。\n             * @method inherits\n             * @grammar Base.inherits( super ) => child\n             * @grammar Base.inherits( super, protos ) => child\n             * @grammar Base.inherits( super, protos, statics ) => child\n             * @param  {Class} super 父类\n             * @param  {Object | Function} [protos] 子类或者对象。如果对象中包含constructor，子类将是用此属性值。\n             * @param  {Function} [protos.constructor] 子类构造器，不指定的话将创建个临时的直接执行父类构造器的方法。\n             * @param  {Object} [statics] 静态属性或方法。\n             * @return {Class} 返回子类。\n             * @example\n             * function Person() {\n             *     console.log( 'Super' );\n             * }\n             * Person.prototype.hello = function() {\n             *     console.log( 'hello' );\n             * };\n             *\n             * var Manager = Base.inherits( Person, {\n             *     world: function() {\n             *         console.log( 'World' );\n             *     }\n             * });\n             *\n             * // 因为没有指定构造器，父类的构造器将会执行。\n             * var instance = new Manager();    // => Super\n             *\n             * // 继承子父类的方法\n             * instance.hello();    // => hello\n             * instance.world();    // => World\n             *\n             * // 子类的__super__属性指向父类\n             * console.log( Manager.__super__ === Person );    // => true\n             */\n            inherits: function( Super, protos, staticProtos ) {\n                var child;\n\n                if ( typeof protos === 'function' ) {\n                    child = protos;\n                    protos = null;\n                } else if ( protos && protos.hasOwnProperty('constructor') ) {\n                    child = protos.constructor;\n                } else {\n                    child = function() {\n                        return Super.apply( this, arguments );\n                    };\n                }\n\n                // 复制静态方法\n                $.extend( true, child, Super, staticProtos || {} );\n\n                /* jshint camelcase: false */\n\n                // 让子类的__super__属性指向父类。\n                child.__super__ = Super.prototype;\n\n                // 构建原型，添加原型方法或属性。\n                // 暂时用Object.create实现。\n                child.prototype = createObject( Super.prototype );\n                protos && $.extend( true, child.prototype, protos );\n\n                return child;\n            },\n\n            /**\n             * 一个不做任何事情的方法。可以用来赋值给默认的callback.\n             * @method noop\n             */\n            noop: noop,\n\n            /**\n             * 返回一个新的方法，此方法将已指定的`context`来执行。\n             * @grammar Base.bindFn( fn, context ) => Function\n             * @method bindFn\n             * @example\n             * var doSomething = function() {\n             *         console.log( this.name );\n             *     },\n             *     obj = {\n             *         name: 'Object Name'\n             *     },\n             *     aliasFn = Base.bind( doSomething, obj );\n             *\n             *  aliasFn();    // => Object Name\n             *\n             */\n            bindFn: bindFn,\n\n            /**\n             * 引用Console.log如果存在的话，否则引用一个[空函数noop](#WebUploader:Base.noop)。\n             * @grammar Base.log( args... ) => undefined\n             * @method log\n             */\n            log: (function() {\n                if ( window.console ) {\n                    return bindFn( console.log, console );\n                }\n                return noop;\n            })(),\n\n            nextTick: (function() {\n\n                return function( cb ) {\n                    setTimeout( cb, 1 );\n                };\n\n                // @bug 当浏览器不在当前窗口时就停了。\n                // var next = window.requestAnimationFrame ||\n                //     window.webkitRequestAnimationFrame ||\n                //     window.mozRequestAnimationFrame ||\n                //     function( cb ) {\n                //         window.setTimeout( cb, 1000 / 60 );\n                //     };\n\n                // // fix: Uncaught TypeError: Illegal invocation\n                // return bindFn( next, window );\n            })(),\n\n            /**\n             * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的数组slice方法。\n             * 将用来将非数组对象转化成数组对象。\n             * @grammar Base.slice( target, start[, end] ) => Array\n             * @method slice\n             * @example\n             * function doSomthing() {\n             *     var args = Base.slice( arguments, 1 );\n             *     console.log( args );\n             * }\n             *\n             * doSomthing( 'ignored', 'arg2', 'arg3' );    // => Array [\"arg2\", \"arg3\"]\n             */\n            slice: uncurryThis( [].slice ),\n\n            /**\n             * 生成唯一的ID\n             * @method guid\n             * @grammar Base.guid() => String\n             * @grammar Base.guid( prefx ) => String\n             */\n            guid: (function() {\n                var counter = 0;\n\n                return function( prefix ) {\n                    var guid = (+new Date()).toString( 32 ),\n                        i = 0;\n\n                    for ( ; i < 5; i++ ) {\n                        guid += Math.floor( Math.random() * 65535 ).toString( 32 );\n                    }\n\n                    return (prefix || 'wu_') + guid + (counter++).toString( 32 );\n                };\n            })(),\n\n            /**\n             * 格式化文件大小, 输出成带单位的字符串\n             * @method formatSize\n             * @grammar Base.formatSize( size ) => String\n             * @grammar Base.formatSize( size, pointLength ) => String\n             * @grammar Base.formatSize( size, pointLength, units ) => String\n             * @param {Number} size 文件大小\n             * @param {Number} [pointLength=2] 精确到的小数点数。\n             * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 单位数组。从字节，到千字节，一直往上指定。如果单位数组里面只指定了到了K(千字节)，同时文件大小大于M, 此方法的输出将还是显示成多少K.\n             * @example\n             * console.log( Base.formatSize( 100 ) );    // => 100B\n             * console.log( Base.formatSize( 1024 ) );    // => 1.00K\n             * console.log( Base.formatSize( 1024, 0 ) );    // => 1K\n             * console.log( Base.formatSize( 1024 * 1024 ) );    // => 1.00M\n             * console.log( Base.formatSize( 1024 * 1024 * 1024 ) );    // => 1.00G\n             * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) );    // => 1024MB\n             */\n            formatSize: function( size, pointLength, units ) {\n                var unit;\n\n                units = units || [ 'B', 'K', 'M', 'G', 'TB' ];\n\n                while ( (unit = units.shift()) && size > 1024 ) {\n                    size = size / 1024;\n                }\n\n                return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) +\n                        unit;\n            }\n        };\n    });\n    /**\n     * 事件处理类，可以独立使用，也可以扩展给对象使用。\n     * @fileOverview Mediator\n     */\n    define('mediator',[\n        'base'\n    ], function( Base ) {\n        var $ = Base.$,\n            slice = [].slice,\n            separator = /\\s+/,\n            protos;\n\n        // 根据条件过滤出事件handlers.\n        function findHandlers( arr, name, callback, context ) {\n            return $.grep( arr, function( handler ) {\n                return handler &&\n                        (!name || handler.e === name) &&\n                        (!callback || handler.cb === callback ||\n                        handler.cb._cb === callback) &&\n                        (!context || handler.ctx === context);\n            });\n        }\n\n        function eachEvent( events, callback, iterator ) {\n            // 不支持对象，只支持多个event用空格隔开\n            $.each( (events || '').split( separator ), function( _, key ) {\n                iterator( key, callback );\n            });\n        }\n\n        function triggerHanders( events, args ) {\n            var stoped = false,\n                i = -1,\n                len = events.length,\n                handler;\n\n            while ( ++i < len ) {\n                handler = events[ i ];\n\n                if ( handler.cb.apply( handler.ctx2, args ) === false ) {\n                    stoped = true;\n                    break;\n                }\n            }\n\n            return !stoped;\n        }\n\n        protos = {\n\n            /**\n             * 绑定事件。\n             *\n             * `callback`方法在执行时，arguments将会来源于trigger的时候携带的参数。如\n             * ```javascript\n             * var obj = {};\n             *\n             * // 使得obj有事件行为\n             * Mediator.installTo( obj );\n             *\n             * obj.on( 'testa', function( arg1, arg2 ) {\n             *     console.log( arg1, arg2 ); // => 'arg1', 'arg2'\n             * });\n             *\n             * obj.trigger( 'testa', 'arg1', 'arg2' );\n             * ```\n             *\n             * 如果`callback`中，某一个方法`return false`了，则后续的其他`callback`都不会被执行到。\n             * 切会影响到`trigger`方法的返回值，为`false`。\n             *\n             * `on`还可以用来添加一个特殊事件`all`, 这样所有的事件触发都会响应到。同时此类`callback`中的arguments有一个不同处，\n             * 就是第一个参数为`type`，记录当前是什么事件在触发。此类`callback`的优先级比脚低，会再正常`callback`执行完后触发。\n             * ```javascript\n             * obj.on( 'all', function( type, arg1, arg2 ) {\n             *     console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2'\n             * });\n             * ```\n             *\n             * @method on\n             * @grammar on( name, callback[, context] ) => self\n             * @param  {String}   name     事件名，支持多个事件用空格隔开\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             * @class Mediator\n             */\n            on: function( name, callback, context ) {\n                var me = this,\n                    set;\n\n                if ( !callback ) {\n                    return this;\n                }\n\n                set = this._events || (this._events = []);\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var handler = { e: name };\n\n                    handler.cb = callback;\n                    handler.ctx = context;\n                    handler.ctx2 = context || me;\n                    handler.id = set.length;\n\n                    set.push( handler );\n                });\n\n                return this;\n            },\n\n            /**\n             * 绑定事件，且当handler执行完后，自动解除绑定。\n             * @method once\n             * @grammar once( name, callback[, context] ) => self\n             * @param  {String}   name     事件名\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            once: function( name, callback, context ) {\n                var me = this;\n\n                if ( !callback ) {\n                    return me;\n                }\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var once = function() {\n                            me.off( name, once );\n                            return callback.apply( context || me, arguments );\n                        };\n\n                    once._cb = callback;\n                    me.on( name, once, context );\n                });\n\n                return me;\n            },\n\n            /**\n             * 解除事件绑定\n             * @method off\n             * @grammar off( [name[, callback[, context] ] ] ) => self\n             * @param  {String}   [name]     事件名\n             * @param  {Function} [callback] 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            off: function( name, cb, ctx ) {\n                var events = this._events;\n\n                if ( !events ) {\n                    return this;\n                }\n\n                if ( !name && !cb && !ctx ) {\n                    this._events = [];\n                    return this;\n                }\n\n                eachEvent( name, cb, function( name, cb ) {\n                    $.each( findHandlers( events, name, cb, ctx ), function() {\n                        delete events[ this.id ];\n                    });\n                });\n\n                return this;\n            },\n\n            /**\n             * 触发事件\n             * @method trigger\n             * @grammar trigger( name[, args...] ) => self\n             * @param  {String}   type     事件名\n             * @param  {*} [...] 任意参数\n             * @return {Boolean} 如果handler中return false了，则返回false, 否则返回true\n             */\n            trigger: function( type ) {\n                var args, events, allEvents;\n\n                if ( !this._events || !type ) {\n                    return this;\n                }\n\n                args = slice.call( arguments, 1 );\n                events = findHandlers( this._events, type );\n                allEvents = findHandlers( this._events, 'all' );\n\n                return triggerHanders( events, args ) &&\n                        triggerHanders( allEvents, arguments );\n            }\n        };\n\n        /**\n         * 中介者，它本身是个单例，但可以通过[installTo](#WebUploader:Mediator:installTo)方法，使任何对象具备事件行为。\n         * 主要目的是负责模块与模块之间的合作，降低耦合度。\n         *\n         * @class Mediator\n         */\n        return $.extend({\n\n            /**\n             * 可以通过这个接口，使任何对象具备事件功能。\n             * @method installTo\n             * @param  {Object} obj 需要具备事件行为的对象。\n             * @return {Object} 返回obj.\n             */\n            installTo: function( obj ) {\n                return $.extend( obj, protos );\n            }\n\n        }, protos );\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('uploader',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$;\n\n        /**\n         * 上传入口类。\n         * @class Uploader\n         * @constructor\n         * @grammar new Uploader( opts ) => Uploader\n         * @example\n         * var uploader = WebUploader.Uploader({\n         *     swf: 'path_of_swf/Uploader.swf',\n         *\n         *     // 开起分片上传。\n         *     chunked: true\n         * });\n         */\n        function Uploader( opts ) {\n            this.options = $.extend( true, {}, Uploader.options, opts );\n            this._init( this.options );\n        }\n\n        // default Options\n        // widgets中有相应扩展\n        Uploader.options = {};\n        Mediator.installTo( Uploader.prototype );\n\n        // 批量添加纯命令式方法。\n        $.each({\n            upload: 'start-upload',\n            stop: 'stop-upload',\n            getFile: 'get-file',\n            getFiles: 'get-files',\n            addFile: 'add-file',\n            addFiles: 'add-file',\n            sort: 'sort-files',\n            removeFile: 'remove-file',\n            cancelFile: 'cancel-file',\n            skipFile: 'skip-file',\n            retry: 'retry',\n            isInProgress: 'is-in-progress',\n            makeThumb: 'make-thumb',\n            md5File: 'md5-file',\n            getDimension: 'get-dimension',\n            addButton: 'add-btn',\n            predictRuntimeType: 'predict-runtime-type',\n            refresh: 'refresh',\n            disable: 'disable',\n            enable: 'enable',\n            reset: 'reset'\n        }, function( fn, command ) {\n            Uploader.prototype[ fn ] = function() {\n                return this.request( command, arguments );\n            };\n        });\n\n        $.extend( Uploader.prototype, {\n            state: 'pending',\n\n            _init: function( opts ) {\n                var me = this;\n\n                me.request( 'init', opts, function() {\n                    me.state = 'ready';\n                    me.trigger('ready');\n                });\n            },\n\n            /**\n             * 获取或者设置Uploader配置项。\n             * @method option\n             * @grammar option( key ) => *\n             * @grammar option( key, val ) => self\n             * @example\n             *\n             * // 初始状态图片上传前不会压缩\n             * var uploader = new WebUploader.Uploader({\n             *     compress: null;\n             * });\n             *\n             * // 修改后图片上传前，尝试将图片压缩到1600 * 1600\n             * uploader.option( 'compress', {\n             *     width: 1600,\n             *     height: 1600\n             * });\n             */\n            option: function( key, val ) {\n                var opts = this.options;\n\n                // setter\n                if ( arguments.length > 1 ) {\n\n                    if ( $.isPlainObject( val ) &&\n                            $.isPlainObject( opts[ key ] ) ) {\n                        $.extend( opts[ key ], val );\n                    } else {\n                        opts[ key ] = val;\n                    }\n\n                } else {    // getter\n                    return key ? opts[ key ] : opts;\n                }\n            },\n\n            /**\n             * 获取文件统计信息。返回一个包含一下信息的对象。\n             * * `successNum` 上传成功的文件数\n             * * `progressNum` 上传中的文件数\n             * * `cancelNum` 被删除的文件数\n             * * `invalidNum` 无效的文件数\n             * * `uploadFailNum` 上传失败的文件数\n             * * `queueNum` 还在队列中的文件数\n             * * `interruptNum` 被暂停的文件数\n             * @method getStats\n             * @grammar getStats() => Object\n             */\n            getStats: function() {\n                // return this._mgr.getStats.apply( this._mgr, arguments );\n                var stats = this.request('get-stats');\n\n                return stats ? {\n                    successNum: stats.numOfSuccess,\n                    progressNum: stats.numOfProgress,\n\n                    // who care?\n                    // queueFailNum: 0,\n                    cancelNum: stats.numOfCancel,\n                    invalidNum: stats.numOfInvalid,\n                    uploadFailNum: stats.numOfUploadFailed,\n                    queueNum: stats.numOfQueue,\n                    interruptNum: stats.numofInterrupt\n                } : {};\n            },\n\n            // 需要重写此方法来来支持opts.onEvent和instance.onEvent的处理器\n            trigger: function( type/*, args...*/ ) {\n                var args = [].slice.call( arguments, 1 ),\n                    opts = this.options,\n                    name = 'on' + type.substring( 0, 1 ).toUpperCase() +\n                        type.substring( 1 );\n\n                if (\n                        // 调用通过on方法注册的handler.\n                        Mediator.trigger.apply( this, arguments ) === false ||\n\n                        // 调用opts.onEvent\n                        $.isFunction( opts[ name ] ) &&\n                        opts[ name ].apply( this, args ) === false ||\n\n                        // 调用this.onEvent\n                        $.isFunction( this[ name ] ) &&\n                        this[ name ].apply( this, args ) === false ||\n\n                        // 广播所有uploader的事件。\n                        Mediator.trigger.apply( Mediator,\n                        [ this, type ].concat( args ) ) === false ) {\n\n                    return false;\n                }\n\n                return true;\n            },\n\n            /**\n             * 销毁 webuploader 实例\n             * @method destroy\n             * @grammar destroy() => undefined\n             */\n            destroy: function() {\n                this.request( 'destroy', arguments );\n                this.off();\n            },\n\n            // widgets/widget.js将补充此方法的详细文档。\n            request: Base.noop\n        });\n\n        /**\n         * 创建Uploader实例，等同于new Uploader( opts );\n         * @method create\n         * @class Base\n         * @static\n         * @grammar Base.create( opts ) => Uploader\n         */\n        Base.create = Uploader.create = function( opts ) {\n            return new Uploader( opts );\n        };\n\n        // 暴露Uploader，可以通过它来扩展业务逻辑。\n        Base.Uploader = Uploader;\n\n        return Uploader;\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/runtime',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            factories = {},\n\n            // 获取对象的第一个key\n            getFirstKey = function( obj ) {\n                for ( var key in obj ) {\n                    if ( obj.hasOwnProperty( key ) ) {\n                        return key;\n                    }\n                }\n                return null;\n            };\n\n        // 接口类。\n        function Runtime( options ) {\n            this.options = $.extend({\n                container: document.body\n            }, options );\n            this.uid = Base.guid('rt_');\n        }\n\n        $.extend( Runtime.prototype, {\n\n            getContainer: function() {\n                var opts = this.options,\n                    parent, container;\n\n                if ( this._container ) {\n                    return this._container;\n                }\n\n                parent = $( opts.container || document.body );\n                container = $( document.createElement('div') );\n\n                container.attr( 'id', 'rt_' + this.uid );\n                container.css({\n                    position: 'absolute',\n                    top: '0px',\n                    left: '0px',\n                    width: '1px',\n                    height: '1px',\n                    overflow: 'hidden'\n                });\n\n                parent.append( container );\n                parent.addClass('webuploader-container');\n                this._container = container;\n                this._parent = parent;\n                return container;\n            },\n\n            init: Base.noop,\n            exec: Base.noop,\n\n            destroy: function() {\n                this._container && this._container.remove();\n                this._parent && this._parent.removeClass('webuploader-container');\n                this.off();\n            }\n        });\n\n        Runtime.orders = 'html5,flash';\n\n\n        /**\n         * 添加Runtime实现。\n         * @param {String} type    类型\n         * @param {Runtime} factory 具体Runtime实现。\n         */\n        Runtime.addRuntime = function( type, factory ) {\n            factories[ type ] = factory;\n        };\n\n        Runtime.hasRuntime = function( type ) {\n            return !!(type ? factories[ type ] : getFirstKey( factories ));\n        };\n\n        Runtime.create = function( opts, orders ) {\n            var type, runtime;\n\n            orders = orders || Runtime.orders;\n            $.each( orders.split( /\\s*,\\s*/g ), function() {\n                if ( factories[ this ] ) {\n                    type = this;\n                    return false;\n                }\n            });\n\n            type = type || getFirstKey( factories );\n\n            if ( !type ) {\n                throw new Error('Runtime Error');\n            }\n\n            runtime = new factories[ type ]( opts );\n            return runtime;\n        };\n\n        Mediator.installTo( Runtime.prototype );\n        return Runtime;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/client',[\n        'base',\n        'mediator',\n        'runtime/runtime'\n    ], function( Base, Mediator, Runtime ) {\n\n        var cache;\n\n        cache = (function() {\n            var obj = {};\n\n            return {\n                add: function( runtime ) {\n                    obj[ runtime.uid ] = runtime;\n                },\n\n                get: function( ruid, standalone ) {\n                    var i;\n\n                    if ( ruid ) {\n                        return obj[ ruid ];\n                    }\n\n                    for ( i in obj ) {\n                        // 有些类型不能重用，比如filepicker.\n                        if ( standalone && obj[ i ].__standalone ) {\n                            continue;\n                        }\n\n                        return obj[ i ];\n                    }\n\n                    return null;\n                },\n\n                remove: function( runtime ) {\n                    delete obj[ runtime.uid ];\n                }\n            };\n        })();\n\n        function RuntimeClient( component, standalone ) {\n            var deferred = Base.Deferred(),\n                runtime;\n\n            this.uid = Base.guid('client_');\n\n            // 允许runtime没有初始化之前，注册一些方法在初始化后执行。\n            this.runtimeReady = function( cb ) {\n                return deferred.done( cb );\n            };\n\n            this.connectRuntime = function( opts, cb ) {\n\n                // already connected.\n                if ( runtime ) {\n                    throw new Error('already connected!');\n                }\n\n                deferred.done( cb );\n\n                if ( typeof opts === 'string' && cache.get( opts ) ) {\n                    runtime = cache.get( opts );\n                }\n\n                // 像filePicker只能独立存在，不能公用。\n                runtime = runtime || cache.get( null, standalone );\n\n                // 需要创建\n                if ( !runtime ) {\n                    runtime = Runtime.create( opts, opts.runtimeOrder );\n                    runtime.__promise = deferred.promise();\n                    runtime.once( 'ready', deferred.resolve );\n                    runtime.init();\n                    cache.add( runtime );\n                    runtime.__client = 1;\n                } else {\n                    // 来自cache\n                    Base.$.extend( runtime.options, opts );\n                    runtime.__promise.then( deferred.resolve );\n                    runtime.__client++;\n                }\n\n                standalone && (runtime.__standalone = standalone);\n                return runtime;\n            };\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.disconnectRuntime = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                runtime.__client--;\n\n                if ( runtime.__client <= 0 ) {\n                    cache.remove( runtime );\n                    delete runtime.__promise;\n                    runtime.destroy();\n                }\n\n                runtime = null;\n            };\n\n            this.exec = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                var args = Base.slice( arguments );\n                component && args.unshift( component );\n\n                return runtime.exec.apply( this, args );\n            };\n\n            this.getRuid = function() {\n                return runtime && runtime.uid;\n            };\n\n            this.destroy = (function( destroy ) {\n                return function() {\n                    destroy && destroy.apply( this, arguments );\n                    this.trigger('destroy');\n                    this.off();\n                    this.exec('destroy');\n                    this.disconnectRuntime();\n                };\n            })( this.destroy );\n        }\n\n        Mediator.installTo( RuntimeClient.prototype );\n        return RuntimeClient;\n    });\n    /**\n     * @fileOverview Blob\n     */\n    define('lib/blob',[\n        'base',\n        'runtime/client'\n    ], function( Base, RuntimeClient ) {\n\n        function Blob( ruid, source ) {\n            var me = this;\n\n            me.source = source;\n            me.ruid = ruid;\n            this.size = source.size || 0;\n\n            // 如果没有指定 mimetype, 但是知道文件后缀。\n            if ( !source.type && this.ext &&\n                    ~'jpg,jpeg,png,gif,bmp'.indexOf( this.ext ) ) {\n                this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);\n            } else {\n                this.type = source.type || 'application/octet-stream';\n            }\n\n            RuntimeClient.call( me, 'Blob' );\n            this.uid = source.uid || this.uid;\n\n            if ( ruid ) {\n                me.connectRuntime( ruid );\n            }\n        }\n\n        Base.inherits( RuntimeClient, {\n            constructor: Blob,\n\n            slice: function( start, end ) {\n                return this.exec( 'slice', start, end );\n            },\n\n            getSource: function() {\n                return this.source;\n            }\n        });\n\n        return Blob;\n    });\n    /**\n     * 为了统一化Flash的File和HTML5的File而存在。\n     * 以至于要调用Flash里面的File，也可以像调用HTML5版本的File一下。\n     * @fileOverview File\n     */\n    define('lib/file',[\n        'base',\n        'lib/blob'\n    ], function( Base, Blob ) {\n\n        var uid = 1,\n            rExt = /\\.([^.]+)$/;\n\n        function File( ruid, file ) {\n            var ext;\n\n            this.name = file.name || ('untitled' + uid++);\n            ext = rExt.exec( file.name ) ? RegExp.$1.toLowerCase() : '';\n\n            // todo 支持其他类型文件的转换。\n            // 如果有 mimetype, 但是文件名里面没有找出后缀规律\n            if ( !ext && file.type ) {\n                ext = /\\/(jpg|jpeg|png|gif|bmp)$/i.exec( file.type ) ?\n                        RegExp.$1.toLowerCase() : '';\n                this.name += '.' + ext;\n            }\n\n            this.ext = ext;\n            this.lastModifiedDate = file.lastModifiedDate ||\n                    (new Date()).toLocaleString();\n\n            Blob.apply( this, arguments );\n        }\n\n        return Base.inherits( Blob, File );\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepicker',[\n        'base',\n        'runtime/client',\n        'lib/file'\n    ], function( Base, RuntimeClent, File ) {\n\n        var $ = Base.$;\n\n        function FilePicker( opts ) {\n            opts = this.options = $.extend({}, FilePicker.options, opts );\n\n            opts.container = $( opts.id );\n\n            if ( !opts.container.length ) {\n                throw new Error('按钮指定错误');\n            }\n\n            opts.innerHTML = opts.innerHTML || opts.label ||\n                    opts.container.html() || '';\n\n            opts.button = $( opts.button || document.createElement('div') );\n            opts.button.html( opts.innerHTML );\n            opts.container.html( opts.button );\n\n            RuntimeClent.call( this, 'FilePicker', true );\n        }\n\n        FilePicker.options = {\n            button: null,\n            container: null,\n            label: null,\n            innerHTML: null,\n            multiple: true,\n            accept: null,\n            name: 'file'\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePicker,\n\n            init: function() {\n                var me = this,\n                    opts = me.options,\n                    button = opts.button;\n\n                button.addClass('webuploader-pick');\n\n                me.on( 'all', function( type ) {\n                    var files;\n\n                    switch ( type ) {\n                        case 'mouseenter':\n                            button.addClass('webuploader-pick-hover');\n                            break;\n\n                        case 'mouseleave':\n                            button.removeClass('webuploader-pick-hover');\n                            break;\n\n                        case 'change':\n                            files = me.exec('getFiles');\n                            me.trigger( 'select', $.map( files, function( file ) {\n                                file = new File( me.getRuid(), file );\n\n                                // 记录来源。\n                                file._refer = opts.container;\n                                return file;\n                            }), opts.container );\n                            break;\n                    }\n                });\n\n                me.connectRuntime( opts, function() {\n                    me.refresh();\n                    me.exec( 'init', opts );\n                    me.trigger('ready');\n                });\n\n                this._resizeHandler = Base.bindFn( this.refresh, this );\n                $( window ).on( 'resize', this._resizeHandler );\n            },\n\n            refresh: function() {\n                var shimContainer = this.getRuntime().getContainer(),\n                    button = this.options.button,\n                    width = button.outerWidth ?\n                            button.outerWidth() : button.width(),\n\n                    height = button.outerHeight ?\n                            button.outerHeight() : button.height(),\n\n                    pos = button.offset();\n\n                width && height && shimContainer.css({\n                    bottom: 'auto',\n                    right: 'auto',\n                    width: width + 'px',\n                    height: height + 'px'\n                }).offset( pos );\n            },\n\n            enable: function() {\n                var btn = this.options.button;\n\n                btn.removeClass('webuploader-pick-disable');\n                this.refresh();\n            },\n\n            disable: function() {\n                var btn = this.options.button;\n\n                this.getRuntime().getContainer().css({\n                    top: '-99999px'\n                });\n\n                btn.addClass('webuploader-pick-disable');\n            },\n\n            destroy: function() {\n                var btn = this.options.button;\n                $( window ).off( 'resize', this._resizeHandler );\n                btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +\n                    'webuploader-pick');\n            }\n        });\n\n        return FilePicker;\n    });\n\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/widget',[\n        'base',\n        'uploader'\n    ], function( Base, Uploader ) {\n\n        var $ = Base.$,\n            _init = Uploader.prototype._init,\n            _destroy = Uploader.prototype.destroy,\n            IGNORE = {},\n            widgetClass = [];\n\n        function isArrayLike( obj ) {\n            if ( !obj ) {\n                return false;\n            }\n\n            var length = obj.length,\n                type = $.type( obj );\n\n            if ( obj.nodeType === 1 && length ) {\n                return true;\n            }\n\n            return type === 'array' || type !== 'function' && type !== 'string' &&\n                    (length === 0 || typeof length === 'number' && length > 0 &&\n                    (length - 1) in obj);\n        }\n\n        function Widget( uploader ) {\n            this.owner = uploader;\n            this.options = uploader.options;\n        }\n\n        $.extend( Widget.prototype, {\n\n            init: Base.noop,\n\n            // 类Backbone的事件监听声明，监听uploader实例上的事件\n            // widget直接无法监听事件，事件只能通过uploader来传递\n            invoke: function( apiName, args ) {\n\n                /*\n                    {\n                        'make-thumb': 'makeThumb'\n                    }\n                 */\n                var map = this.responseMap;\n\n                // 如果无API响应声明则忽略\n                if ( !map || !(apiName in map) || !(map[ apiName ] in this) ||\n                        !$.isFunction( this[ map[ apiName ] ] ) ) {\n\n                    return IGNORE;\n                }\n\n                return this[ map[ apiName ] ].apply( this, args );\n\n            },\n\n            /**\n             * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。\n             * @method request\n             * @grammar request( command, args ) => * | Promise\n             * @grammar request( command, args, callback ) => Promise\n             * @for  Uploader\n             */\n            request: function() {\n                return this.owner.request.apply( this.owner, arguments );\n            }\n        });\n\n        // 扩展Uploader.\n        $.extend( Uploader.prototype, {\n\n            /**\n             * @property {String | Array} [disableWidgets=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。\n             */\n\n            // 覆写_init用来初始化widgets\n            _init: function() {\n                var me = this,\n                    widgets = me._widgets = [],\n                    deactives = me.options.disableWidgets || '';\n\n                $.each( widgetClass, function( _, klass ) {\n                    (!deactives || !~deactives.indexOf( klass._name )) &&\n                        widgets.push( new klass( me ) );\n                });\n\n                return _init.apply( me, arguments );\n            },\n\n            request: function( apiName, args, callback ) {\n                var i = 0,\n                    widgets = this._widgets,\n                    len = widgets && widgets.length,\n                    rlts = [],\n                    dfds = [],\n                    widget, rlt, promise, key;\n\n                args = isArrayLike( args ) ? args : [ args ];\n\n                for ( ; i < len; i++ ) {\n                    widget = widgets[ i ];\n                    rlt = widget.invoke( apiName, args );\n\n                    if ( rlt !== IGNORE ) {\n\n                        // Deferred对象\n                        if ( Base.isPromise( rlt ) ) {\n                            dfds.push( rlt );\n                        } else {\n                            rlts.push( rlt );\n                        }\n                    }\n                }\n\n                // 如果有callback，则用异步方式。\n                if ( callback || dfds.length ) {\n                    promise = Base.when.apply( Base, dfds );\n                    key = promise.pipe ? 'pipe' : 'then';\n\n                    // 很重要不能删除。删除了会死循环。\n                    // 保证执行顺序。让callback总是在下一个 tick 中执行。\n                    return promise[ key ](function() {\n                                var deferred = Base.Deferred(),\n                                    args = arguments;\n\n                                if ( args.length === 1 ) {\n                                    args = args[ 0 ];\n                                }\n\n                                setTimeout(function() {\n                                    deferred.resolve( args );\n                                }, 1 );\n\n                                return deferred.promise();\n                            })[ callback ? key : 'done' ]( callback || Base.noop );\n                } else {\n                    return rlts[ 0 ];\n                }\n            },\n\n            destroy: function() {\n                _destroy.apply( this, arguments );\n                this._widgets = null;\n            }\n        });\n\n        /**\n         * 添加组件\n         * @grammar Uploader.register(proto);\n         * @grammar Uploader.register(map, proto);\n         * @param  {object} responseMap API 名称与函数实现的映射\n         * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义\n         * @method Uploader.register\n         * @for Uploader\n         * @example\n         * Uploader.register({\n         *     'make-thumb': 'makeThumb'\n         * }, {\n         *     init: function( options ) {},\n         *     makeThumb: function() {}\n         * });\n         *\n         * Uploader.register({\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         */\n        Uploader.register = Widget.register = function( responseMap, widgetProto ) {\n            var map = { init: 'init', destroy: 'destroy', name: 'anonymous' },\n                klass;\n\n            if ( arguments.length === 1 ) {\n                widgetProto = responseMap;\n\n                // 自动生成 map 表。\n                $.each(widgetProto, function(key) {\n                    if ( key[0] === '_' || key === 'name' ) {\n                        key === 'name' && (map.name = widgetProto.name);\n                        return;\n                    }\n\n                    map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;\n                });\n\n            } else {\n                map = $.extend( map, responseMap );\n            }\n\n            widgetProto.responseMap = map;\n            klass = Base.inherits( Widget, widgetProto );\n            klass._name = map.name;\n            widgetClass.push( klass );\n\n            return klass;\n        };\n\n        /**\n         * 删除插件，只有在注册时指定了名字的才能被删除。\n         * @grammar Uploader.unRegister(name);\n         * @param  {string} name 组件名字\n         * @method Uploader.unRegister\n         * @for Uploader\n         * @example\n         *\n         * Uploader.register({\n         *     name: 'custom',\n         *\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         *\n         * Uploader.unRegister('custom');\n         */\n        Uploader.unRegister = Widget.unRegister = function( name ) {\n            if ( !name || name === 'anonymous' ) {\n                return;\n            }\n\n            // 删除指定的插件。\n            for ( var i = widgetClass.length; i--; ) {\n                if ( widgetClass[i]._name === name ) {\n                    widgetClass.splice(i, 1)\n                }\n            }\n        };\n\n        return Widget;\n    });\n    /**\n     * @fileOverview 文件选择相关\n     */\n    define('widgets/filepicker',[\n        'base',\n        'uploader',\n        'lib/filepicker',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePicker ) {\n        var $ = Base.$;\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Selector | Object} [pick=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 指定选择文件的按钮容器，不指定则不创建按钮。\n             *\n             * * `id` {Seletor|dom} 指定选择文件的按钮容器，不指定则不创建按钮。**注意** 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。\n             * * `label` {String} 请采用 `innerHTML` 代替\n             * * `innerHTML` {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。\n             * * `multiple` {Boolean} 是否开起同时选择多个文件能力。\n             */\n            pick: null,\n\n            /**\n             * @property {Arroy} [accept=null]\n             * @namespace options\n             * @for Uploader\n             * @description 指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。\n             *\n             * * `title` {String} 文字描述\n             * * `extensions` {String} 允许的文件后缀，不带点，多个用逗号分割。\n             * * `mimeTypes` {String} 多个用逗号分割。\n             *\n             * 如：\n             *\n             * ```\n             * {\n             *     title: 'Images',\n             *     extensions: 'gif,jpg,jpeg,bmp,png',\n             *     mimeTypes: 'image/*'\n             * }\n             * ```\n             */\n            accept: null/*{\n                title: 'Images',\n                extensions: 'gif,jpg,jpeg,bmp,png',\n                mimeTypes: 'image/*'\n            }*/\n        });\n\n        return Uploader.register({\n            name: 'picker',\n\n            init: function( opts ) {\n                this.pickers = [];\n                return opts.pick && this.addBtn( opts.pick );\n            },\n\n            refresh: function() {\n                $.each( this.pickers, function() {\n                    this.refresh();\n                });\n            },\n\n            /**\n             * @method addButton\n             * @for Uploader\n             * @grammar addButton( pick ) => Promise\n             * @description\n             * 添加文件选择按钮，如果一个按钮不够，需要调用此方法来添加。参数跟[options.pick](#WebUploader:Uploader:options)一致。\n             * @example\n             * uploader.addButton({\n             *     id: '#btnContainer',\n             *     innerHTML: '选择文件'\n             * });\n             */\n            addBtn: function( pick ) {\n                var me = this,\n                    opts = me.options,\n                    accept = opts.accept,\n                    promises = [];\n\n                if ( !pick ) {\n                    return;\n                }\n\n                $.isPlainObject( pick ) || (pick = {\n                    id: pick\n                });\n\n                $( pick.id ).each(function() {\n                    var options, picker, deferred;\n\n                    deferred = Base.Deferred();\n\n                    options = $.extend({}, pick, {\n                        accept: $.isPlainObject( accept ) ? [ accept ] : accept,\n                        swf: opts.swf,\n                        runtimeOrder: opts.runtimeOrder,\n                        id: this\n                    });\n\n                    picker = new FilePicker( options );\n\n                    picker.once( 'ready', deferred.resolve );\n                    picker.on( 'select', function( files ) {\n                        me.owner.request( 'add-file', [ files ]);\n                    });\n                    picker.init();\n\n                    me.pickers.push( picker );\n\n                    promises.push( deferred.promise() );\n                });\n\n                return Base.when.apply( Base, promises );\n            },\n\n            disable: function() {\n                $.each( this.pickers, function() {\n                    this.disable();\n                });\n            },\n\n            enable: function() {\n                $.each( this.pickers, function() {\n                    this.enable();\n                });\n            },\n\n            destroy: function() {\n                $.each( this.pickers, function() {\n                    this.destroy();\n                });\n                this.pickers = null;\n            }\n        });\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('lib/image',[\n        'base',\n        'runtime/client',\n        'lib/blob'\n    ], function( Base, RuntimeClient, Blob ) {\n        var $ = Base.$;\n\n        // 构造器。\n        function Image( opts ) {\n            this.options = $.extend({}, Image.options, opts );\n            RuntimeClient.call( this, 'Image' );\n\n            this.on( 'load', function() {\n                this._info = this.exec('info');\n                this._meta = this.exec('meta');\n            });\n        }\n\n        // 默认选项。\n        Image.options = {\n\n            // 默认的图片处理质量\n            quality: 90,\n\n            // 是否裁剪\n            crop: false,\n\n            // 是否保留头部信息\n            preserveHeaders: false,\n\n            // 是否允许放大。\n            allowMagnify: false\n        };\n\n        // 继承RuntimeClient.\n        Base.inherits( RuntimeClient, {\n            constructor: Image,\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    ruid = blob.getRuid();\n\n                this.connectRuntime( ruid, function() {\n                    me.exec( 'init', me.options );\n                    me.exec( 'loadFromBlob', blob );\n                });\n            },\n\n            resize: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'resize' ].concat( args ) );\n            },\n\n            crop: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'crop' ].concat( args ) );\n            },\n\n            getAsDataUrl: function( type ) {\n                return this.exec( 'getAsDataUrl', type );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this.exec( 'getAsBlob', type );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n\n        return Image;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/image',[\n        'base',\n        'uploader',\n        'lib/image',\n        'widgets/widget'\n    ], function( Base, Uploader, Image ) {\n\n        var $ = Base.$,\n            throttle;\n\n        // 根据要处理的文件大小来节流，一次不能处理太多，会卡。\n        throttle = (function( max ) {\n            var occupied = 0,\n                waiting = [],\n                tick = function() {\n                    var item;\n\n                    while ( waiting.length && occupied < max ) {\n                        item = waiting.shift();\n                        occupied += item[ 0 ];\n                        item[ 1 ]();\n                    }\n                };\n\n            return function( emiter, size, cb ) {\n                waiting.push([ size, cb ]);\n                emiter.once( 'destroy', function() {\n                    occupied -= size;\n                    setTimeout( tick, 1 );\n                });\n                setTimeout( tick, 1 );\n            };\n        })( 5 * 1024 * 1024 );\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Object} [thumb]\n             * @namespace options\n             * @for Uploader\n             * @description 配置生成缩略图的选项。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 110,\n             *     height: 110,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 70,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: true,\n             *\n             *     // 是否允许裁剪。\n             *     crop: true,\n             *\n             *     // 为空的话则保留原有图片格式。\n             *     // 否则强制转换成指定的类型。\n             *     type: 'image/jpeg'\n             * }\n             * ```\n             */\n            thumb: {\n                width: 110,\n                height: 110,\n                quality: 70,\n                allowMagnify: true,\n                crop: true,\n                preserveHeaders: false,\n\n                // 为空的话则保留原有图片格式。\n                // 否则强制转换成指定的类型。\n                // IE 8下面 base64 大小不能超过 32K 否则预览失败，而非 jpeg 编码的图片很可\n                // 能会超过 32k, 所以这里设置成预览的时候都是 image/jpeg\n                type: 'image/jpeg'\n            },\n\n            /**\n             * @property {Object} [compress]\n             * @namespace options\n             * @for Uploader\n             * @description 配置压缩的图片的选项。如果此选项为`false`, 则图片在上传前不进行压缩。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 1600,\n             *     height: 1600,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 90,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: false,\n             *\n             *     // 是否允许裁剪。\n             *     crop: false,\n             *\n             *     // 是否保留头部meta信息。\n             *     preserveHeaders: true,\n             *\n             *     // 如果发现压缩后文件大小比原来还大，则使用原来图片\n             *     // 此属性可能会影响图片自动纠正功能\n             *     noCompressIfLarger: false,\n             *\n             *     // 单位字节，如果图片大小小于此值，不会采用压缩。\n             *     compressSize: 0\n             * }\n             * ```\n             */\n            compress: {\n                width: 1600,\n                height: 1600,\n                quality: 90,\n                allowMagnify: false,\n                crop: false,\n                preserveHeaders: true\n            }\n        });\n\n        return Uploader.register({\n\n            name: 'image',\n\n\n            /**\n             * 生成缩略图，此过程为异步，所以需要传入`callback`。\n             * 通常情况在图片加入队里后调用此方法来生成预览图以增强交互效果。\n             *\n             * 当 width 或者 height 的值介于 0 - 1 时，被当成百分比使用。\n             *\n             * `callback`中可以接收到两个参数。\n             * * 第一个为error，如果生成缩略图有错误，此error将为真。\n             * * 第二个为ret, 缩略图的Data URL值。\n             *\n             * **注意**\n             * Date URL在IE6/7中不支持，所以不用调用此方法了，直接显示一张暂不支持预览图片好了。\n             * 也可以借助服务端，将 base64 数据传给服务端，生成一个临时文件供预览。\n             *\n             * @method makeThumb\n             * @grammar makeThumb( file, callback ) => undefined\n             * @grammar makeThumb( file, callback, width, height ) => undefined\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.makeThumb( file, function( error, ret ) {\n             *         if ( error ) {\n             *             $li.text('预览错误');\n             *         } else {\n             *             $li.append('<img alt=\"\" src=\"' + ret + '\" />');\n             *         }\n             *     });\n             *\n             * });\n             */\n            makeThumb: function( file, cb, width, height ) {\n                var opts, image;\n\n                file = this.request( 'get-file', file );\n\n                // 只预览图片格式。\n                if ( !file.type.match( /^image/ ) ) {\n                    cb( true );\n                    return;\n                }\n\n                opts = $.extend({}, this.options.thumb );\n\n                // 如果传入的是object.\n                if ( $.isPlainObject( width ) ) {\n                    opts = $.extend( opts, width );\n                    width = null;\n                }\n\n                width = width || opts.width;\n                height = height || opts.height;\n\n                image = new Image( opts );\n\n                image.once( 'load', function() {\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                // 当 resize 完后\n                image.once( 'complete', function() {\n                    cb( false, image.getAsDataUrl( opts.type ) );\n                    image.destroy();\n                });\n\n                image.once( 'error', function( reason ) {\n                    cb( reason || true );\n                    image.destroy();\n                });\n\n                throttle( image, file.source.size, function() {\n                    file._info && image.info( file._info );\n                    file._meta && image.meta( file._meta );\n                    image.loadFromBlob( file.source );\n                });\n            },\n\n            beforeSendFile: function( file ) {\n                var opts = this.options.compress || this.options.resize,\n                    compressSize = opts && opts.compressSize || 0,\n                    noCompressIfLarger = opts && opts.noCompressIfLarger || false,\n                    image, deferred;\n\n                file = this.request( 'get-file', file );\n\n                // 只压缩 jpeg 图片格式。\n                // gif 可能会丢失针\n                // bmp png 基本上尺寸都不大，且压缩比比较小。\n                if ( !opts || !~'image/jpeg,image/jpg'.indexOf( file.type ) ||\n                        file.size < compressSize ||\n                        file._compressed ) {\n                    return;\n                }\n\n                opts = $.extend({}, opts );\n                deferred = Base.Deferred();\n\n                image = new Image( opts );\n\n                deferred.always(function() {\n                    image.destroy();\n                    image = null;\n                });\n                image.once( 'error', deferred.reject );\n                image.once( 'load', function() {\n                    var width = opts.width,\n                        height = opts.height;\n\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                image.once( 'complete', function() {\n                    var blob, size;\n\n                    // 移动端 UC / qq 浏览器的无图模式下\n                    // ctx.getImageData 处理大图的时候会报 Exception\n                    // INDEX_SIZE_ERR: DOM Exception 1\n                    try {\n                        blob = image.getAsBlob( opts.type );\n\n                        size = file.size;\n\n                        // 如果压缩后，比原来还大则不用压缩后的。\n                        if ( !noCompressIfLarger || blob.size < size ) {\n                            // file.source.destroy && file.source.destroy();\n                            file.source = blob;\n                            file.size = blob.size;\n\n                            file.trigger( 'resize', blob.size, size );\n                        }\n\n                        // 标记，避免重复压缩。\n                        file._compressed = true;\n                        deferred.resolve();\n                    } catch ( e ) {\n                        // 出错了直接继续，让其上传原始图片\n                        deferred.resolve();\n                    }\n                });\n\n                file._info && image.info( file._info );\n                file._meta && image.meta( file._meta );\n\n                image.loadFromBlob( file.source );\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview 文件属性封装\n     */\n    define('file',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            idPrefix = 'WU_FILE_',\n            idSuffix = 0,\n            rExt = /\\.([^.]+)$/,\n            statusMap = {};\n\n        function gid() {\n            return idPrefix + idSuffix++;\n        }\n\n        /**\n         * 文件类\n         * @class File\n         * @constructor 构造函数\n         * @grammar new File( source ) => File\n         * @param {Lib.File} source [lib.File](#Lib.File)实例, 此source对象是带有Runtime信息的。\n         */\n        function WUFile( source ) {\n\n            /**\n             * 文件名，包括扩展名（后缀）\n             * @property name\n             * @type {string}\n             */\n            this.name = source.name || 'Untitled';\n\n            /**\n             * 文件体积（字节）\n             * @property size\n             * @type {uint}\n             * @default 0\n             */\n            this.size = source.size || 0;\n\n            /**\n             * 文件MIMETYPE类型，与文件类型的对应关系请参考[http://t.cn/z8ZnFny](http://t.cn/z8ZnFny)\n             * @property type\n             * @type {string}\n             * @default 'application/octet-stream'\n             */\n            this.type = source.type || 'application/octet-stream';\n\n            /**\n             * 文件最后修改日期\n             * @property lastModifiedDate\n             * @type {int}\n             * @default 当前时间戳\n             */\n            this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);\n\n            /**\n             * 文件ID，每个对象具有唯一ID，与文件名无关\n             * @property id\n             * @type {string}\n             */\n            this.id = gid();\n\n            /**\n             * 文件扩展名，通过文件名获取，例如test.png的扩展名为png\n             * @property ext\n             * @type {string}\n             */\n            this.ext = rExt.exec( this.name ) ? RegExp.$1 : '';\n\n\n            /**\n             * 状态文字说明。在不同的status语境下有不同的用途。\n             * @property statusText\n             * @type {string}\n             */\n            this.statusText = '';\n\n            // 存储文件状态，防止通过属性直接修改\n            statusMap[ this.id ] = WUFile.Status.INITED;\n\n            this.source = source;\n            this.loaded = 0;\n\n            this.on( 'error', function( msg ) {\n                this.setStatus( WUFile.Status.ERROR, msg );\n            });\n        }\n\n        $.extend( WUFile.prototype, {\n\n            /**\n             * 设置状态，状态变化时会触发`change`事件。\n             * @method setStatus\n             * @grammar setStatus( status[, statusText] );\n             * @param {File.Status|String} status [文件状态值](#WebUploader:File:File.Status)\n             * @param {String} [statusText=''] 状态说明，常在error时使用，用http, abort,server等来标记是由于什么原因导致文件错误。\n             */\n            setStatus: function( status, text ) {\n\n                var prevStatus = statusMap[ this.id ];\n\n                typeof text !== 'undefined' && (this.statusText = text);\n\n                if ( status !== prevStatus ) {\n                    statusMap[ this.id ] = status;\n                    /**\n                     * 文件状态变化\n                     * @event statuschange\n                     */\n                    this.trigger( 'statuschange', status, prevStatus );\n                }\n\n            },\n\n            /**\n             * 获取文件状态\n             * @return {File.Status}\n             * @example\n                     文件状态具体包括以下几种类型：\n                     {\n                         // 初始化\n                        INITED:     0,\n                        // 已入队列\n                        QUEUED:     1,\n                        // 正在上传\n                        PROGRESS:     2,\n                        // 上传出错\n                        ERROR:         3,\n                        // 上传成功\n                        COMPLETE:     4,\n                        // 上传取消\n                        CANCELLED:     5\n                    }\n             */\n            getStatus: function() {\n                return statusMap[ this.id ];\n            },\n\n            /**\n             * 获取文件原始信息。\n             * @return {*}\n             */\n            getSource: function() {\n                return this.source;\n            },\n\n            destroy: function() {\n                this.off();\n                delete statusMap[ this.id ];\n            }\n        });\n\n        Mediator.installTo( WUFile.prototype );\n\n        /**\n         * 文件状态值，具体包括以下几种类型：\n         * * `inited` 初始状态\n         * * `queued` 已经进入队列, 等待上传\n         * * `progress` 上传中\n         * * `complete` 上传完成。\n         * * `error` 上传出错，可重试\n         * * `interrupt` 上传中断，可续传。\n         * * `invalid` 文件不合格，不能重试上传。会自动从队列中移除。\n         * * `cancelled` 文件被移除。\n         * @property {Object} Status\n         * @namespace File\n         * @class File\n         * @static\n         */\n        WUFile.Status = {\n            INITED:     'inited',    // 初始状态\n            QUEUED:     'queued',    // 已经进入队列, 等待上传\n            PROGRESS:   'progress',    // 上传中\n            ERROR:      'error',    // 上传出错，可重试\n            COMPLETE:   'complete',    // 上传完成。\n            CANCELLED:  'cancelled',    // 上传取消。\n            INTERRUPT:  'interrupt',    // 上传中断，可续传。\n            INVALID:    'invalid'    // 文件不合格，不能重试上传。\n        };\n\n        return WUFile;\n    });\n\n    /**\n     * @fileOverview 文件队列\n     */\n    define('queue',[\n        'base',\n        'mediator',\n        'file'\n    ], function( Base, Mediator, WUFile ) {\n\n        var $ = Base.$,\n            STATUS = WUFile.Status;\n\n        /**\n         * 文件队列, 用来存储各个状态中的文件。\n         * @class Queue\n         * @extends Mediator\n         */\n        function Queue() {\n\n            /**\n             * 统计文件数。\n             * * `numOfQueue` 队列中的文件数。\n             * * `numOfSuccess` 上传成功的文件数\n             * * `numOfCancel` 被取消的文件数\n             * * `numOfProgress` 正在上传中的文件数\n             * * `numOfUploadFailed` 上传错误的文件数。\n             * * `numOfInvalid` 无效的文件数。\n             * * `numofDeleted` 被移除的文件数。\n             * @property {Object} stats\n             */\n            this.stats = {\n                numOfQueue: 0,\n                numOfSuccess: 0,\n                numOfCancel: 0,\n                numOfProgress: 0,\n                numOfUploadFailed: 0,\n                numOfInvalid: 0,\n                numofDeleted: 0,\n                numofInterrupt: 0\n            };\n\n            // 上传队列，仅包括等待上传的文件\n            this._queue = [];\n\n            // 存储所有文件\n            this._map = {};\n        }\n\n        $.extend( Queue.prototype, {\n\n            /**\n             * 将新文件加入对队列尾部\n             *\n             * @method append\n             * @param  {File} file   文件对象\n             */\n            append: function( file ) {\n                this._queue.push( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 将新文件加入对队列头部\n             *\n             * @method prepend\n             * @param  {File} file   文件对象\n             */\n            prepend: function( file ) {\n                this._queue.unshift( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 获取文件对象\n             *\n             * @method getFile\n             * @param  {String} fileId   文件ID\n             * @return {File}\n             */\n            getFile: function( fileId ) {\n                if ( typeof fileId !== 'string' ) {\n                    return fileId;\n                }\n                return this._map[ fileId ];\n            },\n\n            /**\n             * 从队列中取出一个指定状态的文件。\n             * @grammar fetch( status ) => File\n             * @method fetch\n             * @param {String} status [文件状态值](#WebUploader:File:File.Status)\n             * @return {File} [File](#WebUploader:File)\n             */\n            fetch: function( status ) {\n                var len = this._queue.length,\n                    i, file;\n\n                status = status || STATUS.QUEUED;\n\n                for ( i = 0; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( status === file.getStatus() ) {\n                        return file;\n                    }\n                }\n\n                return null;\n            },\n\n            /**\n             * 对队列进行排序，能够控制文件上传顺序。\n             * @grammar sort( fn ) => undefined\n             * @method sort\n             * @param {Function} fn 排序方法\n             */\n            sort: function( fn ) {\n                if ( typeof fn === 'function' ) {\n                    this._queue.sort( fn );\n                }\n            },\n\n            /**\n             * 获取指定类型的文件列表, 列表中每一个成员为[File](#WebUploader:File)对象。\n             * @grammar getFiles( [status1[, status2 ...]] ) => Array\n             * @method getFiles\n             * @param {String} [status] [文件状态值](#WebUploader:File:File.Status)\n             */\n            getFiles: function() {\n                var sts = [].slice.call( arguments, 0 ),\n                    ret = [],\n                    i = 0,\n                    len = this._queue.length,\n                    file;\n\n                for ( ; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( sts.length && !~$.inArray( file.getStatus(), sts ) ) {\n                        continue;\n                    }\n\n                    ret.push( file );\n                }\n\n                return ret;\n            },\n\n            /**\n             * 在队列中删除文件。\n             * @grammar removeFile( file ) => Array\n             * @method removeFile\n             * @param {File} 文件对象。\n             */\n            removeFile: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( existing ) {\n                    delete this._map[ file.id ];\n                    file.destroy();\n                    this.stats.numofDeleted++;\n                }\n            },\n\n            _fileAdded: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( !existing ) {\n                    this._map[ file.id ] = file;\n\n                    file.on( 'statuschange', function( cur, pre ) {\n                        me._onFileStatusChange( cur, pre );\n                    });\n                }\n            },\n\n            _onFileStatusChange: function( curStatus, preStatus ) {\n                var stats = this.stats;\n\n                switch ( preStatus ) {\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress--;\n                        break;\n\n                    case STATUS.QUEUED:\n                        stats.numOfQueue --;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed--;\n                        break;\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid--;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt--;\n                        break;\n                }\n\n                switch ( curStatus ) {\n                    case STATUS.QUEUED:\n                        stats.numOfQueue++;\n                        break;\n\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress++;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed++;\n                        break;\n\n                    case STATUS.COMPLETE:\n                        stats.numOfSuccess++;\n                        break;\n\n                    case STATUS.CANCELLED:\n                        stats.numOfCancel++;\n                        break;\n\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid++;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt++;\n                        break;\n                }\n            }\n\n        });\n\n        Mediator.installTo( Queue.prototype );\n\n        return Queue;\n    });\n    /**\n     * @fileOverview 队列\n     */\n    define('widgets/queue',[\n        'base',\n        'uploader',\n        'queue',\n        'file',\n        'lib/file',\n        'runtime/client',\n        'widgets/widget'\n    ], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {\n\n        var $ = Base.$,\n            rExt = /\\.\\w+$/,\n            Status = WUFile.Status;\n\n        return Uploader.register({\n            name: 'queue',\n\n            init: function( opts ) {\n                var me = this,\n                    deferred, len, i, item, arr, accept, runtime;\n\n                if ( $.isPlainObject( opts.accept ) ) {\n                    opts.accept = [ opts.accept ];\n                }\n\n                // accept中的中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].extensions;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = '\\\\.' + arr.join(',')\n                                .replace( /,/g, '$|\\\\.' )\n                                .replace( /\\*/g, '.*' ) + '$';\n                    }\n\n                    me.accept = new RegExp( accept, 'i' );\n                }\n\n                me.queue = new Queue();\n                me.stats = me.queue.stats;\n\n                // 如果当前不是html5运行时，那就算了。\n                // 不执行后续操作\n                if ( this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                // 创建一个 html5 运行时的 placeholder\n                // 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。\n                deferred = Base.Deferred();\n                this.placeholder = runtime = new RuntimeClient('Placeholder');\n                runtime.connectRuntime({\n                    runtimeOrder: 'html5'\n                }, function() {\n                    me._ruid = runtime.getRuid();\n                    deferred.resolve();\n                });\n                return deferred.promise();\n            },\n\n\n            // 为了支持外部直接添加一个原生File对象。\n            _wrapFile: function( file ) {\n                if ( !(file instanceof WUFile) ) {\n\n                    if ( !(file instanceof File) ) {\n                        if ( !this._ruid ) {\n                            throw new Error('Can\\'t add external files.');\n                        }\n                        file = new File( this._ruid, file );\n                    }\n\n                    file = new WUFile( file );\n                }\n\n                return file;\n            },\n\n            // 判断文件是否可以被加入队列\n            acceptFile: function( file ) {\n                var invalid = !file || !file.size || this.accept &&\n\n                        // 如果名字中有后缀，才做后缀白名单处理。\n                        rExt.exec( file.name ) && !this.accept.test( file.name );\n\n                return !invalid;\n            },\n\n\n            /**\n             * @event beforeFileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列之前触发，此事件的handler返回值为`false`，则此文件不会被添加进入队列。\n             * @for  Uploader\n             */\n\n            /**\n             * @event fileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列以后触发。\n             * @for  Uploader\n             */\n\n            _addFile: function( file ) {\n                var me = this;\n\n                file = me._wrapFile( file );\n\n                // 不过类型判断允许不允许，先派送 `beforeFileQueued`\n                if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {\n                    return;\n                }\n\n                // 类型不匹配，则派送错误事件，并返回。\n                if ( !me.acceptFile( file ) ) {\n                    me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );\n                    return;\n                }\n\n                me.queue.append( file );\n                me.owner.trigger( 'fileQueued', file );\n                return file;\n            },\n\n            getFile: function( fileId ) {\n                return this.queue.getFile( fileId );\n            },\n\n            /**\n             * @event filesQueued\n             * @param {File} files 数组，内容为原始File(lib/File）对象。\n             * @description 当一批文件添加进队列以后触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @property {Boolean} [auto=false]\n             * @namespace options\n             * @for Uploader\n             * @description 设置为 true 后，不需要手动调用上传，有文件选择即开始上传。\n             *\n             */\n\n            /**\n             * @method addFiles\n             * @grammar addFiles( file ) => undefined\n             * @grammar addFiles( [file1, file2 ...] ) => undefined\n             * @param {Array of File or File} [files] Files 对象 数组\n             * @description 添加文件到队列\n             * @for  Uploader\n             */\n            addFile: function( files ) {\n                var me = this;\n\n                if ( !files.length ) {\n                    files = [ files ];\n                }\n\n                files = $.map( files, function( file ) {\n                    return me._addFile( file );\n                });\n\n                me.owner.trigger( 'filesQueued', files );\n\n                if ( me.options.auto ) {\n                    setTimeout(function() {\n                        me.request('start-upload');\n                    }, 20 );\n                }\n            },\n\n            getStats: function() {\n                return this.stats;\n            },\n\n            /**\n             * @event fileDequeued\n             * @param {File} file File对象\n             * @description 当文件被移除队列后触发。\n             * @for  Uploader\n             */\n\n             /**\n             * @method removeFile\n             * @grammar removeFile( file ) => undefined\n             * @grammar removeFile( id ) => undefined\n             * @grammar removeFile( file, true ) => undefined\n             * @grammar removeFile( id, true ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 移除某一文件, 默认只会标记文件状态为已取消，如果第二个参数为 `true` 则会从 queue 中移除。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.removeFile( file );\n             * })\n             */\n            removeFile: function( file, remove ) {\n                var me = this;\n\n                file = file.id ? file : me.queue.getFile( file );\n\n                this.request( 'cancel-file', file );\n\n                if ( remove ) {\n                    this.queue.removeFile( file );\n                }\n            },\n\n            /**\n             * @method getFiles\n             * @grammar getFiles() => Array\n             * @grammar getFiles( status1, status2, status... ) => Array\n             * @description 返回指定状态的文件集合，不传参数将返回所有状态的文件。\n             * @for  Uploader\n             * @example\n             * console.log( uploader.getFiles() );    // => all files\n             * console.log( uploader.getFiles('error') )    // => all error files.\n             */\n            getFiles: function() {\n                return this.queue.getFiles.apply( this.queue, arguments );\n            },\n\n            fetchFile: function() {\n                return this.queue.fetch.apply( this.queue, arguments );\n            },\n\n            /**\n             * @method retry\n             * @grammar retry() => undefined\n             * @grammar retry( file ) => undefined\n             * @description 重试上传，重试指定文件，或者从出错的文件开始重新上传。\n             * @for  Uploader\n             * @example\n             * function retry() {\n             *     uploader.retry();\n             * }\n             */\n            retry: function( file, noForceStart ) {\n                var me = this,\n                    files, i, len;\n\n                if ( file ) {\n                    file = file.id ? file : me.queue.getFile( file );\n                    file.setStatus( Status.QUEUED );\n                    noForceStart || me.request('start-upload');\n                    return;\n                }\n\n                files = me.queue.getFiles( Status.ERROR );\n                i = 0;\n                len = files.length;\n\n                for ( ; i < len; i++ ) {\n                    file = files[ i ];\n                    file.setStatus( Status.QUEUED );\n                }\n\n                me.request('start-upload');\n            },\n\n            /**\n             * @method sort\n             * @grammar sort( fn ) => undefined\n             * @description 排序队列中的文件，在上传之前调整可以控制上传顺序。\n             * @for  Uploader\n             */\n            sortFiles: function() {\n                return this.queue.sort.apply( this.queue, arguments );\n            },\n\n            /**\n             * @event reset\n             * @description 当 uploader 被重置的时候触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @method reset\n             * @grammar reset() => undefined\n             * @description 重置uploader。目前只重置了队列。\n             * @for  Uploader\n             * @example\n             * uploader.reset();\n             */\n            reset: function() {\n                this.owner.trigger('reset');\n                this.queue = new Queue();\n                this.stats = this.queue.stats;\n            },\n\n            destroy: function() {\n                this.reset();\n                this.placeholder && this.placeholder.destroy();\n            }\n        });\n\n    });\n    /**\n     * @fileOverview 添加获取Runtime相关信息的方法。\n     */\n    define('widgets/runtime',[\n        'uploader',\n        'runtime/runtime',\n        'widgets/widget'\n    ], function( Uploader, Runtime ) {\n\n        Uploader.support = function() {\n            return Runtime.hasRuntime.apply( Runtime, arguments );\n        };\n\n        /**\n         * @property {Object} [runtimeOrder=html5,flash]\n         * @namespace options\n         * @for Uploader\n         * @description 指定运行时启动顺序。默认会想尝试 html5 是否支持，如果支持则使用 html5, 否则则使用 flash.\n         *\n         * 可以将此值设置成 `flash`，来强制使用 flash 运行时。\n         */\n\n        return Uploader.register({\n            name: 'runtime',\n\n            init: function() {\n                if ( !this.predictRuntimeType() ) {\n                    throw Error('Runtime Error');\n                }\n            },\n\n            /**\n             * 预测Uploader将采用哪个`Runtime`\n             * @grammar predictRuntimeType() => String\n             * @method predictRuntimeType\n             * @for  Uploader\n             */\n            predictRuntimeType: function() {\n                var orders = this.options.runtimeOrder || Runtime.orders,\n                    type = this.type,\n                    i, len;\n\n                if ( !type ) {\n                    orders = orders.split( /\\s*,\\s*/g );\n\n                    for ( i = 0, len = orders.length; i < len; i++ ) {\n                        if ( Runtime.hasRuntime( orders[ i ] ) ) {\n                            this.type = type = orders[ i ];\n                            break;\n                        }\n                    }\n                }\n\n                return type;\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     */\n    define('lib/transport',[\n        'base',\n        'runtime/client',\n        'mediator'\n    ], function( Base, RuntimeClient, Mediator ) {\n\n        var $ = Base.$;\n\n        function Transport( opts ) {\n            var me = this;\n\n            opts = me.options = $.extend( true, {}, Transport.options, opts || {} );\n            RuntimeClient.call( this, 'Transport' );\n\n            this._blob = null;\n            this._formData = opts.formData || {};\n            this._headers = opts.headers || {};\n\n            this.on( 'progress', this._timeout );\n            this.on( 'load error', function() {\n                me.trigger( 'progress', 1 );\n                clearTimeout( me._timer );\n            });\n        }\n\n        Transport.options = {\n            server: '',\n            method: 'POST',\n\n            // 跨域时，是否允许携带cookie, 只有html5 runtime才有效\n            withCredentials: false,\n            fileVal: 'file',\n            timeout: 2 * 60 * 1000,    // 2分钟\n            formData: {},\n            headers: {},\n            sendAsBinary: false\n        };\n\n        $.extend( Transport.prototype, {\n\n            // 添加Blob, 只能添加一次，最后一次有效。\n            appendBlob: function( key, blob, filename ) {\n                var me = this,\n                    opts = me.options;\n\n                if ( me.getRuid() ) {\n                    me.disconnectRuntime();\n                }\n\n                // 连接到blob归属的同一个runtime.\n                me.connectRuntime( blob.ruid, function() {\n                    me.exec('init');\n                });\n\n                me._blob = blob;\n                opts.fileVal = key || opts.fileVal;\n                opts.filename = filename || opts.filename;\n            },\n\n            // 添加其他字段\n            append: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._formData, key );\n                } else {\n                    this._formData[ key ] = value;\n                }\n            },\n\n            setRequestHeader: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._headers, key );\n                } else {\n                    this._headers[ key ] = value;\n                }\n            },\n\n            send: function( method ) {\n                this.exec( 'send', method );\n                this._timeout();\n            },\n\n            abort: function() {\n                clearTimeout( this._timer );\n                return this.exec('abort');\n            },\n\n            destroy: function() {\n                this.trigger('destroy');\n                this.off();\n                this.exec('destroy');\n                this.disconnectRuntime();\n            },\n\n            getResponse: function() {\n                return this.exec('getResponse');\n            },\n\n            getResponseAsJson: function() {\n                return this.exec('getResponseAsJson');\n            },\n\n            getStatus: function() {\n                return this.exec('getStatus');\n            },\n\n            _timeout: function() {\n                var me = this,\n                    duration = me.options.timeout;\n\n                if ( !duration ) {\n                    return;\n                }\n\n                clearTimeout( me._timer );\n                me._timer = setTimeout(function() {\n                    me.abort();\n                    me.trigger( 'error', 'timeout' );\n                }, duration );\n            }\n\n        });\n\n        // 让Transport具备事件功能。\n        Mediator.installTo( Transport.prototype );\n\n        return Transport;\n    });\n    /**\n     * @fileOverview 负责文件上传相关。\n     */\n    define('widgets/upload',[\n        'base',\n        'uploader',\n        'file',\n        'lib/transport',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile, Transport ) {\n\n        var $ = Base.$,\n            isPromise = Base.isPromise,\n            Status = WUFile.Status;\n\n        // 添加默认配置项\n        $.extend( Uploader.options, {\n\n\n            /**\n             * @property {Boolean} [prepareNextFile=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否允许在文件传输时提前把下一个文件准备好。\n             * 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。\n             * 如果能提前在当前文件传输期处理，可以节省总体耗时。\n             */\n            prepareNextFile: false,\n\n            /**\n             * @property {Boolean} [chunked=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否要分片处理大文件上传。\n             */\n            chunked: false,\n\n            /**\n             * @property {Boolean} [chunkSize=5242880]\n             * @namespace options\n             * @for Uploader\n             * @description 如果要分片，分多大一片？ 默认大小为5M.\n             */\n            chunkSize: 5 * 1024 * 1024,\n\n            /**\n             * @property {Boolean} [chunkRetry=2]\n             * @namespace options\n             * @for Uploader\n             * @description 如果某个分片由于网络问题出错，允许自动重传多少次？\n             */\n            chunkRetry: 2,\n\n            /**\n             * @property {Boolean} [threads=3]\n             * @namespace options\n             * @for Uploader\n             * @description 上传并发数。允许同时最大上传进程数。\n             */\n            threads: 3,\n\n\n            /**\n             * @property {Object} [formData={}]\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传请求的参数表，每次发送都会发送此对象中的参数。\n             */\n            formData: {}\n\n            /**\n             * @property {Object} [fileVal='file']\n             * @namespace options\n             * @for Uploader\n             * @description 设置文件上传域的name。\n             */\n\n            /**\n             * @property {Object} [method='POST']\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传方式，`POST`或者`GET`。\n             */\n\n            /**\n             * @property {Object} [sendAsBinary=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否已二进制的流的方式发送文件，这样整个上传内容`php://input`都为文件内容，\n             * 其他参数在$_GET数组中。\n             */\n        });\n\n        // 负责将文件切片。\n        function CuteFile( file, chunkSize ) {\n            var pending = [],\n                blob = file.source,\n                total = blob.size,\n                chunks = chunkSize ? Math.ceil( total / chunkSize ) : 1,\n                start = 0,\n                index = 0,\n                len, api;\n\n            api = {\n                file: file,\n\n                has: function() {\n                    return !!pending.length;\n                },\n\n                shift: function() {\n                    return pending.shift();\n                },\n\n                unshift: function( block ) {\n                    pending.unshift( block );\n                }\n            };\n\n            while ( index < chunks ) {\n                len = Math.min( chunkSize, total - start );\n\n                pending.push({\n                    file: file,\n                    start: start,\n                    end: chunkSize ? (start + len) : total,\n                    total: total,\n                    chunks: chunks,\n                    chunk: index++,\n                    cuted: api\n                });\n                start += len;\n            }\n\n            file.blocks = pending.concat();\n            file.remaning = pending.length;\n\n            return api;\n        }\n\n        Uploader.register({\n            name: 'upload',\n\n            init: function() {\n                var owner = this.owner,\n                    me = this;\n\n                this.runing = false;\n                this.progress = false;\n\n                owner\n                    .on( 'startUpload', function() {\n                        me.progress = true;\n                    })\n                    .on( 'uploadFinished', function() {\n                        me.progress = false;\n                    });\n\n                // 记录当前正在传的数据，跟threads相关\n                this.pool = [];\n\n                // 缓存分好片的文件。\n                this.stack = [];\n\n                // 缓存即将上传的文件。\n                this.pending = [];\n\n                // 跟踪还有多少分片在上传中但是没有完成上传。\n                this.remaning = 0;\n                this.__tick = Base.bindFn( this._tick, this );\n\n                owner.on( 'uploadComplete', function( file ) {\n\n                    // 把其他块取消了。\n                    file.blocks && $.each( file.blocks, function( _, v ) {\n                        v.transport && (v.transport.abort(), v.transport.destroy());\n                        delete v.transport;\n                    });\n\n                    delete file.blocks;\n                    delete file.remaning;\n                });\n            },\n\n            reset: function() {\n                this.request( 'stop-upload', true );\n                this.runing = false;\n                this.pool = [];\n                this.stack = [];\n                this.pending = [];\n                this.remaning = 0;\n                this._trigged = false;\n                this._promise = null;\n            },\n\n            /**\n             * @event startUpload\n             * @description 当开始上传流程时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 开始上传。此方法可以从初始状态调用开始上传流程，也可以从暂停状态调用，继续上传流程。\n             *\n             * 可以指定开始某一个文件。\n             * @grammar upload() => undefined\n             * @grammar upload( file | fileId) => undefined\n             * @method upload\n             * @for  Uploader\n             */\n            startUpload: function(file) {\n                var me = this;\n\n                // 移出invalid的文件\n                $.each( me.request( 'get-files', Status.INVALID ), function() {\n                    me.request( 'remove-file', this );\n                });\n\n                // 如果指定了开始某个文件，则只开始指定文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        $.each( me.pool, function( _, v ) {\n\n                            // 之前暂停过。\n                            if (v.file !== file) {\n                                return;\n                            }\n\n                            v.transport && v.transport.send();\n                        });\n\n                        file.setStatus( Status.QUEUED );\n                    } else if (file.getStatus() === Status.PROGRESS) {\n                        return;\n                    } else {\n                        file.setStatus( Status.QUEUED );\n                    }\n                } else {\n                    $.each( me.request( 'get-files', [ Status.INITED ] ), function() {\n                        this.setStatus( Status.QUEUED );\n                    });\n                }\n\n                if ( me.runing ) {\n                    return;\n                }\n\n                me.runing = true;\n\n                var files = [];\n\n                // 如果有暂停的，则续传\n                $.each( me.pool, function( _, v ) {\n                    var file = v.file;\n\n                    if ( file.getStatus() === Status.INTERRUPT ) {\n                        files.push(file);\n                        me._trigged = false;\n                        v.transport && v.transport.send();\n                    }\n                });\n\n                var file;\n                while ( (file = files.shift()) ) {\n                    file.setStatus( Status.PROGRESS );\n                }\n\n                file || $.each( me.request( 'get-files',\n                        Status.INTERRUPT ), function() {\n                    this.setStatus( Status.PROGRESS );\n                });\n\n                me._trigged = false;\n                Base.nextTick( me.__tick );\n                me.owner.trigger('startUpload');\n            },\n\n            /**\n             * @event stopUpload\n             * @description 当开始上传流程暂停时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 暂停上传。第一个参数为是否中断上传当前正在上传的文件。\n             *\n             * 如果第一个参数是文件，则只暂停指定文件。\n             * @grammar stop() => undefined\n             * @grammar stop( true ) => undefined\n             * @grammar stop( file ) => undefined\n             * @method stop\n             * @for  Uploader\n             */\n            stopUpload: function( file, interrupt ) {\n                var me = this;\n\n                if (file === true) {\n                    interrupt = file;\n                    file = null;\n                }\n\n                if ( me.runing === false ) {\n                    return;\n                }\n\n                // 如果只是暂停某个文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if ( file.getStatus() !== Status.PROGRESS &&\n                            file.getStatus() !== Status.QUEUED ) {\n                        return;\n                    }\n\n                    file.setStatus( Status.INTERRUPT );\n                    $.each( me.pool, function( _, v ) {\n\n                        // 只 abort 指定的文件。\n                        if (v.file !== file) {\n                            return;\n                        }\n\n                        v.transport && v.transport.abort();\n                        me._putback(v);\n                        me._popBlock(v);\n                    });\n\n                    return Base.nextTick( me.__tick );\n                }\n\n                me.runing = false;\n\n                if (this._promise && this._promise.file) {\n                    this._promise.file.setStatus( Status.INTERRUPT );\n                }\n\n                interrupt && $.each( me.pool, function( _, v ) {\n                    v.transport && v.transport.abort();\n                    v.file.setStatus( Status.INTERRUPT );\n                });\n\n                me.owner.trigger('stopUpload');\n            },\n\n            /**\n             * @method cancelFile\n             * @grammar cancelFile( file ) => undefined\n             * @grammar cancelFile( id ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 标记文件状态为已取消, 同时将中断文件传输。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.cancelFile( file );\n             * })\n             */\n            cancelFile: function( file ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                file.setStatus( Status.CANCELLED );\n                this.owner.trigger( 'fileDequeued', file );\n            },\n\n            /**\n             * 判断`Uplaode`r是否正在上传中。\n             * @grammar isInProgress() => Boolean\n             * @method isInProgress\n             * @for  Uploader\n             */\n            isInProgress: function() {\n                return !!this.progress;\n            },\n\n            _getStats: function() {\n                return this.request('get-stats');\n            },\n\n            /**\n             * 掉过一个文件上传，直接标记指定文件为已上传状态。\n             * @grammar skipFile( file ) => undefined\n             * @method skipFile\n             * @for  Uploader\n             */\n            skipFile: function( file, status ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                file.setStatus( status || Status.COMPLETE );\n                file.skipped = true;\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                this.owner.trigger( 'uploadSkip', file );\n            },\n\n            /**\n             * @event uploadFinished\n             * @description 当所有文件上传结束时触发。\n             * @for  Uploader\n             */\n            _tick: function() {\n                var me = this,\n                    opts = me.options,\n                    fn, val;\n\n                // 上一个promise还没有结束，则等待完成后再执行。\n                if ( me._promise ) {\n                    return me._promise.always( me.__tick );\n                }\n\n                // 还有位置，且还有文件要处理的话。\n                if ( me.pool.length < opts.threads && (val = me._nextBlock()) ) {\n                    me._trigged = false;\n\n                    fn = function( val ) {\n                        me._promise = null;\n\n                        // 有可能是reject过来的，所以要检测val的类型。\n                        val && val.file && me._startSend( val );\n                        Base.nextTick( me.__tick );\n                    };\n\n                    me._promise = isPromise( val ) ? val.always( fn ) : fn( val );\n\n                // 没有要上传的了，且没有正在传输的了。\n                } else if ( !me.remaning && !me._getStats().numOfQueue &&\n                    !me._getStats().numofInterrupt ) {\n                    me.runing = false;\n\n                    me._trigged || Base.nextTick(function() {\n                        me.owner.trigger('uploadFinished');\n                    });\n                    me._trigged = true;\n                }\n            },\n\n            _putback: function(block) {\n                var idx;\n\n                block.cuted.unshift(block);\n                idx = this.stack.indexOf(block.cuted);\n\n                if (!~idx) {\n                    this.stack.unshift(block.cuted);\n                }\n            },\n\n            _getStack: function() {\n                var i = 0,\n                    act;\n\n                while ( (act = this.stack[ i++ ]) ) {\n                    if ( act.has() && act.file.getStatus() === Status.PROGRESS ) {\n                        return act;\n                    } else if (!act.has() ||\n                            act.file.getStatus() !== Status.PROGRESS &&\n                            act.file.getStatus() !== Status.INTERRUPT ) {\n\n                        // 把已经处理完了的，或者，状态为非 progress（上传中）、\n                        // interupt（暂停中） 的移除。\n                        this.stack.splice( --i, 1 );\n                    }\n                }\n\n                return null;\n            },\n\n            _nextBlock: function() {\n                var me = this,\n                    opts = me.options,\n                    act, next, done, preparing;\n\n                // 如果当前文件还有没有需要传输的，则直接返回剩下的。\n                if ( (act = this._getStack()) ) {\n\n                    // 是否提前准备下一个文件\n                    if ( opts.prepareNextFile && !me.pending.length ) {\n                        me._prepareNextFile();\n                    }\n\n                    return act.shift();\n\n                // 否则，如果正在运行，则准备下一个文件，并等待完成后返回下个分片。\n                } else if ( me.runing ) {\n\n                    // 如果缓存中有，则直接在缓存中取，没有则去queue中取。\n                    if ( !me.pending.length && me._getStats().numOfQueue ) {\n                        me._prepareNextFile();\n                    }\n\n                    next = me.pending.shift();\n                    done = function( file ) {\n                        if ( !file ) {\n                            return null;\n                        }\n\n                        act = CuteFile( file, opts.chunked ? opts.chunkSize : 0 );\n                        me.stack.push(act);\n                        return act.shift();\n                    };\n\n                    // 文件可能还在prepare中，也有可能已经完全准备好了。\n                    if ( isPromise( next) ) {\n                        preparing = next.file;\n                        next = next[ next.pipe ? 'pipe' : 'then' ]( done );\n                        next.file = preparing;\n                        return next;\n                    }\n\n                    return done( next );\n                }\n            },\n\n\n            /**\n             * @event uploadStart\n             * @param {File} file File对象\n             * @description 某个文件开始上传前触发，一个文件只会触发一次。\n             * @for  Uploader\n             */\n            _prepareNextFile: function() {\n                var me = this,\n                    file = me.request('fetch-file'),\n                    pending = me.pending,\n                    promise;\n\n                if ( file ) {\n                    promise = me.request( 'before-send-file', file, function() {\n\n                        // 有可能文件被skip掉了。文件被skip掉后，状态坑定不是Queued.\n                        if ( file.getStatus() === Status.PROGRESS ||\n                            file.getStatus() === Status.INTERRUPT ) {\n                            return file;\n                        }\n\n                        return me._finishFile( file );\n                    });\n\n                    me.owner.trigger( 'uploadStart', file );\n                    file.setStatus( Status.PROGRESS );\n\n                    promise.file = file;\n\n                    // 如果还在pending中，则替换成文件本身。\n                    promise.done(function() {\n                        var idx = $.inArray( promise, pending );\n\n                        ~idx && pending.splice( idx, 1, file );\n                    });\n\n                    // befeore-send-file的钩子就有错误发生。\n                    promise.fail(function( reason ) {\n                        file.setStatus( Status.ERROR, reason );\n                        me.owner.trigger( 'uploadError', file, reason );\n                        me.owner.trigger( 'uploadComplete', file );\n                    });\n\n                    pending.push( promise );\n                }\n            },\n\n            // 让出位置了，可以让其他分片开始上传\n            _popBlock: function( block ) {\n                var idx = $.inArray( block, this.pool );\n\n                this.pool.splice( idx, 1 );\n                block.file.remaning--;\n                this.remaning--;\n            },\n\n            // 开始上传，可以被掉过。如果promise被reject了，则表示跳过此分片。\n            _startSend: function( block ) {\n                var me = this,\n                    file = block.file,\n                    promise;\n\n                // 有可能在 before-send-file 的 promise 期间改变了文件状态。\n                // 如：暂停，取消\n                // 我们不能中断 promise, 但是可以在 promise 完后，不做上传操作。\n                if ( file.getStatus() !== Status.PROGRESS ) {\n\n                    // 如果是中断，则还需要放回去。\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        me._putback(block);\n                    }\n\n                    return;\n                }\n\n                me.pool.push( block );\n                me.remaning++;\n\n                // 如果没有分片，则直接使用原始的。\n                // 不会丢失content-type信息。\n                block.blob = block.chunks === 1 ? file.source :\n                        file.source.slice( block.start, block.end );\n\n                // hook, 每个分片发送之前可能要做些异步的事情。\n                promise = me.request( 'before-send', block, function() {\n\n                    // 有可能文件已经上传出错了，所以不需要再传输了。\n                    if ( file.getStatus() === Status.PROGRESS ) {\n                        me._doSend( block );\n                    } else {\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n\n                // 如果为fail了，则跳过此分片。\n                promise.fail(function() {\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file ).always(function() {\n                            block.percentage = 1;\n                            me._popBlock( block );\n                            me.owner.trigger( 'uploadComplete', file );\n                            Base.nextTick( me.__tick );\n                        });\n                    } else {\n                        block.percentage = 1;\n                        me.updateFileProgress( file );\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n            },\n\n\n            /**\n             * @event uploadBeforeSend\n             * @param {Object} object\n             * @param {Object} data 默认的上传参数，可以扩展此对象来控制上传参数。\n             * @param {Object} headers 可以扩展此对象来控制上传头部。\n             * @description 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadAccept\n             * @param {Object} object\n             * @param {Object} ret 服务端的返回数据，json格式，如果服务端不是json格式，从ret._raw中取数据，自行解析。\n             * @description 当某个文件上传到服务端响应后，会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为`false`, 则此文件将派送`server`类型的`uploadError`事件。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadProgress\n             * @param {File} file File对象\n             * @param {Number} percentage 上传进度\n             * @description 上传过程中触发，携带上传进度。\n             * @for  Uploader\n             */\n\n\n            /**\n             * @event uploadError\n             * @param {File} file File对象\n             * @param {String} reason 出错的code\n             * @description 当文件上传出错时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadSuccess\n             * @param {File} file File对象\n             * @param {Object} response 服务端返回的数据\n             * @description 当文件上传成功时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadComplete\n             * @param {File} [file] File对象\n             * @description 不管成功或者失败，文件上传完成时触发。\n             * @for  Uploader\n             */\n\n            // 做上传操作。\n            _doSend: function( block ) {\n                var me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    file = block.file,\n                    tr = new Transport( opts ),\n                    data = $.extend({}, opts.formData ),\n                    headers = $.extend({}, opts.headers ),\n                    requestAccept, ret;\n\n                block.transport = tr;\n\n                tr.on( 'destroy', function() {\n                    delete block.transport;\n                    me._popBlock( block );\n                    Base.nextTick( me.__tick );\n                });\n\n                // 广播上传进度。以文件为单位。\n                tr.on( 'progress', function( percentage ) {\n                    block.percentage = percentage;\n                    me.updateFileProgress( file );\n                });\n\n                // 用来询问，是否返回的结果是有错误的。\n                requestAccept = function( reject ) {\n                    var fn;\n\n                    ret = tr.getResponseAsJson() || {};\n                    ret._raw = tr.getResponse();\n                    fn = function( value ) {\n                        reject = value;\n                    };\n\n                    // 服务端响应了，不代表成功了，询问是否响应正确。\n                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {\n                        reject = reject || 'server';\n                    }\n\n                    return reject;\n                };\n\n                // 尝试重试，然后广播文件上传出错。\n                tr.on( 'error', function( type, flag ) {\n                    block.retried = block.retried || 0;\n\n                    // 自动重试\n                    if ( block.chunks > 1 && ~'http,abort'.indexOf( type ) &&\n                            block.retried < opts.chunkRetry ) {\n\n                        block.retried++;\n                        tr.send();\n\n                    } else {\n\n                        // http status 500 ~ 600\n                        if ( !flag && type === 'server' ) {\n                            type = requestAccept( type );\n                        }\n\n                        file.setStatus( Status.ERROR, type );\n                        owner.trigger( 'uploadError', file, type );\n                        owner.trigger( 'uploadComplete', file );\n                    }\n                });\n\n                // 上传成功\n                tr.on( 'load', function() {\n                    var reason;\n\n                    // 如果非预期，转向上传出错。\n                    if ( (reason = requestAccept()) ) {\n                        tr.trigger( 'error', reason, true );\n                        return;\n                    }\n\n                    // 全部上传完成。\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file, ret );\n                    } else {\n                        tr.destroy();\n                    }\n                });\n\n                // 配置默认的上传字段。\n                data = $.extend( data, {\n                    id: file.id,\n                    name: file.name,\n                    type: file.type,\n                    lastModifiedDate: file.lastModifiedDate,\n                    size: file.size\n                });\n\n                block.chunks > 1 && $.extend( data, {\n                    chunks: block.chunks,\n                    chunk: block.chunk\n                });\n\n                // 在发送之间可以添加字段什么的。。。\n                // 如果默认的字段不够使用，可以通过监听此事件来扩展\n                owner.trigger( 'uploadBeforeSend', block, data, headers );\n\n                // 开始发送。\n                tr.appendBlob( opts.fileVal, block.blob, file.name );\n                tr.append( data );\n                tr.setRequestHeader( headers );\n                tr.send();\n            },\n\n            // 完成上传。\n            _finishFile: function( file, ret, hds ) {\n                var owner = this.owner;\n\n                return owner\n                        .request( 'after-send-file', arguments, function() {\n                            file.setStatus( Status.COMPLETE );\n                            owner.trigger( 'uploadSuccess', file, ret, hds );\n                        })\n                        .fail(function( reason ) {\n\n                            // 如果外部已经标记为invalid什么的，不再改状态。\n                            if ( file.getStatus() === Status.PROGRESS ) {\n                                file.setStatus( Status.ERROR, reason );\n                            }\n\n                            owner.trigger( 'uploadError', file, reason );\n                        })\n                        .always(function() {\n                            owner.trigger( 'uploadComplete', file );\n                        });\n            },\n\n            updateFileProgress: function(file) {\n                var totalPercent = 0,\n                    uploaded = 0;\n\n                if (!file.blocks) {\n                    return;\n                }\n\n                $.each( file.blocks, function( _, v ) {\n                    uploaded += (v.percentage || 0) * (v.end - v.start);\n                });\n\n                totalPercent = uploaded / file.size;\n                this.owner.trigger( 'uploadProgress', file, totalPercent || 0 );\n            }\n\n        });\n    });\n    /**\n     * @fileOverview 各种验证，包括文件总大小是否超出、单文件是否超出和文件是否重复。\n     */\n\n    define('widgets/validator',[\n        'base',\n        'uploader',\n        'file',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile ) {\n\n        var $ = Base.$,\n            validators = {},\n            api;\n\n        /**\n         * @event error\n         * @param {String} type 错误类型。\n         * @description 当validate不通过时，会以派送错误事件的形式通知调用者。通过`upload.on('error', handler)`可以捕获到此类错误，目前有以下错误会在特定的情况下派送错来。\n         *\n         * * `Q_EXCEED_NUM_LIMIT` 在设置了`fileNumLimit`且尝试给`uploader`添加的文件数量超出这个值时派送。\n         * * `Q_EXCEED_SIZE_LIMIT` 在设置了`Q_EXCEED_SIZE_LIMIT`且尝试给`uploader`添加的文件总大小超出这个值时派送。\n         * * `Q_TYPE_DENIED` 当文件类型不满足时触发。。\n         * @for  Uploader\n         */\n\n        // 暴露给外面的api\n        api = {\n\n            // 添加验证器\n            addValidator: function( type, cb ) {\n                validators[ type ] = cb;\n            },\n\n            // 移除验证器\n            removeValidator: function( type ) {\n                delete validators[ type ];\n            }\n        };\n\n        // 在Uploader初始化的时候启动Validators的初始化\n        Uploader.register({\n            name: 'validator',\n\n            init: function() {\n                var me = this;\n                Base.nextTick(function() {\n                    $.each( validators, function() {\n                        this.call( me.owner );\n                    });\n                });\n            }\n        });\n\n        /**\n         * @property {int} [fileNumLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总数量, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileNumLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileNumLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( count >= max && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_NUM_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return count >= max ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function() {\n                count++;\n            });\n\n            uploader.on( 'fileDequeued', function() {\n                count--;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n\n        /**\n         * @property {int} [fileSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileSizeLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var invalid = count + file.size > max;\n\n                if ( invalid && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_SIZE_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return invalid ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                count += file.size;\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                count -= file.size;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n        /**\n         * @property {int} [fileSingleSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证单个文件大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSingleSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                max = opts.fileSingleSizeLimit;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( file.size > max ) {\n                    file.setStatus( WUFile.Status.INVALID, 'exceed_size' );\n                    this.trigger( 'error', 'F_EXCEED_SIZE', max, file );\n                    return false;\n                }\n\n            });\n\n        });\n\n        /**\n         * @property {Boolean} [duplicate=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 去重， 根据文件名字、文件大小和最后修改时间来生成hash Key.\n         */\n        api.addValidator( 'duplicate', function() {\n            var uploader = this,\n                opts = uploader.options,\n                mapping = {};\n\n            if ( opts.duplicate ) {\n                return;\n            }\n\n            function hashString( str ) {\n                var hash = 0,\n                    i = 0,\n                    len = str.length,\n                    _char;\n\n                for ( ; i < len; i++ ) {\n                    _char = str.charCodeAt( i );\n                    hash = _char + (hash << 6) + (hash << 16) - hash;\n                }\n\n                return hash;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var hash = file.__hash || (file.__hash = hashString( file.name +\n                        file.size + file.lastModifiedDate ));\n\n                // 已经重复了\n                if ( mapping[ hash ] ) {\n                    this.trigger( 'error', 'F_DUPLICATE', file );\n                    return false;\n                }\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (mapping[ hash ] = true);\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (delete mapping[ hash ]);\n            });\n\n            uploader.on( 'reset', function() {\n                mapping = {};\n            });\n        });\n\n        return api;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/compbase',[],function() {\n\n        function CompBase( owner, runtime ) {\n\n            this.owner = owner;\n            this.options = owner.options;\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.getRuid = function() {\n                return runtime.uid;\n            };\n\n            this.trigger = function() {\n                return owner.trigger.apply( owner, arguments );\n            };\n        }\n\n        return CompBase;\n    });\n    /**\n     * @fileOverview FlashRuntime\n     */\n    define('runtime/flash/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var $ = Base.$,\n            type = 'flash',\n            components = {};\n\n\n        function getFlashVersion() {\n            var version;\n\n            try {\n                version = navigator.plugins[ 'Shockwave Flash' ];\n                version = version.description;\n            } catch ( ex ) {\n                try {\n                    version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')\n                            .GetVariable('$version');\n                } catch ( ex2 ) {\n                    version = '0.0';\n                }\n            }\n            version = version.match( /\\d+/g );\n            return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 );\n        }\n\n        function FlashRuntime() {\n            var pool = {},\n                clients = {},\n                destroy = this.destroy,\n                me = this,\n                jsreciver = Base.guid('webuploader_');\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/ ) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                clients[ uid ] = client;\n\n                if ( components[ comp ] ) {\n                    if ( !pool[ uid ] ) {\n                        pool[ uid ] = new components[ comp ]( client, me );\n                    }\n\n                    instance = pool[ uid ];\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n\n                return me.flashExec.apply( client, arguments );\n            };\n\n            function handler( evt, obj ) {\n                var type = evt.type || evt,\n                    parts, uid;\n\n                parts = type.split('::');\n                uid = parts[ 0 ];\n                type = parts[ 1 ];\n\n                // console.log.apply( console, arguments );\n\n                if ( type === 'Ready' && uid === me.uid ) {\n                    me.trigger('ready');\n                } else if ( clients[ uid ] ) {\n                    clients[ uid ].trigger( type.toLowerCase(), evt, obj );\n                }\n\n                // Base.log( evt, obj );\n            }\n\n            // flash的接受器。\n            window[ jsreciver ] = function() {\n                var args = arguments;\n\n                // 为了能捕获得到。\n                setTimeout(function() {\n                    handler.apply( null, args );\n                }, 1 );\n            };\n\n            this.jsreciver = jsreciver;\n\n            this.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n\n            this.flashExec = function( comp, fn ) {\n                var flash = me.getFlash(),\n                    args = Base.slice( arguments, 2 );\n\n                return flash.exec( this.uid, comp, fn, args );\n            };\n\n            // @todo\n        }\n\n        Base.inherits( Runtime, {\n            constructor: FlashRuntime,\n\n            init: function() {\n                var container = this.getContainer(),\n                    opts = this.options,\n                    html;\n\n                // if not the minimal height, shims are not initialized\n                // in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)\n                container.css({\n                    position: 'absolute',\n                    top: '-8px',\n                    left: '-8px',\n                    width: '9px',\n                    height: '9px',\n                    overflow: 'hidden'\n                });\n\n                // insert flash object\n                html = '<object id=\"' + this.uid + '\" type=\"application/' +\n                        'x-shockwave-flash\" data=\"' +  opts.swf + '\" ';\n\n                if ( Base.browser.ie ) {\n                    html += 'classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" ';\n                }\n\n                html += 'width=\"100%\" height=\"100%\" style=\"outline:0\">'  +\n                    '<param name=\"movie\" value=\"' + opts.swf + '\" />' +\n                    '<param name=\"flashvars\" value=\"uid=' + this.uid +\n                    '&jsreciver=' + this.jsreciver + '\" />' +\n                    '<param name=\"wmode\" value=\"transparent\" />' +\n                    '<param name=\"allowscriptaccess\" value=\"always\" />' +\n                '</object>';\n\n                container.html( html );\n            },\n\n            getFlash: function() {\n                if ( this._flash ) {\n                    return this._flash;\n                }\n\n                this._flash = $( '#' + this.uid ).get( 0 );\n                return this._flash;\n            }\n\n        });\n\n        FlashRuntime.register = function( name, component ) {\n            component = components[ name ] = Base.inherits( CompBase, $.extend({\n\n                // @todo fix this later\n                flashExec: function() {\n                    var owner = this.owner,\n                        runtime = this.getRuntime();\n\n                    return runtime.flashExec.apply( owner, arguments );\n                }\n            }, component ) );\n\n            return component;\n        };\n\n        if ( getFlashVersion() >= 11.4 ) {\n            Runtime.addRuntime( type, FlashRuntime );\n        }\n\n        return FlashRuntime;\n    });\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/flash/filepicker',[\n        'base',\n        'runtime/flash/runtime'\n    ], function( Base, FlashRuntime ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'FilePicker', {\n            init: function( opts ) {\n                var copy = $.extend({}, opts ),\n                    len, i;\n\n                // 修复Flash再没有设置title的情况下无法弹出flash文件选择框的bug.\n                len = copy.accept && copy.accept.length;\n                for (  i = 0; i < len; i++ ) {\n                    if ( !copy.accept[ i ].title ) {\n                        copy.accept[ i ].title = 'Files';\n                    }\n                }\n\n                delete copy.button;\n                delete copy.id;\n                delete copy.container;\n\n                this.flashExec( 'FilePicker', 'init', copy );\n            },\n\n            destroy: function() {\n                this.flashExec( 'FilePicker', 'destroy' );\n            }\n        });\n    });\n    /**\n     * @fileOverview 图片压缩\n     */\n    define('runtime/flash/image',[\n        'runtime/flash/runtime'\n    ], function( FlashRuntime ) {\n\n        return FlashRuntime.register( 'Image', {\n            // init: function( options ) {\n            //     var owner = this.owner;\n\n            //     this.flashExec( 'Image', 'init', options );\n            //     owner.on( 'load', function() {\n            //         debugger;\n            //     });\n            // },\n\n            loadFromBlob: function( blob ) {\n                var owner = this.owner;\n\n                owner.info() && this.flashExec( 'Image', 'info', owner.info() );\n                owner.meta() && this.flashExec( 'Image', 'meta', owner.meta() );\n\n                this.flashExec( 'Image', 'loadFromBlob', blob.uid );\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/flash/blob',[\n        'runtime/flash/runtime',\n        'lib/blob'\n    ], function( FlashRuntime, Blob ) {\n\n        return FlashRuntime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.flashExec( 'Blob', 'slice', start, end );\n\n                return new Blob( blob.uid, blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/flash/transport',[\n        'base',\n        'runtime/flash/runtime',\n        'runtime/client'\n    ], function( Base, FlashRuntime, RuntimeClient ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n                this._responseJson = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    binary;\n\n                xhr.connectRuntime( blob.ruid );\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.uid;\n                } else {\n                    $.each( owner._formData, function( k, v ) {\n                        xhr.exec( 'append', k, v );\n                    });\n\n                    xhr.exec( 'appendBlob', opts.fileVal, blob.uid,\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n                xhr.exec( 'send', {\n                    method: opts.method,\n                    url: server,\n                    forceURLStream: opts.forceURLStream,\n                    mimeType: 'application/octet-stream'\n                }, binary );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            getResponse: function() {\n                return this._response || '';\n            },\n\n            getResponseAsJson: function() {\n                return this._responseJson;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.exec('abort');\n                    xhr.destroy();\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new RuntimeClient('XMLHttpRequest');\n\n                xhr.on( 'uploadprogress progress', function( e ) {\n                    var percent = e.loaded / e.total;\n                    percent = Math.min( 1, Math.max( 0, percent ) );\n                    return me.trigger( 'progress', percent );\n                });\n\n                xhr.on( 'load', function() {\n                    var status = xhr.exec('getStatus'),\n                        readBody = false,\n                        err = '',\n                        p;\n\n                    xhr.off();\n                    me._xhr = null;\n\n                    if ( status >= 200 && status < 300 ) {\n                        readBody = true;\n                    } else if ( status >= 500 && status < 600 ) {\n                        readBody = true;\n                        err = 'server';\n                    } else {\n                        err = 'http';\n                    }\n\n                    if ( readBody ) {\n                        me._response = xhr.exec('getResponse');\n                        me._response = decodeURIComponent( me._response );\n\n                        // flash 处理可能存在 bug, 没辙只能靠 js 了\n                        // try {\n                        //     me._responseJson = xhr.exec('getResponseAsJson');\n                        // } catch ( error ) {\n\n                        p = window.JSON && window.JSON.parse || function( s ) {\n                            try {\n                                return new Function('return ' + s).call();\n                            } catch ( err ) {\n                                return {};\n                            }\n                        };\n                        me._responseJson  = me._response ? p(me._response) : {};\n\n                        // }\n                    }\n\n                    xhr.destroy();\n                    xhr = null;\n\n                    return err ? me.trigger( 'error', err ) : me.trigger('load');\n                });\n\n                xhr.on( 'error', function() {\n                    xhr.off();\n                    me._xhr = null;\n                    me.trigger( 'error', 'http' );\n                });\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.exec( 'setRequestHeader', key, val );\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview 只有flash实现的文件版本。\n     */\n    define('preset/flashonly',[\n        'base',\n\n        // widgets\n        'widgets/filepicker',\n        'widgets/image',\n        'widgets/queue',\n        'widgets/runtime',\n        'widgets/upload',\n        'widgets/validator',\n\n        // runtimes\n\n        // flash\n        'runtime/flash/filepicker',\n        'runtime/flash/image',\n        'runtime/flash/blob',\n        'runtime/flash/transport'\n    ], function( Base ) {\n        return Base;\n    });\n    define('webuploader',[\n        'preset/flashonly'\n    ], function( preset ) {\n        return preset;\n    });\n    return require('webuploader');\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.html5only.js",
    "content": "/*! WebUploader 0.1.5 */\n\n\n/**\n * @fileOverview 让内部各个部件的代码可以用[amd](https://github.com/amdjs/amdjs-api/wiki/AMD)模块定义方式组织起来。\n *\n * AMD API 内部的简单不完全实现，请忽略。只有当WebUploader被合并成一个文件的时候才会引入。\n */\n(function( root, factory ) {\n    var modules = {},\n\n        // 内部require, 简单不完全实现。\n        // https://github.com/amdjs/amdjs-api/wiki/require\n        _require = function( deps, callback ) {\n            var args, len, i;\n\n            // 如果deps不是数组，则直接返回指定module\n            if ( typeof deps === 'string' ) {\n                return getModule( deps );\n            } else {\n                args = [];\n                for( len = deps.length, i = 0; i < len; i++ ) {\n                    args.push( getModule( deps[ i ] ) );\n                }\n\n                return callback.apply( null, args );\n            }\n        },\n\n        // 内部define，暂时不支持不指定id.\n        _define = function( id, deps, factory ) {\n            if ( arguments.length === 2 ) {\n                factory = deps;\n                deps = null;\n            }\n\n            _require( deps || [], function() {\n                setModule( id, factory, arguments );\n            });\n        },\n\n        // 设置module, 兼容CommonJs写法。\n        setModule = function( id, factory, args ) {\n            var module = {\n                    exports: factory\n                },\n                returned;\n\n            if ( typeof factory === 'function' ) {\n                args.length || (args = [ _require, module.exports, module ]);\n                returned = factory.apply( null, args );\n                returned !== undefined && (module.exports = returned);\n            }\n\n            modules[ id ] = module.exports;\n        },\n\n        // 根据id获取module\n        getModule = function( id ) {\n            var module = modules[ id ] || root[ id ];\n\n            if ( !module ) {\n                throw new Error( '`' + id + '` is undefined' );\n            }\n\n            return module;\n        },\n\n        // 将所有modules，将路径ids装换成对象。\n        exportsTo = function( obj ) {\n            var key, host, parts, part, last, ucFirst;\n\n            // make the first character upper case.\n            ucFirst = function( str ) {\n                return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 ));\n            };\n\n            for ( key in modules ) {\n                host = obj;\n\n                if ( !modules.hasOwnProperty( key ) ) {\n                    continue;\n                }\n\n                parts = key.split('/');\n                last = ucFirst( parts.pop() );\n\n                while( (part = ucFirst( parts.shift() )) ) {\n                    host[ part ] = host[ part ] || {};\n                    host = host[ part ];\n                }\n\n                host[ last ] = modules[ key ];\n            }\n\n            return obj;\n        },\n\n        makeExport = function( dollar ) {\n            root.__dollar = dollar;\n\n            // exports every module.\n            return exportsTo( factory( root, _define, _require ) );\n        },\n\n        origin;\n\n    if ( typeof module === 'object' && typeof module.exports === 'object' ) {\n\n        // For CommonJS and CommonJS-like environments where a proper window is present,\n        module.exports = makeExport();\n    } else if ( typeof define === 'function' && define.amd ) {\n\n        // Allow using this built library as an AMD module\n        // in another project. That other project will only\n        // see this AMD call, not the internal modules in\n        // the closure below.\n        define([ 'jquery' ], makeExport );\n    } else {\n\n        // Browser globals case. Just assign the\n        // result to a property on the global.\n        origin = root.WebUploader;\n        root.WebUploader = makeExport();\n        root.WebUploader.noConflict = function() {\n            root.WebUploader = origin;\n        };\n    }\n})( window, function( window, define, require ) {\n\n\n    /**\n     * @fileOverview jQuery or Zepto\n     */\n    define('dollar-third',[],function() {\n        var $ = window.__dollar || window.jQuery || window.Zepto;\n\n        if ( !$ ) {\n            throw new Error('jQuery or Zepto not found!');\n        }\n\n        return $;\n    });\n    /**\n     * @fileOverview Dom 操作相关\n     */\n    define('dollar',[\n        'dollar-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 使用jQuery的Promise\n     */\n    define('promise-third',[\n        'dollar'\n    ], function( $ ) {\n        return {\n            Deferred: $.Deferred,\n            when: $.when,\n\n            isPromise: function( anything ) {\n                return anything && typeof anything.then === 'function';\n            }\n        };\n    });\n    /**\n     * @fileOverview Promise/A+\n     */\n    define('promise',[\n        'promise-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 基础类方法。\n     */\n\n    /**\n     * Web Uploader内部类的详细说明，以下提及的功能类，都可以在`WebUploader`这个变量中访问到。\n     *\n     * As you know, Web Uploader的每个文件都是用过[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)规范中的`define`组织起来的, 每个Module都会有个module id.\n     * 默认module id为该文件的路径，而此路径将会转化成名字空间存放在WebUploader中。如：\n     *\n     * * module `base`：WebUploader.Base\n     * * module `file`: WebUploader.File\n     * * module `lib/dnd`: WebUploader.Lib.Dnd\n     * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd\n     *\n     *\n     * 以下文档中对类的使用可能省略掉了`WebUploader`前缀。\n     * @module WebUploader\n     * @title WebUploader API文档\n     */\n    define('base',[\n        'dollar',\n        'promise'\n    ], function( $, promise ) {\n\n        var noop = function() {},\n            call = Function.call;\n\n        // http://jsperf.com/uncurrythis\n        // 反科里化\n        function uncurryThis( fn ) {\n            return function() {\n                return call.apply( fn, arguments );\n            };\n        }\n\n        function bindFn( fn, context ) {\n            return function() {\n                return fn.apply( context, arguments );\n            };\n        }\n\n        function createObject( proto ) {\n            var f;\n\n            if ( Object.create ) {\n                return Object.create( proto );\n            } else {\n                f = function() {};\n                f.prototype = proto;\n                return new f();\n            }\n        }\n\n\n        /**\n         * 基础类，提供一些简单常用的方法。\n         * @class Base\n         */\n        return {\n\n            /**\n             * @property {String} version 当前版本号。\n             */\n            version: '0.1.5',\n\n            /**\n             * @property {jQuery|Zepto} $ 引用依赖的jQuery或者Zepto对象。\n             */\n            $: $,\n\n            Deferred: promise.Deferred,\n\n            isPromise: promise.isPromise,\n\n            when: promise.when,\n\n            /**\n             * @description  简单的浏览器检查结果。\n             *\n             * * `webkit`  webkit版本号，如果浏览器为非webkit内核，此属性为`undefined`。\n             * * `chrome`  chrome浏览器版本号，如果浏览器为chrome，此属性为`undefined`。\n             * * `ie`  ie浏览器版本号，如果浏览器为非ie，此属性为`undefined`。**暂不支持ie10+**\n             * * `firefox`  firefox浏览器版本号，如果浏览器为非firefox，此属性为`undefined`。\n             * * `safari`  safari浏览器版本号，如果浏览器为非safari，此属性为`undefined`。\n             * * `opera`  opera浏览器版本号，如果浏览器为非opera，此属性为`undefined`。\n             *\n             * @property {Object} [browser]\n             */\n            browser: (function( ua ) {\n                var ret = {},\n                    webkit = ua.match( /WebKit\\/([\\d.]+)/ ),\n                    chrome = ua.match( /Chrome\\/([\\d.]+)/ ) ||\n                        ua.match( /CriOS\\/([\\d.]+)/ ),\n\n                    ie = ua.match( /MSIE\\s([\\d\\.]+)/ ) ||\n                        ua.match( /(?:trident)(?:.*rv:([\\w.]+))?/i ),\n                    firefox = ua.match( /Firefox\\/([\\d.]+)/ ),\n                    safari = ua.match( /Safari\\/([\\d.]+)/ ),\n                    opera = ua.match( /OPR\\/([\\d.]+)/ );\n\n                webkit && (ret.webkit = parseFloat( webkit[ 1 ] ));\n                chrome && (ret.chrome = parseFloat( chrome[ 1 ] ));\n                ie && (ret.ie = parseFloat( ie[ 1 ] ));\n                firefox && (ret.firefox = parseFloat( firefox[ 1 ] ));\n                safari && (ret.safari = parseFloat( safari[ 1 ] ));\n                opera && (ret.opera = parseFloat( opera[ 1 ] ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * @description  操作系统检查结果。\n             *\n             * * `android`  如果在android浏览器环境下，此值为对应的android版本号，否则为`undefined`。\n             * * `ios` 如果在ios浏览器环境下，此值为对应的ios版本号，否则为`undefined`。\n             * @property {Object} [os]\n             */\n            os: (function( ua ) {\n                var ret = {},\n\n                    // osx = !!ua.match( /\\(Macintosh\\; Intel / ),\n                    android = ua.match( /(?:Android);?[\\s\\/]+([\\d.]+)?/ ),\n                    ios = ua.match( /(?:iPad|iPod|iPhone).*OS\\s([\\d_]+)/ );\n\n                // osx && (ret.osx = true);\n                android && (ret.android = parseFloat( android[ 1 ] ));\n                ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * 实现类与类之间的继承。\n             * @method inherits\n             * @grammar Base.inherits( super ) => child\n             * @grammar Base.inherits( super, protos ) => child\n             * @grammar Base.inherits( super, protos, statics ) => child\n             * @param  {Class} super 父类\n             * @param  {Object | Function} [protos] 子类或者对象。如果对象中包含constructor，子类将是用此属性值。\n             * @param  {Function} [protos.constructor] 子类构造器，不指定的话将创建个临时的直接执行父类构造器的方法。\n             * @param  {Object} [statics] 静态属性或方法。\n             * @return {Class} 返回子类。\n             * @example\n             * function Person() {\n             *     console.log( 'Super' );\n             * }\n             * Person.prototype.hello = function() {\n             *     console.log( 'hello' );\n             * };\n             *\n             * var Manager = Base.inherits( Person, {\n             *     world: function() {\n             *         console.log( 'World' );\n             *     }\n             * });\n             *\n             * // 因为没有指定构造器，父类的构造器将会执行。\n             * var instance = new Manager();    // => Super\n             *\n             * // 继承子父类的方法\n             * instance.hello();    // => hello\n             * instance.world();    // => World\n             *\n             * // 子类的__super__属性指向父类\n             * console.log( Manager.__super__ === Person );    // => true\n             */\n            inherits: function( Super, protos, staticProtos ) {\n                var child;\n\n                if ( typeof protos === 'function' ) {\n                    child = protos;\n                    protos = null;\n                } else if ( protos && protos.hasOwnProperty('constructor') ) {\n                    child = protos.constructor;\n                } else {\n                    child = function() {\n                        return Super.apply( this, arguments );\n                    };\n                }\n\n                // 复制静态方法\n                $.extend( true, child, Super, staticProtos || {} );\n\n                /* jshint camelcase: false */\n\n                // 让子类的__super__属性指向父类。\n                child.__super__ = Super.prototype;\n\n                // 构建原型，添加原型方法或属性。\n                // 暂时用Object.create实现。\n                child.prototype = createObject( Super.prototype );\n                protos && $.extend( true, child.prototype, protos );\n\n                return child;\n            },\n\n            /**\n             * 一个不做任何事情的方法。可以用来赋值给默认的callback.\n             * @method noop\n             */\n            noop: noop,\n\n            /**\n             * 返回一个新的方法，此方法将已指定的`context`来执行。\n             * @grammar Base.bindFn( fn, context ) => Function\n             * @method bindFn\n             * @example\n             * var doSomething = function() {\n             *         console.log( this.name );\n             *     },\n             *     obj = {\n             *         name: 'Object Name'\n             *     },\n             *     aliasFn = Base.bind( doSomething, obj );\n             *\n             *  aliasFn();    // => Object Name\n             *\n             */\n            bindFn: bindFn,\n\n            /**\n             * 引用Console.log如果存在的话，否则引用一个[空函数noop](#WebUploader:Base.noop)。\n             * @grammar Base.log( args... ) => undefined\n             * @method log\n             */\n            log: (function() {\n                if ( window.console ) {\n                    return bindFn( console.log, console );\n                }\n                return noop;\n            })(),\n\n            nextTick: (function() {\n\n                return function( cb ) {\n                    setTimeout( cb, 1 );\n                };\n\n                // @bug 当浏览器不在当前窗口时就停了。\n                // var next = window.requestAnimationFrame ||\n                //     window.webkitRequestAnimationFrame ||\n                //     window.mozRequestAnimationFrame ||\n                //     function( cb ) {\n                //         window.setTimeout( cb, 1000 / 60 );\n                //     };\n\n                // // fix: Uncaught TypeError: Illegal invocation\n                // return bindFn( next, window );\n            })(),\n\n            /**\n             * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的数组slice方法。\n             * 将用来将非数组对象转化成数组对象。\n             * @grammar Base.slice( target, start[, end] ) => Array\n             * @method slice\n             * @example\n             * function doSomthing() {\n             *     var args = Base.slice( arguments, 1 );\n             *     console.log( args );\n             * }\n             *\n             * doSomthing( 'ignored', 'arg2', 'arg3' );    // => Array [\"arg2\", \"arg3\"]\n             */\n            slice: uncurryThis( [].slice ),\n\n            /**\n             * 生成唯一的ID\n             * @method guid\n             * @grammar Base.guid() => String\n             * @grammar Base.guid( prefx ) => String\n             */\n            guid: (function() {\n                var counter = 0;\n\n                return function( prefix ) {\n                    var guid = (+new Date()).toString( 32 ),\n                        i = 0;\n\n                    for ( ; i < 5; i++ ) {\n                        guid += Math.floor( Math.random() * 65535 ).toString( 32 );\n                    }\n\n                    return (prefix || 'wu_') + guid + (counter++).toString( 32 );\n                };\n            })(),\n\n            /**\n             * 格式化文件大小, 输出成带单位的字符串\n             * @method formatSize\n             * @grammar Base.formatSize( size ) => String\n             * @grammar Base.formatSize( size, pointLength ) => String\n             * @grammar Base.formatSize( size, pointLength, units ) => String\n             * @param {Number} size 文件大小\n             * @param {Number} [pointLength=2] 精确到的小数点数。\n             * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 单位数组。从字节，到千字节，一直往上指定。如果单位数组里面只指定了到了K(千字节)，同时文件大小大于M, 此方法的输出将还是显示成多少K.\n             * @example\n             * console.log( Base.formatSize( 100 ) );    // => 100B\n             * console.log( Base.formatSize( 1024 ) );    // => 1.00K\n             * console.log( Base.formatSize( 1024, 0 ) );    // => 1K\n             * console.log( Base.formatSize( 1024 * 1024 ) );    // => 1.00M\n             * console.log( Base.formatSize( 1024 * 1024 * 1024 ) );    // => 1.00G\n             * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) );    // => 1024MB\n             */\n            formatSize: function( size, pointLength, units ) {\n                var unit;\n\n                units = units || [ 'B', 'K', 'M', 'G', 'TB' ];\n\n                while ( (unit = units.shift()) && size > 1024 ) {\n                    size = size / 1024;\n                }\n\n                return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) +\n                        unit;\n            }\n        };\n    });\n    /**\n     * 事件处理类，可以独立使用，也可以扩展给对象使用。\n     * @fileOverview Mediator\n     */\n    define('mediator',[\n        'base'\n    ], function( Base ) {\n        var $ = Base.$,\n            slice = [].slice,\n            separator = /\\s+/,\n            protos;\n\n        // 根据条件过滤出事件handlers.\n        function findHandlers( arr, name, callback, context ) {\n            return $.grep( arr, function( handler ) {\n                return handler &&\n                        (!name || handler.e === name) &&\n                        (!callback || handler.cb === callback ||\n                        handler.cb._cb === callback) &&\n                        (!context || handler.ctx === context);\n            });\n        }\n\n        function eachEvent( events, callback, iterator ) {\n            // 不支持对象，只支持多个event用空格隔开\n            $.each( (events || '').split( separator ), function( _, key ) {\n                iterator( key, callback );\n            });\n        }\n\n        function triggerHanders( events, args ) {\n            var stoped = false,\n                i = -1,\n                len = events.length,\n                handler;\n\n            while ( ++i < len ) {\n                handler = events[ i ];\n\n                if ( handler.cb.apply( handler.ctx2, args ) === false ) {\n                    stoped = true;\n                    break;\n                }\n            }\n\n            return !stoped;\n        }\n\n        protos = {\n\n            /**\n             * 绑定事件。\n             *\n             * `callback`方法在执行时，arguments将会来源于trigger的时候携带的参数。如\n             * ```javascript\n             * var obj = {};\n             *\n             * // 使得obj有事件行为\n             * Mediator.installTo( obj );\n             *\n             * obj.on( 'testa', function( arg1, arg2 ) {\n             *     console.log( arg1, arg2 ); // => 'arg1', 'arg2'\n             * });\n             *\n             * obj.trigger( 'testa', 'arg1', 'arg2' );\n             * ```\n             *\n             * 如果`callback`中，某一个方法`return false`了，则后续的其他`callback`都不会被执行到。\n             * 切会影响到`trigger`方法的返回值，为`false`。\n             *\n             * `on`还可以用来添加一个特殊事件`all`, 这样所有的事件触发都会响应到。同时此类`callback`中的arguments有一个不同处，\n             * 就是第一个参数为`type`，记录当前是什么事件在触发。此类`callback`的优先级比脚低，会再正常`callback`执行完后触发。\n             * ```javascript\n             * obj.on( 'all', function( type, arg1, arg2 ) {\n             *     console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2'\n             * });\n             * ```\n             *\n             * @method on\n             * @grammar on( name, callback[, context] ) => self\n             * @param  {String}   name     事件名，支持多个事件用空格隔开\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             * @class Mediator\n             */\n            on: function( name, callback, context ) {\n                var me = this,\n                    set;\n\n                if ( !callback ) {\n                    return this;\n                }\n\n                set = this._events || (this._events = []);\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var handler = { e: name };\n\n                    handler.cb = callback;\n                    handler.ctx = context;\n                    handler.ctx2 = context || me;\n                    handler.id = set.length;\n\n                    set.push( handler );\n                });\n\n                return this;\n            },\n\n            /**\n             * 绑定事件，且当handler执行完后，自动解除绑定。\n             * @method once\n             * @grammar once( name, callback[, context] ) => self\n             * @param  {String}   name     事件名\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            once: function( name, callback, context ) {\n                var me = this;\n\n                if ( !callback ) {\n                    return me;\n                }\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var once = function() {\n                            me.off( name, once );\n                            return callback.apply( context || me, arguments );\n                        };\n\n                    once._cb = callback;\n                    me.on( name, once, context );\n                });\n\n                return me;\n            },\n\n            /**\n             * 解除事件绑定\n             * @method off\n             * @grammar off( [name[, callback[, context] ] ] ) => self\n             * @param  {String}   [name]     事件名\n             * @param  {Function} [callback] 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            off: function( name, cb, ctx ) {\n                var events = this._events;\n\n                if ( !events ) {\n                    return this;\n                }\n\n                if ( !name && !cb && !ctx ) {\n                    this._events = [];\n                    return this;\n                }\n\n                eachEvent( name, cb, function( name, cb ) {\n                    $.each( findHandlers( events, name, cb, ctx ), function() {\n                        delete events[ this.id ];\n                    });\n                });\n\n                return this;\n            },\n\n            /**\n             * 触发事件\n             * @method trigger\n             * @grammar trigger( name[, args...] ) => self\n             * @param  {String}   type     事件名\n             * @param  {*} [...] 任意参数\n             * @return {Boolean} 如果handler中return false了，则返回false, 否则返回true\n             */\n            trigger: function( type ) {\n                var args, events, allEvents;\n\n                if ( !this._events || !type ) {\n                    return this;\n                }\n\n                args = slice.call( arguments, 1 );\n                events = findHandlers( this._events, type );\n                allEvents = findHandlers( this._events, 'all' );\n\n                return triggerHanders( events, args ) &&\n                        triggerHanders( allEvents, arguments );\n            }\n        };\n\n        /**\n         * 中介者，它本身是个单例，但可以通过[installTo](#WebUploader:Mediator:installTo)方法，使任何对象具备事件行为。\n         * 主要目的是负责模块与模块之间的合作，降低耦合度。\n         *\n         * @class Mediator\n         */\n        return $.extend({\n\n            /**\n             * 可以通过这个接口，使任何对象具备事件功能。\n             * @method installTo\n             * @param  {Object} obj 需要具备事件行为的对象。\n             * @return {Object} 返回obj.\n             */\n            installTo: function( obj ) {\n                return $.extend( obj, protos );\n            }\n\n        }, protos );\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('uploader',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$;\n\n        /**\n         * 上传入口类。\n         * @class Uploader\n         * @constructor\n         * @grammar new Uploader( opts ) => Uploader\n         * @example\n         * var uploader = WebUploader.Uploader({\n         *     swf: 'path_of_swf/Uploader.swf',\n         *\n         *     // 开起分片上传。\n         *     chunked: true\n         * });\n         */\n        function Uploader( opts ) {\n            this.options = $.extend( true, {}, Uploader.options, opts );\n            this._init( this.options );\n        }\n\n        // default Options\n        // widgets中有相应扩展\n        Uploader.options = {};\n        Mediator.installTo( Uploader.prototype );\n\n        // 批量添加纯命令式方法。\n        $.each({\n            upload: 'start-upload',\n            stop: 'stop-upload',\n            getFile: 'get-file',\n            getFiles: 'get-files',\n            addFile: 'add-file',\n            addFiles: 'add-file',\n            sort: 'sort-files',\n            removeFile: 'remove-file',\n            cancelFile: 'cancel-file',\n            skipFile: 'skip-file',\n            retry: 'retry',\n            isInProgress: 'is-in-progress',\n            makeThumb: 'make-thumb',\n            md5File: 'md5-file',\n            getDimension: 'get-dimension',\n            addButton: 'add-btn',\n            predictRuntimeType: 'predict-runtime-type',\n            refresh: 'refresh',\n            disable: 'disable',\n            enable: 'enable',\n            reset: 'reset'\n        }, function( fn, command ) {\n            Uploader.prototype[ fn ] = function() {\n                return this.request( command, arguments );\n            };\n        });\n\n        $.extend( Uploader.prototype, {\n            state: 'pending',\n\n            _init: function( opts ) {\n                var me = this;\n\n                me.request( 'init', opts, function() {\n                    me.state = 'ready';\n                    me.trigger('ready');\n                });\n            },\n\n            /**\n             * 获取或者设置Uploader配置项。\n             * @method option\n             * @grammar option( key ) => *\n             * @grammar option( key, val ) => self\n             * @example\n             *\n             * // 初始状态图片上传前不会压缩\n             * var uploader = new WebUploader.Uploader({\n             *     compress: null;\n             * });\n             *\n             * // 修改后图片上传前，尝试将图片压缩到1600 * 1600\n             * uploader.option( 'compress', {\n             *     width: 1600,\n             *     height: 1600\n             * });\n             */\n            option: function( key, val ) {\n                var opts = this.options;\n\n                // setter\n                if ( arguments.length > 1 ) {\n\n                    if ( $.isPlainObject( val ) &&\n                            $.isPlainObject( opts[ key ] ) ) {\n                        $.extend( opts[ key ], val );\n                    } else {\n                        opts[ key ] = val;\n                    }\n\n                } else {    // getter\n                    return key ? opts[ key ] : opts;\n                }\n            },\n\n            /**\n             * 获取文件统计信息。返回一个包含一下信息的对象。\n             * * `successNum` 上传成功的文件数\n             * * `progressNum` 上传中的文件数\n             * * `cancelNum` 被删除的文件数\n             * * `invalidNum` 无效的文件数\n             * * `uploadFailNum` 上传失败的文件数\n             * * `queueNum` 还在队列中的文件数\n             * * `interruptNum` 被暂停的文件数\n             * @method getStats\n             * @grammar getStats() => Object\n             */\n            getStats: function() {\n                // return this._mgr.getStats.apply( this._mgr, arguments );\n                var stats = this.request('get-stats');\n\n                return stats ? {\n                    successNum: stats.numOfSuccess,\n                    progressNum: stats.numOfProgress,\n\n                    // who care?\n                    // queueFailNum: 0,\n                    cancelNum: stats.numOfCancel,\n                    invalidNum: stats.numOfInvalid,\n                    uploadFailNum: stats.numOfUploadFailed,\n                    queueNum: stats.numOfQueue,\n                    interruptNum: stats.numofInterrupt\n                } : {};\n            },\n\n            // 需要重写此方法来来支持opts.onEvent和instance.onEvent的处理器\n            trigger: function( type/*, args...*/ ) {\n                var args = [].slice.call( arguments, 1 ),\n                    opts = this.options,\n                    name = 'on' + type.substring( 0, 1 ).toUpperCase() +\n                        type.substring( 1 );\n\n                if (\n                        // 调用通过on方法注册的handler.\n                        Mediator.trigger.apply( this, arguments ) === false ||\n\n                        // 调用opts.onEvent\n                        $.isFunction( opts[ name ] ) &&\n                        opts[ name ].apply( this, args ) === false ||\n\n                        // 调用this.onEvent\n                        $.isFunction( this[ name ] ) &&\n                        this[ name ].apply( this, args ) === false ||\n\n                        // 广播所有uploader的事件。\n                        Mediator.trigger.apply( Mediator,\n                        [ this, type ].concat( args ) ) === false ) {\n\n                    return false;\n                }\n\n                return true;\n            },\n\n            /**\n             * 销毁 webuploader 实例\n             * @method destroy\n             * @grammar destroy() => undefined\n             */\n            destroy: function() {\n                this.request( 'destroy', arguments );\n                this.off();\n            },\n\n            // widgets/widget.js将补充此方法的详细文档。\n            request: Base.noop\n        });\n\n        /**\n         * 创建Uploader实例，等同于new Uploader( opts );\n         * @method create\n         * @class Base\n         * @static\n         * @grammar Base.create( opts ) => Uploader\n         */\n        Base.create = Uploader.create = function( opts ) {\n            return new Uploader( opts );\n        };\n\n        // 暴露Uploader，可以通过它来扩展业务逻辑。\n        Base.Uploader = Uploader;\n\n        return Uploader;\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/runtime',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            factories = {},\n\n            // 获取对象的第一个key\n            getFirstKey = function( obj ) {\n                for ( var key in obj ) {\n                    if ( obj.hasOwnProperty( key ) ) {\n                        return key;\n                    }\n                }\n                return null;\n            };\n\n        // 接口类。\n        function Runtime( options ) {\n            this.options = $.extend({\n                container: document.body\n            }, options );\n            this.uid = Base.guid('rt_');\n        }\n\n        $.extend( Runtime.prototype, {\n\n            getContainer: function() {\n                var opts = this.options,\n                    parent, container;\n\n                if ( this._container ) {\n                    return this._container;\n                }\n\n                parent = $( opts.container || document.body );\n                container = $( document.createElement('div') );\n\n                container.attr( 'id', 'rt_' + this.uid );\n                container.css({\n                    position: 'absolute',\n                    top: '0px',\n                    left: '0px',\n                    width: '1px',\n                    height: '1px',\n                    overflow: 'hidden'\n                });\n\n                parent.append( container );\n                parent.addClass('webuploader-container');\n                this._container = container;\n                this._parent = parent;\n                return container;\n            },\n\n            init: Base.noop,\n            exec: Base.noop,\n\n            destroy: function() {\n                this._container && this._container.remove();\n                this._parent && this._parent.removeClass('webuploader-container');\n                this.off();\n            }\n        });\n\n        Runtime.orders = 'html5,flash';\n\n\n        /**\n         * 添加Runtime实现。\n         * @param {String} type    类型\n         * @param {Runtime} factory 具体Runtime实现。\n         */\n        Runtime.addRuntime = function( type, factory ) {\n            factories[ type ] = factory;\n        };\n\n        Runtime.hasRuntime = function( type ) {\n            return !!(type ? factories[ type ] : getFirstKey( factories ));\n        };\n\n        Runtime.create = function( opts, orders ) {\n            var type, runtime;\n\n            orders = orders || Runtime.orders;\n            $.each( orders.split( /\\s*,\\s*/g ), function() {\n                if ( factories[ this ] ) {\n                    type = this;\n                    return false;\n                }\n            });\n\n            type = type || getFirstKey( factories );\n\n            if ( !type ) {\n                throw new Error('Runtime Error');\n            }\n\n            runtime = new factories[ type ]( opts );\n            return runtime;\n        };\n\n        Mediator.installTo( Runtime.prototype );\n        return Runtime;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/client',[\n        'base',\n        'mediator',\n        'runtime/runtime'\n    ], function( Base, Mediator, Runtime ) {\n\n        var cache;\n\n        cache = (function() {\n            var obj = {};\n\n            return {\n                add: function( runtime ) {\n                    obj[ runtime.uid ] = runtime;\n                },\n\n                get: function( ruid, standalone ) {\n                    var i;\n\n                    if ( ruid ) {\n                        return obj[ ruid ];\n                    }\n\n                    for ( i in obj ) {\n                        // 有些类型不能重用，比如filepicker.\n                        if ( standalone && obj[ i ].__standalone ) {\n                            continue;\n                        }\n\n                        return obj[ i ];\n                    }\n\n                    return null;\n                },\n\n                remove: function( runtime ) {\n                    delete obj[ runtime.uid ];\n                }\n            };\n        })();\n\n        function RuntimeClient( component, standalone ) {\n            var deferred = Base.Deferred(),\n                runtime;\n\n            this.uid = Base.guid('client_');\n\n            // 允许runtime没有初始化之前，注册一些方法在初始化后执行。\n            this.runtimeReady = function( cb ) {\n                return deferred.done( cb );\n            };\n\n            this.connectRuntime = function( opts, cb ) {\n\n                // already connected.\n                if ( runtime ) {\n                    throw new Error('already connected!');\n                }\n\n                deferred.done( cb );\n\n                if ( typeof opts === 'string' && cache.get( opts ) ) {\n                    runtime = cache.get( opts );\n                }\n\n                // 像filePicker只能独立存在，不能公用。\n                runtime = runtime || cache.get( null, standalone );\n\n                // 需要创建\n                if ( !runtime ) {\n                    runtime = Runtime.create( opts, opts.runtimeOrder );\n                    runtime.__promise = deferred.promise();\n                    runtime.once( 'ready', deferred.resolve );\n                    runtime.init();\n                    cache.add( runtime );\n                    runtime.__client = 1;\n                } else {\n                    // 来自cache\n                    Base.$.extend( runtime.options, opts );\n                    runtime.__promise.then( deferred.resolve );\n                    runtime.__client++;\n                }\n\n                standalone && (runtime.__standalone = standalone);\n                return runtime;\n            };\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.disconnectRuntime = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                runtime.__client--;\n\n                if ( runtime.__client <= 0 ) {\n                    cache.remove( runtime );\n                    delete runtime.__promise;\n                    runtime.destroy();\n                }\n\n                runtime = null;\n            };\n\n            this.exec = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                var args = Base.slice( arguments );\n                component && args.unshift( component );\n\n                return runtime.exec.apply( this, args );\n            };\n\n            this.getRuid = function() {\n                return runtime && runtime.uid;\n            };\n\n            this.destroy = (function( destroy ) {\n                return function() {\n                    destroy && destroy.apply( this, arguments );\n                    this.trigger('destroy');\n                    this.off();\n                    this.exec('destroy');\n                    this.disconnectRuntime();\n                };\n            })( this.destroy );\n        }\n\n        Mediator.installTo( RuntimeClient.prototype );\n        return RuntimeClient;\n    });\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/dnd',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function DragAndDrop( opts ) {\n            opts = this.options = $.extend({}, DragAndDrop.options, opts );\n\n            opts.container = $( opts.container );\n\n            if ( !opts.container.length ) {\n                return;\n            }\n\n            RuntimeClent.call( this, 'DragAndDrop' );\n        }\n\n        DragAndDrop.options = {\n            accept: null,\n            disableGlobalDnd: false\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: DragAndDrop,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( DragAndDrop.prototype );\n\n        return DragAndDrop;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/widget',[\n        'base',\n        'uploader'\n    ], function( Base, Uploader ) {\n\n        var $ = Base.$,\n            _init = Uploader.prototype._init,\n            _destroy = Uploader.prototype.destroy,\n            IGNORE = {},\n            widgetClass = [];\n\n        function isArrayLike( obj ) {\n            if ( !obj ) {\n                return false;\n            }\n\n            var length = obj.length,\n                type = $.type( obj );\n\n            if ( obj.nodeType === 1 && length ) {\n                return true;\n            }\n\n            return type === 'array' || type !== 'function' && type !== 'string' &&\n                    (length === 0 || typeof length === 'number' && length > 0 &&\n                    (length - 1) in obj);\n        }\n\n        function Widget( uploader ) {\n            this.owner = uploader;\n            this.options = uploader.options;\n        }\n\n        $.extend( Widget.prototype, {\n\n            init: Base.noop,\n\n            // 类Backbone的事件监听声明，监听uploader实例上的事件\n            // widget直接无法监听事件，事件只能通过uploader来传递\n            invoke: function( apiName, args ) {\n\n                /*\n                    {\n                        'make-thumb': 'makeThumb'\n                    }\n                 */\n                var map = this.responseMap;\n\n                // 如果无API响应声明则忽略\n                if ( !map || !(apiName in map) || !(map[ apiName ] in this) ||\n                        !$.isFunction( this[ map[ apiName ] ] ) ) {\n\n                    return IGNORE;\n                }\n\n                return this[ map[ apiName ] ].apply( this, args );\n\n            },\n\n            /**\n             * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。\n             * @method request\n             * @grammar request( command, args ) => * | Promise\n             * @grammar request( command, args, callback ) => Promise\n             * @for  Uploader\n             */\n            request: function() {\n                return this.owner.request.apply( this.owner, arguments );\n            }\n        });\n\n        // 扩展Uploader.\n        $.extend( Uploader.prototype, {\n\n            /**\n             * @property {String | Array} [disableWidgets=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。\n             */\n\n            // 覆写_init用来初始化widgets\n            _init: function() {\n                var me = this,\n                    widgets = me._widgets = [],\n                    deactives = me.options.disableWidgets || '';\n\n                $.each( widgetClass, function( _, klass ) {\n                    (!deactives || !~deactives.indexOf( klass._name )) &&\n                        widgets.push( new klass( me ) );\n                });\n\n                return _init.apply( me, arguments );\n            },\n\n            request: function( apiName, args, callback ) {\n                var i = 0,\n                    widgets = this._widgets,\n                    len = widgets && widgets.length,\n                    rlts = [],\n                    dfds = [],\n                    widget, rlt, promise, key;\n\n                args = isArrayLike( args ) ? args : [ args ];\n\n                for ( ; i < len; i++ ) {\n                    widget = widgets[ i ];\n                    rlt = widget.invoke( apiName, args );\n\n                    if ( rlt !== IGNORE ) {\n\n                        // Deferred对象\n                        if ( Base.isPromise( rlt ) ) {\n                            dfds.push( rlt );\n                        } else {\n                            rlts.push( rlt );\n                        }\n                    }\n                }\n\n                // 如果有callback，则用异步方式。\n                if ( callback || dfds.length ) {\n                    promise = Base.when.apply( Base, dfds );\n                    key = promise.pipe ? 'pipe' : 'then';\n\n                    // 很重要不能删除。删除了会死循环。\n                    // 保证执行顺序。让callback总是在下一个 tick 中执行。\n                    return promise[ key ](function() {\n                                var deferred = Base.Deferred(),\n                                    args = arguments;\n\n                                if ( args.length === 1 ) {\n                                    args = args[ 0 ];\n                                }\n\n                                setTimeout(function() {\n                                    deferred.resolve( args );\n                                }, 1 );\n\n                                return deferred.promise();\n                            })[ callback ? key : 'done' ]( callback || Base.noop );\n                } else {\n                    return rlts[ 0 ];\n                }\n            },\n\n            destroy: function() {\n                _destroy.apply( this, arguments );\n                this._widgets = null;\n            }\n        });\n\n        /**\n         * 添加组件\n         * @grammar Uploader.register(proto);\n         * @grammar Uploader.register(map, proto);\n         * @param  {object} responseMap API 名称与函数实现的映射\n         * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义\n         * @method Uploader.register\n         * @for Uploader\n         * @example\n         * Uploader.register({\n         *     'make-thumb': 'makeThumb'\n         * }, {\n         *     init: function( options ) {},\n         *     makeThumb: function() {}\n         * });\n         *\n         * Uploader.register({\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         */\n        Uploader.register = Widget.register = function( responseMap, widgetProto ) {\n            var map = { init: 'init', destroy: 'destroy', name: 'anonymous' },\n                klass;\n\n            if ( arguments.length === 1 ) {\n                widgetProto = responseMap;\n\n                // 自动生成 map 表。\n                $.each(widgetProto, function(key) {\n                    if ( key[0] === '_' || key === 'name' ) {\n                        key === 'name' && (map.name = widgetProto.name);\n                        return;\n                    }\n\n                    map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;\n                });\n\n            } else {\n                map = $.extend( map, responseMap );\n            }\n\n            widgetProto.responseMap = map;\n            klass = Base.inherits( Widget, widgetProto );\n            klass._name = map.name;\n            widgetClass.push( klass );\n\n            return klass;\n        };\n\n        /**\n         * 删除插件，只有在注册时指定了名字的才能被删除。\n         * @grammar Uploader.unRegister(name);\n         * @param  {string} name 组件名字\n         * @method Uploader.unRegister\n         * @for Uploader\n         * @example\n         *\n         * Uploader.register({\n         *     name: 'custom',\n         *\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         *\n         * Uploader.unRegister('custom');\n         */\n        Uploader.unRegister = Widget.unRegister = function( name ) {\n            if ( !name || name === 'anonymous' ) {\n                return;\n            }\n\n            // 删除指定的插件。\n            for ( var i = widgetClass.length; i--; ) {\n                if ( widgetClass[i]._name === name ) {\n                    widgetClass.splice(i, 1)\n                }\n            }\n        };\n\n        return Widget;\n    });\n    /**\n     * @fileOverview DragAndDrop Widget。\n     */\n    define('widgets/filednd',[\n        'base',\n        'uploader',\n        'lib/dnd',\n        'widgets/widget'\n    ], function( Base, Uploader, Dnd ) {\n        var $ = Base.$;\n\n        Uploader.options.dnd = '';\n\n        /**\n         * @property {Selector} [dnd=undefined]  指定Drag And Drop拖拽的容器，如果不指定，则不启动。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @property {Selector} [disableGlobalDnd=false]  是否禁掉整个页面的拖拽功能，如果不禁用，图片拖进来的时候会默认被浏览器打开。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @event dndAccept\n         * @param {DataTransferItemList} items DataTransferItem\n         * @description 阻止此事件可以拒绝某些类型的文件拖入进来。目前只有 chrome 提供这样的 API，且只能通过 mime-type 验证。\n         * @for  Uploader\n         */\n        return Uploader.register({\n            name: 'dnd',\n\n            init: function( opts ) {\n\n                if ( !opts.dnd ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        disableGlobalDnd: opts.disableGlobalDnd,\n                        container: opts.dnd,\n                        accept: opts.accept\n                    }),\n                    dnd;\n\n                this.dnd = dnd = new Dnd( options );\n\n                dnd.once( 'ready', deferred.resolve );\n                dnd.on( 'drop', function( files ) {\n                    me.request( 'add-file', [ files ]);\n                });\n\n                // 检测文件是否全部允许添加。\n                dnd.on( 'accept', function( items ) {\n                    return me.owner.trigger( 'dndAccept', items );\n                });\n\n                dnd.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.dnd && this.dnd.destroy();\n            }\n        });\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepaste',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function FilePaste( opts ) {\n            opts = this.options = $.extend({}, opts );\n            opts.container = $( opts.container || document.body );\n            RuntimeClent.call( this, 'FilePaste' );\n        }\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePaste,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( FilePaste.prototype );\n\n        return FilePaste;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/filepaste',[\n        'base',\n        'uploader',\n        'lib/filepaste',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePaste ) {\n        var $ = Base.$;\n\n        /**\n         * @property {Selector} [paste=undefined]  指定监听paste事件的容器，如果不指定，不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为`document.body`.\n         * @namespace options\n         * @for Uploader\n         */\n        return Uploader.register({\n            name: 'paste',\n\n            init: function( opts ) {\n\n                if ( !opts.paste ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        container: opts.paste,\n                        accept: opts.accept\n                    }),\n                    paste;\n\n                this.paste = paste = new FilePaste( options );\n\n                paste.once( 'ready', deferred.resolve );\n                paste.on( 'paste', function( files ) {\n                    me.owner.request( 'add-file', [ files ]);\n                });\n                paste.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.paste && this.paste.destroy();\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob\n     */\n    define('lib/blob',[\n        'base',\n        'runtime/client'\n    ], function( Base, RuntimeClient ) {\n\n        function Blob( ruid, source ) {\n            var me = this;\n\n            me.source = source;\n            me.ruid = ruid;\n            this.size = source.size || 0;\n\n            // 如果没有指定 mimetype, 但是知道文件后缀。\n            if ( !source.type && this.ext &&\n                    ~'jpg,jpeg,png,gif,bmp'.indexOf( this.ext ) ) {\n                this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);\n            } else {\n                this.type = source.type || 'application/octet-stream';\n            }\n\n            RuntimeClient.call( me, 'Blob' );\n            this.uid = source.uid || this.uid;\n\n            if ( ruid ) {\n                me.connectRuntime( ruid );\n            }\n        }\n\n        Base.inherits( RuntimeClient, {\n            constructor: Blob,\n\n            slice: function( start, end ) {\n                return this.exec( 'slice', start, end );\n            },\n\n            getSource: function() {\n                return this.source;\n            }\n        });\n\n        return Blob;\n    });\n    /**\n     * 为了统一化Flash的File和HTML5的File而存在。\n     * 以至于要调用Flash里面的File，也可以像调用HTML5版本的File一下。\n     * @fileOverview File\n     */\n    define('lib/file',[\n        'base',\n        'lib/blob'\n    ], function( Base, Blob ) {\n\n        var uid = 1,\n            rExt = /\\.([^.]+)$/;\n\n        function File( ruid, file ) {\n            var ext;\n\n            this.name = file.name || ('untitled' + uid++);\n            ext = rExt.exec( file.name ) ? RegExp.$1.toLowerCase() : '';\n\n            // todo 支持其他类型文件的转换。\n            // 如果有 mimetype, 但是文件名里面没有找出后缀规律\n            if ( !ext && file.type ) {\n                ext = /\\/(jpg|jpeg|png|gif|bmp)$/i.exec( file.type ) ?\n                        RegExp.$1.toLowerCase() : '';\n                this.name += '.' + ext;\n            }\n\n            this.ext = ext;\n            this.lastModifiedDate = file.lastModifiedDate ||\n                    (new Date()).toLocaleString();\n\n            Blob.apply( this, arguments );\n        }\n\n        return Base.inherits( Blob, File );\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepicker',[\n        'base',\n        'runtime/client',\n        'lib/file'\n    ], function( Base, RuntimeClent, File ) {\n\n        var $ = Base.$;\n\n        function FilePicker( opts ) {\n            opts = this.options = $.extend({}, FilePicker.options, opts );\n\n            opts.container = $( opts.id );\n\n            if ( !opts.container.length ) {\n                throw new Error('按钮指定错误');\n            }\n\n            opts.innerHTML = opts.innerHTML || opts.label ||\n                    opts.container.html() || '';\n\n            opts.button = $( opts.button || document.createElement('div') );\n            opts.button.html( opts.innerHTML );\n            opts.container.html( opts.button );\n\n            RuntimeClent.call( this, 'FilePicker', true );\n        }\n\n        FilePicker.options = {\n            button: null,\n            container: null,\n            label: null,\n            innerHTML: null,\n            multiple: true,\n            accept: null,\n            name: 'file'\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePicker,\n\n            init: function() {\n                var me = this,\n                    opts = me.options,\n                    button = opts.button;\n\n                button.addClass('webuploader-pick');\n\n                me.on( 'all', function( type ) {\n                    var files;\n\n                    switch ( type ) {\n                        case 'mouseenter':\n                            button.addClass('webuploader-pick-hover');\n                            break;\n\n                        case 'mouseleave':\n                            button.removeClass('webuploader-pick-hover');\n                            break;\n\n                        case 'change':\n                            files = me.exec('getFiles');\n                            me.trigger( 'select', $.map( files, function( file ) {\n                                file = new File( me.getRuid(), file );\n\n                                // 记录来源。\n                                file._refer = opts.container;\n                                return file;\n                            }), opts.container );\n                            break;\n                    }\n                });\n\n                me.connectRuntime( opts, function() {\n                    me.refresh();\n                    me.exec( 'init', opts );\n                    me.trigger('ready');\n                });\n\n                this._resizeHandler = Base.bindFn( this.refresh, this );\n                $( window ).on( 'resize', this._resizeHandler );\n            },\n\n            refresh: function() {\n                var shimContainer = this.getRuntime().getContainer(),\n                    button = this.options.button,\n                    width = button.outerWidth ?\n                            button.outerWidth() : button.width(),\n\n                    height = button.outerHeight ?\n                            button.outerHeight() : button.height(),\n\n                    pos = button.offset();\n\n                width && height && shimContainer.css({\n                    bottom: 'auto',\n                    right: 'auto',\n                    width: width + 'px',\n                    height: height + 'px'\n                }).offset( pos );\n            },\n\n            enable: function() {\n                var btn = this.options.button;\n\n                btn.removeClass('webuploader-pick-disable');\n                this.refresh();\n            },\n\n            disable: function() {\n                var btn = this.options.button;\n\n                this.getRuntime().getContainer().css({\n                    top: '-99999px'\n                });\n\n                btn.addClass('webuploader-pick-disable');\n            },\n\n            destroy: function() {\n                var btn = this.options.button;\n                $( window ).off( 'resize', this._resizeHandler );\n                btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +\n                    'webuploader-pick');\n            }\n        });\n\n        return FilePicker;\n    });\n\n    /**\n     * @fileOverview 文件选择相关\n     */\n    define('widgets/filepicker',[\n        'base',\n        'uploader',\n        'lib/filepicker',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePicker ) {\n        var $ = Base.$;\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Selector | Object} [pick=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 指定选择文件的按钮容器，不指定则不创建按钮。\n             *\n             * * `id` {Seletor|dom} 指定选择文件的按钮容器，不指定则不创建按钮。**注意** 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。\n             * * `label` {String} 请采用 `innerHTML` 代替\n             * * `innerHTML` {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。\n             * * `multiple` {Boolean} 是否开起同时选择多个文件能力。\n             */\n            pick: null,\n\n            /**\n             * @property {Arroy} [accept=null]\n             * @namespace options\n             * @for Uploader\n             * @description 指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。\n             *\n             * * `title` {String} 文字描述\n             * * `extensions` {String} 允许的文件后缀，不带点，多个用逗号分割。\n             * * `mimeTypes` {String} 多个用逗号分割。\n             *\n             * 如：\n             *\n             * ```\n             * {\n             *     title: 'Images',\n             *     extensions: 'gif,jpg,jpeg,bmp,png',\n             *     mimeTypes: 'image/*'\n             * }\n             * ```\n             */\n            accept: null/*{\n                title: 'Images',\n                extensions: 'gif,jpg,jpeg,bmp,png',\n                mimeTypes: 'image/*'\n            }*/\n        });\n\n        return Uploader.register({\n            name: 'picker',\n\n            init: function( opts ) {\n                this.pickers = [];\n                return opts.pick && this.addBtn( opts.pick );\n            },\n\n            refresh: function() {\n                $.each( this.pickers, function() {\n                    this.refresh();\n                });\n            },\n\n            /**\n             * @method addButton\n             * @for Uploader\n             * @grammar addButton( pick ) => Promise\n             * @description\n             * 添加文件选择按钮，如果一个按钮不够，需要调用此方法来添加。参数跟[options.pick](#WebUploader:Uploader:options)一致。\n             * @example\n             * uploader.addButton({\n             *     id: '#btnContainer',\n             *     innerHTML: '选择文件'\n             * });\n             */\n            addBtn: function( pick ) {\n                var me = this,\n                    opts = me.options,\n                    accept = opts.accept,\n                    promises = [];\n\n                if ( !pick ) {\n                    return;\n                }\n\n                $.isPlainObject( pick ) || (pick = {\n                    id: pick\n                });\n\n                $( pick.id ).each(function() {\n                    var options, picker, deferred;\n\n                    deferred = Base.Deferred();\n\n                    options = $.extend({}, pick, {\n                        accept: $.isPlainObject( accept ) ? [ accept ] : accept,\n                        swf: opts.swf,\n                        runtimeOrder: opts.runtimeOrder,\n                        id: this\n                    });\n\n                    picker = new FilePicker( options );\n\n                    picker.once( 'ready', deferred.resolve );\n                    picker.on( 'select', function( files ) {\n                        me.owner.request( 'add-file', [ files ]);\n                    });\n                    picker.init();\n\n                    me.pickers.push( picker );\n\n                    promises.push( deferred.promise() );\n                });\n\n                return Base.when.apply( Base, promises );\n            },\n\n            disable: function() {\n                $.each( this.pickers, function() {\n                    this.disable();\n                });\n            },\n\n            enable: function() {\n                $.each( this.pickers, function() {\n                    this.enable();\n                });\n            },\n\n            destroy: function() {\n                $.each( this.pickers, function() {\n                    this.destroy();\n                });\n                this.pickers = null;\n            }\n        });\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('lib/image',[\n        'base',\n        'runtime/client',\n        'lib/blob'\n    ], function( Base, RuntimeClient, Blob ) {\n        var $ = Base.$;\n\n        // 构造器。\n        function Image( opts ) {\n            this.options = $.extend({}, Image.options, opts );\n            RuntimeClient.call( this, 'Image' );\n\n            this.on( 'load', function() {\n                this._info = this.exec('info');\n                this._meta = this.exec('meta');\n            });\n        }\n\n        // 默认选项。\n        Image.options = {\n\n            // 默认的图片处理质量\n            quality: 90,\n\n            // 是否裁剪\n            crop: false,\n\n            // 是否保留头部信息\n            preserveHeaders: false,\n\n            // 是否允许放大。\n            allowMagnify: false\n        };\n\n        // 继承RuntimeClient.\n        Base.inherits( RuntimeClient, {\n            constructor: Image,\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    ruid = blob.getRuid();\n\n                this.connectRuntime( ruid, function() {\n                    me.exec( 'init', me.options );\n                    me.exec( 'loadFromBlob', blob );\n                });\n            },\n\n            resize: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'resize' ].concat( args ) );\n            },\n\n            crop: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'crop' ].concat( args ) );\n            },\n\n            getAsDataUrl: function( type ) {\n                return this.exec( 'getAsDataUrl', type );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this.exec( 'getAsBlob', type );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n\n        return Image;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/image',[\n        'base',\n        'uploader',\n        'lib/image',\n        'widgets/widget'\n    ], function( Base, Uploader, Image ) {\n\n        var $ = Base.$,\n            throttle;\n\n        // 根据要处理的文件大小来节流，一次不能处理太多，会卡。\n        throttle = (function( max ) {\n            var occupied = 0,\n                waiting = [],\n                tick = function() {\n                    var item;\n\n                    while ( waiting.length && occupied < max ) {\n                        item = waiting.shift();\n                        occupied += item[ 0 ];\n                        item[ 1 ]();\n                    }\n                };\n\n            return function( emiter, size, cb ) {\n                waiting.push([ size, cb ]);\n                emiter.once( 'destroy', function() {\n                    occupied -= size;\n                    setTimeout( tick, 1 );\n                });\n                setTimeout( tick, 1 );\n            };\n        })( 5 * 1024 * 1024 );\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Object} [thumb]\n             * @namespace options\n             * @for Uploader\n             * @description 配置生成缩略图的选项。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 110,\n             *     height: 110,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 70,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: true,\n             *\n             *     // 是否允许裁剪。\n             *     crop: true,\n             *\n             *     // 为空的话则保留原有图片格式。\n             *     // 否则强制转换成指定的类型。\n             *     type: 'image/jpeg'\n             * }\n             * ```\n             */\n            thumb: {\n                width: 110,\n                height: 110,\n                quality: 70,\n                allowMagnify: true,\n                crop: true,\n                preserveHeaders: false,\n\n                // 为空的话则保留原有图片格式。\n                // 否则强制转换成指定的类型。\n                // IE 8下面 base64 大小不能超过 32K 否则预览失败，而非 jpeg 编码的图片很可\n                // 能会超过 32k, 所以这里设置成预览的时候都是 image/jpeg\n                type: 'image/jpeg'\n            },\n\n            /**\n             * @property {Object} [compress]\n             * @namespace options\n             * @for Uploader\n             * @description 配置压缩的图片的选项。如果此选项为`false`, 则图片在上传前不进行压缩。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 1600,\n             *     height: 1600,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 90,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: false,\n             *\n             *     // 是否允许裁剪。\n             *     crop: false,\n             *\n             *     // 是否保留头部meta信息。\n             *     preserveHeaders: true,\n             *\n             *     // 如果发现压缩后文件大小比原来还大，则使用原来图片\n             *     // 此属性可能会影响图片自动纠正功能\n             *     noCompressIfLarger: false,\n             *\n             *     // 单位字节，如果图片大小小于此值，不会采用压缩。\n             *     compressSize: 0\n             * }\n             * ```\n             */\n            compress: {\n                width: 1600,\n                height: 1600,\n                quality: 90,\n                allowMagnify: false,\n                crop: false,\n                preserveHeaders: true\n            }\n        });\n\n        return Uploader.register({\n\n            name: 'image',\n\n\n            /**\n             * 生成缩略图，此过程为异步，所以需要传入`callback`。\n             * 通常情况在图片加入队里后调用此方法来生成预览图以增强交互效果。\n             *\n             * 当 width 或者 height 的值介于 0 - 1 时，被当成百分比使用。\n             *\n             * `callback`中可以接收到两个参数。\n             * * 第一个为error，如果生成缩略图有错误，此error将为真。\n             * * 第二个为ret, 缩略图的Data URL值。\n             *\n             * **注意**\n             * Date URL在IE6/7中不支持，所以不用调用此方法了，直接显示一张暂不支持预览图片好了。\n             * 也可以借助服务端，将 base64 数据传给服务端，生成一个临时文件供预览。\n             *\n             * @method makeThumb\n             * @grammar makeThumb( file, callback ) => undefined\n             * @grammar makeThumb( file, callback, width, height ) => undefined\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.makeThumb( file, function( error, ret ) {\n             *         if ( error ) {\n             *             $li.text('预览错误');\n             *         } else {\n             *             $li.append('<img alt=\"\" src=\"' + ret + '\" />');\n             *         }\n             *     });\n             *\n             * });\n             */\n            makeThumb: function( file, cb, width, height ) {\n                var opts, image;\n\n                file = this.request( 'get-file', file );\n\n                // 只预览图片格式。\n                if ( !file.type.match( /^image/ ) ) {\n                    cb( true );\n                    return;\n                }\n\n                opts = $.extend({}, this.options.thumb );\n\n                // 如果传入的是object.\n                if ( $.isPlainObject( width ) ) {\n                    opts = $.extend( opts, width );\n                    width = null;\n                }\n\n                width = width || opts.width;\n                height = height || opts.height;\n\n                image = new Image( opts );\n\n                image.once( 'load', function() {\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                // 当 resize 完后\n                image.once( 'complete', function() {\n                    cb( false, image.getAsDataUrl( opts.type ) );\n                    image.destroy();\n                });\n\n                image.once( 'error', function( reason ) {\n                    cb( reason || true );\n                    image.destroy();\n                });\n\n                throttle( image, file.source.size, function() {\n                    file._info && image.info( file._info );\n                    file._meta && image.meta( file._meta );\n                    image.loadFromBlob( file.source );\n                });\n            },\n\n            beforeSendFile: function( file ) {\n                var opts = this.options.compress || this.options.resize,\n                    compressSize = opts && opts.compressSize || 0,\n                    noCompressIfLarger = opts && opts.noCompressIfLarger || false,\n                    image, deferred;\n\n                file = this.request( 'get-file', file );\n\n                // 只压缩 jpeg 图片格式。\n                // gif 可能会丢失针\n                // bmp png 基本上尺寸都不大，且压缩比比较小。\n                if ( !opts || !~'image/jpeg,image/jpg'.indexOf( file.type ) ||\n                        file.size < compressSize ||\n                        file._compressed ) {\n                    return;\n                }\n\n                opts = $.extend({}, opts );\n                deferred = Base.Deferred();\n\n                image = new Image( opts );\n\n                deferred.always(function() {\n                    image.destroy();\n                    image = null;\n                });\n                image.once( 'error', deferred.reject );\n                image.once( 'load', function() {\n                    var width = opts.width,\n                        height = opts.height;\n\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                image.once( 'complete', function() {\n                    var blob, size;\n\n                    // 移动端 UC / qq 浏览器的无图模式下\n                    // ctx.getImageData 处理大图的时候会报 Exception\n                    // INDEX_SIZE_ERR: DOM Exception 1\n                    try {\n                        blob = image.getAsBlob( opts.type );\n\n                        size = file.size;\n\n                        // 如果压缩后，比原来还大则不用压缩后的。\n                        if ( !noCompressIfLarger || blob.size < size ) {\n                            // file.source.destroy && file.source.destroy();\n                            file.source = blob;\n                            file.size = blob.size;\n\n                            file.trigger( 'resize', blob.size, size );\n                        }\n\n                        // 标记，避免重复压缩。\n                        file._compressed = true;\n                        deferred.resolve();\n                    } catch ( e ) {\n                        // 出错了直接继续，让其上传原始图片\n                        deferred.resolve();\n                    }\n                });\n\n                file._info && image.info( file._info );\n                file._meta && image.meta( file._meta );\n\n                image.loadFromBlob( file.source );\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview 文件属性封装\n     */\n    define('file',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            idPrefix = 'WU_FILE_',\n            idSuffix = 0,\n            rExt = /\\.([^.]+)$/,\n            statusMap = {};\n\n        function gid() {\n            return idPrefix + idSuffix++;\n        }\n\n        /**\n         * 文件类\n         * @class File\n         * @constructor 构造函数\n         * @grammar new File( source ) => File\n         * @param {Lib.File} source [lib.File](#Lib.File)实例, 此source对象是带有Runtime信息的。\n         */\n        function WUFile( source ) {\n\n            /**\n             * 文件名，包括扩展名（后缀）\n             * @property name\n             * @type {string}\n             */\n            this.name = source.name || 'Untitled';\n\n            /**\n             * 文件体积（字节）\n             * @property size\n             * @type {uint}\n             * @default 0\n             */\n            this.size = source.size || 0;\n\n            /**\n             * 文件MIMETYPE类型，与文件类型的对应关系请参考[http://t.cn/z8ZnFny](http://t.cn/z8ZnFny)\n             * @property type\n             * @type {string}\n             * @default 'application/octet-stream'\n             */\n            this.type = source.type || 'application/octet-stream';\n\n            /**\n             * 文件最后修改日期\n             * @property lastModifiedDate\n             * @type {int}\n             * @default 当前时间戳\n             */\n            this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);\n\n            /**\n             * 文件ID，每个对象具有唯一ID，与文件名无关\n             * @property id\n             * @type {string}\n             */\n            this.id = gid();\n\n            /**\n             * 文件扩展名，通过文件名获取，例如test.png的扩展名为png\n             * @property ext\n             * @type {string}\n             */\n            this.ext = rExt.exec( this.name ) ? RegExp.$1 : '';\n\n\n            /**\n             * 状态文字说明。在不同的status语境下有不同的用途。\n             * @property statusText\n             * @type {string}\n             */\n            this.statusText = '';\n\n            // 存储文件状态，防止通过属性直接修改\n            statusMap[ this.id ] = WUFile.Status.INITED;\n\n            this.source = source;\n            this.loaded = 0;\n\n            this.on( 'error', function( msg ) {\n                this.setStatus( WUFile.Status.ERROR, msg );\n            });\n        }\n\n        $.extend( WUFile.prototype, {\n\n            /**\n             * 设置状态，状态变化时会触发`change`事件。\n             * @method setStatus\n             * @grammar setStatus( status[, statusText] );\n             * @param {File.Status|String} status [文件状态值](#WebUploader:File:File.Status)\n             * @param {String} [statusText=''] 状态说明，常在error时使用，用http, abort,server等来标记是由于什么原因导致文件错误。\n             */\n            setStatus: function( status, text ) {\n\n                var prevStatus = statusMap[ this.id ];\n\n                typeof text !== 'undefined' && (this.statusText = text);\n\n                if ( status !== prevStatus ) {\n                    statusMap[ this.id ] = status;\n                    /**\n                     * 文件状态变化\n                     * @event statuschange\n                     */\n                    this.trigger( 'statuschange', status, prevStatus );\n                }\n\n            },\n\n            /**\n             * 获取文件状态\n             * @return {File.Status}\n             * @example\n                     文件状态具体包括以下几种类型：\n                     {\n                         // 初始化\n                        INITED:     0,\n                        // 已入队列\n                        QUEUED:     1,\n                        // 正在上传\n                        PROGRESS:     2,\n                        // 上传出错\n                        ERROR:         3,\n                        // 上传成功\n                        COMPLETE:     4,\n                        // 上传取消\n                        CANCELLED:     5\n                    }\n             */\n            getStatus: function() {\n                return statusMap[ this.id ];\n            },\n\n            /**\n             * 获取文件原始信息。\n             * @return {*}\n             */\n            getSource: function() {\n                return this.source;\n            },\n\n            destroy: function() {\n                this.off();\n                delete statusMap[ this.id ];\n            }\n        });\n\n        Mediator.installTo( WUFile.prototype );\n\n        /**\n         * 文件状态值，具体包括以下几种类型：\n         * * `inited` 初始状态\n         * * `queued` 已经进入队列, 等待上传\n         * * `progress` 上传中\n         * * `complete` 上传完成。\n         * * `error` 上传出错，可重试\n         * * `interrupt` 上传中断，可续传。\n         * * `invalid` 文件不合格，不能重试上传。会自动从队列中移除。\n         * * `cancelled` 文件被移除。\n         * @property {Object} Status\n         * @namespace File\n         * @class File\n         * @static\n         */\n        WUFile.Status = {\n            INITED:     'inited',    // 初始状态\n            QUEUED:     'queued',    // 已经进入队列, 等待上传\n            PROGRESS:   'progress',    // 上传中\n            ERROR:      'error',    // 上传出错，可重试\n            COMPLETE:   'complete',    // 上传完成。\n            CANCELLED:  'cancelled',    // 上传取消。\n            INTERRUPT:  'interrupt',    // 上传中断，可续传。\n            INVALID:    'invalid'    // 文件不合格，不能重试上传。\n        };\n\n        return WUFile;\n    });\n\n    /**\n     * @fileOverview 文件队列\n     */\n    define('queue',[\n        'base',\n        'mediator',\n        'file'\n    ], function( Base, Mediator, WUFile ) {\n\n        var $ = Base.$,\n            STATUS = WUFile.Status;\n\n        /**\n         * 文件队列, 用来存储各个状态中的文件。\n         * @class Queue\n         * @extends Mediator\n         */\n        function Queue() {\n\n            /**\n             * 统计文件数。\n             * * `numOfQueue` 队列中的文件数。\n             * * `numOfSuccess` 上传成功的文件数\n             * * `numOfCancel` 被取消的文件数\n             * * `numOfProgress` 正在上传中的文件数\n             * * `numOfUploadFailed` 上传错误的文件数。\n             * * `numOfInvalid` 无效的文件数。\n             * * `numofDeleted` 被移除的文件数。\n             * @property {Object} stats\n             */\n            this.stats = {\n                numOfQueue: 0,\n                numOfSuccess: 0,\n                numOfCancel: 0,\n                numOfProgress: 0,\n                numOfUploadFailed: 0,\n                numOfInvalid: 0,\n                numofDeleted: 0,\n                numofInterrupt: 0\n            };\n\n            // 上传队列，仅包括等待上传的文件\n            this._queue = [];\n\n            // 存储所有文件\n            this._map = {};\n        }\n\n        $.extend( Queue.prototype, {\n\n            /**\n             * 将新文件加入对队列尾部\n             *\n             * @method append\n             * @param  {File} file   文件对象\n             */\n            append: function( file ) {\n                this._queue.push( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 将新文件加入对队列头部\n             *\n             * @method prepend\n             * @param  {File} file   文件对象\n             */\n            prepend: function( file ) {\n                this._queue.unshift( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 获取文件对象\n             *\n             * @method getFile\n             * @param  {String} fileId   文件ID\n             * @return {File}\n             */\n            getFile: function( fileId ) {\n                if ( typeof fileId !== 'string' ) {\n                    return fileId;\n                }\n                return this._map[ fileId ];\n            },\n\n            /**\n             * 从队列中取出一个指定状态的文件。\n             * @grammar fetch( status ) => File\n             * @method fetch\n             * @param {String} status [文件状态值](#WebUploader:File:File.Status)\n             * @return {File} [File](#WebUploader:File)\n             */\n            fetch: function( status ) {\n                var len = this._queue.length,\n                    i, file;\n\n                status = status || STATUS.QUEUED;\n\n                for ( i = 0; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( status === file.getStatus() ) {\n                        return file;\n                    }\n                }\n\n                return null;\n            },\n\n            /**\n             * 对队列进行排序，能够控制文件上传顺序。\n             * @grammar sort( fn ) => undefined\n             * @method sort\n             * @param {Function} fn 排序方法\n             */\n            sort: function( fn ) {\n                if ( typeof fn === 'function' ) {\n                    this._queue.sort( fn );\n                }\n            },\n\n            /**\n             * 获取指定类型的文件列表, 列表中每一个成员为[File](#WebUploader:File)对象。\n             * @grammar getFiles( [status1[, status2 ...]] ) => Array\n             * @method getFiles\n             * @param {String} [status] [文件状态值](#WebUploader:File:File.Status)\n             */\n            getFiles: function() {\n                var sts = [].slice.call( arguments, 0 ),\n                    ret = [],\n                    i = 0,\n                    len = this._queue.length,\n                    file;\n\n                for ( ; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( sts.length && !~$.inArray( file.getStatus(), sts ) ) {\n                        continue;\n                    }\n\n                    ret.push( file );\n                }\n\n                return ret;\n            },\n\n            /**\n             * 在队列中删除文件。\n             * @grammar removeFile( file ) => Array\n             * @method removeFile\n             * @param {File} 文件对象。\n             */\n            removeFile: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( existing ) {\n                    delete this._map[ file.id ];\n                    file.destroy();\n                    this.stats.numofDeleted++;\n                }\n            },\n\n            _fileAdded: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( !existing ) {\n                    this._map[ file.id ] = file;\n\n                    file.on( 'statuschange', function( cur, pre ) {\n                        me._onFileStatusChange( cur, pre );\n                    });\n                }\n            },\n\n            _onFileStatusChange: function( curStatus, preStatus ) {\n                var stats = this.stats;\n\n                switch ( preStatus ) {\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress--;\n                        break;\n\n                    case STATUS.QUEUED:\n                        stats.numOfQueue --;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed--;\n                        break;\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid--;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt--;\n                        break;\n                }\n\n                switch ( curStatus ) {\n                    case STATUS.QUEUED:\n                        stats.numOfQueue++;\n                        break;\n\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress++;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed++;\n                        break;\n\n                    case STATUS.COMPLETE:\n                        stats.numOfSuccess++;\n                        break;\n\n                    case STATUS.CANCELLED:\n                        stats.numOfCancel++;\n                        break;\n\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid++;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt++;\n                        break;\n                }\n            }\n\n        });\n\n        Mediator.installTo( Queue.prototype );\n\n        return Queue;\n    });\n    /**\n     * @fileOverview 队列\n     */\n    define('widgets/queue',[\n        'base',\n        'uploader',\n        'queue',\n        'file',\n        'lib/file',\n        'runtime/client',\n        'widgets/widget'\n    ], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {\n\n        var $ = Base.$,\n            rExt = /\\.\\w+$/,\n            Status = WUFile.Status;\n\n        return Uploader.register({\n            name: 'queue',\n\n            init: function( opts ) {\n                var me = this,\n                    deferred, len, i, item, arr, accept, runtime;\n\n                if ( $.isPlainObject( opts.accept ) ) {\n                    opts.accept = [ opts.accept ];\n                }\n\n                // accept中的中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].extensions;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = '\\\\.' + arr.join(',')\n                                .replace( /,/g, '$|\\\\.' )\n                                .replace( /\\*/g, '.*' ) + '$';\n                    }\n\n                    me.accept = new RegExp( accept, 'i' );\n                }\n\n                me.queue = new Queue();\n                me.stats = me.queue.stats;\n\n                // 如果当前不是html5运行时，那就算了。\n                // 不执行后续操作\n                if ( this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                // 创建一个 html5 运行时的 placeholder\n                // 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。\n                deferred = Base.Deferred();\n                this.placeholder = runtime = new RuntimeClient('Placeholder');\n                runtime.connectRuntime({\n                    runtimeOrder: 'html5'\n                }, function() {\n                    me._ruid = runtime.getRuid();\n                    deferred.resolve();\n                });\n                return deferred.promise();\n            },\n\n\n            // 为了支持外部直接添加一个原生File对象。\n            _wrapFile: function( file ) {\n                if ( !(file instanceof WUFile) ) {\n\n                    if ( !(file instanceof File) ) {\n                        if ( !this._ruid ) {\n                            throw new Error('Can\\'t add external files.');\n                        }\n                        file = new File( this._ruid, file );\n                    }\n\n                    file = new WUFile( file );\n                }\n\n                return file;\n            },\n\n            // 判断文件是否可以被加入队列\n            acceptFile: function( file ) {\n                var invalid = !file || !file.size || this.accept &&\n\n                        // 如果名字中有后缀，才做后缀白名单处理。\n                        rExt.exec( file.name ) && !this.accept.test( file.name );\n\n                return !invalid;\n            },\n\n\n            /**\n             * @event beforeFileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列之前触发，此事件的handler返回值为`false`，则此文件不会被添加进入队列。\n             * @for  Uploader\n             */\n\n            /**\n             * @event fileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列以后触发。\n             * @for  Uploader\n             */\n\n            _addFile: function( file ) {\n                var me = this;\n\n                file = me._wrapFile( file );\n\n                // 不过类型判断允许不允许，先派送 `beforeFileQueued`\n                if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {\n                    return;\n                }\n\n                // 类型不匹配，则派送错误事件，并返回。\n                if ( !me.acceptFile( file ) ) {\n                    me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );\n                    return;\n                }\n\n                me.queue.append( file );\n                me.owner.trigger( 'fileQueued', file );\n                return file;\n            },\n\n            getFile: function( fileId ) {\n                return this.queue.getFile( fileId );\n            },\n\n            /**\n             * @event filesQueued\n             * @param {File} files 数组，内容为原始File(lib/File）对象。\n             * @description 当一批文件添加进队列以后触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @property {Boolean} [auto=false]\n             * @namespace options\n             * @for Uploader\n             * @description 设置为 true 后，不需要手动调用上传，有文件选择即开始上传。\n             *\n             */\n\n            /**\n             * @method addFiles\n             * @grammar addFiles( file ) => undefined\n             * @grammar addFiles( [file1, file2 ...] ) => undefined\n             * @param {Array of File or File} [files] Files 对象 数组\n             * @description 添加文件到队列\n             * @for  Uploader\n             */\n            addFile: function( files ) {\n                var me = this;\n\n                if ( !files.length ) {\n                    files = [ files ];\n                }\n\n                files = $.map( files, function( file ) {\n                    return me._addFile( file );\n                });\n\n                me.owner.trigger( 'filesQueued', files );\n\n                if ( me.options.auto ) {\n                    setTimeout(function() {\n                        me.request('start-upload');\n                    }, 20 );\n                }\n            },\n\n            getStats: function() {\n                return this.stats;\n            },\n\n            /**\n             * @event fileDequeued\n             * @param {File} file File对象\n             * @description 当文件被移除队列后触发。\n             * @for  Uploader\n             */\n\n             /**\n             * @method removeFile\n             * @grammar removeFile( file ) => undefined\n             * @grammar removeFile( id ) => undefined\n             * @grammar removeFile( file, true ) => undefined\n             * @grammar removeFile( id, true ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 移除某一文件, 默认只会标记文件状态为已取消，如果第二个参数为 `true` 则会从 queue 中移除。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.removeFile( file );\n             * })\n             */\n            removeFile: function( file, remove ) {\n                var me = this;\n\n                file = file.id ? file : me.queue.getFile( file );\n\n                this.request( 'cancel-file', file );\n\n                if ( remove ) {\n                    this.queue.removeFile( file );\n                }\n            },\n\n            /**\n             * @method getFiles\n             * @grammar getFiles() => Array\n             * @grammar getFiles( status1, status2, status... ) => Array\n             * @description 返回指定状态的文件集合，不传参数将返回所有状态的文件。\n             * @for  Uploader\n             * @example\n             * console.log( uploader.getFiles() );    // => all files\n             * console.log( uploader.getFiles('error') )    // => all error files.\n             */\n            getFiles: function() {\n                return this.queue.getFiles.apply( this.queue, arguments );\n            },\n\n            fetchFile: function() {\n                return this.queue.fetch.apply( this.queue, arguments );\n            },\n\n            /**\n             * @method retry\n             * @grammar retry() => undefined\n             * @grammar retry( file ) => undefined\n             * @description 重试上传，重试指定文件，或者从出错的文件开始重新上传。\n             * @for  Uploader\n             * @example\n             * function retry() {\n             *     uploader.retry();\n             * }\n             */\n            retry: function( file, noForceStart ) {\n                var me = this,\n                    files, i, len;\n\n                if ( file ) {\n                    file = file.id ? file : me.queue.getFile( file );\n                    file.setStatus( Status.QUEUED );\n                    noForceStart || me.request('start-upload');\n                    return;\n                }\n\n                files = me.queue.getFiles( Status.ERROR );\n                i = 0;\n                len = files.length;\n\n                for ( ; i < len; i++ ) {\n                    file = files[ i ];\n                    file.setStatus( Status.QUEUED );\n                }\n\n                me.request('start-upload');\n            },\n\n            /**\n             * @method sort\n             * @grammar sort( fn ) => undefined\n             * @description 排序队列中的文件，在上传之前调整可以控制上传顺序。\n             * @for  Uploader\n             */\n            sortFiles: function() {\n                return this.queue.sort.apply( this.queue, arguments );\n            },\n\n            /**\n             * @event reset\n             * @description 当 uploader 被重置的时候触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @method reset\n             * @grammar reset() => undefined\n             * @description 重置uploader。目前只重置了队列。\n             * @for  Uploader\n             * @example\n             * uploader.reset();\n             */\n            reset: function() {\n                this.owner.trigger('reset');\n                this.queue = new Queue();\n                this.stats = this.queue.stats;\n            },\n\n            destroy: function() {\n                this.reset();\n                this.placeholder && this.placeholder.destroy();\n            }\n        });\n\n    });\n    /**\n     * @fileOverview 添加获取Runtime相关信息的方法。\n     */\n    define('widgets/runtime',[\n        'uploader',\n        'runtime/runtime',\n        'widgets/widget'\n    ], function( Uploader, Runtime ) {\n\n        Uploader.support = function() {\n            return Runtime.hasRuntime.apply( Runtime, arguments );\n        };\n\n        /**\n         * @property {Object} [runtimeOrder=html5,flash]\n         * @namespace options\n         * @for Uploader\n         * @description 指定运行时启动顺序。默认会想尝试 html5 是否支持，如果支持则使用 html5, 否则则使用 flash.\n         *\n         * 可以将此值设置成 `flash`，来强制使用 flash 运行时。\n         */\n\n        return Uploader.register({\n            name: 'runtime',\n\n            init: function() {\n                if ( !this.predictRuntimeType() ) {\n                    throw Error('Runtime Error');\n                }\n            },\n\n            /**\n             * 预测Uploader将采用哪个`Runtime`\n             * @grammar predictRuntimeType() => String\n             * @method predictRuntimeType\n             * @for  Uploader\n             */\n            predictRuntimeType: function() {\n                var orders = this.options.runtimeOrder || Runtime.orders,\n                    type = this.type,\n                    i, len;\n\n                if ( !type ) {\n                    orders = orders.split( /\\s*,\\s*/g );\n\n                    for ( i = 0, len = orders.length; i < len; i++ ) {\n                        if ( Runtime.hasRuntime( orders[ i ] ) ) {\n                            this.type = type = orders[ i ];\n                            break;\n                        }\n                    }\n                }\n\n                return type;\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     */\n    define('lib/transport',[\n        'base',\n        'runtime/client',\n        'mediator'\n    ], function( Base, RuntimeClient, Mediator ) {\n\n        var $ = Base.$;\n\n        function Transport( opts ) {\n            var me = this;\n\n            opts = me.options = $.extend( true, {}, Transport.options, opts || {} );\n            RuntimeClient.call( this, 'Transport' );\n\n            this._blob = null;\n            this._formData = opts.formData || {};\n            this._headers = opts.headers || {};\n\n            this.on( 'progress', this._timeout );\n            this.on( 'load error', function() {\n                me.trigger( 'progress', 1 );\n                clearTimeout( me._timer );\n            });\n        }\n\n        Transport.options = {\n            server: '',\n            method: 'POST',\n\n            // 跨域时，是否允许携带cookie, 只有html5 runtime才有效\n            withCredentials: false,\n            fileVal: 'file',\n            timeout: 2 * 60 * 1000,    // 2分钟\n            formData: {},\n            headers: {},\n            sendAsBinary: false\n        };\n\n        $.extend( Transport.prototype, {\n\n            // 添加Blob, 只能添加一次，最后一次有效。\n            appendBlob: function( key, blob, filename ) {\n                var me = this,\n                    opts = me.options;\n\n                if ( me.getRuid() ) {\n                    me.disconnectRuntime();\n                }\n\n                // 连接到blob归属的同一个runtime.\n                me.connectRuntime( blob.ruid, function() {\n                    me.exec('init');\n                });\n\n                me._blob = blob;\n                opts.fileVal = key || opts.fileVal;\n                opts.filename = filename || opts.filename;\n            },\n\n            // 添加其他字段\n            append: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._formData, key );\n                } else {\n                    this._formData[ key ] = value;\n                }\n            },\n\n            setRequestHeader: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._headers, key );\n                } else {\n                    this._headers[ key ] = value;\n                }\n            },\n\n            send: function( method ) {\n                this.exec( 'send', method );\n                this._timeout();\n            },\n\n            abort: function() {\n                clearTimeout( this._timer );\n                return this.exec('abort');\n            },\n\n            destroy: function() {\n                this.trigger('destroy');\n                this.off();\n                this.exec('destroy');\n                this.disconnectRuntime();\n            },\n\n            getResponse: function() {\n                return this.exec('getResponse');\n            },\n\n            getResponseAsJson: function() {\n                return this.exec('getResponseAsJson');\n            },\n\n            getStatus: function() {\n                return this.exec('getStatus');\n            },\n\n            _timeout: function() {\n                var me = this,\n                    duration = me.options.timeout;\n\n                if ( !duration ) {\n                    return;\n                }\n\n                clearTimeout( me._timer );\n                me._timer = setTimeout(function() {\n                    me.abort();\n                    me.trigger( 'error', 'timeout' );\n                }, duration );\n            }\n\n        });\n\n        // 让Transport具备事件功能。\n        Mediator.installTo( Transport.prototype );\n\n        return Transport;\n    });\n    /**\n     * @fileOverview 负责文件上传相关。\n     */\n    define('widgets/upload',[\n        'base',\n        'uploader',\n        'file',\n        'lib/transport',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile, Transport ) {\n\n        var $ = Base.$,\n            isPromise = Base.isPromise,\n            Status = WUFile.Status;\n\n        // 添加默认配置项\n        $.extend( Uploader.options, {\n\n\n            /**\n             * @property {Boolean} [prepareNextFile=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否允许在文件传输时提前把下一个文件准备好。\n             * 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。\n             * 如果能提前在当前文件传输期处理，可以节省总体耗时。\n             */\n            prepareNextFile: false,\n\n            /**\n             * @property {Boolean} [chunked=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否要分片处理大文件上传。\n             */\n            chunked: false,\n\n            /**\n             * @property {Boolean} [chunkSize=5242880]\n             * @namespace options\n             * @for Uploader\n             * @description 如果要分片，分多大一片？ 默认大小为5M.\n             */\n            chunkSize: 5 * 1024 * 1024,\n\n            /**\n             * @property {Boolean} [chunkRetry=2]\n             * @namespace options\n             * @for Uploader\n             * @description 如果某个分片由于网络问题出错，允许自动重传多少次？\n             */\n            chunkRetry: 2,\n\n            /**\n             * @property {Boolean} [threads=3]\n             * @namespace options\n             * @for Uploader\n             * @description 上传并发数。允许同时最大上传进程数。\n             */\n            threads: 3,\n\n\n            /**\n             * @property {Object} [formData={}]\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传请求的参数表，每次发送都会发送此对象中的参数。\n             */\n            formData: {}\n\n            /**\n             * @property {Object} [fileVal='file']\n             * @namespace options\n             * @for Uploader\n             * @description 设置文件上传域的name。\n             */\n\n            /**\n             * @property {Object} [method='POST']\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传方式，`POST`或者`GET`。\n             */\n\n            /**\n             * @property {Object} [sendAsBinary=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否已二进制的流的方式发送文件，这样整个上传内容`php://input`都为文件内容，\n             * 其他参数在$_GET数组中。\n             */\n        });\n\n        // 负责将文件切片。\n        function CuteFile( file, chunkSize ) {\n            var pending = [],\n                blob = file.source,\n                total = blob.size,\n                chunks = chunkSize ? Math.ceil( total / chunkSize ) : 1,\n                start = 0,\n                index = 0,\n                len, api;\n\n            api = {\n                file: file,\n\n                has: function() {\n                    return !!pending.length;\n                },\n\n                shift: function() {\n                    return pending.shift();\n                },\n\n                unshift: function( block ) {\n                    pending.unshift( block );\n                }\n            };\n\n            while ( index < chunks ) {\n                len = Math.min( chunkSize, total - start );\n\n                pending.push({\n                    file: file,\n                    start: start,\n                    end: chunkSize ? (start + len) : total,\n                    total: total,\n                    chunks: chunks,\n                    chunk: index++,\n                    cuted: api\n                });\n                start += len;\n            }\n\n            file.blocks = pending.concat();\n            file.remaning = pending.length;\n\n            return api;\n        }\n\n        Uploader.register({\n            name: 'upload',\n\n            init: function() {\n                var owner = this.owner,\n                    me = this;\n\n                this.runing = false;\n                this.progress = false;\n\n                owner\n                    .on( 'startUpload', function() {\n                        me.progress = true;\n                    })\n                    .on( 'uploadFinished', function() {\n                        me.progress = false;\n                    });\n\n                // 记录当前正在传的数据，跟threads相关\n                this.pool = [];\n\n                // 缓存分好片的文件。\n                this.stack = [];\n\n                // 缓存即将上传的文件。\n                this.pending = [];\n\n                // 跟踪还有多少分片在上传中但是没有完成上传。\n                this.remaning = 0;\n                this.__tick = Base.bindFn( this._tick, this );\n\n                owner.on( 'uploadComplete', function( file ) {\n\n                    // 把其他块取消了。\n                    file.blocks && $.each( file.blocks, function( _, v ) {\n                        v.transport && (v.transport.abort(), v.transport.destroy());\n                        delete v.transport;\n                    });\n\n                    delete file.blocks;\n                    delete file.remaning;\n                });\n            },\n\n            reset: function() {\n                this.request( 'stop-upload', true );\n                this.runing = false;\n                this.pool = [];\n                this.stack = [];\n                this.pending = [];\n                this.remaning = 0;\n                this._trigged = false;\n                this._promise = null;\n            },\n\n            /**\n             * @event startUpload\n             * @description 当开始上传流程时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 开始上传。此方法可以从初始状态调用开始上传流程，也可以从暂停状态调用，继续上传流程。\n             *\n             * 可以指定开始某一个文件。\n             * @grammar upload() => undefined\n             * @grammar upload( file | fileId) => undefined\n             * @method upload\n             * @for  Uploader\n             */\n            startUpload: function(file) {\n                var me = this;\n\n                // 移出invalid的文件\n                $.each( me.request( 'get-files', Status.INVALID ), function() {\n                    me.request( 'remove-file', this );\n                });\n\n                // 如果指定了开始某个文件，则只开始指定文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        $.each( me.pool, function( _, v ) {\n\n                            // 之前暂停过。\n                            if (v.file !== file) {\n                                return;\n                            }\n\n                            v.transport && v.transport.send();\n                        });\n\n                        file.setStatus( Status.QUEUED );\n                    } else if (file.getStatus() === Status.PROGRESS) {\n                        return;\n                    } else {\n                        file.setStatus( Status.QUEUED );\n                    }\n                } else {\n                    $.each( me.request( 'get-files', [ Status.INITED ] ), function() {\n                        this.setStatus( Status.QUEUED );\n                    });\n                }\n\n                if ( me.runing ) {\n                    return;\n                }\n\n                me.runing = true;\n\n                var files = [];\n\n                // 如果有暂停的，则续传\n                $.each( me.pool, function( _, v ) {\n                    var file = v.file;\n\n                    if ( file.getStatus() === Status.INTERRUPT ) {\n                        files.push(file);\n                        me._trigged = false;\n                        v.transport && v.transport.send();\n                    }\n                });\n\n                var file;\n                while ( (file = files.shift()) ) {\n                    file.setStatus( Status.PROGRESS );\n                }\n\n                file || $.each( me.request( 'get-files',\n                        Status.INTERRUPT ), function() {\n                    this.setStatus( Status.PROGRESS );\n                });\n\n                me._trigged = false;\n                Base.nextTick( me.__tick );\n                me.owner.trigger('startUpload');\n            },\n\n            /**\n             * @event stopUpload\n             * @description 当开始上传流程暂停时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 暂停上传。第一个参数为是否中断上传当前正在上传的文件。\n             *\n             * 如果第一个参数是文件，则只暂停指定文件。\n             * @grammar stop() => undefined\n             * @grammar stop( true ) => undefined\n             * @grammar stop( file ) => undefined\n             * @method stop\n             * @for  Uploader\n             */\n            stopUpload: function( file, interrupt ) {\n                var me = this;\n\n                if (file === true) {\n                    interrupt = file;\n                    file = null;\n                }\n\n                if ( me.runing === false ) {\n                    return;\n                }\n\n                // 如果只是暂停某个文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if ( file.getStatus() !== Status.PROGRESS &&\n                            file.getStatus() !== Status.QUEUED ) {\n                        return;\n                    }\n\n                    file.setStatus( Status.INTERRUPT );\n                    $.each( me.pool, function( _, v ) {\n\n                        // 只 abort 指定的文件。\n                        if (v.file !== file) {\n                            return;\n                        }\n\n                        v.transport && v.transport.abort();\n                        me._putback(v);\n                        me._popBlock(v);\n                    });\n\n                    return Base.nextTick( me.__tick );\n                }\n\n                me.runing = false;\n\n                if (this._promise && this._promise.file) {\n                    this._promise.file.setStatus( Status.INTERRUPT );\n                }\n\n                interrupt && $.each( me.pool, function( _, v ) {\n                    v.transport && v.transport.abort();\n                    v.file.setStatus( Status.INTERRUPT );\n                });\n\n                me.owner.trigger('stopUpload');\n            },\n\n            /**\n             * @method cancelFile\n             * @grammar cancelFile( file ) => undefined\n             * @grammar cancelFile( id ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 标记文件状态为已取消, 同时将中断文件传输。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.cancelFile( file );\n             * })\n             */\n            cancelFile: function( file ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                file.setStatus( Status.CANCELLED );\n                this.owner.trigger( 'fileDequeued', file );\n            },\n\n            /**\n             * 判断`Uplaode`r是否正在上传中。\n             * @grammar isInProgress() => Boolean\n             * @method isInProgress\n             * @for  Uploader\n             */\n            isInProgress: function() {\n                return !!this.progress;\n            },\n\n            _getStats: function() {\n                return this.request('get-stats');\n            },\n\n            /**\n             * 掉过一个文件上传，直接标记指定文件为已上传状态。\n             * @grammar skipFile( file ) => undefined\n             * @method skipFile\n             * @for  Uploader\n             */\n            skipFile: function( file, status ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                file.setStatus( status || Status.COMPLETE );\n                file.skipped = true;\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                this.owner.trigger( 'uploadSkip', file );\n            },\n\n            /**\n             * @event uploadFinished\n             * @description 当所有文件上传结束时触发。\n             * @for  Uploader\n             */\n            _tick: function() {\n                var me = this,\n                    opts = me.options,\n                    fn, val;\n\n                // 上一个promise还没有结束，则等待完成后再执行。\n                if ( me._promise ) {\n                    return me._promise.always( me.__tick );\n                }\n\n                // 还有位置，且还有文件要处理的话。\n                if ( me.pool.length < opts.threads && (val = me._nextBlock()) ) {\n                    me._trigged = false;\n\n                    fn = function( val ) {\n                        me._promise = null;\n\n                        // 有可能是reject过来的，所以要检测val的类型。\n                        val && val.file && me._startSend( val );\n                        Base.nextTick( me.__tick );\n                    };\n\n                    me._promise = isPromise( val ) ? val.always( fn ) : fn( val );\n\n                // 没有要上传的了，且没有正在传输的了。\n                } else if ( !me.remaning && !me._getStats().numOfQueue &&\n                    !me._getStats().numofInterrupt ) {\n                    me.runing = false;\n\n                    me._trigged || Base.nextTick(function() {\n                        me.owner.trigger('uploadFinished');\n                    });\n                    me._trigged = true;\n                }\n            },\n\n            _putback: function(block) {\n                var idx;\n\n                block.cuted.unshift(block);\n                idx = this.stack.indexOf(block.cuted);\n\n                if (!~idx) {\n                    this.stack.unshift(block.cuted);\n                }\n            },\n\n            _getStack: function() {\n                var i = 0,\n                    act;\n\n                while ( (act = this.stack[ i++ ]) ) {\n                    if ( act.has() && act.file.getStatus() === Status.PROGRESS ) {\n                        return act;\n                    } else if (!act.has() ||\n                            act.file.getStatus() !== Status.PROGRESS &&\n                            act.file.getStatus() !== Status.INTERRUPT ) {\n\n                        // 把已经处理完了的，或者，状态为非 progress（上传中）、\n                        // interupt（暂停中） 的移除。\n                        this.stack.splice( --i, 1 );\n                    }\n                }\n\n                return null;\n            },\n\n            _nextBlock: function() {\n                var me = this,\n                    opts = me.options,\n                    act, next, done, preparing;\n\n                // 如果当前文件还有没有需要传输的，则直接返回剩下的。\n                if ( (act = this._getStack()) ) {\n\n                    // 是否提前准备下一个文件\n                    if ( opts.prepareNextFile && !me.pending.length ) {\n                        me._prepareNextFile();\n                    }\n\n                    return act.shift();\n\n                // 否则，如果正在运行，则准备下一个文件，并等待完成后返回下个分片。\n                } else if ( me.runing ) {\n\n                    // 如果缓存中有，则直接在缓存中取，没有则去queue中取。\n                    if ( !me.pending.length && me._getStats().numOfQueue ) {\n                        me._prepareNextFile();\n                    }\n\n                    next = me.pending.shift();\n                    done = function( file ) {\n                        if ( !file ) {\n                            return null;\n                        }\n\n                        act = CuteFile( file, opts.chunked ? opts.chunkSize : 0 );\n                        me.stack.push(act);\n                        return act.shift();\n                    };\n\n                    // 文件可能还在prepare中，也有可能已经完全准备好了。\n                    if ( isPromise( next) ) {\n                        preparing = next.file;\n                        next = next[ next.pipe ? 'pipe' : 'then' ]( done );\n                        next.file = preparing;\n                        return next;\n                    }\n\n                    return done( next );\n                }\n            },\n\n\n            /**\n             * @event uploadStart\n             * @param {File} file File对象\n             * @description 某个文件开始上传前触发，一个文件只会触发一次。\n             * @for  Uploader\n             */\n            _prepareNextFile: function() {\n                var me = this,\n                    file = me.request('fetch-file'),\n                    pending = me.pending,\n                    promise;\n\n                if ( file ) {\n                    promise = me.request( 'before-send-file', file, function() {\n\n                        // 有可能文件被skip掉了。文件被skip掉后，状态坑定不是Queued.\n                        if ( file.getStatus() === Status.PROGRESS ||\n                            file.getStatus() === Status.INTERRUPT ) {\n                            return file;\n                        }\n\n                        return me._finishFile( file );\n                    });\n\n                    me.owner.trigger( 'uploadStart', file );\n                    file.setStatus( Status.PROGRESS );\n\n                    promise.file = file;\n\n                    // 如果还在pending中，则替换成文件本身。\n                    promise.done(function() {\n                        var idx = $.inArray( promise, pending );\n\n                        ~idx && pending.splice( idx, 1, file );\n                    });\n\n                    // befeore-send-file的钩子就有错误发生。\n                    promise.fail(function( reason ) {\n                        file.setStatus( Status.ERROR, reason );\n                        me.owner.trigger( 'uploadError', file, reason );\n                        me.owner.trigger( 'uploadComplete', file );\n                    });\n\n                    pending.push( promise );\n                }\n            },\n\n            // 让出位置了，可以让其他分片开始上传\n            _popBlock: function( block ) {\n                var idx = $.inArray( block, this.pool );\n\n                this.pool.splice( idx, 1 );\n                block.file.remaning--;\n                this.remaning--;\n            },\n\n            // 开始上传，可以被掉过。如果promise被reject了，则表示跳过此分片。\n            _startSend: function( block ) {\n                var me = this,\n                    file = block.file,\n                    promise;\n\n                // 有可能在 before-send-file 的 promise 期间改变了文件状态。\n                // 如：暂停，取消\n                // 我们不能中断 promise, 但是可以在 promise 完后，不做上传操作。\n                if ( file.getStatus() !== Status.PROGRESS ) {\n\n                    // 如果是中断，则还需要放回去。\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        me._putback(block);\n                    }\n\n                    return;\n                }\n\n                me.pool.push( block );\n                me.remaning++;\n\n                // 如果没有分片，则直接使用原始的。\n                // 不会丢失content-type信息。\n                block.blob = block.chunks === 1 ? file.source :\n                        file.source.slice( block.start, block.end );\n\n                // hook, 每个分片发送之前可能要做些异步的事情。\n                promise = me.request( 'before-send', block, function() {\n\n                    // 有可能文件已经上传出错了，所以不需要再传输了。\n                    if ( file.getStatus() === Status.PROGRESS ) {\n                        me._doSend( block );\n                    } else {\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n\n                // 如果为fail了，则跳过此分片。\n                promise.fail(function() {\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file ).always(function() {\n                            block.percentage = 1;\n                            me._popBlock( block );\n                            me.owner.trigger( 'uploadComplete', file );\n                            Base.nextTick( me.__tick );\n                        });\n                    } else {\n                        block.percentage = 1;\n                        me.updateFileProgress( file );\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n            },\n\n\n            /**\n             * @event uploadBeforeSend\n             * @param {Object} object\n             * @param {Object} data 默认的上传参数，可以扩展此对象来控制上传参数。\n             * @param {Object} headers 可以扩展此对象来控制上传头部。\n             * @description 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadAccept\n             * @param {Object} object\n             * @param {Object} ret 服务端的返回数据，json格式，如果服务端不是json格式，从ret._raw中取数据，自行解析。\n             * @description 当某个文件上传到服务端响应后，会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为`false`, 则此文件将派送`server`类型的`uploadError`事件。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadProgress\n             * @param {File} file File对象\n             * @param {Number} percentage 上传进度\n             * @description 上传过程中触发，携带上传进度。\n             * @for  Uploader\n             */\n\n\n            /**\n             * @event uploadError\n             * @param {File} file File对象\n             * @param {String} reason 出错的code\n             * @description 当文件上传出错时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadSuccess\n             * @param {File} file File对象\n             * @param {Object} response 服务端返回的数据\n             * @description 当文件上传成功时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadComplete\n             * @param {File} [file] File对象\n             * @description 不管成功或者失败，文件上传完成时触发。\n             * @for  Uploader\n             */\n\n            // 做上传操作。\n            _doSend: function( block ) {\n                var me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    file = block.file,\n                    tr = new Transport( opts ),\n                    data = $.extend({}, opts.formData ),\n                    headers = $.extend({}, opts.headers ),\n                    requestAccept, ret;\n\n                block.transport = tr;\n\n                tr.on( 'destroy', function() {\n                    delete block.transport;\n                    me._popBlock( block );\n                    Base.nextTick( me.__tick );\n                });\n\n                // 广播上传进度。以文件为单位。\n                tr.on( 'progress', function( percentage ) {\n                    block.percentage = percentage;\n                    me.updateFileProgress( file );\n                });\n\n                // 用来询问，是否返回的结果是有错误的。\n                requestAccept = function( reject ) {\n                    var fn;\n\n                    ret = tr.getResponseAsJson() || {};\n                    ret._raw = tr.getResponse();\n                    fn = function( value ) {\n                        reject = value;\n                    };\n\n                    // 服务端响应了，不代表成功了，询问是否响应正确。\n                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {\n                        reject = reject || 'server';\n                    }\n\n                    return reject;\n                };\n\n                // 尝试重试，然后广播文件上传出错。\n                tr.on( 'error', function( type, flag ) {\n                    block.retried = block.retried || 0;\n\n                    // 自动重试\n                    if ( block.chunks > 1 && ~'http,abort'.indexOf( type ) &&\n                            block.retried < opts.chunkRetry ) {\n\n                        block.retried++;\n                        tr.send();\n\n                    } else {\n\n                        // http status 500 ~ 600\n                        if ( !flag && type === 'server' ) {\n                            type = requestAccept( type );\n                        }\n\n                        file.setStatus( Status.ERROR, type );\n                        owner.trigger( 'uploadError', file, type );\n                        owner.trigger( 'uploadComplete', file );\n                    }\n                });\n\n                // 上传成功\n                tr.on( 'load', function() {\n                    var reason;\n\n                    // 如果非预期，转向上传出错。\n                    if ( (reason = requestAccept()) ) {\n                        tr.trigger( 'error', reason, true );\n                        return;\n                    }\n\n                    // 全部上传完成。\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file, ret );\n                    } else {\n                        tr.destroy();\n                    }\n                });\n\n                // 配置默认的上传字段。\n                data = $.extend( data, {\n                    id: file.id,\n                    name: file.name,\n                    type: file.type,\n                    lastModifiedDate: file.lastModifiedDate,\n                    size: file.size\n                });\n\n                block.chunks > 1 && $.extend( data, {\n                    chunks: block.chunks,\n                    chunk: block.chunk\n                });\n\n                // 在发送之间可以添加字段什么的。。。\n                // 如果默认的字段不够使用，可以通过监听此事件来扩展\n                owner.trigger( 'uploadBeforeSend', block, data, headers );\n\n                // 开始发送。\n                tr.appendBlob( opts.fileVal, block.blob, file.name );\n                tr.append( data );\n                tr.setRequestHeader( headers );\n                tr.send();\n            },\n\n            // 完成上传。\n            _finishFile: function( file, ret, hds ) {\n                var owner = this.owner;\n\n                return owner\n                        .request( 'after-send-file', arguments, function() {\n                            file.setStatus( Status.COMPLETE );\n                            owner.trigger( 'uploadSuccess', file, ret, hds );\n                        })\n                        .fail(function( reason ) {\n\n                            // 如果外部已经标记为invalid什么的，不再改状态。\n                            if ( file.getStatus() === Status.PROGRESS ) {\n                                file.setStatus( Status.ERROR, reason );\n                            }\n\n                            owner.trigger( 'uploadError', file, reason );\n                        })\n                        .always(function() {\n                            owner.trigger( 'uploadComplete', file );\n                        });\n            },\n\n            updateFileProgress: function(file) {\n                var totalPercent = 0,\n                    uploaded = 0;\n\n                if (!file.blocks) {\n                    return;\n                }\n\n                $.each( file.blocks, function( _, v ) {\n                    uploaded += (v.percentage || 0) * (v.end - v.start);\n                });\n\n                totalPercent = uploaded / file.size;\n                this.owner.trigger( 'uploadProgress', file, totalPercent || 0 );\n            }\n\n        });\n    });\n    /**\n     * @fileOverview 各种验证，包括文件总大小是否超出、单文件是否超出和文件是否重复。\n     */\n\n    define('widgets/validator',[\n        'base',\n        'uploader',\n        'file',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile ) {\n\n        var $ = Base.$,\n            validators = {},\n            api;\n\n        /**\n         * @event error\n         * @param {String} type 错误类型。\n         * @description 当validate不通过时，会以派送错误事件的形式通知调用者。通过`upload.on('error', handler)`可以捕获到此类错误，目前有以下错误会在特定的情况下派送错来。\n         *\n         * * `Q_EXCEED_NUM_LIMIT` 在设置了`fileNumLimit`且尝试给`uploader`添加的文件数量超出这个值时派送。\n         * * `Q_EXCEED_SIZE_LIMIT` 在设置了`Q_EXCEED_SIZE_LIMIT`且尝试给`uploader`添加的文件总大小超出这个值时派送。\n         * * `Q_TYPE_DENIED` 当文件类型不满足时触发。。\n         * @for  Uploader\n         */\n\n        // 暴露给外面的api\n        api = {\n\n            // 添加验证器\n            addValidator: function( type, cb ) {\n                validators[ type ] = cb;\n            },\n\n            // 移除验证器\n            removeValidator: function( type ) {\n                delete validators[ type ];\n            }\n        };\n\n        // 在Uploader初始化的时候启动Validators的初始化\n        Uploader.register({\n            name: 'validator',\n\n            init: function() {\n                var me = this;\n                Base.nextTick(function() {\n                    $.each( validators, function() {\n                        this.call( me.owner );\n                    });\n                });\n            }\n        });\n\n        /**\n         * @property {int} [fileNumLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总数量, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileNumLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileNumLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( count >= max && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_NUM_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return count >= max ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function() {\n                count++;\n            });\n\n            uploader.on( 'fileDequeued', function() {\n                count--;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n\n        /**\n         * @property {int} [fileSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileSizeLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var invalid = count + file.size > max;\n\n                if ( invalid && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_SIZE_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return invalid ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                count += file.size;\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                count -= file.size;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n        /**\n         * @property {int} [fileSingleSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证单个文件大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSingleSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                max = opts.fileSingleSizeLimit;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( file.size > max ) {\n                    file.setStatus( WUFile.Status.INVALID, 'exceed_size' );\n                    this.trigger( 'error', 'F_EXCEED_SIZE', max, file );\n                    return false;\n                }\n\n            });\n\n        });\n\n        /**\n         * @property {Boolean} [duplicate=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 去重， 根据文件名字、文件大小和最后修改时间来生成hash Key.\n         */\n        api.addValidator( 'duplicate', function() {\n            var uploader = this,\n                opts = uploader.options,\n                mapping = {};\n\n            if ( opts.duplicate ) {\n                return;\n            }\n\n            function hashString( str ) {\n                var hash = 0,\n                    i = 0,\n                    len = str.length,\n                    _char;\n\n                for ( ; i < len; i++ ) {\n                    _char = str.charCodeAt( i );\n                    hash = _char + (hash << 6) + (hash << 16) - hash;\n                }\n\n                return hash;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var hash = file.__hash || (file.__hash = hashString( file.name +\n                        file.size + file.lastModifiedDate ));\n\n                // 已经重复了\n                if ( mapping[ hash ] ) {\n                    this.trigger( 'error', 'F_DUPLICATE', file );\n                    return false;\n                }\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (mapping[ hash ] = true);\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (delete mapping[ hash ]);\n            });\n\n            uploader.on( 'reset', function() {\n                mapping = {};\n            });\n        });\n\n        return api;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/compbase',[],function() {\n\n        function CompBase( owner, runtime ) {\n\n            this.owner = owner;\n            this.options = owner.options;\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.getRuid = function() {\n                return runtime.uid;\n            };\n\n            this.trigger = function() {\n                return owner.trigger.apply( owner, arguments );\n            };\n        }\n\n        return CompBase;\n    });\n    /**\n     * @fileOverview Html5Runtime\n     */\n    define('runtime/html5/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var type = 'html5',\n            components = {};\n\n        function Html5Runtime() {\n            var pool = {},\n                me = this,\n                destroy = this.destroy;\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                if ( components[ comp ] ) {\n                    instance = pool[ uid ] = pool[ uid ] ||\n                            new components[ comp ]( client, me );\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n            };\n\n            me.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n        }\n\n        Base.inherits( Runtime, {\n            constructor: Html5Runtime,\n\n            // 不需要连接其他程序，直接执行callback\n            init: function() {\n                var me = this;\n                setTimeout(function() {\n                    me.trigger('ready');\n                }, 1 );\n            }\n\n        });\n\n        // 注册Components\n        Html5Runtime.register = function( name, component ) {\n            var klass = components[ name ] = Base.inherits( CompBase, component );\n            return klass;\n        };\n\n        // 注册html5运行时。\n        // 只有在支持的前提下注册。\n        if ( window.Blob && window.FileReader && window.DataView ) {\n            Runtime.addRuntime( type, Html5Runtime );\n        }\n\n        return Html5Runtime;\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/html5/blob',[\n        'runtime/html5/runtime',\n        'lib/blob'\n    ], function( Html5Runtime, Blob ) {\n\n        return Html5Runtime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.owner.source,\n                    slice = blob.slice || blob.webkitSlice || blob.mozSlice;\n\n                blob = slice.call( blob, start, end );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/dnd',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        var $ = Base.$,\n            prefix = 'webuploader-dnd-';\n\n        return Html5Runtime.register( 'DragAndDrop', {\n            init: function() {\n                var elem = this.elem = this.options.container;\n\n                this.dragEnterHandler = Base.bindFn( this._dragEnterHandler, this );\n                this.dragOverHandler = Base.bindFn( this._dragOverHandler, this );\n                this.dragLeaveHandler = Base.bindFn( this._dragLeaveHandler, this );\n                this.dropHandler = Base.bindFn( this._dropHandler, this );\n                this.dndOver = false;\n\n                elem.on( 'dragenter', this.dragEnterHandler );\n                elem.on( 'dragover', this.dragOverHandler );\n                elem.on( 'dragleave', this.dragLeaveHandler );\n                elem.on( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).on( 'dragover', this.dragOverHandler );\n                    $( document ).on( 'drop', this.dropHandler );\n                }\n            },\n\n            _dragEnterHandler: function( e ) {\n                var me = this,\n                    denied = me._denied || false,\n                    items;\n\n                e = e.originalEvent || e;\n\n                if ( !me.dndOver ) {\n                    me.dndOver = true;\n\n                    // 注意只有 chrome 支持。\n                    items = e.dataTransfer.items;\n\n                    if ( items && items.length ) {\n                        me._denied = denied = !me.trigger( 'accept', items );\n                    }\n\n                    me.elem.addClass( prefix + 'over' );\n                    me.elem[ denied ? 'addClass' :\n                            'removeClass' ]( prefix + 'denied' );\n                }\n\n                e.dataTransfer.dropEffect = denied ? 'none' : 'copy';\n\n                return false;\n            },\n\n            _dragOverHandler: function( e ) {\n                // 只处理框内的。\n                var parentElem = this.elem.parent().get( 0 );\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                clearTimeout( this._leaveTimer );\n                this._dragEnterHandler.call( this, e );\n\n                return false;\n            },\n\n            _dragLeaveHandler: function() {\n                var me = this,\n                    handler;\n\n                handler = function() {\n                    me.dndOver = false;\n                    me.elem.removeClass( prefix + 'over ' + prefix + 'denied' );\n                };\n\n                clearTimeout( me._leaveTimer );\n                me._leaveTimer = setTimeout( handler, 100 );\n                return false;\n            },\n\n            _dropHandler: function( e ) {\n                var me = this,\n                    ruid = me.getRuid(),\n                    parentElem = me.elem.parent().get( 0 ),\n                    dataTransfer, data;\n\n                // 只处理框内的。\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                e = e.originalEvent || e;\n                dataTransfer = e.dataTransfer;\n\n                // 如果是页面内拖拽，还不能处理，不阻止事件。\n                // 此处 ie11 下会报参数错误，\n                try {\n                    data = dataTransfer.getData('text/html');\n                } catch( err ) {\n                }\n\n                if ( data ) {\n                    return;\n                }\n\n                me._getTansferFiles( dataTransfer, function( results ) {\n                    me.trigger( 'drop', $.map( results, function( file ) {\n                        return new File( ruid, file );\n                    }) );\n                });\n\n                me.dndOver = false;\n                me.elem.removeClass( prefix + 'over' );\n                return false;\n            },\n\n            // 如果传入 callback 则去查看文件夹，否则只管当前文件夹。\n            _getTansferFiles: function( dataTransfer, callback ) {\n                var results  = [],\n                    promises = [],\n                    items, files, file, item, i, len, canAccessFolder;\n\n                items = dataTransfer.items;\n                files = dataTransfer.files;\n\n                canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);\n\n                for ( i = 0, len = files.length; i < len; i++ ) {\n                    file = files[ i ];\n                    item = items && items[ i ];\n\n                    if ( canAccessFolder && item.webkitGetAsEntry().isDirectory ) {\n\n                        promises.push( this._traverseDirectoryTree(\n                                item.webkitGetAsEntry(), results ) );\n                    } else {\n                        results.push( file );\n                    }\n                }\n\n                Base.when.apply( Base, promises ).done(function() {\n\n                    if ( !results.length ) {\n                        return;\n                    }\n\n                    callback( results );\n                });\n            },\n\n            _traverseDirectoryTree: function( entry, results ) {\n                var deferred = Base.Deferred(),\n                    me = this;\n\n                if ( entry.isFile ) {\n                    entry.file(function( file ) {\n                        results.push( file );\n                        deferred.resolve();\n                    });\n                } else if ( entry.isDirectory ) {\n                    entry.createReader().readEntries(function( entries ) {\n                        var len = entries.length,\n                            promises = [],\n                            arr = [],    // 为了保证顺序。\n                            i;\n\n                        for ( i = 0; i < len; i++ ) {\n                            promises.push( me._traverseDirectoryTree(\n                                    entries[ i ], arr ) );\n                        }\n\n                        Base.when.apply( Base, promises ).then(function() {\n                            results.push.apply( results, arr );\n                            deferred.resolve();\n                        }, deferred.reject );\n                    });\n                }\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                var elem = this.elem;\n\n                // 还没 init 就调用 destroy\n                if (!elem) {\n                    return;\n                }\n\n                elem.off( 'dragenter', this.dragEnterHandler );\n                elem.off( 'dragover', this.dragOverHandler );\n                elem.off( 'dragleave', this.dragLeaveHandler );\n                elem.off( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).off( 'dragover', this.dragOverHandler );\n                    $( document ).off( 'drop', this.dropHandler );\n                }\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/filepaste',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        return Html5Runtime.register( 'FilePaste', {\n            init: function() {\n                var opts = this.options,\n                    elem = this.elem = opts.container,\n                    accept = '.*',\n                    arr, i, len, item;\n\n                // accetp的mimeTypes中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].mimeTypes;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = arr.join(',');\n                        accept = accept.replace( /,/g, '|' ).replace( /\\*/g, '.*' );\n                    }\n                }\n                this.accept = accept = new RegExp( accept, 'i' );\n                this.hander = Base.bindFn( this._pasteHander, this );\n                elem.on( 'paste', this.hander );\n            },\n\n            _pasteHander: function( e ) {\n                var allowed = [],\n                    ruid = this.getRuid(),\n                    items, item, blob, i, len;\n\n                e = e.originalEvent || e;\n                items = e.clipboardData.items;\n\n                for ( i = 0, len = items.length; i < len; i++ ) {\n                    item = items[ i ];\n\n                    if ( item.kind !== 'file' || !(blob = item.getAsFile()) ) {\n                        continue;\n                    }\n\n                    allowed.push( new File( ruid, blob ) );\n                }\n\n                if ( allowed.length ) {\n                    // 不阻止非文件粘贴（文字粘贴）的事件冒泡\n                    e.preventDefault();\n                    e.stopPropagation();\n                    this.trigger( 'paste', allowed );\n                }\n            },\n\n            destroy: function() {\n                this.elem.off( 'paste', this.hander );\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/html5/filepicker',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var $ = Base.$;\n\n        return Html5Runtime.register( 'FilePicker', {\n            init: function() {\n                var container = this.getRuntime().getContainer(),\n                    me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    label = this.label = $( document.createElement('label') ),\n                    input =  this.input = $( document.createElement('input') ),\n                    arr, i, len, mouseHandler;\n\n                input.attr( 'type', 'file' );\n                input.attr( 'name', opts.name );\n                input.addClass('webuploader-element-invisible');\n\n                label.on( 'click', function() {\n                    input.trigger('click');\n                });\n\n                label.css({\n                    opacity: 0,\n                    width: '100%',\n                    height: '100%',\n                    display: 'block',\n                    cursor: 'pointer',\n                    background: '#ffffff'\n                });\n\n                if ( opts.multiple ) {\n                    input.attr( 'multiple', 'multiple' );\n                }\n\n                // @todo Firefox不支持单独指定后缀\n                if ( opts.accept && opts.accept.length > 0 ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        arr.push( opts.accept[ i ].mimeTypes );\n                    }\n\n                    input.attr( 'accept', arr.join(',') );\n                }\n\n                container.append( input );\n                container.append( label );\n\n                mouseHandler = function( e ) {\n                    owner.trigger( e.type );\n                };\n\n                input.on( 'change', function( e ) {\n                    var fn = arguments.callee,\n                        clone;\n\n                    me.files = e.target.files;\n\n                    // reset input\n                    clone = this.cloneNode( true );\n                    clone.value = null;\n                    this.parentNode.replaceChild( clone, this );\n\n                    input.off();\n                    input = $( clone ).on( 'change', fn )\n                            .on( 'mouseenter mouseleave', mouseHandler );\n\n                    owner.trigger('change');\n                });\n\n                label.on( 'mouseenter mouseleave', mouseHandler );\n\n            },\n\n\n            getFiles: function() {\n                return this.files;\n            },\n\n            destroy: function() {\n                this.input.off();\n                this.label.off();\n            }\n        });\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/util',[\n        'base'\n    ], function( Base ) {\n\n        var urlAPI = window.createObjectURL && window ||\n                window.URL && URL.revokeObjectURL && URL ||\n                window.webkitURL,\n            createObjectURL = Base.noop,\n            revokeObjectURL = createObjectURL;\n\n        if ( urlAPI ) {\n\n            // 更安全的方式调用，比如android里面就能把context改成其他的对象。\n            createObjectURL = function() {\n                return urlAPI.createObjectURL.apply( urlAPI, arguments );\n            };\n\n            revokeObjectURL = function() {\n                return urlAPI.revokeObjectURL.apply( urlAPI, arguments );\n            };\n        }\n\n        return {\n            createObjectURL: createObjectURL,\n            revokeObjectURL: revokeObjectURL,\n\n            dataURL2Blob: function( dataURI ) {\n                var byteStr, intArray, ab, i, mimetype, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                ab = new ArrayBuffer( byteStr.length );\n                intArray = new Uint8Array( ab );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                mimetype = parts[ 0 ].split(':')[ 1 ].split(';')[ 0 ];\n\n                return this.arrayBufferToBlob( ab, mimetype );\n            },\n\n            dataURL2ArrayBuffer: function( dataURI ) {\n                var byteStr, intArray, i, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                intArray = new Uint8Array( byteStr.length );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                return intArray.buffer;\n            },\n\n            arrayBufferToBlob: function( buffer, type ) {\n                var builder = window.BlobBuilder || window.WebKitBlobBuilder,\n                    bb;\n\n                // android不支持直接new Blob, 只能借助blobbuilder.\n                if ( builder ) {\n                    bb = new builder();\n                    bb.append( buffer );\n                    return bb.getBlob( type );\n                }\n\n                return new Blob([ buffer ], type ? { type: type } : {} );\n            },\n\n            // 抽出来主要是为了解决android下面canvas.toDataUrl不支持jpeg.\n            // 你得到的结果是png.\n            canvasToDataUrl: function( canvas, type, quality ) {\n                return canvas.toDataURL( type, quality / 100 );\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            parseMeta: function( blob, callback ) {\n                callback( false, {});\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            updateImageHead: function( data ) {\n                return data;\n            }\n        };\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/imagemeta',[\n        'runtime/html5/util'\n    ], function( Util ) {\n\n        var api;\n\n        api = {\n            parsers: {\n                0xffe1: []\n            },\n\n            maxMetaDataSize: 262144,\n\n            parse: function( blob, cb ) {\n                var me = this,\n                    fr = new FileReader();\n\n                fr.onload = function() {\n                    cb( false, me._parse( this.result ) );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                fr.onerror = function( e ) {\n                    cb( e.message );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                blob = blob.slice( 0, me.maxMetaDataSize );\n                fr.readAsArrayBuffer( blob.getSource() );\n            },\n\n            _parse: function( buffer, noParse ) {\n                if ( buffer.byteLength < 6 ) {\n                    return;\n                }\n\n                var dataview = new DataView( buffer ),\n                    offset = 2,\n                    maxOffset = dataview.byteLength - 4,\n                    headLength = offset,\n                    ret = {},\n                    markerBytes, markerLength, parsers, i;\n\n                if ( dataview.getUint16( 0 ) === 0xffd8 ) {\n\n                    while ( offset < maxOffset ) {\n                        markerBytes = dataview.getUint16( offset );\n\n                        if ( markerBytes >= 0xffe0 && markerBytes <= 0xffef ||\n                                markerBytes === 0xfffe ) {\n\n                            markerLength = dataview.getUint16( offset + 2 ) + 2;\n\n                            if ( offset + markerLength > dataview.byteLength ) {\n                                break;\n                            }\n\n                            parsers = api.parsers[ markerBytes ];\n\n                            if ( !noParse && parsers ) {\n                                for ( i = 0; i < parsers.length; i += 1 ) {\n                                    parsers[ i ].call( api, dataview, offset,\n                                            markerLength, ret );\n                                }\n                            }\n\n                            offset += markerLength;\n                            headLength = offset;\n                        } else {\n                            break;\n                        }\n                    }\n\n                    if ( headLength > 6 ) {\n                        if ( buffer.slice ) {\n                            ret.imageHead = buffer.slice( 2, headLength );\n                        } else {\n                            // Workaround for IE10, which does not yet\n                            // support ArrayBuffer.slice:\n                            ret.imageHead = new Uint8Array( buffer )\n                                    .subarray( 2, headLength );\n                        }\n                    }\n                }\n\n                return ret;\n            },\n\n            updateImageHead: function( buffer, head ) {\n                var data = this._parse( buffer, true ),\n                    buf1, buf2, bodyoffset;\n\n\n                bodyoffset = 2;\n                if ( data.imageHead ) {\n                    bodyoffset = 2 + data.imageHead.byteLength;\n                }\n\n                if ( buffer.slice ) {\n                    buf2 = buffer.slice( bodyoffset );\n                } else {\n                    buf2 = new Uint8Array( buffer ).subarray( bodyoffset );\n                }\n\n                buf1 = new Uint8Array( head.byteLength + 2 + buf2.byteLength );\n\n                buf1[ 0 ] = 0xFF;\n                buf1[ 1 ] = 0xD8;\n                buf1.set( new Uint8Array( head ), 2 );\n                buf1.set( new Uint8Array( buf2 ), head.byteLength + 2 );\n\n                return buf1.buffer;\n            }\n        };\n\n        Util.parseMeta = function() {\n            return api.parse.apply( api, arguments );\n        };\n\n        Util.updateImageHead = function() {\n            return api.updateImageHead.apply( api, arguments );\n        };\n\n        return api;\n    });\n    /**\n     * 代码来自于：https://github.com/blueimp/JavaScript-Load-Image\n     * 暂时项目中只用了orientation.\n     *\n     * 去除了 Exif Sub IFD Pointer, GPS Info IFD Pointer, Exif Thumbnail.\n     * @fileOverview EXIF解析\n     */\n\n    // Sample\n    // ====================================\n    // Make : Apple\n    // Model : iPhone 4S\n    // Orientation : 1\n    // XResolution : 72 [72/1]\n    // YResolution : 72 [72/1]\n    // ResolutionUnit : 2\n    // Software : QuickTime 7.7.1\n    // DateTime : 2013:09:01 22:53:55\n    // ExifIFDPointer : 190\n    // ExposureTime : 0.058823529411764705 [1/17]\n    // FNumber : 2.4 [12/5]\n    // ExposureProgram : Normal program\n    // ISOSpeedRatings : 800\n    // ExifVersion : 0220\n    // DateTimeOriginal : 2013:09:01 22:52:51\n    // DateTimeDigitized : 2013:09:01 22:52:51\n    // ComponentsConfiguration : YCbCr\n    // ShutterSpeedValue : 4.058893515764426\n    // ApertureValue : 2.5260688216892597 [4845/1918]\n    // BrightnessValue : -0.3126686601998395\n    // MeteringMode : Pattern\n    // Flash : Flash did not fire, compulsory flash mode\n    // FocalLength : 4.28 [107/25]\n    // SubjectArea : [4 values]\n    // FlashpixVersion : 0100\n    // ColorSpace : 1\n    // PixelXDimension : 2448\n    // PixelYDimension : 3264\n    // SensingMethod : One-chip color area sensor\n    // ExposureMode : 0\n    // WhiteBalance : Auto white balance\n    // FocalLengthIn35mmFilm : 35\n    // SceneCaptureType : Standard\n    define('runtime/html5/imagemeta/exif',[\n        'base',\n        'runtime/html5/imagemeta'\n    ], function( Base, ImageMeta ) {\n\n        var EXIF = {};\n\n        EXIF.ExifMap = function() {\n            return this;\n        };\n\n        EXIF.ExifMap.prototype.map = {\n            'Orientation': 0x0112\n        };\n\n        EXIF.ExifMap.prototype.get = function( id ) {\n            return this[ id ] || this[ this.map[ id ] ];\n        };\n\n        EXIF.exifTagTypes = {\n            // byte, 8-bit unsigned int:\n            1: {\n                getValue: function( dataView, dataOffset ) {\n                    return dataView.getUint8( dataOffset );\n                },\n                size: 1\n            },\n\n            // ascii, 8-bit byte:\n            2: {\n                getValue: function( dataView, dataOffset ) {\n                    return String.fromCharCode( dataView.getUint8( dataOffset ) );\n                },\n                size: 1,\n                ascii: true\n            },\n\n            // short, 16 bit int:\n            3: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint16( dataOffset, littleEndian );\n                },\n                size: 2\n            },\n\n            // long, 32 bit int:\n            4: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // rational = two long values,\n            // first is numerator, second is denominator:\n            5: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian ) /\n                        dataView.getUint32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            },\n\n            // slong, 32 bit signed int:\n            9: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // srational, two slongs, first is numerator, second is denominator:\n            10: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian ) /\n                        dataView.getInt32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            }\n        };\n\n        // undefined, 8-bit byte, value depending on field:\n        EXIF.exifTagTypes[ 7 ] = EXIF.exifTagTypes[ 1 ];\n\n        EXIF.getExifValue = function( dataView, tiffOffset, offset, type, length,\n                littleEndian ) {\n\n            var tagType = EXIF.exifTagTypes[ type ],\n                tagSize, dataOffset, values, i, str, c;\n\n            if ( !tagType ) {\n                Base.log('Invalid Exif data: Invalid tag type.');\n                return;\n            }\n\n            tagSize = tagType.size * length;\n\n            // Determine if the value is contained in the dataOffset bytes,\n            // or if the value at the dataOffset is a pointer to the actual data:\n            dataOffset = tagSize > 4 ? tiffOffset + dataView.getUint32( offset + 8,\n                    littleEndian ) : (offset + 8);\n\n            if ( dataOffset + tagSize > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid data offset.');\n                return;\n            }\n\n            if ( length === 1 ) {\n                return tagType.getValue( dataView, dataOffset, littleEndian );\n            }\n\n            values = [];\n\n            for ( i = 0; i < length; i += 1 ) {\n                values[ i ] = tagType.getValue( dataView,\n                        dataOffset + i * tagType.size, littleEndian );\n            }\n\n            if ( tagType.ascii ) {\n                str = '';\n\n                // Concatenate the chars:\n                for ( i = 0; i < values.length; i += 1 ) {\n                    c = values[ i ];\n\n                    // Ignore the terminating NULL byte(s):\n                    if ( c === '\\u0000' ) {\n                        break;\n                    }\n                    str += c;\n                }\n\n                return str;\n            }\n            return values;\n        };\n\n        EXIF.parseExifTag = function( dataView, tiffOffset, offset, littleEndian,\n                data ) {\n\n            var tag = dataView.getUint16( offset, littleEndian );\n            data.exif[ tag ] = EXIF.getExifValue( dataView, tiffOffset, offset,\n                    dataView.getUint16( offset + 2, littleEndian ),    // tag type\n                    dataView.getUint32( offset + 4, littleEndian ),    // tag length\n                    littleEndian );\n        };\n\n        EXIF.parseExifTags = function( dataView, tiffOffset, dirOffset,\n                littleEndian, data ) {\n\n            var tagsNumber, dirEndOffset, i;\n\n            if ( dirOffset + 6 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory offset.');\n                return;\n            }\n\n            tagsNumber = dataView.getUint16( dirOffset, littleEndian );\n            dirEndOffset = dirOffset + 2 + 12 * tagsNumber;\n\n            if ( dirEndOffset + 4 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory size.');\n                return;\n            }\n\n            for ( i = 0; i < tagsNumber; i += 1 ) {\n                this.parseExifTag( dataView, tiffOffset,\n                        dirOffset + 2 + 12 * i,    // tag offset\n                        littleEndian, data );\n            }\n\n            // Return the offset to the next directory:\n            return dataView.getUint32( dirEndOffset, littleEndian );\n        };\n\n        // EXIF.getExifThumbnail = function(dataView, offset, length) {\n        //     var hexData,\n        //         i,\n        //         b;\n        //     if (!length || offset + length > dataView.byteLength) {\n        //         Base.log('Invalid Exif data: Invalid thumbnail data.');\n        //         return;\n        //     }\n        //     hexData = [];\n        //     for (i = 0; i < length; i += 1) {\n        //         b = dataView.getUint8(offset + i);\n        //         hexData.push((b < 16 ? '0' : '') + b.toString(16));\n        //     }\n        //     return 'data:image/jpeg,%' + hexData.join('%');\n        // };\n\n        EXIF.parseExifData = function( dataView, offset, length, data ) {\n\n            var tiffOffset = offset + 10,\n                littleEndian, dirOffset;\n\n            // Check for the ASCII code for \"Exif\" (0x45786966):\n            if ( dataView.getUint32( offset + 4 ) !== 0x45786966 ) {\n                // No Exif data, might be XMP data instead\n                return;\n            }\n            if ( tiffOffset + 8 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid segment size.');\n                return;\n            }\n\n            // Check for the two null bytes:\n            if ( dataView.getUint16( offset + 8 ) !== 0x0000 ) {\n                Base.log('Invalid Exif data: Missing byte alignment offset.');\n                return;\n            }\n\n            // Check the byte alignment:\n            switch ( dataView.getUint16( tiffOffset ) ) {\n                case 0x4949:\n                    littleEndian = true;\n                    break;\n\n                case 0x4D4D:\n                    littleEndian = false;\n                    break;\n\n                default:\n                    Base.log('Invalid Exif data: Invalid byte alignment marker.');\n                    return;\n            }\n\n            // Check for the TIFF tag marker (0x002A):\n            if ( dataView.getUint16( tiffOffset + 2, littleEndian ) !== 0x002A ) {\n                Base.log('Invalid Exif data: Missing TIFF marker.');\n                return;\n            }\n\n            // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:\n            dirOffset = dataView.getUint32( tiffOffset + 4, littleEndian );\n            // Create the exif object to store the tags:\n            data.exif = new EXIF.ExifMap();\n            // Parse the tags of the main image directory and retrieve the\n            // offset to the next directory, usually the thumbnail directory:\n            dirOffset = EXIF.parseExifTags( dataView, tiffOffset,\n                    tiffOffset + dirOffset, littleEndian, data );\n\n            // 尝试读取缩略图\n            // if ( dirOffset ) {\n            //     thumbnailData = {exif: {}};\n            //     dirOffset = EXIF.parseExifTags(\n            //         dataView,\n            //         tiffOffset,\n            //         tiffOffset + dirOffset,\n            //         littleEndian,\n            //         thumbnailData\n            //     );\n\n            //     // Check for JPEG Thumbnail offset:\n            //     if (thumbnailData.exif[0x0201]) {\n            //         data.exif.Thumbnail = EXIF.getExifThumbnail(\n            //             dataView,\n            //             tiffOffset + thumbnailData.exif[0x0201],\n            //             thumbnailData.exif[0x0202] // Thumbnail data length\n            //         );\n            //     }\n            // }\n        };\n\n        ImageMeta.parsers[ 0xffe1 ].push( EXIF.parseExifData );\n        return EXIF;\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('runtime/html5/image',[\n        'base',\n        'runtime/html5/runtime',\n        'runtime/html5/util'\n    ], function( Base, Html5Runtime, Util ) {\n\n        var BLANK = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D';\n\n        return Html5Runtime.register( 'Image', {\n\n            // flag: 标记是否被修改过。\n            modified: false,\n\n            init: function() {\n                var me = this,\n                    img = new Image();\n\n                img.onload = function() {\n\n                    me._info = {\n                        type: me.type,\n                        width: this.width,\n                        height: this.height\n                    };\n\n                    // 读取meta信息。\n                    if ( !me._metas && 'image/jpeg' === me.type ) {\n                        Util.parseMeta( me._blob, function( error, ret ) {\n                            me._metas = ret;\n                            me.owner.trigger('load');\n                        });\n                    } else {\n                        me.owner.trigger('load');\n                    }\n                };\n\n                img.onerror = function() {\n                    me.owner.trigger('error');\n                };\n\n                me._img = img;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    img = me._img;\n\n                me._blob = blob;\n                me.type = blob.type;\n                img.src = Util.createObjectURL( blob.getSource() );\n                me.owner.once( 'load', function() {\n                    Util.revokeObjectURL( img.src );\n                });\n            },\n\n            resize: function( width, height ) {\n                var canvas = this._canvas ||\n                        (this._canvas = document.createElement('canvas'));\n\n                this._resize( this._img, canvas, width, height );\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'resize' );\n            },\n\n            crop: function( x, y, w, h, s ) {\n                var cvs = this._canvas ||\n                        (this._canvas = document.createElement('canvas')),\n                    opts = this.options,\n                    img = this._img,\n                    iw = img.naturalWidth,\n                    ih = img.naturalHeight,\n                    orientation = this.getOrientation();\n\n                s = s || 1;\n\n                // todo 解决 orientation 的问题。\n                // values that require 90 degree rotation\n                // if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                //     switch ( orientation ) {\n                //         case 6:\n                //             tmp = x;\n                //             x = y;\n                //             y = iw * s - tmp - w;\n                //             console.log(ih * s, tmp, w)\n                //             break;\n                //     }\n\n                //     (w ^= h, h ^= w, w ^= h);\n                // }\n\n                cvs.width = w;\n                cvs.height = h;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n                this._renderImageToCanvas( cvs, img, -x, -y, iw * s, ih * s );\n\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'crop' );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this._blob,\n                    opts = this.options,\n                    canvas;\n\n                type = type || this.type;\n\n                // blob需要重新生成。\n                if ( this.modified || this.type !== type ) {\n                    canvas = this._canvas;\n\n                    if ( type === 'image/jpeg' ) {\n\n                        blob = Util.canvasToDataUrl( canvas, type, opts.quality );\n\n                        if ( opts.preserveHeaders && this._metas &&\n                                this._metas.imageHead ) {\n\n                            blob = Util.dataURL2ArrayBuffer( blob );\n                            blob = Util.updateImageHead( blob,\n                                    this._metas.imageHead );\n                            blob = Util.arrayBufferToBlob( blob, type );\n                            return blob;\n                        }\n                    } else {\n                        blob = Util.canvasToDataUrl( canvas, type );\n                    }\n\n                    blob = Util.dataURL2Blob( blob );\n                }\n\n                return blob;\n            },\n\n            getAsDataUrl: function( type ) {\n                var opts = this.options;\n\n                type = type || this.type;\n\n                if ( type === 'image/jpeg' ) {\n                    return Util.canvasToDataUrl( this._canvas, type, opts.quality );\n                } else {\n                    return this._canvas.toDataURL( type );\n                }\n            },\n\n            getOrientation: function() {\n                return this._metas && this._metas.exif &&\n                        this._metas.exif.get('Orientation') || 1;\n            },\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            destroy: function() {\n                var canvas = this._canvas;\n                this._img.onload = null;\n\n                if ( canvas ) {\n                    canvas.getContext('2d')\n                            .clearRect( 0, 0, canvas.width, canvas.height );\n                    canvas.width = canvas.height = 0;\n                    this._canvas = null;\n                }\n\n                // 释放内存。非常重要，否则释放不了image的内存。\n                this._img.src = BLANK;\n                this._img = this._blob = null;\n            },\n\n            _resize: function( img, cvs, width, height ) {\n                var opts = this.options,\n                    naturalWidth = img.width,\n                    naturalHeight = img.height,\n                    orientation = this.getOrientation(),\n                    scale, w, h, x, y;\n\n                // values that require 90 degree rotation\n                if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                    // 交换width, height的值。\n                    width ^= height;\n                    height ^= width;\n                    width ^= height;\n                }\n\n                scale = Math[ opts.crop ? 'max' : 'min' ]( width / naturalWidth,\n                        height / naturalHeight );\n\n                // 不允许放大。\n                opts.allowMagnify || (scale = Math.min( 1, scale ));\n\n                w = naturalWidth * scale;\n                h = naturalHeight * scale;\n\n                if ( opts.crop ) {\n                    cvs.width = width;\n                    cvs.height = height;\n                } else {\n                    cvs.width = w;\n                    cvs.height = h;\n                }\n\n                x = (cvs.width - w) / 2;\n                y = (cvs.height - h) / 2;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n\n                this._renderImageToCanvas( cvs, img, x, y, w, h );\n            },\n\n            _rotate2Orientaion: function( canvas, orientation ) {\n                var width = canvas.width,\n                    height = canvas.height,\n                    ctx = canvas.getContext('2d');\n\n                switch ( orientation ) {\n                    case 5:\n                    case 6:\n                    case 7:\n                    case 8:\n                        canvas.width = height;\n                        canvas.height = width;\n                        break;\n                }\n\n                switch ( orientation ) {\n                    case 2:    // horizontal flip\n                        ctx.translate( width, 0 );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 3:    // 180 rotate left\n                        ctx.translate( width, height );\n                        ctx.rotate( Math.PI );\n                        break;\n\n                    case 4:    // vertical flip\n                        ctx.translate( 0, height );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 5:    // vertical flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 6:    // 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( 0, -height );\n                        break;\n\n                    case 7:    // horizontal flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( width, -height );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 8:    // 90 rotate left\n                        ctx.rotate( -0.5 * Math.PI );\n                        ctx.translate( -width, 0 );\n                        break;\n                }\n            },\n\n            // https://github.com/stomita/ios-imagefile-megapixel/\n            // blob/master/src/megapix-image.js\n            _renderImageToCanvas: (function() {\n\n                // 如果不是ios, 不需要这么复杂！\n                if ( !Base.os.ios ) {\n                    return function( canvas ) {\n                        var args = Base.slice( arguments, 1 ),\n                            ctx = canvas.getContext('2d');\n\n                        ctx.drawImage.apply( ctx, args );\n                    };\n                }\n\n                /**\n                 * Detecting vertical squash in loaded image.\n                 * Fixes a bug which squash image vertically while drawing into\n                 * canvas for some images.\n                 */\n                function detectVerticalSquash( img, iw, ih ) {\n                    var canvas = document.createElement('canvas'),\n                        ctx = canvas.getContext('2d'),\n                        sy = 0,\n                        ey = ih,\n                        py = ih,\n                        data, alpha, ratio;\n\n\n                    canvas.width = 1;\n                    canvas.height = ih;\n                    ctx.drawImage( img, 0, 0 );\n                    data = ctx.getImageData( 0, 0, 1, ih ).data;\n\n                    // search image edge pixel position in case\n                    // it is squashed vertically.\n                    while ( py > sy ) {\n                        alpha = data[ (py - 1) * 4 + 3 ];\n\n                        if ( alpha === 0 ) {\n                            ey = py;\n                        } else {\n                            sy = py;\n                        }\n\n                        py = (ey + sy) >> 1;\n                    }\n\n                    ratio = (py / ih);\n                    return (ratio === 0) ? 1 : ratio;\n                }\n\n                // fix ie7 bug\n                // http://stackoverflow.com/questions/11929099/\n                // html5-canvas-drawimage-ratio-bug-ios\n                if ( Base.os.ios >= 7 ) {\n                    return function( canvas, img, x, y, w, h ) {\n                        var iw = img.naturalWidth,\n                            ih = img.naturalHeight,\n                            vertSquashRatio = detectVerticalSquash( img, iw, ih );\n\n                        return canvas.getContext('2d').drawImage( img, 0, 0,\n                                iw * vertSquashRatio, ih * vertSquashRatio,\n                                x, y, w, h );\n                    };\n                }\n\n                /**\n                 * Detect subsampling in loaded image.\n                 * In iOS, larger images than 2M pixels may be\n                 * subsampled in rendering.\n                 */\n                function detectSubsampling( img ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        canvas, ctx;\n\n                    // subsampling may happen overmegapixel image\n                    if ( iw * ih > 1024 * 1024 ) {\n                        canvas = document.createElement('canvas');\n                        canvas.width = canvas.height = 1;\n                        ctx = canvas.getContext('2d');\n                        ctx.drawImage( img, -iw + 1, 0 );\n\n                        // subsampled image becomes half smaller in rendering size.\n                        // check alpha channel value to confirm image is covering\n                        // edge pixel or not. if alpha value is 0\n                        // image is not covering, hence subsampled.\n                        return ctx.getImageData( 0, 0, 1, 1 ).data[ 3 ] === 0;\n                    } else {\n                        return false;\n                    }\n                }\n\n\n                return function( canvas, img, x, y, width, height ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        ctx = canvas.getContext('2d'),\n                        subsampled = detectSubsampling( img ),\n                        doSquash = this.type === 'image/jpeg',\n                        d = 1024,\n                        sy = 0,\n                        dy = 0,\n                        tmpCanvas, tmpCtx, vertSquashRatio, dw, dh, sx, dx;\n\n                    if ( subsampled ) {\n                        iw /= 2;\n                        ih /= 2;\n                    }\n\n                    ctx.save();\n                    tmpCanvas = document.createElement('canvas');\n                    tmpCanvas.width = tmpCanvas.height = d;\n\n                    tmpCtx = tmpCanvas.getContext('2d');\n                    vertSquashRatio = doSquash ?\n                            detectVerticalSquash( img, iw, ih ) : 1;\n\n                    dw = Math.ceil( d * width / iw );\n                    dh = Math.ceil( d * height / ih / vertSquashRatio );\n\n                    while ( sy < ih ) {\n                        sx = 0;\n                        dx = 0;\n                        while ( sx < iw ) {\n                            tmpCtx.clearRect( 0, 0, d, d );\n                            tmpCtx.drawImage( img, -sx, -sy );\n                            ctx.drawImage( tmpCanvas, 0, 0, d, d,\n                                    x + dx, y + dy, dw, dh );\n                            sx += d;\n                            dx += dw;\n                        }\n                        sy += d;\n                        dy += dh;\n                    }\n                    ctx.restore();\n                    tmpCanvas = tmpCtx = null;\n                };\n            })()\n        });\n    });\n    /**\n     * @fileOverview Transport\n     * @todo 支持chunked传输，优势：\n     * 可以将大文件分成小块，挨个传输，可以提高大文件成功率，当失败的时候，也只需要重传那小部分，\n     * 而不需要重头再传一次。另外断点续传也需要用chunked方式。\n     */\n    define('runtime/html5/transport',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var noop = Base.noop,\n            $ = Base.$;\n\n        return Html5Runtime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    formData, binary, fr;\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.getSource();\n                } else {\n                    formData = new FormData();\n                    $.each( owner._formData, function( k, v ) {\n                        formData.append( k, v );\n                    });\n\n                    formData.append( opts.fileVal, blob.getSource(),\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                if ( opts.withCredentials && 'withCredentials' in xhr ) {\n                    xhr.open( opts.method, server, true );\n                    xhr.withCredentials = true;\n                } else {\n                    xhr.open( opts.method, server );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n\n                if ( binary ) {\n                    // 强制设置成 content-type 为文件流。\n                    xhr.overrideMimeType &&\n                            xhr.overrideMimeType('application/octet-stream');\n\n                    // android直接发送blob会导致服务端接收到的是空文件。\n                    // bug详情。\n                    // https://code.google.com/p/android/issues/detail?id=39882\n                    // 所以先用fileReader读取出来再通过arraybuffer的方式发送。\n                    if ( Base.os.android ) {\n                        fr = new FileReader();\n\n                        fr.onload = function() {\n                            xhr.send( this.result );\n                            fr = fr.onload = null;\n                        };\n\n                        fr.readAsArrayBuffer( binary );\n                    } else {\n                        xhr.send( binary );\n                    }\n                } else {\n                    xhr.send( formData );\n                }\n            },\n\n            getResponse: function() {\n                return this._response;\n            },\n\n            getResponseAsJson: function() {\n                return this._parseJson( this._response );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    xhr.abort();\n\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new XMLHttpRequest(),\n                    opts = this.options;\n\n                if ( opts.withCredentials && !('withCredentials' in xhr) &&\n                        typeof XDomainRequest !== 'undefined' ) {\n                    xhr = new XDomainRequest();\n                }\n\n                xhr.upload.onprogress = function( e ) {\n                    var percentage = 0;\n\n                    if ( e.lengthComputable ) {\n                        percentage = e.loaded / e.total;\n                    }\n\n                    return me.trigger( 'progress', percentage );\n                };\n\n                xhr.onreadystatechange = function() {\n\n                    if ( xhr.readyState !== 4 ) {\n                        return;\n                    }\n\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    me._xhr = null;\n                    me._status = xhr.status;\n\n                    if ( xhr.status >= 200 && xhr.status < 300 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger('load');\n                    } else if ( xhr.status >= 500 && xhr.status < 600 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger( 'error', 'server' );\n                    }\n\n\n                    return me.trigger( 'error', me._status ? 'http' : 'abort' );\n                };\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.setRequestHeader( key, val );\n                });\n            },\n\n            _parseJson: function( str ) {\n                var json;\n\n                try {\n                    json = JSON.parse( str );\n                } catch ( ex ) {\n                    json = {};\n                }\n\n                return json;\n            }\n        });\n    });\n    /**\n     * @fileOverview 只有html5实现的文件版本。\n     */\n    define('preset/html5only',[\n        'base',\n\n        // widgets\n        'widgets/filednd',\n        'widgets/filepaste',\n        'widgets/filepicker',\n        'widgets/image',\n        'widgets/queue',\n        'widgets/runtime',\n        'widgets/upload',\n        'widgets/validator',\n\n        // runtimes\n        // html5\n        'runtime/html5/blob',\n        'runtime/html5/dnd',\n        'runtime/html5/filepaste',\n        'runtime/html5/filepicker',\n        'runtime/html5/imagemeta/exif',\n        'runtime/html5/image',\n        'runtime/html5/transport'\n    ], function( Base ) {\n        return Base;\n    });\n    define('webuploader',[\n        'preset/html5only'\n    ], function( preset ) {\n        return preset;\n    });\n    return require('webuploader');\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.js",
    "content": "/*! WebUploader 0.1.5 */\n\n\n/**\n * @fileOverview 让内部各个部件的代码可以用[amd](https://github.com/amdjs/amdjs-api/wiki/AMD)模块定义方式组织起来。\n *\n * AMD API 内部的简单不完全实现，请忽略。只有当WebUploader被合并成一个文件的时候才会引入。\n */\n(function( root, factory ) {\n    var modules = {},\n\n        // 内部require, 简单不完全实现。\n        // https://github.com/amdjs/amdjs-api/wiki/require\n        _require = function( deps, callback ) {\n            var args, len, i;\n\n            // 如果deps不是数组，则直接返回指定module\n            if ( typeof deps === 'string' ) {\n                return getModule( deps );\n            } else {\n                args = [];\n                for( len = deps.length, i = 0; i < len; i++ ) {\n                    args.push( getModule( deps[ i ] ) );\n                }\n\n                return callback.apply( null, args );\n            }\n        },\n\n        // 内部define，暂时不支持不指定id.\n        _define = function( id, deps, factory ) {\n            if ( arguments.length === 2 ) {\n                factory = deps;\n                deps = null;\n            }\n\n            _require( deps || [], function() {\n                setModule( id, factory, arguments );\n            });\n        },\n\n        // 设置module, 兼容CommonJs写法。\n        setModule = function( id, factory, args ) {\n            var module = {\n                    exports: factory\n                },\n                returned;\n\n            if ( typeof factory === 'function' ) {\n                args.length || (args = [ _require, module.exports, module ]);\n                returned = factory.apply( null, args );\n                returned !== undefined && (module.exports = returned);\n            }\n\n            modules[ id ] = module.exports;\n        },\n\n        // 根据id获取module\n        getModule = function( id ) {\n            var module = modules[ id ] || root[ id ];\n\n            if ( !module ) {\n                throw new Error( '`' + id + '` is undefined' );\n            }\n\n            return module;\n        },\n\n        // 将所有modules，将路径ids装换成对象。\n        exportsTo = function( obj ) {\n            var key, host, parts, part, last, ucFirst;\n\n            // make the first character upper case.\n            ucFirst = function( str ) {\n                return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 ));\n            };\n\n            for ( key in modules ) {\n                host = obj;\n\n                if ( !modules.hasOwnProperty( key ) ) {\n                    continue;\n                }\n\n                parts = key.split('/');\n                last = ucFirst( parts.pop() );\n\n                while( (part = ucFirst( parts.shift() )) ) {\n                    host[ part ] = host[ part ] || {};\n                    host = host[ part ];\n                }\n\n                host[ last ] = modules[ key ];\n            }\n\n            return obj;\n        },\n\n        makeExport = function( dollar ) {\n            root.__dollar = dollar;\n\n            // exports every module.\n            return exportsTo( factory( root, _define, _require ) );\n        },\n\n        origin;\n\n    if ( typeof module === 'object' && typeof module.exports === 'object' ) {\n\n        // For CommonJS and CommonJS-like environments where a proper window is present,\n        module.exports = makeExport();\n    } else if ( typeof define === 'function' && define.amd ) {\n\n        // Allow using this built library as an AMD module\n        // in another project. That other project will only\n        // see this AMD call, not the internal modules in\n        // the closure below.\n        define([ 'jquery' ], makeExport );\n    } else {\n\n        // Browser globals case. Just assign the\n        // result to a property on the global.\n        origin = root.WebUploader;\n        root.WebUploader = makeExport();\n        root.WebUploader.noConflict = function() {\n            root.WebUploader = origin;\n        };\n    }\n})( window, function( window, define, require ) {\n\n\n    /**\n     * @fileOverview jQuery or Zepto\n     */\n    define('dollar-third',[],function() {\n        var $ = window.__dollar || window.jQuery || window.Zepto;\n\n        if ( !$ ) {\n            throw new Error('jQuery or Zepto not found!');\n        }\n\n        return $;\n    });\n    /**\n     * @fileOverview Dom 操作相关\n     */\n    define('dollar',[\n        'dollar-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 使用jQuery的Promise\n     */\n    define('promise-third',[\n        'dollar'\n    ], function( $ ) {\n        return {\n            Deferred: $.Deferred,\n            when: $.when,\n\n            isPromise: function( anything ) {\n                return anything && typeof anything.then === 'function';\n            }\n        };\n    });\n    /**\n     * @fileOverview Promise/A+\n     */\n    define('promise',[\n        'promise-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 基础类方法。\n     */\n\n    /**\n     * Web Uploader内部类的详细说明，以下提及的功能类，都可以在`WebUploader`这个变量中访问到。\n     *\n     * As you know, Web Uploader的每个文件都是用过[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)规范中的`define`组织起来的, 每个Module都会有个module id.\n     * 默认module id为该文件的路径，而此路径将会转化成名字空间存放在WebUploader中。如：\n     *\n     * * module `base`：WebUploader.Base\n     * * module `file`: WebUploader.File\n     * * module `lib/dnd`: WebUploader.Lib.Dnd\n     * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd\n     *\n     *\n     * 以下文档中对类的使用可能省略掉了`WebUploader`前缀。\n     * @module WebUploader\n     * @title WebUploader API文档\n     */\n    define('base',[\n        'dollar',\n        'promise'\n    ], function( $, promise ) {\n\n        var noop = function() {},\n            call = Function.call;\n\n        // http://jsperf.com/uncurrythis\n        // 反科里化\n        function uncurryThis( fn ) {\n            return function() {\n                return call.apply( fn, arguments );\n            };\n        }\n\n        function bindFn( fn, context ) {\n            return function() {\n                return fn.apply( context, arguments );\n            };\n        }\n\n        function createObject( proto ) {\n            var f;\n\n            if ( Object.create ) {\n                return Object.create( proto );\n            } else {\n                f = function() {};\n                f.prototype = proto;\n                return new f();\n            }\n        }\n\n\n        /**\n         * 基础类，提供一些简单常用的方法。\n         * @class Base\n         */\n        return {\n\n            /**\n             * @property {String} version 当前版本号。\n             */\n            version: '0.1.5',\n\n            /**\n             * @property {jQuery|Zepto} $ 引用依赖的jQuery或者Zepto对象。\n             */\n            $: $,\n\n            Deferred: promise.Deferred,\n\n            isPromise: promise.isPromise,\n\n            when: promise.when,\n\n            /**\n             * @description  简单的浏览器检查结果。\n             *\n             * * `webkit`  webkit版本号，如果浏览器为非webkit内核，此属性为`undefined`。\n             * * `chrome`  chrome浏览器版本号，如果浏览器为chrome，此属性为`undefined`。\n             * * `ie`  ie浏览器版本号，如果浏览器为非ie，此属性为`undefined`。**暂不支持ie10+**\n             * * `firefox`  firefox浏览器版本号，如果浏览器为非firefox，此属性为`undefined`。\n             * * `safari`  safari浏览器版本号，如果浏览器为非safari，此属性为`undefined`。\n             * * `opera`  opera浏览器版本号，如果浏览器为非opera，此属性为`undefined`。\n             *\n             * @property {Object} [browser]\n             */\n            browser: (function( ua ) {\n                var ret = {},\n                    webkit = ua.match( /WebKit\\/([\\d.]+)/ ),\n                    chrome = ua.match( /Chrome\\/([\\d.]+)/ ) ||\n                        ua.match( /CriOS\\/([\\d.]+)/ ),\n\n                    ie = ua.match( /MSIE\\s([\\d\\.]+)/ ) ||\n                        ua.match( /(?:trident)(?:.*rv:([\\w.]+))?/i ),\n                    firefox = ua.match( /Firefox\\/([\\d.]+)/ ),\n                    safari = ua.match( /Safari\\/([\\d.]+)/ ),\n                    opera = ua.match( /OPR\\/([\\d.]+)/ );\n\n                webkit && (ret.webkit = parseFloat( webkit[ 1 ] ));\n                chrome && (ret.chrome = parseFloat( chrome[ 1 ] ));\n                ie && (ret.ie = parseFloat( ie[ 1 ] ));\n                firefox && (ret.firefox = parseFloat( firefox[ 1 ] ));\n                safari && (ret.safari = parseFloat( safari[ 1 ] ));\n                opera && (ret.opera = parseFloat( opera[ 1 ] ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * @description  操作系统检查结果。\n             *\n             * * `android`  如果在android浏览器环境下，此值为对应的android版本号，否则为`undefined`。\n             * * `ios` 如果在ios浏览器环境下，此值为对应的ios版本号，否则为`undefined`。\n             * @property {Object} [os]\n             */\n            os: (function( ua ) {\n                var ret = {},\n\n                    // osx = !!ua.match( /\\(Macintosh\\; Intel / ),\n                    android = ua.match( /(?:Android);?[\\s\\/]+([\\d.]+)?/ ),\n                    ios = ua.match( /(?:iPad|iPod|iPhone).*OS\\s([\\d_]+)/ );\n\n                // osx && (ret.osx = true);\n                android && (ret.android = parseFloat( android[ 1 ] ));\n                ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * 实现类与类之间的继承。\n             * @method inherits\n             * @grammar Base.inherits( super ) => child\n             * @grammar Base.inherits( super, protos ) => child\n             * @grammar Base.inherits( super, protos, statics ) => child\n             * @param  {Class} super 父类\n             * @param  {Object | Function} [protos] 子类或者对象。如果对象中包含constructor，子类将是用此属性值。\n             * @param  {Function} [protos.constructor] 子类构造器，不指定的话将创建个临时的直接执行父类构造器的方法。\n             * @param  {Object} [statics] 静态属性或方法。\n             * @return {Class} 返回子类。\n             * @example\n             * function Person() {\n             *     console.log( 'Super' );\n             * }\n             * Person.prototype.hello = function() {\n             *     console.log( 'hello' );\n             * };\n             *\n             * var Manager = Base.inherits( Person, {\n             *     world: function() {\n             *         console.log( 'World' );\n             *     }\n             * });\n             *\n             * // 因为没有指定构造器，父类的构造器将会执行。\n             * var instance = new Manager();    // => Super\n             *\n             * // 继承子父类的方法\n             * instance.hello();    // => hello\n             * instance.world();    // => World\n             *\n             * // 子类的__super__属性指向父类\n             * console.log( Manager.__super__ === Person );    // => true\n             */\n            inherits: function( Super, protos, staticProtos ) {\n                var child;\n\n                if ( typeof protos === 'function' ) {\n                    child = protos;\n                    protos = null;\n                } else if ( protos && protos.hasOwnProperty('constructor') ) {\n                    child = protos.constructor;\n                } else {\n                    child = function() {\n                        return Super.apply( this, arguments );\n                    };\n                }\n\n                // 复制静态方法\n                $.extend( true, child, Super, staticProtos || {} );\n\n                /* jshint camelcase: false */\n\n                // 让子类的__super__属性指向父类。\n                child.__super__ = Super.prototype;\n\n                // 构建原型，添加原型方法或属性。\n                // 暂时用Object.create实现。\n                child.prototype = createObject( Super.prototype );\n                protos && $.extend( true, child.prototype, protos );\n\n                return child;\n            },\n\n            /**\n             * 一个不做任何事情的方法。可以用来赋值给默认的callback.\n             * @method noop\n             */\n            noop: noop,\n\n            /**\n             * 返回一个新的方法，此方法将已指定的`context`来执行。\n             * @grammar Base.bindFn( fn, context ) => Function\n             * @method bindFn\n             * @example\n             * var doSomething = function() {\n             *         console.log( this.name );\n             *     },\n             *     obj = {\n             *         name: 'Object Name'\n             *     },\n             *     aliasFn = Base.bind( doSomething, obj );\n             *\n             *  aliasFn();    // => Object Name\n             *\n             */\n            bindFn: bindFn,\n\n            /**\n             * 引用Console.log如果存在的话，否则引用一个[空函数noop](#WebUploader:Base.noop)。\n             * @grammar Base.log( args... ) => undefined\n             * @method log\n             */\n            log: (function() {\n                if ( window.console ) {\n                    return bindFn( console.log, console );\n                }\n                return noop;\n            })(),\n\n            nextTick: (function() {\n\n                return function( cb ) {\n                    setTimeout( cb, 1 );\n                };\n\n                // @bug 当浏览器不在当前窗口时就停了。\n                // var next = window.requestAnimationFrame ||\n                //     window.webkitRequestAnimationFrame ||\n                //     window.mozRequestAnimationFrame ||\n                //     function( cb ) {\n                //         window.setTimeout( cb, 1000 / 60 );\n                //     };\n\n                // // fix: Uncaught TypeError: Illegal invocation\n                // return bindFn( next, window );\n            })(),\n\n            /**\n             * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的数组slice方法。\n             * 将用来将非数组对象转化成数组对象。\n             * @grammar Base.slice( target, start[, end] ) => Array\n             * @method slice\n             * @example\n             * function doSomthing() {\n             *     var args = Base.slice( arguments, 1 );\n             *     console.log( args );\n             * }\n             *\n             * doSomthing( 'ignored', 'arg2', 'arg3' );    // => Array [\"arg2\", \"arg3\"]\n             */\n            slice: uncurryThis( [].slice ),\n\n            /**\n             * 生成唯一的ID\n             * @method guid\n             * @grammar Base.guid() => String\n             * @grammar Base.guid( prefx ) => String\n             */\n            guid: (function() {\n                var counter = 0;\n\n                return function( prefix ) {\n                    var guid = (+new Date()).toString( 32 ),\n                        i = 0;\n\n                    for ( ; i < 5; i++ ) {\n                        guid += Math.floor( Math.random() * 65535 ).toString( 32 );\n                    }\n\n                    return (prefix || 'wu_') + guid + (counter++).toString( 32 );\n                };\n            })(),\n\n            /**\n             * 格式化文件大小, 输出成带单位的字符串\n             * @method formatSize\n             * @grammar Base.formatSize( size ) => String\n             * @grammar Base.formatSize( size, pointLength ) => String\n             * @grammar Base.formatSize( size, pointLength, units ) => String\n             * @param {Number} size 文件大小\n             * @param {Number} [pointLength=2] 精确到的小数点数。\n             * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 单位数组。从字节，到千字节，一直往上指定。如果单位数组里面只指定了到了K(千字节)，同时文件大小大于M, 此方法的输出将还是显示成多少K.\n             * @example\n             * console.log( Base.formatSize( 100 ) );    // => 100B\n             * console.log( Base.formatSize( 1024 ) );    // => 1.00K\n             * console.log( Base.formatSize( 1024, 0 ) );    // => 1K\n             * console.log( Base.formatSize( 1024 * 1024 ) );    // => 1.00M\n             * console.log( Base.formatSize( 1024 * 1024 * 1024 ) );    // => 1.00G\n             * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) );    // => 1024MB\n             */\n            formatSize: function( size, pointLength, units ) {\n                var unit;\n\n                units = units || [ 'B', 'K', 'M', 'G', 'TB' ];\n\n                while ( (unit = units.shift()) && size > 1024 ) {\n                    size = size / 1024;\n                }\n\n                return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) +\n                        unit;\n            }\n        };\n    });\n    /**\n     * 事件处理类，可以独立使用，也可以扩展给对象使用。\n     * @fileOverview Mediator\n     */\n    define('mediator',[\n        'base'\n    ], function( Base ) {\n        var $ = Base.$,\n            slice = [].slice,\n            separator = /\\s+/,\n            protos;\n\n        // 根据条件过滤出事件handlers.\n        function findHandlers( arr, name, callback, context ) {\n            return $.grep( arr, function( handler ) {\n                return handler &&\n                        (!name || handler.e === name) &&\n                        (!callback || handler.cb === callback ||\n                        handler.cb._cb === callback) &&\n                        (!context || handler.ctx === context);\n            });\n        }\n\n        function eachEvent( events, callback, iterator ) {\n            // 不支持对象，只支持多个event用空格隔开\n            $.each( (events || '').split( separator ), function( _, key ) {\n                iterator( key, callback );\n            });\n        }\n\n        function triggerHanders( events, args ) {\n            var stoped = false,\n                i = -1,\n                len = events.length,\n                handler;\n\n            while ( ++i < len ) {\n                handler = events[ i ];\n\n                if ( handler.cb.apply( handler.ctx2, args ) === false ) {\n                    stoped = true;\n                    break;\n                }\n            }\n\n            return !stoped;\n        }\n\n        protos = {\n\n            /**\n             * 绑定事件。\n             *\n             * `callback`方法在执行时，arguments将会来源于trigger的时候携带的参数。如\n             * ```javascript\n             * var obj = {};\n             *\n             * // 使得obj有事件行为\n             * Mediator.installTo( obj );\n             *\n             * obj.on( 'testa', function( arg1, arg2 ) {\n             *     console.log( arg1, arg2 ); // => 'arg1', 'arg2'\n             * });\n             *\n             * obj.trigger( 'testa', 'arg1', 'arg2' );\n             * ```\n             *\n             * 如果`callback`中，某一个方法`return false`了，则后续的其他`callback`都不会被执行到。\n             * 切会影响到`trigger`方法的返回值，为`false`。\n             *\n             * `on`还可以用来添加一个特殊事件`all`, 这样所有的事件触发都会响应到。同时此类`callback`中的arguments有一个不同处，\n             * 就是第一个参数为`type`，记录当前是什么事件在触发。此类`callback`的优先级比脚低，会再正常`callback`执行完后触发。\n             * ```javascript\n             * obj.on( 'all', function( type, arg1, arg2 ) {\n             *     console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2'\n             * });\n             * ```\n             *\n             * @method on\n             * @grammar on( name, callback[, context] ) => self\n             * @param  {String}   name     事件名，支持多个事件用空格隔开\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             * @class Mediator\n             */\n            on: function( name, callback, context ) {\n                var me = this,\n                    set;\n\n                if ( !callback ) {\n                    return this;\n                }\n\n                set = this._events || (this._events = []);\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var handler = { e: name };\n\n                    handler.cb = callback;\n                    handler.ctx = context;\n                    handler.ctx2 = context || me;\n                    handler.id = set.length;\n\n                    set.push( handler );\n                });\n\n                return this;\n            },\n\n            /**\n             * 绑定事件，且当handler执行完后，自动解除绑定。\n             * @method once\n             * @grammar once( name, callback[, context] ) => self\n             * @param  {String}   name     事件名\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            once: function( name, callback, context ) {\n                var me = this;\n\n                if ( !callback ) {\n                    return me;\n                }\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var once = function() {\n                            me.off( name, once );\n                            return callback.apply( context || me, arguments );\n                        };\n\n                    once._cb = callback;\n                    me.on( name, once, context );\n                });\n\n                return me;\n            },\n\n            /**\n             * 解除事件绑定\n             * @method off\n             * @grammar off( [name[, callback[, context] ] ] ) => self\n             * @param  {String}   [name]     事件名\n             * @param  {Function} [callback] 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            off: function( name, cb, ctx ) {\n                var events = this._events;\n\n                if ( !events ) {\n                    return this;\n                }\n\n                if ( !name && !cb && !ctx ) {\n                    this._events = [];\n                    return this;\n                }\n\n                eachEvent( name, cb, function( name, cb ) {\n                    $.each( findHandlers( events, name, cb, ctx ), function() {\n                        delete events[ this.id ];\n                    });\n                });\n\n                return this;\n            },\n\n            /**\n             * 触发事件\n             * @method trigger\n             * @grammar trigger( name[, args...] ) => self\n             * @param  {String}   type     事件名\n             * @param  {*} [...] 任意参数\n             * @return {Boolean} 如果handler中return false了，则返回false, 否则返回true\n             */\n            trigger: function( type ) {\n                var args, events, allEvents;\n\n                if ( !this._events || !type ) {\n                    return this;\n                }\n\n                args = slice.call( arguments, 1 );\n                events = findHandlers( this._events, type );\n                allEvents = findHandlers( this._events, 'all' );\n\n                return triggerHanders( events, args ) &&\n                        triggerHanders( allEvents, arguments );\n            }\n        };\n\n        /**\n         * 中介者，它本身是个单例，但可以通过[installTo](#WebUploader:Mediator:installTo)方法，使任何对象具备事件行为。\n         * 主要目的是负责模块与模块之间的合作，降低耦合度。\n         *\n         * @class Mediator\n         */\n        return $.extend({\n\n            /**\n             * 可以通过这个接口，使任何对象具备事件功能。\n             * @method installTo\n             * @param  {Object} obj 需要具备事件行为的对象。\n             * @return {Object} 返回obj.\n             */\n            installTo: function( obj ) {\n                return $.extend( obj, protos );\n            }\n\n        }, protos );\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('uploader',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$;\n\n        /**\n         * 上传入口类。\n         * @class Uploader\n         * @constructor\n         * @grammar new Uploader( opts ) => Uploader\n         * @example\n         * var uploader = WebUploader.Uploader({\n         *     swf: 'path_of_swf/Uploader.swf',\n         *\n         *     // 开起分片上传。\n         *     chunked: true\n         * });\n         */\n        function Uploader( opts ) {\n            this.options = $.extend( true, {}, Uploader.options, opts );\n            this._init( this.options );\n        }\n\n        // default Options\n        // widgets中有相应扩展\n        Uploader.options = {};\n        Mediator.installTo( Uploader.prototype );\n\n        // 批量添加纯命令式方法。\n        $.each({\n            upload: 'start-upload',\n            stop: 'stop-upload',\n            getFile: 'get-file',\n            getFiles: 'get-files',\n            addFile: 'add-file',\n            addFiles: 'add-file',\n            sort: 'sort-files',\n            removeFile: 'remove-file',\n            cancelFile: 'cancel-file',\n            skipFile: 'skip-file',\n            retry: 'retry',\n            isInProgress: 'is-in-progress',\n            makeThumb: 'make-thumb',\n            md5File: 'md5-file',\n            getDimension: 'get-dimension',\n            addButton: 'add-btn',\n            predictRuntimeType: 'predict-runtime-type',\n            refresh: 'refresh',\n            disable: 'disable',\n            enable: 'enable',\n            reset: 'reset'\n        }, function( fn, command ) {\n            Uploader.prototype[ fn ] = function() {\n                return this.request( command, arguments );\n            };\n        });\n\n        $.extend( Uploader.prototype, {\n            state: 'pending',\n\n            _init: function( opts ) {\n                var me = this;\n\n                me.request( 'init', opts, function() {\n                    me.state = 'ready';\n                    me.trigger('ready');\n                });\n            },\n\n            /**\n             * 获取或者设置Uploader配置项。\n             * @method option\n             * @grammar option( key ) => *\n             * @grammar option( key, val ) => self\n             * @example\n             *\n             * // 初始状态图片上传前不会压缩\n             * var uploader = new WebUploader.Uploader({\n             *     compress: null;\n             * });\n             *\n             * // 修改后图片上传前，尝试将图片压缩到1600 * 1600\n             * uploader.option( 'compress', {\n             *     width: 1600,\n             *     height: 1600\n             * });\n             */\n            option: function( key, val ) {\n                var opts = this.options;\n\n                // setter\n                if ( arguments.length > 1 ) {\n\n                    if ( $.isPlainObject( val ) &&\n                            $.isPlainObject( opts[ key ] ) ) {\n                        $.extend( opts[ key ], val );\n                    } else {\n                        opts[ key ] = val;\n                    }\n\n                } else {    // getter\n                    return key ? opts[ key ] : opts;\n                }\n            },\n\n            /**\n             * 获取文件统计信息。返回一个包含一下信息的对象。\n             * * `successNum` 上传成功的文件数\n             * * `progressNum` 上传中的文件数\n             * * `cancelNum` 被删除的文件数\n             * * `invalidNum` 无效的文件数\n             * * `uploadFailNum` 上传失败的文件数\n             * * `queueNum` 还在队列中的文件数\n             * * `interruptNum` 被暂停的文件数\n             * @method getStats\n             * @grammar getStats() => Object\n             */\n            getStats: function() {\n                // return this._mgr.getStats.apply( this._mgr, arguments );\n                var stats = this.request('get-stats');\n\n                return stats ? {\n                    successNum: stats.numOfSuccess,\n                    progressNum: stats.numOfProgress,\n\n                    // who care?\n                    // queueFailNum: 0,\n                    cancelNum: stats.numOfCancel,\n                    invalidNum: stats.numOfInvalid,\n                    uploadFailNum: stats.numOfUploadFailed,\n                    queueNum: stats.numOfQueue,\n                    interruptNum: stats.numofInterrupt\n                } : {};\n            },\n\n            // 需要重写此方法来来支持opts.onEvent和instance.onEvent的处理器\n            trigger: function( type/*, args...*/ ) {\n                var args = [].slice.call( arguments, 1 ),\n                    opts = this.options,\n                    name = 'on' + type.substring( 0, 1 ).toUpperCase() +\n                        type.substring( 1 );\n\n                if (\n                        // 调用通过on方法注册的handler.\n                        Mediator.trigger.apply( this, arguments ) === false ||\n\n                        // 调用opts.onEvent\n                        $.isFunction( opts[ name ] ) &&\n                        opts[ name ].apply( this, args ) === false ||\n\n                        // 调用this.onEvent\n                        $.isFunction( this[ name ] ) &&\n                        this[ name ].apply( this, args ) === false ||\n\n                        // 广播所有uploader的事件。\n                        Mediator.trigger.apply( Mediator,\n                        [ this, type ].concat( args ) ) === false ) {\n\n                    return false;\n                }\n\n                return true;\n            },\n\n            /**\n             * 销毁 webuploader 实例\n             * @method destroy\n             * @grammar destroy() => undefined\n             */\n            destroy: function() {\n                this.request( 'destroy', arguments );\n                this.off();\n            },\n\n            // widgets/widget.js将补充此方法的详细文档。\n            request: Base.noop\n        });\n\n        /**\n         * 创建Uploader实例，等同于new Uploader( opts );\n         * @method create\n         * @class Base\n         * @static\n         * @grammar Base.create( opts ) => Uploader\n         */\n        Base.create = Uploader.create = function( opts ) {\n            return new Uploader( opts );\n        };\n\n        // 暴露Uploader，可以通过它来扩展业务逻辑。\n        Base.Uploader = Uploader;\n\n        return Uploader;\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/runtime',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            factories = {},\n\n            // 获取对象的第一个key\n            getFirstKey = function( obj ) {\n                for ( var key in obj ) {\n                    if ( obj.hasOwnProperty( key ) ) {\n                        return key;\n                    }\n                }\n                return null;\n            };\n\n        // 接口类。\n        function Runtime( options ) {\n            this.options = $.extend({\n                container: document.body\n            }, options );\n            this.uid = Base.guid('rt_');\n        }\n\n        $.extend( Runtime.prototype, {\n\n            getContainer: function() {\n                var opts = this.options,\n                    parent, container;\n\n                if ( this._container ) {\n                    return this._container;\n                }\n\n                parent = $( opts.container || document.body );\n                container = $( document.createElement('div') );\n\n                container.attr( 'id', 'rt_' + this.uid );\n                container.css({\n                    position: 'absolute',\n                    top: '0px',\n                    left: '0px',\n                    width: '1px',\n                    height: '1px',\n                    overflow: 'hidden'\n                });\n\n                parent.append( container );\n                parent.addClass('webuploader-container');\n                this._container = container;\n                this._parent = parent;\n                return container;\n            },\n\n            init: Base.noop,\n            exec: Base.noop,\n\n            destroy: function() {\n                this._container && this._container.remove();\n                this._parent && this._parent.removeClass('webuploader-container');\n                this.off();\n            }\n        });\n\n        Runtime.orders = 'html5,flash';\n\n\n        /**\n         * 添加Runtime实现。\n         * @param {String} type    类型\n         * @param {Runtime} factory 具体Runtime实现。\n         */\n        Runtime.addRuntime = function( type, factory ) {\n            factories[ type ] = factory;\n        };\n\n        Runtime.hasRuntime = function( type ) {\n            return !!(type ? factories[ type ] : getFirstKey( factories ));\n        };\n\n        Runtime.create = function( opts, orders ) {\n            var type, runtime;\n\n            orders = orders || Runtime.orders;\n            $.each( orders.split( /\\s*,\\s*/g ), function() {\n                if ( factories[ this ] ) {\n                    type = this;\n                    return false;\n                }\n            });\n\n            type = type || getFirstKey( factories );\n\n            if ( !type ) {\n                throw new Error('Runtime Error');\n            }\n\n            runtime = new factories[ type ]( opts );\n            return runtime;\n        };\n\n        Mediator.installTo( Runtime.prototype );\n        return Runtime;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/client',[\n        'base',\n        'mediator',\n        'runtime/runtime'\n    ], function( Base, Mediator, Runtime ) {\n\n        var cache;\n\n        cache = (function() {\n            var obj = {};\n\n            return {\n                add: function( runtime ) {\n                    obj[ runtime.uid ] = runtime;\n                },\n\n                get: function( ruid, standalone ) {\n                    var i;\n\n                    if ( ruid ) {\n                        return obj[ ruid ];\n                    }\n\n                    for ( i in obj ) {\n                        // 有些类型不能重用，比如filepicker.\n                        if ( standalone && obj[ i ].__standalone ) {\n                            continue;\n                        }\n\n                        return obj[ i ];\n                    }\n\n                    return null;\n                },\n\n                remove: function( runtime ) {\n                    delete obj[ runtime.uid ];\n                }\n            };\n        })();\n\n        function RuntimeClient( component, standalone ) {\n            var deferred = Base.Deferred(),\n                runtime;\n\n            this.uid = Base.guid('client_');\n\n            // 允许runtime没有初始化之前，注册一些方法在初始化后执行。\n            this.runtimeReady = function( cb ) {\n                return deferred.done( cb );\n            };\n\n            this.connectRuntime = function( opts, cb ) {\n\n                // already connected.\n                if ( runtime ) {\n                    throw new Error('already connected!');\n                }\n\n                deferred.done( cb );\n\n                if ( typeof opts === 'string' && cache.get( opts ) ) {\n                    runtime = cache.get( opts );\n                }\n\n                // 像filePicker只能独立存在，不能公用。\n                runtime = runtime || cache.get( null, standalone );\n\n                // 需要创建\n                if ( !runtime ) {\n                    runtime = Runtime.create( opts, opts.runtimeOrder );\n                    runtime.__promise = deferred.promise();\n                    runtime.once( 'ready', deferred.resolve );\n                    runtime.init();\n                    cache.add( runtime );\n                    runtime.__client = 1;\n                } else {\n                    // 来自cache\n                    Base.$.extend( runtime.options, opts );\n                    runtime.__promise.then( deferred.resolve );\n                    runtime.__client++;\n                }\n\n                standalone && (runtime.__standalone = standalone);\n                return runtime;\n            };\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.disconnectRuntime = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                runtime.__client--;\n\n                if ( runtime.__client <= 0 ) {\n                    cache.remove( runtime );\n                    delete runtime.__promise;\n                    runtime.destroy();\n                }\n\n                runtime = null;\n            };\n\n            this.exec = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                var args = Base.slice( arguments );\n                component && args.unshift( component );\n\n                return runtime.exec.apply( this, args );\n            };\n\n            this.getRuid = function() {\n                return runtime && runtime.uid;\n            };\n\n            this.destroy = (function( destroy ) {\n                return function() {\n                    destroy && destroy.apply( this, arguments );\n                    this.trigger('destroy');\n                    this.off();\n                    this.exec('destroy');\n                    this.disconnectRuntime();\n                };\n            })( this.destroy );\n        }\n\n        Mediator.installTo( RuntimeClient.prototype );\n        return RuntimeClient;\n    });\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/dnd',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function DragAndDrop( opts ) {\n            opts = this.options = $.extend({}, DragAndDrop.options, opts );\n\n            opts.container = $( opts.container );\n\n            if ( !opts.container.length ) {\n                return;\n            }\n\n            RuntimeClent.call( this, 'DragAndDrop' );\n        }\n\n        DragAndDrop.options = {\n            accept: null,\n            disableGlobalDnd: false\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: DragAndDrop,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( DragAndDrop.prototype );\n\n        return DragAndDrop;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/widget',[\n        'base',\n        'uploader'\n    ], function( Base, Uploader ) {\n\n        var $ = Base.$,\n            _init = Uploader.prototype._init,\n            _destroy = Uploader.prototype.destroy,\n            IGNORE = {},\n            widgetClass = [];\n\n        function isArrayLike( obj ) {\n            if ( !obj ) {\n                return false;\n            }\n\n            var length = obj.length,\n                type = $.type( obj );\n\n            if ( obj.nodeType === 1 && length ) {\n                return true;\n            }\n\n            return type === 'array' || type !== 'function' && type !== 'string' &&\n                    (length === 0 || typeof length === 'number' && length > 0 &&\n                    (length - 1) in obj);\n        }\n\n        function Widget( uploader ) {\n            this.owner = uploader;\n            this.options = uploader.options;\n        }\n\n        $.extend( Widget.prototype, {\n\n            init: Base.noop,\n\n            // 类Backbone的事件监听声明，监听uploader实例上的事件\n            // widget直接无法监听事件，事件只能通过uploader来传递\n            invoke: function( apiName, args ) {\n\n                /*\n                    {\n                        'make-thumb': 'makeThumb'\n                    }\n                 */\n                var map = this.responseMap;\n\n                // 如果无API响应声明则忽略\n                if ( !map || !(apiName in map) || !(map[ apiName ] in this) ||\n                        !$.isFunction( this[ map[ apiName ] ] ) ) {\n\n                    return IGNORE;\n                }\n\n                return this[ map[ apiName ] ].apply( this, args );\n\n            },\n\n            /**\n             * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。\n             * @method request\n             * @grammar request( command, args ) => * | Promise\n             * @grammar request( command, args, callback ) => Promise\n             * @for  Uploader\n             */\n            request: function() {\n                return this.owner.request.apply( this.owner, arguments );\n            }\n        });\n\n        // 扩展Uploader.\n        $.extend( Uploader.prototype, {\n\n            /**\n             * @property {String | Array} [disableWidgets=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。\n             */\n\n            // 覆写_init用来初始化widgets\n            _init: function() {\n                var me = this,\n                    widgets = me._widgets = [],\n                    deactives = me.options.disableWidgets || '';\n\n                $.each( widgetClass, function( _, klass ) {\n                    (!deactives || !~deactives.indexOf( klass._name )) &&\n                        widgets.push( new klass( me ) );\n                });\n\n                return _init.apply( me, arguments );\n            },\n\n            request: function( apiName, args, callback ) {\n                var i = 0,\n                    widgets = this._widgets,\n                    len = widgets && widgets.length,\n                    rlts = [],\n                    dfds = [],\n                    widget, rlt, promise, key;\n\n                args = isArrayLike( args ) ? args : [ args ];\n\n                for ( ; i < len; i++ ) {\n                    widget = widgets[ i ];\n                    rlt = widget.invoke( apiName, args );\n\n                    if ( rlt !== IGNORE ) {\n\n                        // Deferred对象\n                        if ( Base.isPromise( rlt ) ) {\n                            dfds.push( rlt );\n                        } else {\n                            rlts.push( rlt );\n                        }\n                    }\n                }\n\n                // 如果有callback，则用异步方式。\n                if ( callback || dfds.length ) {\n                    promise = Base.when.apply( Base, dfds );\n                    key = promise.pipe ? 'pipe' : 'then';\n\n                    // 很重要不能删除。删除了会死循环。\n                    // 保证执行顺序。让callback总是在下一个 tick 中执行。\n                    return promise[ key ](function() {\n                                var deferred = Base.Deferred(),\n                                    args = arguments;\n\n                                if ( args.length === 1 ) {\n                                    args = args[ 0 ];\n                                }\n\n                                setTimeout(function() {\n                                    deferred.resolve( args );\n                                }, 1 );\n\n                                return deferred.promise();\n                            })[ callback ? key : 'done' ]( callback || Base.noop );\n                } else {\n                    return rlts[ 0 ];\n                }\n            },\n\n            destroy: function() {\n                _destroy.apply( this, arguments );\n                this._widgets = null;\n            }\n        });\n\n        /**\n         * 添加组件\n         * @grammar Uploader.register(proto);\n         * @grammar Uploader.register(map, proto);\n         * @param  {object} responseMap API 名称与函数实现的映射\n         * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义\n         * @method Uploader.register\n         * @for Uploader\n         * @example\n         * Uploader.register({\n         *     'make-thumb': 'makeThumb'\n         * }, {\n         *     init: function( options ) {},\n         *     makeThumb: function() {}\n         * });\n         *\n         * Uploader.register({\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         */\n        Uploader.register = Widget.register = function( responseMap, widgetProto ) {\n            var map = { init: 'init', destroy: 'destroy', name: 'anonymous' },\n                klass;\n\n            if ( arguments.length === 1 ) {\n                widgetProto = responseMap;\n\n                // 自动生成 map 表。\n                $.each(widgetProto, function(key) {\n                    if ( key[0] === '_' || key === 'name' ) {\n                        key === 'name' && (map.name = widgetProto.name);\n                        return;\n                    }\n\n                    map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;\n                });\n\n            } else {\n                map = $.extend( map, responseMap );\n            }\n\n            widgetProto.responseMap = map;\n            klass = Base.inherits( Widget, widgetProto );\n            klass._name = map.name;\n            widgetClass.push( klass );\n\n            return klass;\n        };\n\n        /**\n         * 删除插件，只有在注册时指定了名字的才能被删除。\n         * @grammar Uploader.unRegister(name);\n         * @param  {string} name 组件名字\n         * @method Uploader.unRegister\n         * @for Uploader\n         * @example\n         *\n         * Uploader.register({\n         *     name: 'custom',\n         *\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         *\n         * Uploader.unRegister('custom');\n         */\n        Uploader.unRegister = Widget.unRegister = function( name ) {\n            if ( !name || name === 'anonymous' ) {\n                return;\n            }\n\n            // 删除指定的插件。\n            for ( var i = widgetClass.length; i--; ) {\n                if ( widgetClass[i]._name === name ) {\n                    widgetClass.splice(i, 1)\n                }\n            }\n        };\n\n        return Widget;\n    });\n    /**\n     * @fileOverview DragAndDrop Widget。\n     */\n    define('widgets/filednd',[\n        'base',\n        'uploader',\n        'lib/dnd',\n        'widgets/widget'\n    ], function( Base, Uploader, Dnd ) {\n        var $ = Base.$;\n\n        Uploader.options.dnd = '';\n\n        /**\n         * @property {Selector} [dnd=undefined]  指定Drag And Drop拖拽的容器，如果不指定，则不启动。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @property {Selector} [disableGlobalDnd=false]  是否禁掉整个页面的拖拽功能，如果不禁用，图片拖进来的时候会默认被浏览器打开。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @event dndAccept\n         * @param {DataTransferItemList} items DataTransferItem\n         * @description 阻止此事件可以拒绝某些类型的文件拖入进来。目前只有 chrome 提供这样的 API，且只能通过 mime-type 验证。\n         * @for  Uploader\n         */\n        return Uploader.register({\n            name: 'dnd',\n\n            init: function( opts ) {\n\n                if ( !opts.dnd ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        disableGlobalDnd: opts.disableGlobalDnd,\n                        container: opts.dnd,\n                        accept: opts.accept\n                    }),\n                    dnd;\n\n                this.dnd = dnd = new Dnd( options );\n\n                dnd.once( 'ready', deferred.resolve );\n                dnd.on( 'drop', function( files ) {\n                    me.request( 'add-file', [ files ]);\n                });\n\n                // 检测文件是否全部允许添加。\n                dnd.on( 'accept', function( items ) {\n                    return me.owner.trigger( 'dndAccept', items );\n                });\n\n                dnd.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.dnd && this.dnd.destroy();\n            }\n        });\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepaste',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function FilePaste( opts ) {\n            opts = this.options = $.extend({}, opts );\n            opts.container = $( opts.container || document.body );\n            RuntimeClent.call( this, 'FilePaste' );\n        }\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePaste,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( FilePaste.prototype );\n\n        return FilePaste;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/filepaste',[\n        'base',\n        'uploader',\n        'lib/filepaste',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePaste ) {\n        var $ = Base.$;\n\n        /**\n         * @property {Selector} [paste=undefined]  指定监听paste事件的容器，如果不指定，不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为`document.body`.\n         * @namespace options\n         * @for Uploader\n         */\n        return Uploader.register({\n            name: 'paste',\n\n            init: function( opts ) {\n\n                if ( !opts.paste ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        container: opts.paste,\n                        accept: opts.accept\n                    }),\n                    paste;\n\n                this.paste = paste = new FilePaste( options );\n\n                paste.once( 'ready', deferred.resolve );\n                paste.on( 'paste', function( files ) {\n                    me.owner.request( 'add-file', [ files ]);\n                });\n                paste.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.paste && this.paste.destroy();\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob\n     */\n    define('lib/blob',[\n        'base',\n        'runtime/client'\n    ], function( Base, RuntimeClient ) {\n\n        function Blob( ruid, source ) {\n            var me = this;\n\n            me.source = source;\n            me.ruid = ruid;\n            this.size = source.size || 0;\n\n            // 如果没有指定 mimetype, 但是知道文件后缀。\n            if ( !source.type && this.ext &&\n                    ~'jpg,jpeg,png,gif,bmp'.indexOf( this.ext ) ) {\n                this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);\n            } else {\n                this.type = source.type || 'application/octet-stream';\n            }\n\n            RuntimeClient.call( me, 'Blob' );\n            this.uid = source.uid || this.uid;\n\n            if ( ruid ) {\n                me.connectRuntime( ruid );\n            }\n        }\n\n        Base.inherits( RuntimeClient, {\n            constructor: Blob,\n\n            slice: function( start, end ) {\n                return this.exec( 'slice', start, end );\n            },\n\n            getSource: function() {\n                return this.source;\n            }\n        });\n\n        return Blob;\n    });\n    /**\n     * 为了统一化Flash的File和HTML5的File而存在。\n     * 以至于要调用Flash里面的File，也可以像调用HTML5版本的File一下。\n     * @fileOverview File\n     */\n    define('lib/file',[\n        'base',\n        'lib/blob'\n    ], function( Base, Blob ) {\n\n        var uid = 1,\n            rExt = /\\.([^.]+)$/;\n\n        function File( ruid, file ) {\n            var ext;\n\n            this.name = file.name || ('untitled' + uid++);\n            ext = rExt.exec( file.name ) ? RegExp.$1.toLowerCase() : '';\n\n            // todo 支持其他类型文件的转换。\n            // 如果有 mimetype, 但是文件名里面没有找出后缀规律\n            if ( !ext && file.type ) {\n                ext = /\\/(jpg|jpeg|png|gif|bmp)$/i.exec( file.type ) ?\n                        RegExp.$1.toLowerCase() : '';\n                this.name += '.' + ext;\n            }\n\n            this.ext = ext;\n            this.lastModifiedDate = file.lastModifiedDate ||\n                    (new Date()).toLocaleString();\n\n            Blob.apply( this, arguments );\n        }\n\n        return Base.inherits( Blob, File );\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepicker',[\n        'base',\n        'runtime/client',\n        'lib/file'\n    ], function( Base, RuntimeClent, File ) {\n\n        var $ = Base.$;\n\n        function FilePicker( opts ) {\n            opts = this.options = $.extend({}, FilePicker.options, opts );\n\n            opts.container = $( opts.id );\n\n            if ( !opts.container.length ) {\n                throw new Error('按钮指定错误');\n            }\n\n            opts.innerHTML = opts.innerHTML || opts.label ||\n                    opts.container.html() || '';\n\n            opts.button = $( opts.button || document.createElement('div') );\n            opts.button.html( opts.innerHTML );\n            opts.container.html( opts.button );\n\n            RuntimeClent.call( this, 'FilePicker', true );\n        }\n\n        FilePicker.options = {\n            button: null,\n            container: null,\n            label: null,\n            innerHTML: null,\n            multiple: true,\n            accept: null,\n            name: 'file'\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePicker,\n\n            init: function() {\n                var me = this,\n                    opts = me.options,\n                    button = opts.button;\n\n                button.addClass('webuploader-pick');\n\n                me.on( 'all', function( type ) {\n                    var files;\n\n                    switch ( type ) {\n                        case 'mouseenter':\n                            button.addClass('webuploader-pick-hover');\n                            break;\n\n                        case 'mouseleave':\n                            button.removeClass('webuploader-pick-hover');\n                            break;\n\n                        case 'change':\n                            files = me.exec('getFiles');\n                            me.trigger( 'select', $.map( files, function( file ) {\n                                file = new File( me.getRuid(), file );\n\n                                // 记录来源。\n                                file._refer = opts.container;\n                                return file;\n                            }), opts.container );\n                            break;\n                    }\n                });\n\n                me.connectRuntime( opts, function() {\n                    me.refresh();\n                    me.exec( 'init', opts );\n                    me.trigger('ready');\n                });\n\n                this._resizeHandler = Base.bindFn( this.refresh, this );\n                $( window ).on( 'resize', this._resizeHandler );\n            },\n\n            refresh: function() {\n                var shimContainer = this.getRuntime().getContainer(),\n                    button = this.options.button,\n                    width = button.outerWidth ?\n                            button.outerWidth() : button.width(),\n\n                    height = button.outerHeight ?\n                            button.outerHeight() : button.height(),\n\n                    pos = button.offset();\n\n                width && height && shimContainer.css({\n                    bottom: 'auto',\n                    right: 'auto',\n                    width: width + 'px',\n                    height: height + 'px'\n                }).offset( pos );\n            },\n\n            enable: function() {\n                var btn = this.options.button;\n\n                btn.removeClass('webuploader-pick-disable');\n                this.refresh();\n            },\n\n            disable: function() {\n                var btn = this.options.button;\n\n                this.getRuntime().getContainer().css({\n                    top: '-99999px'\n                });\n\n                btn.addClass('webuploader-pick-disable');\n            },\n\n            destroy: function() {\n                var btn = this.options.button;\n                $( window ).off( 'resize', this._resizeHandler );\n                btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +\n                    'webuploader-pick');\n            }\n        });\n\n        return FilePicker;\n    });\n\n    /**\n     * @fileOverview 文件选择相关\n     */\n    define('widgets/filepicker',[\n        'base',\n        'uploader',\n        'lib/filepicker',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePicker ) {\n        var $ = Base.$;\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Selector | Object} [pick=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 指定选择文件的按钮容器，不指定则不创建按钮。\n             *\n             * * `id` {Seletor|dom} 指定选择文件的按钮容器，不指定则不创建按钮。**注意** 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。\n             * * `label` {String} 请采用 `innerHTML` 代替\n             * * `innerHTML` {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。\n             * * `multiple` {Boolean} 是否开起同时选择多个文件能力。\n             */\n            pick: null,\n\n            /**\n             * @property {Arroy} [accept=null]\n             * @namespace options\n             * @for Uploader\n             * @description 指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。\n             *\n             * * `title` {String} 文字描述\n             * * `extensions` {String} 允许的文件后缀，不带点，多个用逗号分割。\n             * * `mimeTypes` {String} 多个用逗号分割。\n             *\n             * 如：\n             *\n             * ```\n             * {\n             *     title: 'Images',\n             *     extensions: 'gif,jpg,jpeg,bmp,png',\n             *     mimeTypes: 'image/*'\n             * }\n             * ```\n             */\n            accept: null/*{\n                title: 'Images',\n                extensions: 'gif,jpg,jpeg,bmp,png',\n                mimeTypes: 'image/*'\n            }*/\n        });\n\n        return Uploader.register({\n            name: 'picker',\n\n            init: function( opts ) {\n                this.pickers = [];\n                return opts.pick && this.addBtn( opts.pick );\n            },\n\n            refresh: function() {\n                $.each( this.pickers, function() {\n                    this.refresh();\n                });\n            },\n\n            /**\n             * @method addButton\n             * @for Uploader\n             * @grammar addButton( pick ) => Promise\n             * @description\n             * 添加文件选择按钮，如果一个按钮不够，需要调用此方法来添加。参数跟[options.pick](#WebUploader:Uploader:options)一致。\n             * @example\n             * uploader.addButton({\n             *     id: '#btnContainer',\n             *     innerHTML: '选择文件'\n             * });\n             */\n            addBtn: function( pick ) {\n                var me = this,\n                    opts = me.options,\n                    accept = opts.accept,\n                    promises = [];\n\n                if ( !pick ) {\n                    return;\n                }\n\n                $.isPlainObject( pick ) || (pick = {\n                    id: pick\n                });\n\n                $( pick.id ).each(function() {\n                    var options, picker, deferred;\n\n                    deferred = Base.Deferred();\n\n                    options = $.extend({}, pick, {\n                        accept: $.isPlainObject( accept ) ? [ accept ] : accept,\n                        swf: opts.swf,\n                        runtimeOrder: opts.runtimeOrder,\n                        id: this\n                    });\n\n                    picker = new FilePicker( options );\n\n                    picker.once( 'ready', deferred.resolve );\n                    picker.on( 'select', function( files ) {\n                        me.owner.request( 'add-file', [ files ]);\n                    });\n                    picker.init();\n\n                    me.pickers.push( picker );\n\n                    promises.push( deferred.promise() );\n                });\n\n                return Base.when.apply( Base, promises );\n            },\n\n            disable: function() {\n                $.each( this.pickers, function() {\n                    this.disable();\n                });\n            },\n\n            enable: function() {\n                $.each( this.pickers, function() {\n                    this.enable();\n                });\n            },\n\n            destroy: function() {\n                $.each( this.pickers, function() {\n                    this.destroy();\n                });\n                this.pickers = null;\n            }\n        });\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('lib/image',[\n        'base',\n        'runtime/client',\n        'lib/blob'\n    ], function( Base, RuntimeClient, Blob ) {\n        var $ = Base.$;\n\n        // 构造器。\n        function Image( opts ) {\n            this.options = $.extend({}, Image.options, opts );\n            RuntimeClient.call( this, 'Image' );\n\n            this.on( 'load', function() {\n                this._info = this.exec('info');\n                this._meta = this.exec('meta');\n            });\n        }\n\n        // 默认选项。\n        Image.options = {\n\n            // 默认的图片处理质量\n            quality: 90,\n\n            // 是否裁剪\n            crop: false,\n\n            // 是否保留头部信息\n            preserveHeaders: false,\n\n            // 是否允许放大。\n            allowMagnify: false\n        };\n\n        // 继承RuntimeClient.\n        Base.inherits( RuntimeClient, {\n            constructor: Image,\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    ruid = blob.getRuid();\n\n                this.connectRuntime( ruid, function() {\n                    me.exec( 'init', me.options );\n                    me.exec( 'loadFromBlob', blob );\n                });\n            },\n\n            resize: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'resize' ].concat( args ) );\n            },\n\n            crop: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'crop' ].concat( args ) );\n            },\n\n            getAsDataUrl: function( type ) {\n                return this.exec( 'getAsDataUrl', type );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this.exec( 'getAsBlob', type );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n\n        return Image;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/image',[\n        'base',\n        'uploader',\n        'lib/image',\n        'widgets/widget'\n    ], function( Base, Uploader, Image ) {\n\n        var $ = Base.$,\n            throttle;\n\n        // 根据要处理的文件大小来节流，一次不能处理太多，会卡。\n        throttle = (function( max ) {\n            var occupied = 0,\n                waiting = [],\n                tick = function() {\n                    var item;\n\n                    while ( waiting.length && occupied < max ) {\n                        item = waiting.shift();\n                        occupied += item[ 0 ];\n                        item[ 1 ]();\n                    }\n                };\n\n            return function( emiter, size, cb ) {\n                waiting.push([ size, cb ]);\n                emiter.once( 'destroy', function() {\n                    occupied -= size;\n                    setTimeout( tick, 1 );\n                });\n                setTimeout( tick, 1 );\n            };\n        })( 5 * 1024 * 1024 );\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Object} [thumb]\n             * @namespace options\n             * @for Uploader\n             * @description 配置生成缩略图的选项。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 110,\n             *     height: 110,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 70,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: true,\n             *\n             *     // 是否允许裁剪。\n             *     crop: true,\n             *\n             *     // 为空的话则保留原有图片格式。\n             *     // 否则强制转换成指定的类型。\n             *     type: 'image/jpeg'\n             * }\n             * ```\n             */\n            thumb: {\n                width: 110,\n                height: 110,\n                quality: 70,\n                allowMagnify: true,\n                crop: true,\n                preserveHeaders: false,\n\n                // 为空的话则保留原有图片格式。\n                // 否则强制转换成指定的类型。\n                // IE 8下面 base64 大小不能超过 32K 否则预览失败，而非 jpeg 编码的图片很可\n                // 能会超过 32k, 所以这里设置成预览的时候都是 image/jpeg\n                type: 'image/jpeg'\n            },\n\n            /**\n             * @property {Object} [compress]\n             * @namespace options\n             * @for Uploader\n             * @description 配置压缩的图片的选项。如果此选项为`false`, 则图片在上传前不进行压缩。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 1600,\n             *     height: 1600,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 90,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: false,\n             *\n             *     // 是否允许裁剪。\n             *     crop: false,\n             *\n             *     // 是否保留头部meta信息。\n             *     preserveHeaders: true,\n             *\n             *     // 如果发现压缩后文件大小比原来还大，则使用原来图片\n             *     // 此属性可能会影响图片自动纠正功能\n             *     noCompressIfLarger: false,\n             *\n             *     // 单位字节，如果图片大小小于此值，不会采用压缩。\n             *     compressSize: 0\n             * }\n             * ```\n             */\n            compress: {\n                width: 1600,\n                height: 1600,\n                quality: 90,\n                allowMagnify: false,\n                crop: false,\n                preserveHeaders: true\n            }\n        });\n\n        return Uploader.register({\n\n            name: 'image',\n\n\n            /**\n             * 生成缩略图，此过程为异步，所以需要传入`callback`。\n             * 通常情况在图片加入队里后调用此方法来生成预览图以增强交互效果。\n             *\n             * 当 width 或者 height 的值介于 0 - 1 时，被当成百分比使用。\n             *\n             * `callback`中可以接收到两个参数。\n             * * 第一个为error，如果生成缩略图有错误，此error将为真。\n             * * 第二个为ret, 缩略图的Data URL值。\n             *\n             * **注意**\n             * Date URL在IE6/7中不支持，所以不用调用此方法了，直接显示一张暂不支持预览图片好了。\n             * 也可以借助服务端，将 base64 数据传给服务端，生成一个临时文件供预览。\n             *\n             * @method makeThumb\n             * @grammar makeThumb( file, callback ) => undefined\n             * @grammar makeThumb( file, callback, width, height ) => undefined\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.makeThumb( file, function( error, ret ) {\n             *         if ( error ) {\n             *             $li.text('预览错误');\n             *         } else {\n             *             $li.append('<img alt=\"\" src=\"' + ret + '\" />');\n             *         }\n             *     });\n             *\n             * });\n             */\n            makeThumb: function( file, cb, width, height ) {\n                var opts, image;\n\n                file = this.request( 'get-file', file );\n\n                // 只预览图片格式。\n                if ( !file.type.match( /^image/ ) ) {\n                    cb( true );\n                    return;\n                }\n\n                opts = $.extend({}, this.options.thumb );\n\n                // 如果传入的是object.\n                if ( $.isPlainObject( width ) ) {\n                    opts = $.extend( opts, width );\n                    width = null;\n                }\n\n                width = width || opts.width;\n                height = height || opts.height;\n\n                image = new Image( opts );\n\n                image.once( 'load', function() {\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                // 当 resize 完后\n                image.once( 'complete', function() {\n                    cb( false, image.getAsDataUrl( opts.type ) );\n                    image.destroy();\n                });\n\n                image.once( 'error', function( reason ) {\n                    cb( reason || true );\n                    image.destroy();\n                });\n\n                throttle( image, file.source.size, function() {\n                    file._info && image.info( file._info );\n                    file._meta && image.meta( file._meta );\n                    image.loadFromBlob( file.source );\n                });\n            },\n\n            beforeSendFile: function( file ) {\n                var opts = this.options.compress || this.options.resize,\n                    compressSize = opts && opts.compressSize || 0,\n                    noCompressIfLarger = opts && opts.noCompressIfLarger || false,\n                    image, deferred;\n\n                file = this.request( 'get-file', file );\n\n                // 只压缩 jpeg 图片格式。\n                // gif 可能会丢失针\n                // bmp png 基本上尺寸都不大，且压缩比比较小。\n                if ( !opts || !~'image/jpeg,image/jpg'.indexOf( file.type ) ||\n                        file.size < compressSize ||\n                        file._compressed ) {\n                    return;\n                }\n\n                opts = $.extend({}, opts );\n                deferred = Base.Deferred();\n\n                image = new Image( opts );\n\n                deferred.always(function() {\n                    image.destroy();\n                    image = null;\n                });\n                image.once( 'error', deferred.reject );\n                image.once( 'load', function() {\n                    var width = opts.width,\n                        height = opts.height;\n\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                image.once( 'complete', function() {\n                    var blob, size;\n\n                    // 移动端 UC / qq 浏览器的无图模式下\n                    // ctx.getImageData 处理大图的时候会报 Exception\n                    // INDEX_SIZE_ERR: DOM Exception 1\n                    try {\n                        blob = image.getAsBlob( opts.type );\n\n                        size = file.size;\n\n                        // 如果压缩后，比原来还大则不用压缩后的。\n                        if ( !noCompressIfLarger || blob.size < size ) {\n                            // file.source.destroy && file.source.destroy();\n                            file.source = blob;\n                            file.size = blob.size;\n\n                            file.trigger( 'resize', blob.size, size );\n                        }\n\n                        // 标记，避免重复压缩。\n                        file._compressed = true;\n                        deferred.resolve();\n                    } catch ( e ) {\n                        // 出错了直接继续，让其上传原始图片\n                        deferred.resolve();\n                    }\n                });\n\n                file._info && image.info( file._info );\n                file._meta && image.meta( file._meta );\n\n                image.loadFromBlob( file.source );\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview 文件属性封装\n     */\n    define('file',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            idPrefix = 'WU_FILE_',\n            idSuffix = 0,\n            rExt = /\\.([^.]+)$/,\n            statusMap = {};\n\n        function gid() {\n            return idPrefix + idSuffix++;\n        }\n\n        /**\n         * 文件类\n         * @class File\n         * @constructor 构造函数\n         * @grammar new File( source ) => File\n         * @param {Lib.File} source [lib.File](#Lib.File)实例, 此source对象是带有Runtime信息的。\n         */\n        function WUFile( source ) {\n\n            /**\n             * 文件名，包括扩展名（后缀）\n             * @property name\n             * @type {string}\n             */\n            this.name = source.name || 'Untitled';\n\n            /**\n             * 文件体积（字节）\n             * @property size\n             * @type {uint}\n             * @default 0\n             */\n            this.size = source.size || 0;\n\n            /**\n             * 文件MIMETYPE类型，与文件类型的对应关系请参考[http://t.cn/z8ZnFny](http://t.cn/z8ZnFny)\n             * @property type\n             * @type {string}\n             * @default 'application/octet-stream'\n             */\n            this.type = source.type || 'application/octet-stream';\n\n            /**\n             * 文件最后修改日期\n             * @property lastModifiedDate\n             * @type {int}\n             * @default 当前时间戳\n             */\n            this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);\n\n            /**\n             * 文件ID，每个对象具有唯一ID，与文件名无关\n             * @property id\n             * @type {string}\n             */\n            this.id = gid();\n\n            /**\n             * 文件扩展名，通过文件名获取，例如test.png的扩展名为png\n             * @property ext\n             * @type {string}\n             */\n            this.ext = rExt.exec( this.name ) ? RegExp.$1 : '';\n\n\n            /**\n             * 状态文字说明。在不同的status语境下有不同的用途。\n             * @property statusText\n             * @type {string}\n             */\n            this.statusText = '';\n\n            // 存储文件状态，防止通过属性直接修改\n            statusMap[ this.id ] = WUFile.Status.INITED;\n\n            this.source = source;\n            this.loaded = 0;\n\n            this.on( 'error', function( msg ) {\n                this.setStatus( WUFile.Status.ERROR, msg );\n            });\n        }\n\n        $.extend( WUFile.prototype, {\n\n            /**\n             * 设置状态，状态变化时会触发`change`事件。\n             * @method setStatus\n             * @grammar setStatus( status[, statusText] );\n             * @param {File.Status|String} status [文件状态值](#WebUploader:File:File.Status)\n             * @param {String} [statusText=''] 状态说明，常在error时使用，用http, abort,server等来标记是由于什么原因导致文件错误。\n             */\n            setStatus: function( status, text ) {\n\n                var prevStatus = statusMap[ this.id ];\n\n                typeof text !== 'undefined' && (this.statusText = text);\n\n                if ( status !== prevStatus ) {\n                    statusMap[ this.id ] = status;\n                    /**\n                     * 文件状态变化\n                     * @event statuschange\n                     */\n                    this.trigger( 'statuschange', status, prevStatus );\n                }\n\n            },\n\n            /**\n             * 获取文件状态\n             * @return {File.Status}\n             * @example\n                     文件状态具体包括以下几种类型：\n                     {\n                         // 初始化\n                        INITED:     0,\n                        // 已入队列\n                        QUEUED:     1,\n                        // 正在上传\n                        PROGRESS:     2,\n                        // 上传出错\n                        ERROR:         3,\n                        // 上传成功\n                        COMPLETE:     4,\n                        // 上传取消\n                        CANCELLED:     5\n                    }\n             */\n            getStatus: function() {\n                return statusMap[ this.id ];\n            },\n\n            /**\n             * 获取文件原始信息。\n             * @return {*}\n             */\n            getSource: function() {\n                return this.source;\n            },\n\n            destroy: function() {\n                this.off();\n                delete statusMap[ this.id ];\n            }\n        });\n\n        Mediator.installTo( WUFile.prototype );\n\n        /**\n         * 文件状态值，具体包括以下几种类型：\n         * * `inited` 初始状态\n         * * `queued` 已经进入队列, 等待上传\n         * * `progress` 上传中\n         * * `complete` 上传完成。\n         * * `error` 上传出错，可重试\n         * * `interrupt` 上传中断，可续传。\n         * * `invalid` 文件不合格，不能重试上传。会自动从队列中移除。\n         * * `cancelled` 文件被移除。\n         * @property {Object} Status\n         * @namespace File\n         * @class File\n         * @static\n         */\n        WUFile.Status = {\n            INITED:     'inited',    // 初始状态\n            QUEUED:     'queued',    // 已经进入队列, 等待上传\n            PROGRESS:   'progress',    // 上传中\n            ERROR:      'error',    // 上传出错，可重试\n            COMPLETE:   'complete',    // 上传完成。\n            CANCELLED:  'cancelled',    // 上传取消。\n            INTERRUPT:  'interrupt',    // 上传中断，可续传。\n            INVALID:    'invalid'    // 文件不合格，不能重试上传。\n        };\n\n        return WUFile;\n    });\n\n    /**\n     * @fileOverview 文件队列\n     */\n    define('queue',[\n        'base',\n        'mediator',\n        'file'\n    ], function( Base, Mediator, WUFile ) {\n\n        var $ = Base.$,\n            STATUS = WUFile.Status;\n\n        /**\n         * 文件队列, 用来存储各个状态中的文件。\n         * @class Queue\n         * @extends Mediator\n         */\n        function Queue() {\n\n            /**\n             * 统计文件数。\n             * * `numOfQueue` 队列中的文件数。\n             * * `numOfSuccess` 上传成功的文件数\n             * * `numOfCancel` 被取消的文件数\n             * * `numOfProgress` 正在上传中的文件数\n             * * `numOfUploadFailed` 上传错误的文件数。\n             * * `numOfInvalid` 无效的文件数。\n             * * `numofDeleted` 被移除的文件数。\n             * @property {Object} stats\n             */\n            this.stats = {\n                numOfQueue: 0,\n                numOfSuccess: 0,\n                numOfCancel: 0,\n                numOfProgress: 0,\n                numOfUploadFailed: 0,\n                numOfInvalid: 0,\n                numofDeleted: 0,\n                numofInterrupt: 0\n            };\n\n            // 上传队列，仅包括等待上传的文件\n            this._queue = [];\n\n            // 存储所有文件\n            this._map = {};\n        }\n\n        $.extend( Queue.prototype, {\n\n            /**\n             * 将新文件加入对队列尾部\n             *\n             * @method append\n             * @param  {File} file   文件对象\n             */\n            append: function( file ) {\n                this._queue.push( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 将新文件加入对队列头部\n             *\n             * @method prepend\n             * @param  {File} file   文件对象\n             */\n            prepend: function( file ) {\n                this._queue.unshift( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 获取文件对象\n             *\n             * @method getFile\n             * @param  {String} fileId   文件ID\n             * @return {File}\n             */\n            getFile: function( fileId ) {\n                if ( typeof fileId !== 'string' ) {\n                    return fileId;\n                }\n                return this._map[ fileId ];\n            },\n\n            /**\n             * 从队列中取出一个指定状态的文件。\n             * @grammar fetch( status ) => File\n             * @method fetch\n             * @param {String} status [文件状态值](#WebUploader:File:File.Status)\n             * @return {File} [File](#WebUploader:File)\n             */\n            fetch: function( status ) {\n                var len = this._queue.length,\n                    i, file;\n\n                status = status || STATUS.QUEUED;\n\n                for ( i = 0; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( status === file.getStatus() ) {\n                        return file;\n                    }\n                }\n\n                return null;\n            },\n\n            /**\n             * 对队列进行排序，能够控制文件上传顺序。\n             * @grammar sort( fn ) => undefined\n             * @method sort\n             * @param {Function} fn 排序方法\n             */\n            sort: function( fn ) {\n                if ( typeof fn === 'function' ) {\n                    this._queue.sort( fn );\n                }\n            },\n\n            /**\n             * 获取指定类型的文件列表, 列表中每一个成员为[File](#WebUploader:File)对象。\n             * @grammar getFiles( [status1[, status2 ...]] ) => Array\n             * @method getFiles\n             * @param {String} [status] [文件状态值](#WebUploader:File:File.Status)\n             */\n            getFiles: function() {\n                var sts = [].slice.call( arguments, 0 ),\n                    ret = [],\n                    i = 0,\n                    len = this._queue.length,\n                    file;\n\n                for ( ; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( sts.length && !~$.inArray( file.getStatus(), sts ) ) {\n                        continue;\n                    }\n\n                    ret.push( file );\n                }\n\n                return ret;\n            },\n\n            /**\n             * 在队列中删除文件。\n             * @grammar removeFile( file ) => Array\n             * @method removeFile\n             * @param {File} 文件对象。\n             */\n            removeFile: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( existing ) {\n                    delete this._map[ file.id ];\n                    file.destroy();\n                    this.stats.numofDeleted++;\n                }\n            },\n\n            _fileAdded: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( !existing ) {\n                    this._map[ file.id ] = file;\n\n                    file.on( 'statuschange', function( cur, pre ) {\n                        me._onFileStatusChange( cur, pre );\n                    });\n                }\n            },\n\n            _onFileStatusChange: function( curStatus, preStatus ) {\n                var stats = this.stats;\n\n                switch ( preStatus ) {\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress--;\n                        break;\n\n                    case STATUS.QUEUED:\n                        stats.numOfQueue --;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed--;\n                        break;\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid--;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt--;\n                        break;\n                }\n\n                switch ( curStatus ) {\n                    case STATUS.QUEUED:\n                        stats.numOfQueue++;\n                        break;\n\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress++;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed++;\n                        break;\n\n                    case STATUS.COMPLETE:\n                        stats.numOfSuccess++;\n                        break;\n\n                    case STATUS.CANCELLED:\n                        stats.numOfCancel++;\n                        break;\n\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid++;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt++;\n                        break;\n                }\n            }\n\n        });\n\n        Mediator.installTo( Queue.prototype );\n\n        return Queue;\n    });\n    /**\n     * @fileOverview 队列\n     */\n    define('widgets/queue',[\n        'base',\n        'uploader',\n        'queue',\n        'file',\n        'lib/file',\n        'runtime/client',\n        'widgets/widget'\n    ], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {\n\n        var $ = Base.$,\n            rExt = /\\.\\w+$/,\n            Status = WUFile.Status;\n\n        return Uploader.register({\n            name: 'queue',\n\n            init: function( opts ) {\n                var me = this,\n                    deferred, len, i, item, arr, accept, runtime;\n\n                if ( $.isPlainObject( opts.accept ) ) {\n                    opts.accept = [ opts.accept ];\n                }\n\n                // accept中的中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].extensions;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = '\\\\.' + arr.join(',')\n                                .replace( /,/g, '$|\\\\.' )\n                                .replace( /\\*/g, '.*' ) + '$';\n                    }\n\n                    me.accept = new RegExp( accept, 'i' );\n                }\n\n                me.queue = new Queue();\n                me.stats = me.queue.stats;\n\n                // 如果当前不是html5运行时，那就算了。\n                // 不执行后续操作\n                if ( this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                // 创建一个 html5 运行时的 placeholder\n                // 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。\n                deferred = Base.Deferred();\n                this.placeholder = runtime = new RuntimeClient('Placeholder');\n                runtime.connectRuntime({\n                    runtimeOrder: 'html5'\n                }, function() {\n                    me._ruid = runtime.getRuid();\n                    deferred.resolve();\n                });\n                return deferred.promise();\n            },\n\n\n            // 为了支持外部直接添加一个原生File对象。\n            _wrapFile: function( file ) {\n                if ( !(file instanceof WUFile) ) {\n\n                    if ( !(file instanceof File) ) {\n                        if ( !this._ruid ) {\n                            throw new Error('Can\\'t add external files.');\n                        }\n                        file = new File( this._ruid, file );\n                    }\n\n                    file = new WUFile( file );\n                }\n\n                return file;\n            },\n\n            // 判断文件是否可以被加入队列\n            acceptFile: function( file ) {\n                var invalid = !file || !file.size || this.accept &&\n\n                        // 如果名字中有后缀，才做后缀白名单处理。\n                        rExt.exec( file.name ) && !this.accept.test( file.name );\n\n                return !invalid;\n            },\n\n\n            /**\n             * @event beforeFileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列之前触发，此事件的handler返回值为`false`，则此文件不会被添加进入队列。\n             * @for  Uploader\n             */\n\n            /**\n             * @event fileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列以后触发。\n             * @for  Uploader\n             */\n\n            _addFile: function( file ) {\n                var me = this;\n\n                file = me._wrapFile( file );\n\n                // 不过类型判断允许不允许，先派送 `beforeFileQueued`\n                if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {\n                    return;\n                }\n\n                // 类型不匹配，则派送错误事件，并返回。\n                if ( !me.acceptFile( file ) ) {\n                    me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );\n                    return;\n                }\n\n                me.queue.append( file );\n                me.owner.trigger( 'fileQueued', file );\n                return file;\n            },\n\n            getFile: function( fileId ) {\n                return this.queue.getFile( fileId );\n            },\n\n            /**\n             * @event filesQueued\n             * @param {File} files 数组，内容为原始File(lib/File）对象。\n             * @description 当一批文件添加进队列以后触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @property {Boolean} [auto=false]\n             * @namespace options\n             * @for Uploader\n             * @description 设置为 true 后，不需要手动调用上传，有文件选择即开始上传。\n             *\n             */\n\n            /**\n             * @method addFiles\n             * @grammar addFiles( file ) => undefined\n             * @grammar addFiles( [file1, file2 ...] ) => undefined\n             * @param {Array of File or File} [files] Files 对象 数组\n             * @description 添加文件到队列\n             * @for  Uploader\n             */\n            addFile: function( files ) {\n                var me = this;\n\n                if ( !files.length ) {\n                    files = [ files ];\n                }\n\n                files = $.map( files, function( file ) {\n                    return me._addFile( file );\n                });\n\n                me.owner.trigger( 'filesQueued', files );\n\n                if ( me.options.auto ) {\n                    setTimeout(function() {\n                        me.request('start-upload');\n                    }, 20 );\n                }\n            },\n\n            getStats: function() {\n                return this.stats;\n            },\n\n            /**\n             * @event fileDequeued\n             * @param {File} file File对象\n             * @description 当文件被移除队列后触发。\n             * @for  Uploader\n             */\n\n             /**\n             * @method removeFile\n             * @grammar removeFile( file ) => undefined\n             * @grammar removeFile( id ) => undefined\n             * @grammar removeFile( file, true ) => undefined\n             * @grammar removeFile( id, true ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 移除某一文件, 默认只会标记文件状态为已取消，如果第二个参数为 `true` 则会从 queue 中移除。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.removeFile( file );\n             * })\n             */\n            removeFile: function( file, remove ) {\n                var me = this;\n\n                file = file.id ? file : me.queue.getFile( file );\n\n                this.request( 'cancel-file', file );\n\n                if ( remove ) {\n                    this.queue.removeFile( file );\n                }\n            },\n\n            /**\n             * @method getFiles\n             * @grammar getFiles() => Array\n             * @grammar getFiles( status1, status2, status... ) => Array\n             * @description 返回指定状态的文件集合，不传参数将返回所有状态的文件。\n             * @for  Uploader\n             * @example\n             * console.log( uploader.getFiles() );    // => all files\n             * console.log( uploader.getFiles('error') )    // => all error files.\n             */\n            getFiles: function() {\n                return this.queue.getFiles.apply( this.queue, arguments );\n            },\n\n            fetchFile: function() {\n                return this.queue.fetch.apply( this.queue, arguments );\n            },\n\n            /**\n             * @method retry\n             * @grammar retry() => undefined\n             * @grammar retry( file ) => undefined\n             * @description 重试上传，重试指定文件，或者从出错的文件开始重新上传。\n             * @for  Uploader\n             * @example\n             * function retry() {\n             *     uploader.retry();\n             * }\n             */\n            retry: function( file, noForceStart ) {\n                var me = this,\n                    files, i, len;\n\n                if ( file ) {\n                    file = file.id ? file : me.queue.getFile( file );\n                    file.setStatus( Status.QUEUED );\n                    noForceStart || me.request('start-upload');\n                    return;\n                }\n\n                files = me.queue.getFiles( Status.ERROR );\n                i = 0;\n                len = files.length;\n\n                for ( ; i < len; i++ ) {\n                    file = files[ i ];\n                    file.setStatus( Status.QUEUED );\n                }\n\n                me.request('start-upload');\n            },\n\n            /**\n             * @method sort\n             * @grammar sort( fn ) => undefined\n             * @description 排序队列中的文件，在上传之前调整可以控制上传顺序。\n             * @for  Uploader\n             */\n            sortFiles: function() {\n                return this.queue.sort.apply( this.queue, arguments );\n            },\n\n            /**\n             * @event reset\n             * @description 当 uploader 被重置的时候触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @method reset\n             * @grammar reset() => undefined\n             * @description 重置uploader。目前只重置了队列。\n             * @for  Uploader\n             * @example\n             * uploader.reset();\n             */\n            reset: function() {\n                this.owner.trigger('reset');\n                this.queue = new Queue();\n                this.stats = this.queue.stats;\n            },\n\n            destroy: function() {\n                this.reset();\n                this.placeholder && this.placeholder.destroy();\n            }\n        });\n\n    });\n    /**\n     * @fileOverview 添加获取Runtime相关信息的方法。\n     */\n    define('widgets/runtime',[\n        'uploader',\n        'runtime/runtime',\n        'widgets/widget'\n    ], function( Uploader, Runtime ) {\n\n        Uploader.support = function() {\n            return Runtime.hasRuntime.apply( Runtime, arguments );\n        };\n\n        /**\n         * @property {Object} [runtimeOrder=html5,flash]\n         * @namespace options\n         * @for Uploader\n         * @description 指定运行时启动顺序。默认会想尝试 html5 是否支持，如果支持则使用 html5, 否则则使用 flash.\n         *\n         * 可以将此值设置成 `flash`，来强制使用 flash 运行时。\n         */\n\n        return Uploader.register({\n            name: 'runtime',\n\n            init: function() {\n                if ( !this.predictRuntimeType() ) {\n                    throw Error('Runtime Error');\n                }\n            },\n\n            /**\n             * 预测Uploader将采用哪个`Runtime`\n             * @grammar predictRuntimeType() => String\n             * @method predictRuntimeType\n             * @for  Uploader\n             */\n            predictRuntimeType: function() {\n                var orders = this.options.runtimeOrder || Runtime.orders,\n                    type = this.type,\n                    i, len;\n\n                if ( !type ) {\n                    orders = orders.split( /\\s*,\\s*/g );\n\n                    for ( i = 0, len = orders.length; i < len; i++ ) {\n                        if ( Runtime.hasRuntime( orders[ i ] ) ) {\n                            this.type = type = orders[ i ];\n                            break;\n                        }\n                    }\n                }\n\n                return type;\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     */\n    define('lib/transport',[\n        'base',\n        'runtime/client',\n        'mediator'\n    ], function( Base, RuntimeClient, Mediator ) {\n\n        var $ = Base.$;\n\n        function Transport( opts ) {\n            var me = this;\n\n            opts = me.options = $.extend( true, {}, Transport.options, opts || {} );\n            RuntimeClient.call( this, 'Transport' );\n\n            this._blob = null;\n            this._formData = opts.formData || {};\n            this._headers = opts.headers || {};\n\n            this.on( 'progress', this._timeout );\n            this.on( 'load error', function() {\n                me.trigger( 'progress', 1 );\n                clearTimeout( me._timer );\n            });\n        }\n\n        Transport.options = {\n            server: '',\n            method: 'POST',\n\n            // 跨域时，是否允许携带cookie, 只有html5 runtime才有效\n            withCredentials: false,\n            fileVal: 'file',\n            timeout: 2 * 60 * 1000,    // 2分钟\n            formData: {},\n            headers: {},\n            sendAsBinary: false\n        };\n\n        $.extend( Transport.prototype, {\n\n            // 添加Blob, 只能添加一次，最后一次有效。\n            appendBlob: function( key, blob, filename ) {\n                var me = this,\n                    opts = me.options;\n\n                if ( me.getRuid() ) {\n                    me.disconnectRuntime();\n                }\n\n                // 连接到blob归属的同一个runtime.\n                me.connectRuntime( blob.ruid, function() {\n                    me.exec('init');\n                });\n\n                me._blob = blob;\n                opts.fileVal = key || opts.fileVal;\n                opts.filename = filename || opts.filename;\n            },\n\n            // 添加其他字段\n            append: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._formData, key );\n                } else {\n                    this._formData[ key ] = value;\n                }\n            },\n\n            setRequestHeader: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._headers, key );\n                } else {\n                    this._headers[ key ] = value;\n                }\n            },\n\n            send: function( method ) {\n                this.exec( 'send', method );\n                this._timeout();\n            },\n\n            abort: function() {\n                clearTimeout( this._timer );\n                return this.exec('abort');\n            },\n\n            destroy: function() {\n                this.trigger('destroy');\n                this.off();\n                this.exec('destroy');\n                this.disconnectRuntime();\n            },\n\n            getResponse: function() {\n                return this.exec('getResponse');\n            },\n\n            getResponseAsJson: function() {\n                return this.exec('getResponseAsJson');\n            },\n\n            getStatus: function() {\n                return this.exec('getStatus');\n            },\n\n            _timeout: function() {\n                var me = this,\n                    duration = me.options.timeout;\n\n                if ( !duration ) {\n                    return;\n                }\n\n                clearTimeout( me._timer );\n                me._timer = setTimeout(function() {\n                    me.abort();\n                    me.trigger( 'error', 'timeout' );\n                }, duration );\n            }\n\n        });\n\n        // 让Transport具备事件功能。\n        Mediator.installTo( Transport.prototype );\n\n        return Transport;\n    });\n    /**\n     * @fileOverview 负责文件上传相关。\n     */\n    define('widgets/upload',[\n        'base',\n        'uploader',\n        'file',\n        'lib/transport',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile, Transport ) {\n\n        var $ = Base.$,\n            isPromise = Base.isPromise,\n            Status = WUFile.Status;\n\n        // 添加默认配置项\n        $.extend( Uploader.options, {\n\n\n            /**\n             * @property {Boolean} [prepareNextFile=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否允许在文件传输时提前把下一个文件准备好。\n             * 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。\n             * 如果能提前在当前文件传输期处理，可以节省总体耗时。\n             */\n            prepareNextFile: false,\n\n            /**\n             * @property {Boolean} [chunked=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否要分片处理大文件上传。\n             */\n            chunked: false,\n\n            /**\n             * @property {Boolean} [chunkSize=5242880]\n             * @namespace options\n             * @for Uploader\n             * @description 如果要分片，分多大一片？ 默认大小为5M.\n             */\n            chunkSize: 5 * 1024 * 1024,\n\n            /**\n             * @property {Boolean} [chunkRetry=2]\n             * @namespace options\n             * @for Uploader\n             * @description 如果某个分片由于网络问题出错，允许自动重传多少次？\n             */\n            chunkRetry: 2,\n\n            /**\n             * @property {Boolean} [threads=3]\n             * @namespace options\n             * @for Uploader\n             * @description 上传并发数。允许同时最大上传进程数。\n             */\n            threads: 3,\n\n\n            /**\n             * @property {Object} [formData={}]\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传请求的参数表，每次发送都会发送此对象中的参数。\n             */\n            formData: {}\n\n            /**\n             * @property {Object} [fileVal='file']\n             * @namespace options\n             * @for Uploader\n             * @description 设置文件上传域的name。\n             */\n\n            /**\n             * @property {Object} [method='POST']\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传方式，`POST`或者`GET`。\n             */\n\n            /**\n             * @property {Object} [sendAsBinary=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否已二进制的流的方式发送文件，这样整个上传内容`php://input`都为文件内容，\n             * 其他参数在$_GET数组中。\n             */\n        });\n\n        // 负责将文件切片。\n        function CuteFile( file, chunkSize ) {\n            var pending = [],\n                blob = file.source,\n                total = blob.size,\n                chunks = chunkSize ? Math.ceil( total / chunkSize ) : 1,\n                start = 0,\n                index = 0,\n                len, api;\n\n            api = {\n                file: file,\n\n                has: function() {\n                    return !!pending.length;\n                },\n\n                shift: function() {\n                    return pending.shift();\n                },\n\n                unshift: function( block ) {\n                    pending.unshift( block );\n                }\n            };\n\n            while ( index < chunks ) {\n                len = Math.min( chunkSize, total - start );\n\n                pending.push({\n                    file: file,\n                    start: start,\n                    end: chunkSize ? (start + len) : total,\n                    total: total,\n                    chunks: chunks,\n                    chunk: index++,\n                    cuted: api\n                });\n                start += len;\n            }\n\n            file.blocks = pending.concat();\n            file.remaning = pending.length;\n\n            return api;\n        }\n\n        Uploader.register({\n            name: 'upload',\n\n            init: function() {\n                var owner = this.owner,\n                    me = this;\n\n                this.runing = false;\n                this.progress = false;\n\n                owner\n                    .on( 'startUpload', function() {\n                        me.progress = true;\n                    })\n                    .on( 'uploadFinished', function() {\n                        me.progress = false;\n                    });\n\n                // 记录当前正在传的数据，跟threads相关\n                this.pool = [];\n\n                // 缓存分好片的文件。\n                this.stack = [];\n\n                // 缓存即将上传的文件。\n                this.pending = [];\n\n                // 跟踪还有多少分片在上传中但是没有完成上传。\n                this.remaning = 0;\n                this.__tick = Base.bindFn( this._tick, this );\n\n                owner.on( 'uploadComplete', function( file ) {\n\n                    // 把其他块取消了。\n                    file.blocks && $.each( file.blocks, function( _, v ) {\n                        v.transport && (v.transport.abort(), v.transport.destroy());\n                        delete v.transport;\n                    });\n\n                    delete file.blocks;\n                    delete file.remaning;\n                });\n            },\n\n            reset: function() {\n                this.request( 'stop-upload', true );\n                this.runing = false;\n                this.pool = [];\n                this.stack = [];\n                this.pending = [];\n                this.remaning = 0;\n                this._trigged = false;\n                this._promise = null;\n            },\n\n            /**\n             * @event startUpload\n             * @description 当开始上传流程时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 开始上传。此方法可以从初始状态调用开始上传流程，也可以从暂停状态调用，继续上传流程。\n             *\n             * 可以指定开始某一个文件。\n             * @grammar upload() => undefined\n             * @grammar upload( file | fileId) => undefined\n             * @method upload\n             * @for  Uploader\n             */\n            startUpload: function(file) {\n                var me = this;\n\n                // 移出invalid的文件\n                $.each( me.request( 'get-files', Status.INVALID ), function() {\n                    me.request( 'remove-file', this );\n                });\n\n                // 如果指定了开始某个文件，则只开始指定文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        $.each( me.pool, function( _, v ) {\n\n                            // 之前暂停过。\n                            if (v.file !== file) {\n                                return;\n                            }\n\n                            v.transport && v.transport.send();\n                        });\n\n                        file.setStatus( Status.QUEUED );\n                    } else if (file.getStatus() === Status.PROGRESS) {\n                        return;\n                    } else {\n                        file.setStatus( Status.QUEUED );\n                    }\n                } else {\n                    $.each( me.request( 'get-files', [ Status.INITED ] ), function() {\n                        this.setStatus( Status.QUEUED );\n                    });\n                }\n\n                if ( me.runing ) {\n                    return;\n                }\n\n                me.runing = true;\n\n                var files = [];\n\n                // 如果有暂停的，则续传\n                $.each( me.pool, function( _, v ) {\n                    var file = v.file;\n\n                    if ( file.getStatus() === Status.INTERRUPT ) {\n                        files.push(file);\n                        me._trigged = false;\n                        v.transport && v.transport.send();\n                    }\n                });\n\n                var file;\n                while ( (file = files.shift()) ) {\n                    file.setStatus( Status.PROGRESS );\n                }\n\n                file || $.each( me.request( 'get-files',\n                        Status.INTERRUPT ), function() {\n                    this.setStatus( Status.PROGRESS );\n                });\n\n                me._trigged = false;\n                Base.nextTick( me.__tick );\n                me.owner.trigger('startUpload');\n            },\n\n            /**\n             * @event stopUpload\n             * @description 当开始上传流程暂停时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 暂停上传。第一个参数为是否中断上传当前正在上传的文件。\n             *\n             * 如果第一个参数是文件，则只暂停指定文件。\n             * @grammar stop() => undefined\n             * @grammar stop( true ) => undefined\n             * @grammar stop( file ) => undefined\n             * @method stop\n             * @for  Uploader\n             */\n            stopUpload: function( file, interrupt ) {\n                var me = this;\n\n                if (file === true) {\n                    interrupt = file;\n                    file = null;\n                }\n\n                if ( me.runing === false ) {\n                    return;\n                }\n\n                // 如果只是暂停某个文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if ( file.getStatus() !== Status.PROGRESS &&\n                            file.getStatus() !== Status.QUEUED ) {\n                        return;\n                    }\n\n                    file.setStatus( Status.INTERRUPT );\n                    $.each( me.pool, function( _, v ) {\n\n                        // 只 abort 指定的文件。\n                        if (v.file !== file) {\n                            return;\n                        }\n\n                        v.transport && v.transport.abort();\n                        me._putback(v);\n                        me._popBlock(v);\n                    });\n\n                    return Base.nextTick( me.__tick );\n                }\n\n                me.runing = false;\n\n                if (this._promise && this._promise.file) {\n                    this._promise.file.setStatus( Status.INTERRUPT );\n                }\n\n                interrupt && $.each( me.pool, function( _, v ) {\n                    v.transport && v.transport.abort();\n                    v.file.setStatus( Status.INTERRUPT );\n                });\n\n                me.owner.trigger('stopUpload');\n            },\n\n            /**\n             * @method cancelFile\n             * @grammar cancelFile( file ) => undefined\n             * @grammar cancelFile( id ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 标记文件状态为已取消, 同时将中断文件传输。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.cancelFile( file );\n             * })\n             */\n            cancelFile: function( file ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                file.setStatus( Status.CANCELLED );\n                this.owner.trigger( 'fileDequeued', file );\n            },\n\n            /**\n             * 判断`Uplaode`r是否正在上传中。\n             * @grammar isInProgress() => Boolean\n             * @method isInProgress\n             * @for  Uploader\n             */\n            isInProgress: function() {\n                return !!this.progress;\n            },\n\n            _getStats: function() {\n                return this.request('get-stats');\n            },\n\n            /**\n             * 掉过一个文件上传，直接标记指定文件为已上传状态。\n             * @grammar skipFile( file ) => undefined\n             * @method skipFile\n             * @for  Uploader\n             */\n            skipFile: function( file, status ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                file.setStatus( status || Status.COMPLETE );\n                file.skipped = true;\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                this.owner.trigger( 'uploadSkip', file );\n            },\n\n            /**\n             * @event uploadFinished\n             * @description 当所有文件上传结束时触发。\n             * @for  Uploader\n             */\n            _tick: function() {\n                var me = this,\n                    opts = me.options,\n                    fn, val;\n\n                // 上一个promise还没有结束，则等待完成后再执行。\n                if ( me._promise ) {\n                    return me._promise.always( me.__tick );\n                }\n\n                // 还有位置，且还有文件要处理的话。\n                if ( me.pool.length < opts.threads && (val = me._nextBlock()) ) {\n                    me._trigged = false;\n\n                    fn = function( val ) {\n                        me._promise = null;\n\n                        // 有可能是reject过来的，所以要检测val的类型。\n                        val && val.file && me._startSend( val );\n                        Base.nextTick( me.__tick );\n                    };\n\n                    me._promise = isPromise( val ) ? val.always( fn ) : fn( val );\n\n                // 没有要上传的了，且没有正在传输的了。\n                } else if ( !me.remaning && !me._getStats().numOfQueue &&\n                    !me._getStats().numofInterrupt ) {\n                    me.runing = false;\n\n                    me._trigged || Base.nextTick(function() {\n                        me.owner.trigger('uploadFinished');\n                    });\n                    me._trigged = true;\n                }\n            },\n\n            _putback: function(block) {\n                var idx;\n\n                block.cuted.unshift(block);\n                idx = this.stack.indexOf(block.cuted);\n\n                if (!~idx) {\n                    this.stack.unshift(block.cuted);\n                }\n            },\n\n            _getStack: function() {\n                var i = 0,\n                    act;\n\n                while ( (act = this.stack[ i++ ]) ) {\n                    if ( act.has() && act.file.getStatus() === Status.PROGRESS ) {\n                        return act;\n                    } else if (!act.has() ||\n                            act.file.getStatus() !== Status.PROGRESS &&\n                            act.file.getStatus() !== Status.INTERRUPT ) {\n\n                        // 把已经处理完了的，或者，状态为非 progress（上传中）、\n                        // interupt（暂停中） 的移除。\n                        this.stack.splice( --i, 1 );\n                    }\n                }\n\n                return null;\n            },\n\n            _nextBlock: function() {\n                var me = this,\n                    opts = me.options,\n                    act, next, done, preparing;\n\n                // 如果当前文件还有没有需要传输的，则直接返回剩下的。\n                if ( (act = this._getStack()) ) {\n\n                    // 是否提前准备下一个文件\n                    if ( opts.prepareNextFile && !me.pending.length ) {\n                        me._prepareNextFile();\n                    }\n\n                    return act.shift();\n\n                // 否则，如果正在运行，则准备下一个文件，并等待完成后返回下个分片。\n                } else if ( me.runing ) {\n\n                    // 如果缓存中有，则直接在缓存中取，没有则去queue中取。\n                    if ( !me.pending.length && me._getStats().numOfQueue ) {\n                        me._prepareNextFile();\n                    }\n\n                    next = me.pending.shift();\n                    done = function( file ) {\n                        if ( !file ) {\n                            return null;\n                        }\n\n                        act = CuteFile( file, opts.chunked ? opts.chunkSize : 0 );\n                        me.stack.push(act);\n                        return act.shift();\n                    };\n\n                    // 文件可能还在prepare中，也有可能已经完全准备好了。\n                    if ( isPromise( next) ) {\n                        preparing = next.file;\n                        next = next[ next.pipe ? 'pipe' : 'then' ]( done );\n                        next.file = preparing;\n                        return next;\n                    }\n\n                    return done( next );\n                }\n            },\n\n\n            /**\n             * @event uploadStart\n             * @param {File} file File对象\n             * @description 某个文件开始上传前触发，一个文件只会触发一次。\n             * @for  Uploader\n             */\n            _prepareNextFile: function() {\n                var me = this,\n                    file = me.request('fetch-file'),\n                    pending = me.pending,\n                    promise;\n\n                if ( file ) {\n                    promise = me.request( 'before-send-file', file, function() {\n\n                        // 有可能文件被skip掉了。文件被skip掉后，状态坑定不是Queued.\n                        if ( file.getStatus() === Status.PROGRESS ||\n                            file.getStatus() === Status.INTERRUPT ) {\n                            return file;\n                        }\n\n                        return me._finishFile( file );\n                    });\n\n                    me.owner.trigger( 'uploadStart', file );\n                    file.setStatus( Status.PROGRESS );\n\n                    promise.file = file;\n\n                    // 如果还在pending中，则替换成文件本身。\n                    promise.done(function() {\n                        var idx = $.inArray( promise, pending );\n\n                        ~idx && pending.splice( idx, 1, file );\n                    });\n\n                    // befeore-send-file的钩子就有错误发生。\n                    promise.fail(function( reason ) {\n                        file.setStatus( Status.ERROR, reason );\n                        me.owner.trigger( 'uploadError', file, reason );\n                        me.owner.trigger( 'uploadComplete', file );\n                    });\n\n                    pending.push( promise );\n                }\n            },\n\n            // 让出位置了，可以让其他分片开始上传\n            _popBlock: function( block ) {\n                var idx = $.inArray( block, this.pool );\n\n                this.pool.splice( idx, 1 );\n                block.file.remaning--;\n                this.remaning--;\n            },\n\n            // 开始上传，可以被掉过。如果promise被reject了，则表示跳过此分片。\n            _startSend: function( block ) {\n                var me = this,\n                    file = block.file,\n                    promise;\n\n                // 有可能在 before-send-file 的 promise 期间改变了文件状态。\n                // 如：暂停，取消\n                // 我们不能中断 promise, 但是可以在 promise 完后，不做上传操作。\n                if ( file.getStatus() !== Status.PROGRESS ) {\n\n                    // 如果是中断，则还需要放回去。\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        me._putback(block);\n                    }\n\n                    return;\n                }\n\n                me.pool.push( block );\n                me.remaning++;\n\n                // 如果没有分片，则直接使用原始的。\n                // 不会丢失content-type信息。\n                block.blob = block.chunks === 1 ? file.source :\n                        file.source.slice( block.start, block.end );\n\n                // hook, 每个分片发送之前可能要做些异步的事情。\n                promise = me.request( 'before-send', block, function() {\n\n                    // 有可能文件已经上传出错了，所以不需要再传输了。\n                    if ( file.getStatus() === Status.PROGRESS ) {\n                        me._doSend( block );\n                    } else {\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n\n                // 如果为fail了，则跳过此分片。\n                promise.fail(function() {\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file ).always(function() {\n                            block.percentage = 1;\n                            me._popBlock( block );\n                            me.owner.trigger( 'uploadComplete', file );\n                            Base.nextTick( me.__tick );\n                        });\n                    } else {\n                        block.percentage = 1;\n                        me.updateFileProgress( file );\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n            },\n\n\n            /**\n             * @event uploadBeforeSend\n             * @param {Object} object\n             * @param {Object} data 默认的上传参数，可以扩展此对象来控制上传参数。\n             * @param {Object} headers 可以扩展此对象来控制上传头部。\n             * @description 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadAccept\n             * @param {Object} object\n             * @param {Object} ret 服务端的返回数据，json格式，如果服务端不是json格式，从ret._raw中取数据，自行解析。\n             * @description 当某个文件上传到服务端响应后，会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为`false`, 则此文件将派送`server`类型的`uploadError`事件。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadProgress\n             * @param {File} file File对象\n             * @param {Number} percentage 上传进度\n             * @description 上传过程中触发，携带上传进度。\n             * @for  Uploader\n             */\n\n\n            /**\n             * @event uploadError\n             * @param {File} file File对象\n             * @param {String} reason 出错的code\n             * @description 当文件上传出错时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadSuccess\n             * @param {File} file File对象\n             * @param {Object} response 服务端返回的数据\n             * @description 当文件上传成功时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadComplete\n             * @param {File} [file] File对象\n             * @description 不管成功或者失败，文件上传完成时触发。\n             * @for  Uploader\n             */\n\n            // 做上传操作。\n            _doSend: function( block ) {\n                var me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    file = block.file,\n                    tr = new Transport( opts ),\n                    data = $.extend({}, opts.formData ),\n                    headers = $.extend({}, opts.headers ),\n                    requestAccept, ret;\n\n                block.transport = tr;\n\n                tr.on( 'destroy', function() {\n                    delete block.transport;\n                    me._popBlock( block );\n                    Base.nextTick( me.__tick );\n                });\n\n                // 广播上传进度。以文件为单位。\n                tr.on( 'progress', function( percentage ) {\n                    block.percentage = percentage;\n                    me.updateFileProgress( file );\n                });\n\n                // 用来询问，是否返回的结果是有错误的。\n                requestAccept = function( reject ) {\n                    var fn;\n\n                    ret = tr.getResponseAsJson() || {};\n                    ret._raw = tr.getResponse();\n                    fn = function( value ) {\n                        reject = value;\n                    };\n\n                    // 服务端响应了，不代表成功了，询问是否响应正确。\n                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {\n                        reject = reject || 'server';\n                    }\n\n                    return reject;\n                };\n\n                // 尝试重试，然后广播文件上传出错。\n                tr.on( 'error', function( type, flag ) {\n                    block.retried = block.retried || 0;\n\n                    // 自动重试\n                    if ( block.chunks > 1 && ~'http,abort'.indexOf( type ) &&\n                            block.retried < opts.chunkRetry ) {\n\n                        block.retried++;\n                        tr.send();\n\n                    } else {\n\n                        // http status 500 ~ 600\n                        if ( !flag && type === 'server' ) {\n                            type = requestAccept( type );\n                        }\n\n                        file.setStatus( Status.ERROR, type );\n                        owner.trigger( 'uploadError', file, type );\n                        owner.trigger( 'uploadComplete', file );\n                    }\n                });\n\n                // 上传成功\n                tr.on( 'load', function() {\n                    var reason;\n\n                    // 如果非预期，转向上传出错。\n                    if ( (reason = requestAccept()) ) {\n                        tr.trigger( 'error', reason, true );\n                        return;\n                    }\n\n                    // 全部上传完成。\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file, ret );\n                    } else {\n                        tr.destroy();\n                    }\n                });\n\n                // 配置默认的上传字段。\n                data = $.extend( data, {\n                    id: file.id,\n                    name: file.name,\n                    type: file.type,\n                    lastModifiedDate: file.lastModifiedDate,\n                    size: file.size\n                });\n\n                block.chunks > 1 && $.extend( data, {\n                    chunks: block.chunks,\n                    chunk: block.chunk\n                });\n\n                // 在发送之间可以添加字段什么的。。。\n                // 如果默认的字段不够使用，可以通过监听此事件来扩展\n                owner.trigger( 'uploadBeforeSend', block, data, headers );\n\n                // 开始发送。\n                tr.appendBlob( opts.fileVal, block.blob, file.name );\n                tr.append( data );\n                tr.setRequestHeader( headers );\n                tr.send();\n            },\n\n            // 完成上传。\n            _finishFile: function( file, ret, hds ) {\n                var owner = this.owner;\n\n                return owner\n                        .request( 'after-send-file', arguments, function() {\n                            file.setStatus( Status.COMPLETE );\n                            owner.trigger( 'uploadSuccess', file, ret, hds );\n                        })\n                        .fail(function( reason ) {\n\n                            // 如果外部已经标记为invalid什么的，不再改状态。\n                            if ( file.getStatus() === Status.PROGRESS ) {\n                                file.setStatus( Status.ERROR, reason );\n                            }\n\n                            owner.trigger( 'uploadError', file, reason );\n                        })\n                        .always(function() {\n                            owner.trigger( 'uploadComplete', file );\n                        });\n            },\n\n            updateFileProgress: function(file) {\n                var totalPercent = 0,\n                    uploaded = 0;\n\n                if (!file.blocks) {\n                    return;\n                }\n\n                $.each( file.blocks, function( _, v ) {\n                    uploaded += (v.percentage || 0) * (v.end - v.start);\n                });\n\n                totalPercent = uploaded / file.size;\n                this.owner.trigger( 'uploadProgress', file, totalPercent || 0 );\n            }\n\n        });\n    });\n    /**\n     * @fileOverview 各种验证，包括文件总大小是否超出、单文件是否超出和文件是否重复。\n     */\n\n    define('widgets/validator',[\n        'base',\n        'uploader',\n        'file',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile ) {\n\n        var $ = Base.$,\n            validators = {},\n            api;\n\n        /**\n         * @event error\n         * @param {String} type 错误类型。\n         * @description 当validate不通过时，会以派送错误事件的形式通知调用者。通过`upload.on('error', handler)`可以捕获到此类错误，目前有以下错误会在特定的情况下派送错来。\n         *\n         * * `Q_EXCEED_NUM_LIMIT` 在设置了`fileNumLimit`且尝试给`uploader`添加的文件数量超出这个值时派送。\n         * * `Q_EXCEED_SIZE_LIMIT` 在设置了`Q_EXCEED_SIZE_LIMIT`且尝试给`uploader`添加的文件总大小超出这个值时派送。\n         * * `Q_TYPE_DENIED` 当文件类型不满足时触发。。\n         * @for  Uploader\n         */\n\n        // 暴露给外面的api\n        api = {\n\n            // 添加验证器\n            addValidator: function( type, cb ) {\n                validators[ type ] = cb;\n            },\n\n            // 移除验证器\n            removeValidator: function( type ) {\n                delete validators[ type ];\n            }\n        };\n\n        // 在Uploader初始化的时候启动Validators的初始化\n        Uploader.register({\n            name: 'validator',\n\n            init: function() {\n                var me = this;\n                Base.nextTick(function() {\n                    $.each( validators, function() {\n                        this.call( me.owner );\n                    });\n                });\n            }\n        });\n\n        /**\n         * @property {int} [fileNumLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总数量, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileNumLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileNumLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( count >= max && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_NUM_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return count >= max ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function() {\n                count++;\n            });\n\n            uploader.on( 'fileDequeued', function() {\n                count--;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n\n        /**\n         * @property {int} [fileSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileSizeLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var invalid = count + file.size > max;\n\n                if ( invalid && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_SIZE_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return invalid ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                count += file.size;\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                count -= file.size;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n        /**\n         * @property {int} [fileSingleSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证单个文件大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSingleSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                max = opts.fileSingleSizeLimit;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( file.size > max ) {\n                    file.setStatus( WUFile.Status.INVALID, 'exceed_size' );\n                    this.trigger( 'error', 'F_EXCEED_SIZE', max, file );\n                    return false;\n                }\n\n            });\n\n        });\n\n        /**\n         * @property {Boolean} [duplicate=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 去重， 根据文件名字、文件大小和最后修改时间来生成hash Key.\n         */\n        api.addValidator( 'duplicate', function() {\n            var uploader = this,\n                opts = uploader.options,\n                mapping = {};\n\n            if ( opts.duplicate ) {\n                return;\n            }\n\n            function hashString( str ) {\n                var hash = 0,\n                    i = 0,\n                    len = str.length,\n                    _char;\n\n                for ( ; i < len; i++ ) {\n                    _char = str.charCodeAt( i );\n                    hash = _char + (hash << 6) + (hash << 16) - hash;\n                }\n\n                return hash;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var hash = file.__hash || (file.__hash = hashString( file.name +\n                        file.size + file.lastModifiedDate ));\n\n                // 已经重复了\n                if ( mapping[ hash ] ) {\n                    this.trigger( 'error', 'F_DUPLICATE', file );\n                    return false;\n                }\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (mapping[ hash ] = true);\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (delete mapping[ hash ]);\n            });\n\n            uploader.on( 'reset', function() {\n                mapping = {};\n            });\n        });\n\n        return api;\n    });\n\n    /**\n     * @fileOverview Md5\n     */\n    define('lib/md5',[\n        'runtime/client',\n        'mediator'\n    ], function( RuntimeClient, Mediator ) {\n\n        function Md5() {\n            RuntimeClient.call( this, 'Md5' );\n        }\n\n        // 让 Md5 具备事件功能。\n        Mediator.installTo( Md5.prototype );\n\n        Md5.prototype.loadFromBlob = function( blob ) {\n            var me = this;\n\n            if ( me.getRuid() ) {\n                me.disconnectRuntime();\n            }\n\n            // 连接到blob归属的同一个runtime.\n            me.connectRuntime( blob.ruid, function() {\n                me.exec('init');\n                me.exec( 'loadFromBlob', blob );\n            });\n        };\n\n        Md5.prototype.getResult = function() {\n            return this.exec('getResult');\n        };\n\n        return Md5;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/md5',[\n        'base',\n        'uploader',\n        'lib/md5',\n        'lib/blob',\n        'widgets/widget'\n    ], function( Base, Uploader, Md5, Blob ) {\n\n        return Uploader.register({\n            name: 'md5',\n\n\n            /**\n             * 计算文件 md5 值，返回一个 promise 对象，可以监听 progress 进度。\n             *\n             *\n             * @method md5File\n             * @grammar md5File( file[, start[, end]] ) => promise\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.md5File( file )\n             *\n             *         // 及时显示进度\n             *         .progress(function(percentage) {\n             *             console.log('Percentage:', percentage);\n             *         })\n             *\n             *         // 完成\n             *         .then(function(val) {\n             *             console.log('md5 result:', val);\n             *         });\n             *\n             * });\n             */\n            md5File: function( file, start, end ) {\n                var md5 = new Md5(),\n                    deferred = Base.Deferred(),\n                    blob = (file instanceof Blob) ? file :\n                        this.request( 'get-file', file ).source;\n\n                md5.on( 'progress load', function( e ) {\n                    e = e || {};\n                    deferred.notify( e.total ? e.loaded / e.total : 1 );\n                });\n\n                md5.on( 'complete', function() {\n                    deferred.resolve( md5.getResult() );\n                });\n\n                md5.on( 'error', function( reason ) {\n                    deferred.reject( reason );\n                });\n\n                if ( arguments.length > 1 ) {\n                    start = start || 0;\n                    end = end || 0;\n                    start < 0 && (start = blob.size + start);\n                    end < 0 && (end = blob.size + end);\n                    end = Math.min( end, blob.size );\n                    blob = blob.slice( start, end );\n                }\n\n                md5.loadFromBlob( blob );\n\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/compbase',[],function() {\n\n        function CompBase( owner, runtime ) {\n\n            this.owner = owner;\n            this.options = owner.options;\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.getRuid = function() {\n                return runtime.uid;\n            };\n\n            this.trigger = function() {\n                return owner.trigger.apply( owner, arguments );\n            };\n        }\n\n        return CompBase;\n    });\n    /**\n     * @fileOverview Html5Runtime\n     */\n    define('runtime/html5/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var type = 'html5',\n            components = {};\n\n        function Html5Runtime() {\n            var pool = {},\n                me = this,\n                destroy = this.destroy;\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                if ( components[ comp ] ) {\n                    instance = pool[ uid ] = pool[ uid ] ||\n                            new components[ comp ]( client, me );\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n            };\n\n            me.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n        }\n\n        Base.inherits( Runtime, {\n            constructor: Html5Runtime,\n\n            // 不需要连接其他程序，直接执行callback\n            init: function() {\n                var me = this;\n                setTimeout(function() {\n                    me.trigger('ready');\n                }, 1 );\n            }\n\n        });\n\n        // 注册Components\n        Html5Runtime.register = function( name, component ) {\n            var klass = components[ name ] = Base.inherits( CompBase, component );\n            return klass;\n        };\n\n        // 注册html5运行时。\n        // 只有在支持的前提下注册。\n        if ( window.Blob && window.FileReader && window.DataView ) {\n            Runtime.addRuntime( type, Html5Runtime );\n        }\n\n        return Html5Runtime;\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/html5/blob',[\n        'runtime/html5/runtime',\n        'lib/blob'\n    ], function( Html5Runtime, Blob ) {\n\n        return Html5Runtime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.owner.source,\n                    slice = blob.slice || blob.webkitSlice || blob.mozSlice;\n\n                blob = slice.call( blob, start, end );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/dnd',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        var $ = Base.$,\n            prefix = 'webuploader-dnd-';\n\n        return Html5Runtime.register( 'DragAndDrop', {\n            init: function() {\n                var elem = this.elem = this.options.container;\n\n                this.dragEnterHandler = Base.bindFn( this._dragEnterHandler, this );\n                this.dragOverHandler = Base.bindFn( this._dragOverHandler, this );\n                this.dragLeaveHandler = Base.bindFn( this._dragLeaveHandler, this );\n                this.dropHandler = Base.bindFn( this._dropHandler, this );\n                this.dndOver = false;\n\n                elem.on( 'dragenter', this.dragEnterHandler );\n                elem.on( 'dragover', this.dragOverHandler );\n                elem.on( 'dragleave', this.dragLeaveHandler );\n                elem.on( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).on( 'dragover', this.dragOverHandler );\n                    $( document ).on( 'drop', this.dropHandler );\n                }\n            },\n\n            _dragEnterHandler: function( e ) {\n                var me = this,\n                    denied = me._denied || false,\n                    items;\n\n                e = e.originalEvent || e;\n\n                if ( !me.dndOver ) {\n                    me.dndOver = true;\n\n                    // 注意只有 chrome 支持。\n                    items = e.dataTransfer.items;\n\n                    if ( items && items.length ) {\n                        me._denied = denied = !me.trigger( 'accept', items );\n                    }\n\n                    me.elem.addClass( prefix + 'over' );\n                    me.elem[ denied ? 'addClass' :\n                            'removeClass' ]( prefix + 'denied' );\n                }\n\n                e.dataTransfer.dropEffect = denied ? 'none' : 'copy';\n\n                return false;\n            },\n\n            _dragOverHandler: function( e ) {\n                // 只处理框内的。\n                var parentElem = this.elem.parent().get( 0 );\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                clearTimeout( this._leaveTimer );\n                this._dragEnterHandler.call( this, e );\n\n                return false;\n            },\n\n            _dragLeaveHandler: function() {\n                var me = this,\n                    handler;\n\n                handler = function() {\n                    me.dndOver = false;\n                    me.elem.removeClass( prefix + 'over ' + prefix + 'denied' );\n                };\n\n                clearTimeout( me._leaveTimer );\n                me._leaveTimer = setTimeout( handler, 100 );\n                return false;\n            },\n\n            _dropHandler: function( e ) {\n                var me = this,\n                    ruid = me.getRuid(),\n                    parentElem = me.elem.parent().get( 0 ),\n                    dataTransfer, data;\n\n                // 只处理框内的。\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                e = e.originalEvent || e;\n                dataTransfer = e.dataTransfer;\n\n                // 如果是页面内拖拽，还不能处理，不阻止事件。\n                // 此处 ie11 下会报参数错误，\n                try {\n                    data = dataTransfer.getData('text/html');\n                } catch( err ) {\n                }\n\n                if ( data ) {\n                    return;\n                }\n\n                me._getTansferFiles( dataTransfer, function( results ) {\n                    me.trigger( 'drop', $.map( results, function( file ) {\n                        return new File( ruid, file );\n                    }) );\n                });\n\n                me.dndOver = false;\n                me.elem.removeClass( prefix + 'over' );\n                return false;\n            },\n\n            // 如果传入 callback 则去查看文件夹，否则只管当前文件夹。\n            _getTansferFiles: function( dataTransfer, callback ) {\n                var results  = [],\n                    promises = [],\n                    items, files, file, item, i, len, canAccessFolder;\n\n                items = dataTransfer.items;\n                files = dataTransfer.files;\n\n                canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);\n\n                for ( i = 0, len = files.length; i < len; i++ ) {\n                    file = files[ i ];\n                    item = items && items[ i ];\n\n                    if ( canAccessFolder && item.webkitGetAsEntry().isDirectory ) {\n\n                        promises.push( this._traverseDirectoryTree(\n                                item.webkitGetAsEntry(), results ) );\n                    } else {\n                        results.push( file );\n                    }\n                }\n\n                Base.when.apply( Base, promises ).done(function() {\n\n                    if ( !results.length ) {\n                        return;\n                    }\n\n                    callback( results );\n                });\n            },\n\n            _traverseDirectoryTree: function( entry, results ) {\n                var deferred = Base.Deferred(),\n                    me = this;\n\n                if ( entry.isFile ) {\n                    entry.file(function( file ) {\n                        results.push( file );\n                        deferred.resolve();\n                    });\n                } else if ( entry.isDirectory ) {\n                    entry.createReader().readEntries(function( entries ) {\n                        var len = entries.length,\n                            promises = [],\n                            arr = [],    // 为了保证顺序。\n                            i;\n\n                        for ( i = 0; i < len; i++ ) {\n                            promises.push( me._traverseDirectoryTree(\n                                    entries[ i ], arr ) );\n                        }\n\n                        Base.when.apply( Base, promises ).then(function() {\n                            results.push.apply( results, arr );\n                            deferred.resolve();\n                        }, deferred.reject );\n                    });\n                }\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                var elem = this.elem;\n\n                // 还没 init 就调用 destroy\n                if (!elem) {\n                    return;\n                }\n\n                elem.off( 'dragenter', this.dragEnterHandler );\n                elem.off( 'dragover', this.dragOverHandler );\n                elem.off( 'dragleave', this.dragLeaveHandler );\n                elem.off( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).off( 'dragover', this.dragOverHandler );\n                    $( document ).off( 'drop', this.dropHandler );\n                }\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/filepaste',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        return Html5Runtime.register( 'FilePaste', {\n            init: function() {\n                var opts = this.options,\n                    elem = this.elem = opts.container,\n                    accept = '.*',\n                    arr, i, len, item;\n\n                // accetp的mimeTypes中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].mimeTypes;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = arr.join(',');\n                        accept = accept.replace( /,/g, '|' ).replace( /\\*/g, '.*' );\n                    }\n                }\n                this.accept = accept = new RegExp( accept, 'i' );\n                this.hander = Base.bindFn( this._pasteHander, this );\n                elem.on( 'paste', this.hander );\n            },\n\n            _pasteHander: function( e ) {\n                var allowed = [],\n                    ruid = this.getRuid(),\n                    items, item, blob, i, len;\n\n                e = e.originalEvent || e;\n                items = e.clipboardData.items;\n\n                for ( i = 0, len = items.length; i < len; i++ ) {\n                    item = items[ i ];\n\n                    if ( item.kind !== 'file' || !(blob = item.getAsFile()) ) {\n                        continue;\n                    }\n\n                    allowed.push( new File( ruid, blob ) );\n                }\n\n                if ( allowed.length ) {\n                    // 不阻止非文件粘贴（文字粘贴）的事件冒泡\n                    e.preventDefault();\n                    e.stopPropagation();\n                    this.trigger( 'paste', allowed );\n                }\n            },\n\n            destroy: function() {\n                this.elem.off( 'paste', this.hander );\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/html5/filepicker',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var $ = Base.$;\n\n        return Html5Runtime.register( 'FilePicker', {\n            init: function() {\n                var container = this.getRuntime().getContainer(),\n                    me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    label = this.label = $( document.createElement('label') ),\n                    input =  this.input = $( document.createElement('input') ),\n                    arr, i, len, mouseHandler;\n\n                input.attr( 'type', 'file' );\n                input.attr( 'name', opts.name );\n                input.addClass('webuploader-element-invisible');\n\n                label.on( 'click', function() {\n                    input.trigger('click');\n                });\n\n                label.css({\n                    opacity: 0,\n                    width: '100%',\n                    height: '100%',\n                    display: 'block',\n                    cursor: 'pointer',\n                    background: '#ffffff'\n                });\n\n                if ( opts.multiple ) {\n                    input.attr( 'multiple', 'multiple' );\n                }\n\n                // @todo Firefox不支持单独指定后缀\n                if ( opts.accept && opts.accept.length > 0 ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        arr.push( opts.accept[ i ].mimeTypes );\n                    }\n\n                    input.attr( 'accept', arr.join(',') );\n                }\n\n                container.append( input );\n                container.append( label );\n\n                mouseHandler = function( e ) {\n                    owner.trigger( e.type );\n                };\n\n                input.on( 'change', function( e ) {\n                    var fn = arguments.callee,\n                        clone;\n\n                    me.files = e.target.files;\n\n                    // reset input\n                    clone = this.cloneNode( true );\n                    clone.value = null;\n                    this.parentNode.replaceChild( clone, this );\n\n                    input.off();\n                    input = $( clone ).on( 'change', fn )\n                            .on( 'mouseenter mouseleave', mouseHandler );\n\n                    owner.trigger('change');\n                });\n\n                label.on( 'mouseenter mouseleave', mouseHandler );\n\n            },\n\n\n            getFiles: function() {\n                return this.files;\n            },\n\n            destroy: function() {\n                this.input.off();\n                this.label.off();\n            }\n        });\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/util',[\n        'base'\n    ], function( Base ) {\n\n        var urlAPI = window.createObjectURL && window ||\n                window.URL && URL.revokeObjectURL && URL ||\n                window.webkitURL,\n            createObjectURL = Base.noop,\n            revokeObjectURL = createObjectURL;\n\n        if ( urlAPI ) {\n\n            // 更安全的方式调用，比如android里面就能把context改成其他的对象。\n            createObjectURL = function() {\n                return urlAPI.createObjectURL.apply( urlAPI, arguments );\n            };\n\n            revokeObjectURL = function() {\n                return urlAPI.revokeObjectURL.apply( urlAPI, arguments );\n            };\n        }\n\n        return {\n            createObjectURL: createObjectURL,\n            revokeObjectURL: revokeObjectURL,\n\n            dataURL2Blob: function( dataURI ) {\n                var byteStr, intArray, ab, i, mimetype, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                ab = new ArrayBuffer( byteStr.length );\n                intArray = new Uint8Array( ab );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                mimetype = parts[ 0 ].split(':')[ 1 ].split(';')[ 0 ];\n\n                return this.arrayBufferToBlob( ab, mimetype );\n            },\n\n            dataURL2ArrayBuffer: function( dataURI ) {\n                var byteStr, intArray, i, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                intArray = new Uint8Array( byteStr.length );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                return intArray.buffer;\n            },\n\n            arrayBufferToBlob: function( buffer, type ) {\n                var builder = window.BlobBuilder || window.WebKitBlobBuilder,\n                    bb;\n\n                // android不支持直接new Blob, 只能借助blobbuilder.\n                if ( builder ) {\n                    bb = new builder();\n                    bb.append( buffer );\n                    return bb.getBlob( type );\n                }\n\n                return new Blob([ buffer ], type ? { type: type } : {} );\n            },\n\n            // 抽出来主要是为了解决android下面canvas.toDataUrl不支持jpeg.\n            // 你得到的结果是png.\n            canvasToDataUrl: function( canvas, type, quality ) {\n                return canvas.toDataURL( type, quality / 100 );\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            parseMeta: function( blob, callback ) {\n                callback( false, {});\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            updateImageHead: function( data ) {\n                return data;\n            }\n        };\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/imagemeta',[\n        'runtime/html5/util'\n    ], function( Util ) {\n\n        var api;\n\n        api = {\n            parsers: {\n                0xffe1: []\n            },\n\n            maxMetaDataSize: 262144,\n\n            parse: function( blob, cb ) {\n                var me = this,\n                    fr = new FileReader();\n\n                fr.onload = function() {\n                    cb( false, me._parse( this.result ) );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                fr.onerror = function( e ) {\n                    cb( e.message );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                blob = blob.slice( 0, me.maxMetaDataSize );\n                fr.readAsArrayBuffer( blob.getSource() );\n            },\n\n            _parse: function( buffer, noParse ) {\n                if ( buffer.byteLength < 6 ) {\n                    return;\n                }\n\n                var dataview = new DataView( buffer ),\n                    offset = 2,\n                    maxOffset = dataview.byteLength - 4,\n                    headLength = offset,\n                    ret = {},\n                    markerBytes, markerLength, parsers, i;\n\n                if ( dataview.getUint16( 0 ) === 0xffd8 ) {\n\n                    while ( offset < maxOffset ) {\n                        markerBytes = dataview.getUint16( offset );\n\n                        if ( markerBytes >= 0xffe0 && markerBytes <= 0xffef ||\n                                markerBytes === 0xfffe ) {\n\n                            markerLength = dataview.getUint16( offset + 2 ) + 2;\n\n                            if ( offset + markerLength > dataview.byteLength ) {\n                                break;\n                            }\n\n                            parsers = api.parsers[ markerBytes ];\n\n                            if ( !noParse && parsers ) {\n                                for ( i = 0; i < parsers.length; i += 1 ) {\n                                    parsers[ i ].call( api, dataview, offset,\n                                            markerLength, ret );\n                                }\n                            }\n\n                            offset += markerLength;\n                            headLength = offset;\n                        } else {\n                            break;\n                        }\n                    }\n\n                    if ( headLength > 6 ) {\n                        if ( buffer.slice ) {\n                            ret.imageHead = buffer.slice( 2, headLength );\n                        } else {\n                            // Workaround for IE10, which does not yet\n                            // support ArrayBuffer.slice:\n                            ret.imageHead = new Uint8Array( buffer )\n                                    .subarray( 2, headLength );\n                        }\n                    }\n                }\n\n                return ret;\n            },\n\n            updateImageHead: function( buffer, head ) {\n                var data = this._parse( buffer, true ),\n                    buf1, buf2, bodyoffset;\n\n\n                bodyoffset = 2;\n                if ( data.imageHead ) {\n                    bodyoffset = 2 + data.imageHead.byteLength;\n                }\n\n                if ( buffer.slice ) {\n                    buf2 = buffer.slice( bodyoffset );\n                } else {\n                    buf2 = new Uint8Array( buffer ).subarray( bodyoffset );\n                }\n\n                buf1 = new Uint8Array( head.byteLength + 2 + buf2.byteLength );\n\n                buf1[ 0 ] = 0xFF;\n                buf1[ 1 ] = 0xD8;\n                buf1.set( new Uint8Array( head ), 2 );\n                buf1.set( new Uint8Array( buf2 ), head.byteLength + 2 );\n\n                return buf1.buffer;\n            }\n        };\n\n        Util.parseMeta = function() {\n            return api.parse.apply( api, arguments );\n        };\n\n        Util.updateImageHead = function() {\n            return api.updateImageHead.apply( api, arguments );\n        };\n\n        return api;\n    });\n    /**\n     * 代码来自于：https://github.com/blueimp/JavaScript-Load-Image\n     * 暂时项目中只用了orientation.\n     *\n     * 去除了 Exif Sub IFD Pointer, GPS Info IFD Pointer, Exif Thumbnail.\n     * @fileOverview EXIF解析\n     */\n\n    // Sample\n    // ====================================\n    // Make : Apple\n    // Model : iPhone 4S\n    // Orientation : 1\n    // XResolution : 72 [72/1]\n    // YResolution : 72 [72/1]\n    // ResolutionUnit : 2\n    // Software : QuickTime 7.7.1\n    // DateTime : 2013:09:01 22:53:55\n    // ExifIFDPointer : 190\n    // ExposureTime : 0.058823529411764705 [1/17]\n    // FNumber : 2.4 [12/5]\n    // ExposureProgram : Normal program\n    // ISOSpeedRatings : 800\n    // ExifVersion : 0220\n    // DateTimeOriginal : 2013:09:01 22:52:51\n    // DateTimeDigitized : 2013:09:01 22:52:51\n    // ComponentsConfiguration : YCbCr\n    // ShutterSpeedValue : 4.058893515764426\n    // ApertureValue : 2.5260688216892597 [4845/1918]\n    // BrightnessValue : -0.3126686601998395\n    // MeteringMode : Pattern\n    // Flash : Flash did not fire, compulsory flash mode\n    // FocalLength : 4.28 [107/25]\n    // SubjectArea : [4 values]\n    // FlashpixVersion : 0100\n    // ColorSpace : 1\n    // PixelXDimension : 2448\n    // PixelYDimension : 3264\n    // SensingMethod : One-chip color area sensor\n    // ExposureMode : 0\n    // WhiteBalance : Auto white balance\n    // FocalLengthIn35mmFilm : 35\n    // SceneCaptureType : Standard\n    define('runtime/html5/imagemeta/exif',[\n        'base',\n        'runtime/html5/imagemeta'\n    ], function( Base, ImageMeta ) {\n\n        var EXIF = {};\n\n        EXIF.ExifMap = function() {\n            return this;\n        };\n\n        EXIF.ExifMap.prototype.map = {\n            'Orientation': 0x0112\n        };\n\n        EXIF.ExifMap.prototype.get = function( id ) {\n            return this[ id ] || this[ this.map[ id ] ];\n        };\n\n        EXIF.exifTagTypes = {\n            // byte, 8-bit unsigned int:\n            1: {\n                getValue: function( dataView, dataOffset ) {\n                    return dataView.getUint8( dataOffset );\n                },\n                size: 1\n            },\n\n            // ascii, 8-bit byte:\n            2: {\n                getValue: function( dataView, dataOffset ) {\n                    return String.fromCharCode( dataView.getUint8( dataOffset ) );\n                },\n                size: 1,\n                ascii: true\n            },\n\n            // short, 16 bit int:\n            3: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint16( dataOffset, littleEndian );\n                },\n                size: 2\n            },\n\n            // long, 32 bit int:\n            4: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // rational = two long values,\n            // first is numerator, second is denominator:\n            5: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian ) /\n                        dataView.getUint32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            },\n\n            // slong, 32 bit signed int:\n            9: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // srational, two slongs, first is numerator, second is denominator:\n            10: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian ) /\n                        dataView.getInt32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            }\n        };\n\n        // undefined, 8-bit byte, value depending on field:\n        EXIF.exifTagTypes[ 7 ] = EXIF.exifTagTypes[ 1 ];\n\n        EXIF.getExifValue = function( dataView, tiffOffset, offset, type, length,\n                littleEndian ) {\n\n            var tagType = EXIF.exifTagTypes[ type ],\n                tagSize, dataOffset, values, i, str, c;\n\n            if ( !tagType ) {\n                Base.log('Invalid Exif data: Invalid tag type.');\n                return;\n            }\n\n            tagSize = tagType.size * length;\n\n            // Determine if the value is contained in the dataOffset bytes,\n            // or if the value at the dataOffset is a pointer to the actual data:\n            dataOffset = tagSize > 4 ? tiffOffset + dataView.getUint32( offset + 8,\n                    littleEndian ) : (offset + 8);\n\n            if ( dataOffset + tagSize > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid data offset.');\n                return;\n            }\n\n            if ( length === 1 ) {\n                return tagType.getValue( dataView, dataOffset, littleEndian );\n            }\n\n            values = [];\n\n            for ( i = 0; i < length; i += 1 ) {\n                values[ i ] = tagType.getValue( dataView,\n                        dataOffset + i * tagType.size, littleEndian );\n            }\n\n            if ( tagType.ascii ) {\n                str = '';\n\n                // Concatenate the chars:\n                for ( i = 0; i < values.length; i += 1 ) {\n                    c = values[ i ];\n\n                    // Ignore the terminating NULL byte(s):\n                    if ( c === '\\u0000' ) {\n                        break;\n                    }\n                    str += c;\n                }\n\n                return str;\n            }\n            return values;\n        };\n\n        EXIF.parseExifTag = function( dataView, tiffOffset, offset, littleEndian,\n                data ) {\n\n            var tag = dataView.getUint16( offset, littleEndian );\n            data.exif[ tag ] = EXIF.getExifValue( dataView, tiffOffset, offset,\n                    dataView.getUint16( offset + 2, littleEndian ),    // tag type\n                    dataView.getUint32( offset + 4, littleEndian ),    // tag length\n                    littleEndian );\n        };\n\n        EXIF.parseExifTags = function( dataView, tiffOffset, dirOffset,\n                littleEndian, data ) {\n\n            var tagsNumber, dirEndOffset, i;\n\n            if ( dirOffset + 6 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory offset.');\n                return;\n            }\n\n            tagsNumber = dataView.getUint16( dirOffset, littleEndian );\n            dirEndOffset = dirOffset + 2 + 12 * tagsNumber;\n\n            if ( dirEndOffset + 4 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory size.');\n                return;\n            }\n\n            for ( i = 0; i < tagsNumber; i += 1 ) {\n                this.parseExifTag( dataView, tiffOffset,\n                        dirOffset + 2 + 12 * i,    // tag offset\n                        littleEndian, data );\n            }\n\n            // Return the offset to the next directory:\n            return dataView.getUint32( dirEndOffset, littleEndian );\n        };\n\n        // EXIF.getExifThumbnail = function(dataView, offset, length) {\n        //     var hexData,\n        //         i,\n        //         b;\n        //     if (!length || offset + length > dataView.byteLength) {\n        //         Base.log('Invalid Exif data: Invalid thumbnail data.');\n        //         return;\n        //     }\n        //     hexData = [];\n        //     for (i = 0; i < length; i += 1) {\n        //         b = dataView.getUint8(offset + i);\n        //         hexData.push((b < 16 ? '0' : '') + b.toString(16));\n        //     }\n        //     return 'data:image/jpeg,%' + hexData.join('%');\n        // };\n\n        EXIF.parseExifData = function( dataView, offset, length, data ) {\n\n            var tiffOffset = offset + 10,\n                littleEndian, dirOffset;\n\n            // Check for the ASCII code for \"Exif\" (0x45786966):\n            if ( dataView.getUint32( offset + 4 ) !== 0x45786966 ) {\n                // No Exif data, might be XMP data instead\n                return;\n            }\n            if ( tiffOffset + 8 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid segment size.');\n                return;\n            }\n\n            // Check for the two null bytes:\n            if ( dataView.getUint16( offset + 8 ) !== 0x0000 ) {\n                Base.log('Invalid Exif data: Missing byte alignment offset.');\n                return;\n            }\n\n            // Check the byte alignment:\n            switch ( dataView.getUint16( tiffOffset ) ) {\n                case 0x4949:\n                    littleEndian = true;\n                    break;\n\n                case 0x4D4D:\n                    littleEndian = false;\n                    break;\n\n                default:\n                    Base.log('Invalid Exif data: Invalid byte alignment marker.');\n                    return;\n            }\n\n            // Check for the TIFF tag marker (0x002A):\n            if ( dataView.getUint16( tiffOffset + 2, littleEndian ) !== 0x002A ) {\n                Base.log('Invalid Exif data: Missing TIFF marker.');\n                return;\n            }\n\n            // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:\n            dirOffset = dataView.getUint32( tiffOffset + 4, littleEndian );\n            // Create the exif object to store the tags:\n            data.exif = new EXIF.ExifMap();\n            // Parse the tags of the main image directory and retrieve the\n            // offset to the next directory, usually the thumbnail directory:\n            dirOffset = EXIF.parseExifTags( dataView, tiffOffset,\n                    tiffOffset + dirOffset, littleEndian, data );\n\n            // 尝试读取缩略图\n            // if ( dirOffset ) {\n            //     thumbnailData = {exif: {}};\n            //     dirOffset = EXIF.parseExifTags(\n            //         dataView,\n            //         tiffOffset,\n            //         tiffOffset + dirOffset,\n            //         littleEndian,\n            //         thumbnailData\n            //     );\n\n            //     // Check for JPEG Thumbnail offset:\n            //     if (thumbnailData.exif[0x0201]) {\n            //         data.exif.Thumbnail = EXIF.getExifThumbnail(\n            //             dataView,\n            //             tiffOffset + thumbnailData.exif[0x0201],\n            //             thumbnailData.exif[0x0202] // Thumbnail data length\n            //         );\n            //     }\n            // }\n        };\n\n        ImageMeta.parsers[ 0xffe1 ].push( EXIF.parseExifData );\n        return EXIF;\n    });\n    /**\n     * 这个方式性能不行，但是可以解决android里面的toDataUrl的bug\n     * android里面toDataUrl('image/jpege')得到的结果却是png.\n     *\n     * 所以这里没辙，只能借助这个工具\n     * @fileOverview jpeg encoder\n     */\n    define('runtime/html5/jpegencoder',[], function( require, exports, module ) {\n\n        /*\n          Copyright (c) 2008, Adobe Systems Incorporated\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\n          met:\n\n          * Redistributions of source code must retain the above copyright notice,\n            this list of conditions and the following disclaimer.\n\n          * Redistributions in binary form must reproduce the above copyright\n            notice, this list of conditions and the following disclaimer in the\n            documentation and/or other materials provided with the distribution.\n\n          * Neither the name of Adobe Systems Incorporated nor the names of its\n            contributors may be used to endorse or promote products derived from\n            this software without specific prior written permission.\n\n          THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n          IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n          THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n          PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n          CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n          EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n          PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n          PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n          LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n          NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n          SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n        */\n        /*\n        JPEG encoder ported to JavaScript and optimized by Andreas Ritter, www.bytestrom.eu, 11/2009\n\n        Basic GUI blocking jpeg encoder\n        */\n\n        function JPEGEncoder(quality) {\n          var self = this;\n            var fround = Math.round;\n            var ffloor = Math.floor;\n            var YTable = new Array(64);\n            var UVTable = new Array(64);\n            var fdtbl_Y = new Array(64);\n            var fdtbl_UV = new Array(64);\n            var YDC_HT;\n            var UVDC_HT;\n            var YAC_HT;\n            var UVAC_HT;\n\n            var bitcode = new Array(65535);\n            var category = new Array(65535);\n            var outputfDCTQuant = new Array(64);\n            var DU = new Array(64);\n            var byteout = [];\n            var bytenew = 0;\n            var bytepos = 7;\n\n            var YDU = new Array(64);\n            var UDU = new Array(64);\n            var VDU = new Array(64);\n            var clt = new Array(256);\n            var RGB_YUV_TABLE = new Array(2048);\n            var currentQuality;\n\n            var ZigZag = [\n                     0, 1, 5, 6,14,15,27,28,\n                     2, 4, 7,13,16,26,29,42,\n                     3, 8,12,17,25,30,41,43,\n                     9,11,18,24,31,40,44,53,\n                    10,19,23,32,39,45,52,54,\n                    20,22,33,38,46,51,55,60,\n                    21,34,37,47,50,56,59,61,\n                    35,36,48,49,57,58,62,63\n                ];\n\n            var std_dc_luminance_nrcodes = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];\n            var std_dc_luminance_values = [0,1,2,3,4,5,6,7,8,9,10,11];\n            var std_ac_luminance_nrcodes = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];\n            var std_ac_luminance_values = [\n                    0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,\n                    0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,\n                    0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\n                    0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,\n                    0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,\n                    0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\n                    0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,\n                    0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,\n                    0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\n                    0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,\n                    0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,\n                    0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\n                    0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,\n                    0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,\n                    0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\n                    0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,\n                    0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,\n                    0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\n                    0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,\n                    0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\n                    0xf9,0xfa\n                ];\n\n            var std_dc_chrominance_nrcodes = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];\n            var std_dc_chrominance_values = [0,1,2,3,4,5,6,7,8,9,10,11];\n            var std_ac_chrominance_nrcodes = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];\n            var std_ac_chrominance_values = [\n                    0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,\n                    0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,\n                    0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\n                    0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,\n                    0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,\n                    0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\n                    0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,\n                    0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,\n                    0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\n                    0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,\n                    0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,\n                    0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\n                    0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,\n                    0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,\n                    0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\n                    0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,\n                    0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,\n                    0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\n                    0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,\n                    0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\n                    0xf9,0xfa\n                ];\n\n            function initQuantTables(sf){\n                    var YQT = [\n                        16, 11, 10, 16, 24, 40, 51, 61,\n                        12, 12, 14, 19, 26, 58, 60, 55,\n                        14, 13, 16, 24, 40, 57, 69, 56,\n                        14, 17, 22, 29, 51, 87, 80, 62,\n                        18, 22, 37, 56, 68,109,103, 77,\n                        24, 35, 55, 64, 81,104,113, 92,\n                        49, 64, 78, 87,103,121,120,101,\n                        72, 92, 95, 98,112,100,103, 99\n                    ];\n\n                    for (var i = 0; i < 64; i++) {\n                        var t = ffloor((YQT[i]*sf+50)/100);\n                        if (t < 1) {\n                            t = 1;\n                        } else if (t > 255) {\n                            t = 255;\n                        }\n                        YTable[ZigZag[i]] = t;\n                    }\n                    var UVQT = [\n                        17, 18, 24, 47, 99, 99, 99, 99,\n                        18, 21, 26, 66, 99, 99, 99, 99,\n                        24, 26, 56, 99, 99, 99, 99, 99,\n                        47, 66, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99\n                    ];\n                    for (var j = 0; j < 64; j++) {\n                        var u = ffloor((UVQT[j]*sf+50)/100);\n                        if (u < 1) {\n                            u = 1;\n                        } else if (u > 255) {\n                            u = 255;\n                        }\n                        UVTable[ZigZag[j]] = u;\n                    }\n                    var aasf = [\n                        1.0, 1.387039845, 1.306562965, 1.175875602,\n                        1.0, 0.785694958, 0.541196100, 0.275899379\n                    ];\n                    var k = 0;\n                    for (var row = 0; row < 8; row++)\n                    {\n                        for (var col = 0; col < 8; col++)\n                        {\n                            fdtbl_Y[k]  = (1.0 / (YTable [ZigZag[k]] * aasf[row] * aasf[col] * 8.0));\n                            fdtbl_UV[k] = (1.0 / (UVTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0));\n                            k++;\n                        }\n                    }\n                }\n\n                function computeHuffmanTbl(nrcodes, std_table){\n                    var codevalue = 0;\n                    var pos_in_table = 0;\n                    var HT = new Array();\n                    for (var k = 1; k <= 16; k++) {\n                        for (var j = 1; j <= nrcodes[k]; j++) {\n                            HT[std_table[pos_in_table]] = [];\n                            HT[std_table[pos_in_table]][0] = codevalue;\n                            HT[std_table[pos_in_table]][1] = k;\n                            pos_in_table++;\n                            codevalue++;\n                        }\n                        codevalue*=2;\n                    }\n                    return HT;\n                }\n\n                function initHuffmanTbl()\n                {\n                    YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);\n                    UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);\n                    YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);\n                    UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);\n                }\n\n                function initCategoryNumber()\n                {\n                    var nrlower = 1;\n                    var nrupper = 2;\n                    for (var cat = 1; cat <= 15; cat++) {\n                        //Positive numbers\n                        for (var nr = nrlower; nr<nrupper; nr++) {\n                            category[32767+nr] = cat;\n                            bitcode[32767+nr] = [];\n                            bitcode[32767+nr][1] = cat;\n                            bitcode[32767+nr][0] = nr;\n                        }\n                        //Negative numbers\n                        for (var nrneg =-(nrupper-1); nrneg<=-nrlower; nrneg++) {\n                            category[32767+nrneg] = cat;\n                            bitcode[32767+nrneg] = [];\n                            bitcode[32767+nrneg][1] = cat;\n                            bitcode[32767+nrneg][0] = nrupper-1+nrneg;\n                        }\n                        nrlower <<= 1;\n                        nrupper <<= 1;\n                    }\n                }\n\n                function initRGBYUVTable() {\n                    for(var i = 0; i < 256;i++) {\n                        RGB_YUV_TABLE[i]            =  19595 * i;\n                        RGB_YUV_TABLE[(i+ 256)>>0]  =  38470 * i;\n                        RGB_YUV_TABLE[(i+ 512)>>0]  =   7471 * i + 0x8000;\n                        RGB_YUV_TABLE[(i+ 768)>>0]  = -11059 * i;\n                        RGB_YUV_TABLE[(i+1024)>>0]  = -21709 * i;\n                        RGB_YUV_TABLE[(i+1280)>>0]  =  32768 * i + 0x807FFF;\n                        RGB_YUV_TABLE[(i+1536)>>0]  = -27439 * i;\n                        RGB_YUV_TABLE[(i+1792)>>0]  = - 5329 * i;\n                    }\n                }\n\n                // IO functions\n                function writeBits(bs)\n                {\n                    var value = bs[0];\n                    var posval = bs[1]-1;\n                    while ( posval >= 0 ) {\n                        if (value & (1 << posval) ) {\n                            bytenew |= (1 << bytepos);\n                        }\n                        posval--;\n                        bytepos--;\n                        if (bytepos < 0) {\n                            if (bytenew == 0xFF) {\n                                writeByte(0xFF);\n                                writeByte(0);\n                            }\n                            else {\n                                writeByte(bytenew);\n                            }\n                            bytepos=7;\n                            bytenew=0;\n                        }\n                    }\n                }\n\n                function writeByte(value)\n                {\n                    byteout.push(clt[value]); // write char directly instead of converting later\n                }\n\n                function writeWord(value)\n                {\n                    writeByte((value>>8)&0xFF);\n                    writeByte((value   )&0xFF);\n                }\n\n                // DCT & quantization core\n                function fDCTQuant(data, fdtbl)\n                {\n                    var d0, d1, d2, d3, d4, d5, d6, d7;\n                    /* Pass 1: process rows. */\n                    var dataOff=0;\n                    var i;\n                    var I8 = 8;\n                    var I64 = 64;\n                    for (i=0; i<I8; ++i)\n                    {\n                        d0 = data[dataOff];\n                        d1 = data[dataOff+1];\n                        d2 = data[dataOff+2];\n                        d3 = data[dataOff+3];\n                        d4 = data[dataOff+4];\n                        d5 = data[dataOff+5];\n                        d6 = data[dataOff+6];\n                        d7 = data[dataOff+7];\n\n                        var tmp0 = d0 + d7;\n                        var tmp7 = d0 - d7;\n                        var tmp1 = d1 + d6;\n                        var tmp6 = d1 - d6;\n                        var tmp2 = d2 + d5;\n                        var tmp5 = d2 - d5;\n                        var tmp3 = d3 + d4;\n                        var tmp4 = d3 - d4;\n\n                        /* Even part */\n                        var tmp10 = tmp0 + tmp3;    /* phase 2 */\n                        var tmp13 = tmp0 - tmp3;\n                        var tmp11 = tmp1 + tmp2;\n                        var tmp12 = tmp1 - tmp2;\n\n                        data[dataOff] = tmp10 + tmp11; /* phase 3 */\n                        data[dataOff+4] = tmp10 - tmp11;\n\n                        var z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */\n                        data[dataOff+2] = tmp13 + z1; /* phase 5 */\n                        data[dataOff+6] = tmp13 - z1;\n\n                        /* Odd part */\n                        tmp10 = tmp4 + tmp5; /* phase 2 */\n                        tmp11 = tmp5 + tmp6;\n                        tmp12 = tmp6 + tmp7;\n\n                        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n                        var z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */\n                        var z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */\n                        var z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */\n                        var z3 = tmp11 * 0.707106781; /* c4 */\n\n                        var z11 = tmp7 + z3;    /* phase 5 */\n                        var z13 = tmp7 - z3;\n\n                        data[dataOff+5] = z13 + z2; /* phase 6 */\n                        data[dataOff+3] = z13 - z2;\n                        data[dataOff+1] = z11 + z4;\n                        data[dataOff+7] = z11 - z4;\n\n                        dataOff += 8; /* advance pointer to next row */\n                    }\n\n                    /* Pass 2: process columns. */\n                    dataOff = 0;\n                    for (i=0; i<I8; ++i)\n                    {\n                        d0 = data[dataOff];\n                        d1 = data[dataOff + 8];\n                        d2 = data[dataOff + 16];\n                        d3 = data[dataOff + 24];\n                        d4 = data[dataOff + 32];\n                        d5 = data[dataOff + 40];\n                        d6 = data[dataOff + 48];\n                        d7 = data[dataOff + 56];\n\n                        var tmp0p2 = d0 + d7;\n                        var tmp7p2 = d0 - d7;\n                        var tmp1p2 = d1 + d6;\n                        var tmp6p2 = d1 - d6;\n                        var tmp2p2 = d2 + d5;\n                        var tmp5p2 = d2 - d5;\n                        var tmp3p2 = d3 + d4;\n                        var tmp4p2 = d3 - d4;\n\n                        /* Even part */\n                        var tmp10p2 = tmp0p2 + tmp3p2;  /* phase 2 */\n                        var tmp13p2 = tmp0p2 - tmp3p2;\n                        var tmp11p2 = tmp1p2 + tmp2p2;\n                        var tmp12p2 = tmp1p2 - tmp2p2;\n\n                        data[dataOff] = tmp10p2 + tmp11p2; /* phase 3 */\n                        data[dataOff+32] = tmp10p2 - tmp11p2;\n\n                        var z1p2 = (tmp12p2 + tmp13p2) * 0.707106781; /* c4 */\n                        data[dataOff+16] = tmp13p2 + z1p2; /* phase 5 */\n                        data[dataOff+48] = tmp13p2 - z1p2;\n\n                        /* Odd part */\n                        tmp10p2 = tmp4p2 + tmp5p2; /* phase 2 */\n                        tmp11p2 = tmp5p2 + tmp6p2;\n                        tmp12p2 = tmp6p2 + tmp7p2;\n\n                        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n                        var z5p2 = (tmp10p2 - tmp12p2) * 0.382683433; /* c6 */\n                        var z2p2 = 0.541196100 * tmp10p2 + z5p2; /* c2-c6 */\n                        var z4p2 = 1.306562965 * tmp12p2 + z5p2; /* c2+c6 */\n                        var z3p2 = tmp11p2 * 0.707106781; /* c4 */\n\n                        var z11p2 = tmp7p2 + z3p2;  /* phase 5 */\n                        var z13p2 = tmp7p2 - z3p2;\n\n                        data[dataOff+40] = z13p2 + z2p2; /* phase 6 */\n                        data[dataOff+24] = z13p2 - z2p2;\n                        data[dataOff+ 8] = z11p2 + z4p2;\n                        data[dataOff+56] = z11p2 - z4p2;\n\n                        dataOff++; /* advance pointer to next column */\n                    }\n\n                    // Quantize/descale the coefficients\n                    var fDCTQuant;\n                    for (i=0; i<I64; ++i)\n                    {\n                        // Apply the quantization and scaling factor & Round to nearest integer\n                        fDCTQuant = data[i]*fdtbl[i];\n                        outputfDCTQuant[i] = (fDCTQuant > 0.0) ? ((fDCTQuant + 0.5)|0) : ((fDCTQuant - 0.5)|0);\n                        //outputfDCTQuant[i] = fround(fDCTQuant);\n\n                    }\n                    return outputfDCTQuant;\n                }\n\n                function writeAPP0()\n                {\n                    writeWord(0xFFE0); // marker\n                    writeWord(16); // length\n                    writeByte(0x4A); // J\n                    writeByte(0x46); // F\n                    writeByte(0x49); // I\n                    writeByte(0x46); // F\n                    writeByte(0); // = \"JFIF\",'\\0'\n                    writeByte(1); // versionhi\n                    writeByte(1); // versionlo\n                    writeByte(0); // xyunits\n                    writeWord(1); // xdensity\n                    writeWord(1); // ydensity\n                    writeByte(0); // thumbnwidth\n                    writeByte(0); // thumbnheight\n                }\n\n                function writeSOF0(width, height)\n                {\n                    writeWord(0xFFC0); // marker\n                    writeWord(17);   // length, truecolor YUV JPG\n                    writeByte(8);    // precision\n                    writeWord(height);\n                    writeWord(width);\n                    writeByte(3);    // nrofcomponents\n                    writeByte(1);    // IdY\n                    writeByte(0x11); // HVY\n                    writeByte(0);    // QTY\n                    writeByte(2);    // IdU\n                    writeByte(0x11); // HVU\n                    writeByte(1);    // QTU\n                    writeByte(3);    // IdV\n                    writeByte(0x11); // HVV\n                    writeByte(1);    // QTV\n                }\n\n                function writeDQT()\n                {\n                    writeWord(0xFFDB); // marker\n                    writeWord(132);    // length\n                    writeByte(0);\n                    for (var i=0; i<64; i++) {\n                        writeByte(YTable[i]);\n                    }\n                    writeByte(1);\n                    for (var j=0; j<64; j++) {\n                        writeByte(UVTable[j]);\n                    }\n                }\n\n                function writeDHT()\n                {\n                    writeWord(0xFFC4); // marker\n                    writeWord(0x01A2); // length\n\n                    writeByte(0); // HTYDCinfo\n                    for (var i=0; i<16; i++) {\n                        writeByte(std_dc_luminance_nrcodes[i+1]);\n                    }\n                    for (var j=0; j<=11; j++) {\n                        writeByte(std_dc_luminance_values[j]);\n                    }\n\n                    writeByte(0x10); // HTYACinfo\n                    for (var k=0; k<16; k++) {\n                        writeByte(std_ac_luminance_nrcodes[k+1]);\n                    }\n                    for (var l=0; l<=161; l++) {\n                        writeByte(std_ac_luminance_values[l]);\n                    }\n\n                    writeByte(1); // HTUDCinfo\n                    for (var m=0; m<16; m++) {\n                        writeByte(std_dc_chrominance_nrcodes[m+1]);\n                    }\n                    for (var n=0; n<=11; n++) {\n                        writeByte(std_dc_chrominance_values[n]);\n                    }\n\n                    writeByte(0x11); // HTUACinfo\n                    for (var o=0; o<16; o++) {\n                        writeByte(std_ac_chrominance_nrcodes[o+1]);\n                    }\n                    for (var p=0; p<=161; p++) {\n                        writeByte(std_ac_chrominance_values[p]);\n                    }\n                }\n\n                function writeSOS()\n                {\n                    writeWord(0xFFDA); // marker\n                    writeWord(12); // length\n                    writeByte(3); // nrofcomponents\n                    writeByte(1); // IdY\n                    writeByte(0); // HTY\n                    writeByte(2); // IdU\n                    writeByte(0x11); // HTU\n                    writeByte(3); // IdV\n                    writeByte(0x11); // HTV\n                    writeByte(0); // Ss\n                    writeByte(0x3f); // Se\n                    writeByte(0); // Bf\n                }\n\n                function processDU(CDU, fdtbl, DC, HTDC, HTAC){\n                    var EOB = HTAC[0x00];\n                    var M16zeroes = HTAC[0xF0];\n                    var pos;\n                    var I16 = 16;\n                    var I63 = 63;\n                    var I64 = 64;\n                    var DU_DCT = fDCTQuant(CDU, fdtbl);\n                    //ZigZag reorder\n                    for (var j=0;j<I64;++j) {\n                        DU[ZigZag[j]]=DU_DCT[j];\n                    }\n                    var Diff = DU[0] - DC; DC = DU[0];\n                    //Encode DC\n                    if (Diff==0) {\n                        writeBits(HTDC[0]); // Diff might be 0\n                    } else {\n                        pos = 32767+Diff;\n                        writeBits(HTDC[category[pos]]);\n                        writeBits(bitcode[pos]);\n                    }\n                    //Encode ACs\n                    var end0pos = 63; // was const... which is crazy\n                    for (; (end0pos>0)&&(DU[end0pos]==0); end0pos--) {};\n                    //end0pos = first element in reverse order !=0\n                    if ( end0pos == 0) {\n                        writeBits(EOB);\n                        return DC;\n                    }\n                    var i = 1;\n                    var lng;\n                    while ( i <= end0pos ) {\n                        var startpos = i;\n                        for (; (DU[i]==0) && (i<=end0pos); ++i) {}\n                        var nrzeroes = i-startpos;\n                        if ( nrzeroes >= I16 ) {\n                            lng = nrzeroes>>4;\n                            for (var nrmarker=1; nrmarker <= lng; ++nrmarker)\n                                writeBits(M16zeroes);\n                            nrzeroes = nrzeroes&0xF;\n                        }\n                        pos = 32767+DU[i];\n                        writeBits(HTAC[(nrzeroes<<4)+category[pos]]);\n                        writeBits(bitcode[pos]);\n                        i++;\n                    }\n                    if ( end0pos != I63 ) {\n                        writeBits(EOB);\n                    }\n                    return DC;\n                }\n\n                function initCharLookupTable(){\n                    var sfcc = String.fromCharCode;\n                    for(var i=0; i < 256; i++){ ///// ACHTUNG // 255\n                        clt[i] = sfcc(i);\n                    }\n                }\n\n                this.encode = function(image,quality) // image data object\n                {\n                    // var time_start = new Date().getTime();\n\n                    if(quality) setQuality(quality);\n\n                    // Initialize bit writer\n                    byteout = new Array();\n                    bytenew=0;\n                    bytepos=7;\n\n                    // Add JPEG headers\n                    writeWord(0xFFD8); // SOI\n                    writeAPP0();\n                    writeDQT();\n                    writeSOF0(image.width,image.height);\n                    writeDHT();\n                    writeSOS();\n\n\n                    // Encode 8x8 macroblocks\n                    var DCY=0;\n                    var DCU=0;\n                    var DCV=0;\n\n                    bytenew=0;\n                    bytepos=7;\n\n\n                    this.encode.displayName = \"_encode_\";\n\n                    var imageData = image.data;\n                    var width = image.width;\n                    var height = image.height;\n\n                    var quadWidth = width*4;\n                    var tripleWidth = width*3;\n\n                    var x, y = 0;\n                    var r, g, b;\n                    var start,p, col,row,pos;\n                    while(y < height){\n                        x = 0;\n                        while(x < quadWidth){\n                        start = quadWidth * y + x;\n                        p = start;\n                        col = -1;\n                        row = 0;\n\n                        for(pos=0; pos < 64; pos++){\n                            row = pos >> 3;// /8\n                            col = ( pos & 7 ) * 4; // %8\n                            p = start + ( row * quadWidth ) + col;\n\n                            if(y+row >= height){ // padding bottom\n                                p-= (quadWidth*(y+1+row-height));\n                            }\n\n                            if(x+col >= quadWidth){ // padding right\n                                p-= ((x+col) - quadWidth +4)\n                            }\n\n                            r = imageData[ p++ ];\n                            g = imageData[ p++ ];\n                            b = imageData[ p++ ];\n\n\n                            /* // calculate YUV values dynamically\n                            YDU[pos]=((( 0.29900)*r+( 0.58700)*g+( 0.11400)*b))-128; //-0x80\n                            UDU[pos]=(((-0.16874)*r+(-0.33126)*g+( 0.50000)*b));\n                            VDU[pos]=((( 0.50000)*r+(-0.41869)*g+(-0.08131)*b));\n                            */\n\n                            // use lookup table (slightly faster)\n                            YDU[pos] = ((RGB_YUV_TABLE[r]             + RGB_YUV_TABLE[(g +  256)>>0] + RGB_YUV_TABLE[(b +  512)>>0]) >> 16)-128;\n                            UDU[pos] = ((RGB_YUV_TABLE[(r +  768)>>0] + RGB_YUV_TABLE[(g + 1024)>>0] + RGB_YUV_TABLE[(b + 1280)>>0]) >> 16)-128;\n                            VDU[pos] = ((RGB_YUV_TABLE[(r + 1280)>>0] + RGB_YUV_TABLE[(g + 1536)>>0] + RGB_YUV_TABLE[(b + 1792)>>0]) >> 16)-128;\n\n                        }\n\n                        DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n                        DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n                        DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n                        x+=32;\n                        }\n                        y+=8;\n                    }\n\n\n                    ////////////////////////////////////////////////////////////////\n\n                    // Do the bit alignment of the EOI marker\n                    if ( bytepos >= 0 ) {\n                        var fillbits = [];\n                        fillbits[1] = bytepos+1;\n                        fillbits[0] = (1<<(bytepos+1))-1;\n                        writeBits(fillbits);\n                    }\n\n                    writeWord(0xFFD9); //EOI\n\n                    var jpegDataUri = 'data:image/jpeg;base64,' + btoa(byteout.join(''));\n\n                    byteout = [];\n\n                    // benchmarking\n                    // var duration = new Date().getTime() - time_start;\n                    // console.log('Encoding time: '+ currentQuality + 'ms');\n                    //\n\n                    return jpegDataUri\n            }\n\n            function setQuality(quality){\n                if (quality <= 0) {\n                    quality = 1;\n                }\n                if (quality > 100) {\n                    quality = 100;\n                }\n\n                if(currentQuality == quality) return // don't recalc if unchanged\n\n                var sf = 0;\n                if (quality < 50) {\n                    sf = Math.floor(5000 / quality);\n                } else {\n                    sf = Math.floor(200 - quality*2);\n                }\n\n                initQuantTables(sf);\n                currentQuality = quality;\n                // console.log('Quality set to: '+quality +'%');\n            }\n\n            function init(){\n                // var time_start = new Date().getTime();\n                if(!quality) quality = 50;\n                // Create tables\n                initCharLookupTable()\n                initHuffmanTbl();\n                initCategoryNumber();\n                initRGBYUVTable();\n\n                setQuality(quality);\n                // var duration = new Date().getTime() - time_start;\n                // console.log('Initialization '+ duration + 'ms');\n            }\n\n            init();\n\n        };\n\n        JPEGEncoder.encode = function( data, quality ) {\n            var encoder = new JPEGEncoder( quality );\n\n            return encoder.encode( data );\n        }\n\n        return JPEGEncoder;\n    });\n    /**\n     * @fileOverview Fix android canvas.toDataUrl bug.\n     */\n    define('runtime/html5/androidpatch',[\n        'runtime/html5/util',\n        'runtime/html5/jpegencoder',\n        'base'\n    ], function( Util, encoder, Base ) {\n        var origin = Util.canvasToDataUrl,\n            supportJpeg;\n\n        Util.canvasToDataUrl = function( canvas, type, quality ) {\n            var ctx, w, h, fragement, parts;\n\n            // 非android手机直接跳过。\n            if ( !Base.os.android ) {\n                return origin.apply( null, arguments );\n            }\n\n            // 检测是否canvas支持jpeg导出，根据数据格式来判断。\n            // JPEG 前两位分别是：255, 216\n            if ( type === 'image/jpeg' && typeof supportJpeg === 'undefined' ) {\n                fragement = origin.apply( null, arguments );\n\n                parts = fragement.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    fragement = atob( parts[ 1 ] );\n                } else {\n                    fragement = decodeURIComponent( parts[ 1 ] );\n                }\n\n                fragement = fragement.substring( 0, 2 );\n\n                supportJpeg = fragement.charCodeAt( 0 ) === 255 &&\n                        fragement.charCodeAt( 1 ) === 216;\n            }\n\n            // 只有在android环境下才修复\n            if ( type === 'image/jpeg' && !supportJpeg ) {\n                w = canvas.width;\n                h = canvas.height;\n                ctx = canvas.getContext('2d');\n\n                return encoder.encode( ctx.getImageData( 0, 0, w, h ), quality );\n            }\n\n            return origin.apply( null, arguments );\n        };\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('runtime/html5/image',[\n        'base',\n        'runtime/html5/runtime',\n        'runtime/html5/util'\n    ], function( Base, Html5Runtime, Util ) {\n\n        var BLANK = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D';\n\n        return Html5Runtime.register( 'Image', {\n\n            // flag: 标记是否被修改过。\n            modified: false,\n\n            init: function() {\n                var me = this,\n                    img = new Image();\n\n                img.onload = function() {\n\n                    me._info = {\n                        type: me.type,\n                        width: this.width,\n                        height: this.height\n                    };\n\n                    // 读取meta信息。\n                    if ( !me._metas && 'image/jpeg' === me.type ) {\n                        Util.parseMeta( me._blob, function( error, ret ) {\n                            me._metas = ret;\n                            me.owner.trigger('load');\n                        });\n                    } else {\n                        me.owner.trigger('load');\n                    }\n                };\n\n                img.onerror = function() {\n                    me.owner.trigger('error');\n                };\n\n                me._img = img;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    img = me._img;\n\n                me._blob = blob;\n                me.type = blob.type;\n                img.src = Util.createObjectURL( blob.getSource() );\n                me.owner.once( 'load', function() {\n                    Util.revokeObjectURL( img.src );\n                });\n            },\n\n            resize: function( width, height ) {\n                var canvas = this._canvas ||\n                        (this._canvas = document.createElement('canvas'));\n\n                this._resize( this._img, canvas, width, height );\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'resize' );\n            },\n\n            crop: function( x, y, w, h, s ) {\n                var cvs = this._canvas ||\n                        (this._canvas = document.createElement('canvas')),\n                    opts = this.options,\n                    img = this._img,\n                    iw = img.naturalWidth,\n                    ih = img.naturalHeight,\n                    orientation = this.getOrientation();\n\n                s = s || 1;\n\n                // todo 解决 orientation 的问题。\n                // values that require 90 degree rotation\n                // if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                //     switch ( orientation ) {\n                //         case 6:\n                //             tmp = x;\n                //             x = y;\n                //             y = iw * s - tmp - w;\n                //             console.log(ih * s, tmp, w)\n                //             break;\n                //     }\n\n                //     (w ^= h, h ^= w, w ^= h);\n                // }\n\n                cvs.width = w;\n                cvs.height = h;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n                this._renderImageToCanvas( cvs, img, -x, -y, iw * s, ih * s );\n\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'crop' );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this._blob,\n                    opts = this.options,\n                    canvas;\n\n                type = type || this.type;\n\n                // blob需要重新生成。\n                if ( this.modified || this.type !== type ) {\n                    canvas = this._canvas;\n\n                    if ( type === 'image/jpeg' ) {\n\n                        blob = Util.canvasToDataUrl( canvas, type, opts.quality );\n\n                        if ( opts.preserveHeaders && this._metas &&\n                                this._metas.imageHead ) {\n\n                            blob = Util.dataURL2ArrayBuffer( blob );\n                            blob = Util.updateImageHead( blob,\n                                    this._metas.imageHead );\n                            blob = Util.arrayBufferToBlob( blob, type );\n                            return blob;\n                        }\n                    } else {\n                        blob = Util.canvasToDataUrl( canvas, type );\n                    }\n\n                    blob = Util.dataURL2Blob( blob );\n                }\n\n                return blob;\n            },\n\n            getAsDataUrl: function( type ) {\n                var opts = this.options;\n\n                type = type || this.type;\n\n                if ( type === 'image/jpeg' ) {\n                    return Util.canvasToDataUrl( this._canvas, type, opts.quality );\n                } else {\n                    return this._canvas.toDataURL( type );\n                }\n            },\n\n            getOrientation: function() {\n                return this._metas && this._metas.exif &&\n                        this._metas.exif.get('Orientation') || 1;\n            },\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            destroy: function() {\n                var canvas = this._canvas;\n                this._img.onload = null;\n\n                if ( canvas ) {\n                    canvas.getContext('2d')\n                            .clearRect( 0, 0, canvas.width, canvas.height );\n                    canvas.width = canvas.height = 0;\n                    this._canvas = null;\n                }\n\n                // 释放内存。非常重要，否则释放不了image的内存。\n                this._img.src = BLANK;\n                this._img = this._blob = null;\n            },\n\n            _resize: function( img, cvs, width, height ) {\n                var opts = this.options,\n                    naturalWidth = img.width,\n                    naturalHeight = img.height,\n                    orientation = this.getOrientation(),\n                    scale, w, h, x, y;\n\n                // values that require 90 degree rotation\n                if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                    // 交换width, height的值。\n                    width ^= height;\n                    height ^= width;\n                    width ^= height;\n                }\n\n                scale = Math[ opts.crop ? 'max' : 'min' ]( width / naturalWidth,\n                        height / naturalHeight );\n\n                // 不允许放大。\n                opts.allowMagnify || (scale = Math.min( 1, scale ));\n\n                w = naturalWidth * scale;\n                h = naturalHeight * scale;\n\n                if ( opts.crop ) {\n                    cvs.width = width;\n                    cvs.height = height;\n                } else {\n                    cvs.width = w;\n                    cvs.height = h;\n                }\n\n                x = (cvs.width - w) / 2;\n                y = (cvs.height - h) / 2;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n\n                this._renderImageToCanvas( cvs, img, x, y, w, h );\n            },\n\n            _rotate2Orientaion: function( canvas, orientation ) {\n                var width = canvas.width,\n                    height = canvas.height,\n                    ctx = canvas.getContext('2d');\n\n                switch ( orientation ) {\n                    case 5:\n                    case 6:\n                    case 7:\n                    case 8:\n                        canvas.width = height;\n                        canvas.height = width;\n                        break;\n                }\n\n                switch ( orientation ) {\n                    case 2:    // horizontal flip\n                        ctx.translate( width, 0 );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 3:    // 180 rotate left\n                        ctx.translate( width, height );\n                        ctx.rotate( Math.PI );\n                        break;\n\n                    case 4:    // vertical flip\n                        ctx.translate( 0, height );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 5:    // vertical flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 6:    // 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( 0, -height );\n                        break;\n\n                    case 7:    // horizontal flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( width, -height );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 8:    // 90 rotate left\n                        ctx.rotate( -0.5 * Math.PI );\n                        ctx.translate( -width, 0 );\n                        break;\n                }\n            },\n\n            // https://github.com/stomita/ios-imagefile-megapixel/\n            // blob/master/src/megapix-image.js\n            _renderImageToCanvas: (function() {\n\n                // 如果不是ios, 不需要这么复杂！\n                if ( !Base.os.ios ) {\n                    return function( canvas ) {\n                        var args = Base.slice( arguments, 1 ),\n                            ctx = canvas.getContext('2d');\n\n                        ctx.drawImage.apply( ctx, args );\n                    };\n                }\n\n                /**\n                 * Detecting vertical squash in loaded image.\n                 * Fixes a bug which squash image vertically while drawing into\n                 * canvas for some images.\n                 */\n                function detectVerticalSquash( img, iw, ih ) {\n                    var canvas = document.createElement('canvas'),\n                        ctx = canvas.getContext('2d'),\n                        sy = 0,\n                        ey = ih,\n                        py = ih,\n                        data, alpha, ratio;\n\n\n                    canvas.width = 1;\n                    canvas.height = ih;\n                    ctx.drawImage( img, 0, 0 );\n                    data = ctx.getImageData( 0, 0, 1, ih ).data;\n\n                    // search image edge pixel position in case\n                    // it is squashed vertically.\n                    while ( py > sy ) {\n                        alpha = data[ (py - 1) * 4 + 3 ];\n\n                        if ( alpha === 0 ) {\n                            ey = py;\n                        } else {\n                            sy = py;\n                        }\n\n                        py = (ey + sy) >> 1;\n                    }\n\n                    ratio = (py / ih);\n                    return (ratio === 0) ? 1 : ratio;\n                }\n\n                // fix ie7 bug\n                // http://stackoverflow.com/questions/11929099/\n                // html5-canvas-drawimage-ratio-bug-ios\n                if ( Base.os.ios >= 7 ) {\n                    return function( canvas, img, x, y, w, h ) {\n                        var iw = img.naturalWidth,\n                            ih = img.naturalHeight,\n                            vertSquashRatio = detectVerticalSquash( img, iw, ih );\n\n                        return canvas.getContext('2d').drawImage( img, 0, 0,\n                                iw * vertSquashRatio, ih * vertSquashRatio,\n                                x, y, w, h );\n                    };\n                }\n\n                /**\n                 * Detect subsampling in loaded image.\n                 * In iOS, larger images than 2M pixels may be\n                 * subsampled in rendering.\n                 */\n                function detectSubsampling( img ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        canvas, ctx;\n\n                    // subsampling may happen overmegapixel image\n                    if ( iw * ih > 1024 * 1024 ) {\n                        canvas = document.createElement('canvas');\n                        canvas.width = canvas.height = 1;\n                        ctx = canvas.getContext('2d');\n                        ctx.drawImage( img, -iw + 1, 0 );\n\n                        // subsampled image becomes half smaller in rendering size.\n                        // check alpha channel value to confirm image is covering\n                        // edge pixel or not. if alpha value is 0\n                        // image is not covering, hence subsampled.\n                        return ctx.getImageData( 0, 0, 1, 1 ).data[ 3 ] === 0;\n                    } else {\n                        return false;\n                    }\n                }\n\n\n                return function( canvas, img, x, y, width, height ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        ctx = canvas.getContext('2d'),\n                        subsampled = detectSubsampling( img ),\n                        doSquash = this.type === 'image/jpeg',\n                        d = 1024,\n                        sy = 0,\n                        dy = 0,\n                        tmpCanvas, tmpCtx, vertSquashRatio, dw, dh, sx, dx;\n\n                    if ( subsampled ) {\n                        iw /= 2;\n                        ih /= 2;\n                    }\n\n                    ctx.save();\n                    tmpCanvas = document.createElement('canvas');\n                    tmpCanvas.width = tmpCanvas.height = d;\n\n                    tmpCtx = tmpCanvas.getContext('2d');\n                    vertSquashRatio = doSquash ?\n                            detectVerticalSquash( img, iw, ih ) : 1;\n\n                    dw = Math.ceil( d * width / iw );\n                    dh = Math.ceil( d * height / ih / vertSquashRatio );\n\n                    while ( sy < ih ) {\n                        sx = 0;\n                        dx = 0;\n                        while ( sx < iw ) {\n                            tmpCtx.clearRect( 0, 0, d, d );\n                            tmpCtx.drawImage( img, -sx, -sy );\n                            ctx.drawImage( tmpCanvas, 0, 0, d, d,\n                                    x + dx, y + dy, dw, dh );\n                            sx += d;\n                            dx += dw;\n                        }\n                        sy += d;\n                        dy += dh;\n                    }\n                    ctx.restore();\n                    tmpCanvas = tmpCtx = null;\n                };\n            })()\n        });\n    });\n    /**\n     * @fileOverview Transport\n     * @todo 支持chunked传输，优势：\n     * 可以将大文件分成小块，挨个传输，可以提高大文件成功率，当失败的时候，也只需要重传那小部分，\n     * 而不需要重头再传一次。另外断点续传也需要用chunked方式。\n     */\n    define('runtime/html5/transport',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var noop = Base.noop,\n            $ = Base.$;\n\n        return Html5Runtime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    formData, binary, fr;\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.getSource();\n                } else {\n                    formData = new FormData();\n                    $.each( owner._formData, function( k, v ) {\n                        formData.append( k, v );\n                    });\n\n                    formData.append( opts.fileVal, blob.getSource(),\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                if ( opts.withCredentials && 'withCredentials' in xhr ) {\n                    xhr.open( opts.method, server, true );\n                    xhr.withCredentials = true;\n                } else {\n                    xhr.open( opts.method, server );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n\n                if ( binary ) {\n                    // 强制设置成 content-type 为文件流。\n                    xhr.overrideMimeType &&\n                            xhr.overrideMimeType('application/octet-stream');\n\n                    // android直接发送blob会导致服务端接收到的是空文件。\n                    // bug详情。\n                    // https://code.google.com/p/android/issues/detail?id=39882\n                    // 所以先用fileReader读取出来再通过arraybuffer的方式发送。\n                    if ( Base.os.android ) {\n                        fr = new FileReader();\n\n                        fr.onload = function() {\n                            xhr.send( this.result );\n                            fr = fr.onload = null;\n                        };\n\n                        fr.readAsArrayBuffer( binary );\n                    } else {\n                        xhr.send( binary );\n                    }\n                } else {\n                    xhr.send( formData );\n                }\n            },\n\n            getResponse: function() {\n                return this._response;\n            },\n\n            getResponseAsJson: function() {\n                return this._parseJson( this._response );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    xhr.abort();\n\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new XMLHttpRequest(),\n                    opts = this.options;\n\n                if ( opts.withCredentials && !('withCredentials' in xhr) &&\n                        typeof XDomainRequest !== 'undefined' ) {\n                    xhr = new XDomainRequest();\n                }\n\n                xhr.upload.onprogress = function( e ) {\n                    var percentage = 0;\n\n                    if ( e.lengthComputable ) {\n                        percentage = e.loaded / e.total;\n                    }\n\n                    return me.trigger( 'progress', percentage );\n                };\n\n                xhr.onreadystatechange = function() {\n\n                    if ( xhr.readyState !== 4 ) {\n                        return;\n                    }\n\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    me._xhr = null;\n                    me._status = xhr.status;\n\n                    if ( xhr.status >= 200 && xhr.status < 300 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger('load');\n                    } else if ( xhr.status >= 500 && xhr.status < 600 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger( 'error', 'server' );\n                    }\n\n\n                    return me.trigger( 'error', me._status ? 'http' : 'abort' );\n                };\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.setRequestHeader( key, val );\n                });\n            },\n\n            _parseJson: function( str ) {\n                var json;\n\n                try {\n                    json = JSON.parse( str );\n                } catch ( ex ) {\n                    json = {};\n                }\n\n                return json;\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/html5/md5',[\n        'runtime/html5/runtime'\n    ], function( FlashRuntime ) {\n\n        /*\n         * Fastest md5 implementation around (JKM md5)\n         * Credits: Joseph Myers\n         *\n         * @see http://www.myersdaily.org/joseph/javascript/md5-text.html\n         * @see http://jsperf.com/md5-shootout/7\n         */\n\n        /* this function is much faster,\n          so if possible we use it. Some IEs\n          are the only ones I know of that\n          need the idiotic second function,\n          generated by an if clause.  */\n        var add32 = function (a, b) {\n            return (a + b) & 0xFFFFFFFF;\n        },\n\n        cmn = function (q, a, b, x, s, t) {\n            a = add32(add32(a, q), add32(x, t));\n            return add32((a << s) | (a >>> (32 - s)), b);\n        },\n\n        ff = function (a, b, c, d, x, s, t) {\n            return cmn((b & c) | ((~b) & d), a, b, x, s, t);\n        },\n\n        gg = function (a, b, c, d, x, s, t) {\n            return cmn((b & d) | (c & (~d)), a, b, x, s, t);\n        },\n\n        hh = function (a, b, c, d, x, s, t) {\n            return cmn(b ^ c ^ d, a, b, x, s, t);\n        },\n\n        ii = function (a, b, c, d, x, s, t) {\n            return cmn(c ^ (b | (~d)), a, b, x, s, t);\n        },\n\n        md5cycle = function (x, k) {\n            var a = x[0],\n                b = x[1],\n                c = x[2],\n                d = x[3];\n\n            a = ff(a, b, c, d, k[0], 7, -680876936);\n            d = ff(d, a, b, c, k[1], 12, -389564586);\n            c = ff(c, d, a, b, k[2], 17, 606105819);\n            b = ff(b, c, d, a, k[3], 22, -1044525330);\n            a = ff(a, b, c, d, k[4], 7, -176418897);\n            d = ff(d, a, b, c, k[5], 12, 1200080426);\n            c = ff(c, d, a, b, k[6], 17, -1473231341);\n            b = ff(b, c, d, a, k[7], 22, -45705983);\n            a = ff(a, b, c, d, k[8], 7, 1770035416);\n            d = ff(d, a, b, c, k[9], 12, -1958414417);\n            c = ff(c, d, a, b, k[10], 17, -42063);\n            b = ff(b, c, d, a, k[11], 22, -1990404162);\n            a = ff(a, b, c, d, k[12], 7, 1804603682);\n            d = ff(d, a, b, c, k[13], 12, -40341101);\n            c = ff(c, d, a, b, k[14], 17, -1502002290);\n            b = ff(b, c, d, a, k[15], 22, 1236535329);\n\n            a = gg(a, b, c, d, k[1], 5, -165796510);\n            d = gg(d, a, b, c, k[6], 9, -1069501632);\n            c = gg(c, d, a, b, k[11], 14, 643717713);\n            b = gg(b, c, d, a, k[0], 20, -373897302);\n            a = gg(a, b, c, d, k[5], 5, -701558691);\n            d = gg(d, a, b, c, k[10], 9, 38016083);\n            c = gg(c, d, a, b, k[15], 14, -660478335);\n            b = gg(b, c, d, a, k[4], 20, -405537848);\n            a = gg(a, b, c, d, k[9], 5, 568446438);\n            d = gg(d, a, b, c, k[14], 9, -1019803690);\n            c = gg(c, d, a, b, k[3], 14, -187363961);\n            b = gg(b, c, d, a, k[8], 20, 1163531501);\n            a = gg(a, b, c, d, k[13], 5, -1444681467);\n            d = gg(d, a, b, c, k[2], 9, -51403784);\n            c = gg(c, d, a, b, k[7], 14, 1735328473);\n            b = gg(b, c, d, a, k[12], 20, -1926607734);\n\n            a = hh(a, b, c, d, k[5], 4, -378558);\n            d = hh(d, a, b, c, k[8], 11, -2022574463);\n            c = hh(c, d, a, b, k[11], 16, 1839030562);\n            b = hh(b, c, d, a, k[14], 23, -35309556);\n            a = hh(a, b, c, d, k[1], 4, -1530992060);\n            d = hh(d, a, b, c, k[4], 11, 1272893353);\n            c = hh(c, d, a, b, k[7], 16, -155497632);\n            b = hh(b, c, d, a, k[10], 23, -1094730640);\n            a = hh(a, b, c, d, k[13], 4, 681279174);\n            d = hh(d, a, b, c, k[0], 11, -358537222);\n            c = hh(c, d, a, b, k[3], 16, -722521979);\n            b = hh(b, c, d, a, k[6], 23, 76029189);\n            a = hh(a, b, c, d, k[9], 4, -640364487);\n            d = hh(d, a, b, c, k[12], 11, -421815835);\n            c = hh(c, d, a, b, k[15], 16, 530742520);\n            b = hh(b, c, d, a, k[2], 23, -995338651);\n\n            a = ii(a, b, c, d, k[0], 6, -198630844);\n            d = ii(d, a, b, c, k[7], 10, 1126891415);\n            c = ii(c, d, a, b, k[14], 15, -1416354905);\n            b = ii(b, c, d, a, k[5], 21, -57434055);\n            a = ii(a, b, c, d, k[12], 6, 1700485571);\n            d = ii(d, a, b, c, k[3], 10, -1894986606);\n            c = ii(c, d, a, b, k[10], 15, -1051523);\n            b = ii(b, c, d, a, k[1], 21, -2054922799);\n            a = ii(a, b, c, d, k[8], 6, 1873313359);\n            d = ii(d, a, b, c, k[15], 10, -30611744);\n            c = ii(c, d, a, b, k[6], 15, -1560198380);\n            b = ii(b, c, d, a, k[13], 21, 1309151649);\n            a = ii(a, b, c, d, k[4], 6, -145523070);\n            d = ii(d, a, b, c, k[11], 10, -1120210379);\n            c = ii(c, d, a, b, k[2], 15, 718787259);\n            b = ii(b, c, d, a, k[9], 21, -343485551);\n\n            x[0] = add32(a, x[0]);\n            x[1] = add32(b, x[1]);\n            x[2] = add32(c, x[2]);\n            x[3] = add32(d, x[3]);\n        },\n\n        /* there needs to be support for Unicode here,\n           * unless we pretend that we can redefine the MD-5\n           * algorithm for multi-byte characters (perhaps\n           * by adding every four 16-bit characters and\n           * shortening the sum to 32 bits). Otherwise\n           * I suggest performing MD-5 as if every character\n           * was two bytes--e.g., 0040 0025 = @%--but then\n           * how will an ordinary MD-5 sum be matched?\n           * There is no way to standardize text to something\n           * like UTF-8 before transformation; speed cost is\n           * utterly prohibitive. The JavaScript standard\n           * itself needs to look at this: it should start\n           * providing access to strings as preformed UTF-8\n           * 8-bit unsigned value arrays.\n           */\n        md5blk = function (s) {\n            var md5blks = [],\n                i; /* Andy King said do it this way. */\n\n            for (i = 0; i < 64; i += 4) {\n                md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);\n            }\n            return md5blks;\n        },\n\n        md5blk_array = function (a) {\n            var md5blks = [],\n                i; /* Andy King said do it this way. */\n\n            for (i = 0; i < 64; i += 4) {\n                md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);\n            }\n            return md5blks;\n        },\n\n        md51 = function (s) {\n            var n = s.length,\n                state = [1732584193, -271733879, -1732584194, 271733878],\n                i,\n                length,\n                tail,\n                tmp,\n                lo,\n                hi;\n\n            for (i = 64; i <= n; i += 64) {\n                md5cycle(state, md5blk(s.substring(i - 64, i)));\n            }\n            s = s.substring(i - 64);\n            length = s.length;\n            tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);\n            }\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Beware that the final length might not fit in 32 bits so we take care of that\n            tmp = n * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n\n            md5cycle(state, tail);\n            return state;\n        },\n\n        md51_array = function (a) {\n            var n = a.length,\n                state = [1732584193, -271733879, -1732584194, 271733878],\n                i,\n                length,\n                tail,\n                tmp,\n                lo,\n                hi;\n\n            for (i = 64; i <= n; i += 64) {\n                md5cycle(state, md5blk_array(a.subarray(i - 64, i)));\n            }\n\n            // Not sure if it is a bug, however IE10 will always produce a sub array of length 1\n            // containing the last element of the parent array if the sub array specified starts\n            // beyond the length of the parent array - weird.\n            // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue\n            a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);\n\n            length = a.length;\n            tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= a[i] << ((i % 4) << 3);\n            }\n\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Beware that the final length might not fit in 32 bits so we take care of that\n            tmp = n * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n\n            md5cycle(state, tail);\n\n            return state;\n        },\n\n        hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'],\n\n        rhex = function (n) {\n            var s = '',\n                j;\n            for (j = 0; j < 4; j += 1) {\n                s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];\n            }\n            return s;\n        },\n\n        hex = function (x) {\n            var i;\n            for (i = 0; i < x.length; i += 1) {\n                x[i] = rhex(x[i]);\n            }\n            return x.join('');\n        },\n\n        md5 = function (s) {\n            return hex(md51(s));\n        },\n\n\n\n        ////////////////////////////////////////////////////////////////////////////\n\n        /**\n         * SparkMD5 OOP implementation.\n         *\n         * Use this class to perform an incremental md5, otherwise use the\n         * static methods instead.\n         */\n        SparkMD5 = function () {\n            // call reset to init the instance\n            this.reset();\n        };\n\n\n        // In some cases the fast add32 function cannot be used..\n        if (md5('hello') !== '5d41402abc4b2a76b9719d911017c592') {\n            add32 = function (x, y) {\n                var lsw = (x & 0xFFFF) + (y & 0xFFFF),\n                    msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n                return (msw << 16) | (lsw & 0xFFFF);\n            };\n        }\n\n\n        /**\n         * Appends a string.\n         * A conversion will be applied if an utf8 string is detected.\n         *\n         * @param {String} str The string to be appended\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.append = function (str) {\n            // converts the string to utf8 bytes if necessary\n            if (/[\\u0080-\\uFFFF]/.test(str)) {\n                str = unescape(encodeURIComponent(str));\n            }\n\n            // then append as binary\n            this.appendBinary(str);\n\n            return this;\n        };\n\n        /**\n         * Appends a binary string.\n         *\n         * @param {String} contents The binary string to be appended\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.appendBinary = function (contents) {\n            this._buff += contents;\n            this._length += contents.length;\n\n            var length = this._buff.length,\n                i;\n\n            for (i = 64; i <= length; i += 64) {\n                md5cycle(this._state, md5blk(this._buff.substring(i - 64, i)));\n            }\n\n            this._buff = this._buff.substr(i - 64);\n\n            return this;\n        };\n\n        /**\n         * Finishes the incremental computation, reseting the internal state and\n         * returning the result.\n         * Use the raw parameter to obtain the raw result instead of the hex one.\n         *\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.prototype.end = function (raw) {\n            var buff = this._buff,\n                length = buff.length,\n                i,\n                tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n                ret;\n\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);\n            }\n\n            this._finish(tail, length);\n            ret = !!raw ? this._state : hex(this._state);\n\n            this.reset();\n\n            return ret;\n        };\n\n        /**\n         * Finish the final calculation based on the tail.\n         *\n         * @param {Array}  tail   The tail (will be modified)\n         * @param {Number} length The length of the remaining buffer\n         */\n        SparkMD5.prototype._finish = function (tail, length) {\n            var i = length,\n                tmp,\n                lo,\n                hi;\n\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(this._state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Do the final computation based on the tail and length\n            // Beware that the final length may not fit in 32 bits so we take care of that\n            tmp = this._length * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n            md5cycle(this._state, tail);\n        };\n\n        /**\n         * Resets the internal state of the computation.\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.reset = function () {\n            this._buff = \"\";\n            this._length = 0;\n            this._state = [1732584193, -271733879, -1732584194, 271733878];\n\n            return this;\n        };\n\n        /**\n         * Releases memory used by the incremental buffer and other aditional\n         * resources. If you plan to use the instance again, use reset instead.\n         */\n        SparkMD5.prototype.destroy = function () {\n            delete this._state;\n            delete this._buff;\n            delete this._length;\n        };\n\n\n        /**\n         * Performs the md5 hash on a string.\n         * A conversion will be applied if utf8 string is detected.\n         *\n         * @param {String}  str The string\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.hash = function (str, raw) {\n            // converts the string to utf8 bytes if necessary\n            if (/[\\u0080-\\uFFFF]/.test(str)) {\n                str = unescape(encodeURIComponent(str));\n            }\n\n            var hash = md51(str);\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        /**\n         * Performs the md5 hash on a binary string.\n         *\n         * @param {String}  content The binary string\n         * @param {Boolean} raw     True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.hashBinary = function (content, raw) {\n            var hash = md51(content);\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        /**\n         * SparkMD5 OOP implementation for array buffers.\n         *\n         * Use this class to perform an incremental md5 ONLY for array buffers.\n         */\n        SparkMD5.ArrayBuffer = function () {\n            // call reset to init the instance\n            this.reset();\n        };\n\n        ////////////////////////////////////////////////////////////////////////////\n\n        /**\n         * Appends an array buffer.\n         *\n         * @param {ArrayBuffer} arr The array to be appended\n         *\n         * @return {SparkMD5.ArrayBuffer} The instance itself\n         */\n        SparkMD5.ArrayBuffer.prototype.append = function (arr) {\n            // TODO: we could avoid the concatenation here but the algorithm would be more complex\n            //       if you find yourself needing extra performance, please make a PR.\n            var buff = this._concatArrayBuffer(this._buff, arr),\n                length = buff.length,\n                i;\n\n            this._length += arr.byteLength;\n\n            for (i = 64; i <= length; i += 64) {\n                md5cycle(this._state, md5blk_array(buff.subarray(i - 64, i)));\n            }\n\n            // Avoids IE10 weirdness (documented above)\n            this._buff = (i - 64) < length ? buff.subarray(i - 64) : new Uint8Array(0);\n\n            return this;\n        };\n\n        /**\n         * Finishes the incremental computation, reseting the internal state and\n         * returning the result.\n         * Use the raw parameter to obtain the raw result instead of the hex one.\n         *\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.ArrayBuffer.prototype.end = function (raw) {\n            var buff = this._buff,\n                length = buff.length,\n                tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n                i,\n                ret;\n\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= buff[i] << ((i % 4) << 3);\n            }\n\n            this._finish(tail, length);\n            ret = !!raw ? this._state : hex(this._state);\n\n            this.reset();\n\n            return ret;\n        };\n\n        SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;\n\n        /**\n         * Resets the internal state of the computation.\n         *\n         * @return {SparkMD5.ArrayBuffer} The instance itself\n         */\n        SparkMD5.ArrayBuffer.prototype.reset = function () {\n            this._buff = new Uint8Array(0);\n            this._length = 0;\n            this._state = [1732584193, -271733879, -1732584194, 271733878];\n\n            return this;\n        };\n\n        /**\n         * Releases memory used by the incremental buffer and other aditional\n         * resources. If you plan to use the instance again, use reset instead.\n         */\n        SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;\n\n        /**\n         * Concats two array buffers, returning a new one.\n         *\n         * @param  {ArrayBuffer} first  The first array buffer\n         * @param  {ArrayBuffer} second The second array buffer\n         *\n         * @return {ArrayBuffer} The new array buffer\n         */\n        SparkMD5.ArrayBuffer.prototype._concatArrayBuffer = function (first, second) {\n            var firstLength = first.length,\n                result = new Uint8Array(firstLength + second.byteLength);\n\n            result.set(first);\n            result.set(new Uint8Array(second), firstLength);\n\n            return result;\n        };\n\n        /**\n         * Performs the md5 hash on an array buffer.\n         *\n         * @param {ArrayBuffer} arr The array buffer\n         * @param {Boolean}     raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.ArrayBuffer.hash = function (arr, raw) {\n            var hash = md51_array(new Uint8Array(arr));\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        return FlashRuntime.register( 'Md5', {\n            init: function() {\n                // do nothing.\n            },\n\n            loadFromBlob: function( file ) {\n                var blob = file.getSource(),\n                    chunkSize = 2 * 1024 * 1024,\n                    chunks = Math.ceil( blob.size / chunkSize ),\n                    chunk = 0,\n                    owner = this.owner,\n                    spark = new SparkMD5.ArrayBuffer(),\n                    me = this,\n                    blobSlice = blob.mozSlice || blob.webkitSlice || blob.slice,\n                    loadNext, fr;\n\n                fr = new FileReader();\n\n                loadNext = function() {\n                    var start, end;\n\n                    start = chunk * chunkSize;\n                    end = Math.min( start + chunkSize, blob.size );\n\n                    fr.onload = function( e ) {\n                        spark.append( e.target.result );\n                        owner.trigger( 'progress', {\n                            total: file.size,\n                            loaded: end\n                        });\n                    };\n\n                    fr.onloadend = function() {\n                        fr.onloadend = fr.onload = null;\n\n                        if ( ++chunk < chunks ) {\n                            setTimeout( loadNext, 1 );\n                        } else {\n                            setTimeout(function(){\n                                owner.trigger('load');\n                                me.result = spark.end();\n                                loadNext = file = blob = spark = null;\n                                owner.trigger('complete');\n                            }, 50 );\n                        }\n                    };\n\n                    fr.readAsArrayBuffer( blobSlice.call( blob, start, end ) );\n                };\n\n                loadNext();\n            },\n\n            getResult: function() {\n                return this.result;\n            }\n        });\n    });\n    /**\n     * @fileOverview FlashRuntime\n     */\n    define('runtime/flash/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var $ = Base.$,\n            type = 'flash',\n            components = {};\n\n\n        function getFlashVersion() {\n            var version;\n\n            try {\n                version = navigator.plugins[ 'Shockwave Flash' ];\n                version = version.description;\n            } catch ( ex ) {\n                try {\n                    version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')\n                            .GetVariable('$version');\n                } catch ( ex2 ) {\n                    version = '0.0';\n                }\n            }\n            version = version.match( /\\d+/g );\n            return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 );\n        }\n\n        function FlashRuntime() {\n            var pool = {},\n                clients = {},\n                destroy = this.destroy,\n                me = this,\n                jsreciver = Base.guid('webuploader_');\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/ ) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                clients[ uid ] = client;\n\n                if ( components[ comp ] ) {\n                    if ( !pool[ uid ] ) {\n                        pool[ uid ] = new components[ comp ]( client, me );\n                    }\n\n                    instance = pool[ uid ];\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n\n                return me.flashExec.apply( client, arguments );\n            };\n\n            function handler( evt, obj ) {\n                var type = evt.type || evt,\n                    parts, uid;\n\n                parts = type.split('::');\n                uid = parts[ 0 ];\n                type = parts[ 1 ];\n\n                // console.log.apply( console, arguments );\n\n                if ( type === 'Ready' && uid === me.uid ) {\n                    me.trigger('ready');\n                } else if ( clients[ uid ] ) {\n                    clients[ uid ].trigger( type.toLowerCase(), evt, obj );\n                }\n\n                // Base.log( evt, obj );\n            }\n\n            // flash的接受器。\n            window[ jsreciver ] = function() {\n                var args = arguments;\n\n                // 为了能捕获得到。\n                setTimeout(function() {\n                    handler.apply( null, args );\n                }, 1 );\n            };\n\n            this.jsreciver = jsreciver;\n\n            this.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n\n            this.flashExec = function( comp, fn ) {\n                var flash = me.getFlash(),\n                    args = Base.slice( arguments, 2 );\n\n                return flash.exec( this.uid, comp, fn, args );\n            };\n\n            // @todo\n        }\n\n        Base.inherits( Runtime, {\n            constructor: FlashRuntime,\n\n            init: function() {\n                var container = this.getContainer(),\n                    opts = this.options,\n                    html;\n\n                // if not the minimal height, shims are not initialized\n                // in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)\n                container.css({\n                    position: 'absolute',\n                    top: '-8px',\n                    left: '-8px',\n                    width: '9px',\n                    height: '9px',\n                    overflow: 'hidden'\n                });\n\n                // insert flash object\n                html = '<object id=\"' + this.uid + '\" type=\"application/' +\n                        'x-shockwave-flash\" data=\"' +  opts.swf + '\" ';\n\n                if ( Base.browser.ie ) {\n                    html += 'classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" ';\n                }\n\n                html += 'width=\"100%\" height=\"100%\" style=\"outline:0\">'  +\n                    '<param name=\"movie\" value=\"' + opts.swf + '\" />' +\n                    '<param name=\"flashvars\" value=\"uid=' + this.uid +\n                    '&jsreciver=' + this.jsreciver + '\" />' +\n                    '<param name=\"wmode\" value=\"transparent\" />' +\n                    '<param name=\"allowscriptaccess\" value=\"always\" />' +\n                '</object>';\n\n                container.html( html );\n            },\n\n            getFlash: function() {\n                if ( this._flash ) {\n                    return this._flash;\n                }\n\n                this._flash = $( '#' + this.uid ).get( 0 );\n                return this._flash;\n            }\n\n        });\n\n        FlashRuntime.register = function( name, component ) {\n            component = components[ name ] = Base.inherits( CompBase, $.extend({\n\n                // @todo fix this later\n                flashExec: function() {\n                    var owner = this.owner,\n                        runtime = this.getRuntime();\n\n                    return runtime.flashExec.apply( owner, arguments );\n                }\n            }, component ) );\n\n            return component;\n        };\n\n        if ( getFlashVersion() >= 11.4 ) {\n            Runtime.addRuntime( type, FlashRuntime );\n        }\n\n        return FlashRuntime;\n    });\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/flash/filepicker',[\n        'base',\n        'runtime/flash/runtime'\n    ], function( Base, FlashRuntime ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'FilePicker', {\n            init: function( opts ) {\n                var copy = $.extend({}, opts ),\n                    len, i;\n\n                // 修复Flash再没有设置title的情况下无法弹出flash文件选择框的bug.\n                len = copy.accept && copy.accept.length;\n                for (  i = 0; i < len; i++ ) {\n                    if ( !copy.accept[ i ].title ) {\n                        copy.accept[ i ].title = 'Files';\n                    }\n                }\n\n                delete copy.button;\n                delete copy.id;\n                delete copy.container;\n\n                this.flashExec( 'FilePicker', 'init', copy );\n            },\n\n            destroy: function() {\n                this.flashExec( 'FilePicker', 'destroy' );\n            }\n        });\n    });\n    /**\n     * @fileOverview 图片压缩\n     */\n    define('runtime/flash/image',[\n        'runtime/flash/runtime'\n    ], function( FlashRuntime ) {\n\n        return FlashRuntime.register( 'Image', {\n            // init: function( options ) {\n            //     var owner = this.owner;\n\n            //     this.flashExec( 'Image', 'init', options );\n            //     owner.on( 'load', function() {\n            //         debugger;\n            //     });\n            // },\n\n            loadFromBlob: function( blob ) {\n                var owner = this.owner;\n\n                owner.info() && this.flashExec( 'Image', 'info', owner.info() );\n                owner.meta() && this.flashExec( 'Image', 'meta', owner.meta() );\n\n                this.flashExec( 'Image', 'loadFromBlob', blob.uid );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/flash/transport',[\n        'base',\n        'runtime/flash/runtime',\n        'runtime/client'\n    ], function( Base, FlashRuntime, RuntimeClient ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n                this._responseJson = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    binary;\n\n                xhr.connectRuntime( blob.ruid );\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.uid;\n                } else {\n                    $.each( owner._formData, function( k, v ) {\n                        xhr.exec( 'append', k, v );\n                    });\n\n                    xhr.exec( 'appendBlob', opts.fileVal, blob.uid,\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n                xhr.exec( 'send', {\n                    method: opts.method,\n                    url: server,\n                    forceURLStream: opts.forceURLStream,\n                    mimeType: 'application/octet-stream'\n                }, binary );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            getResponse: function() {\n                return this._response || '';\n            },\n\n            getResponseAsJson: function() {\n                return this._responseJson;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.exec('abort');\n                    xhr.destroy();\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new RuntimeClient('XMLHttpRequest');\n\n                xhr.on( 'uploadprogress progress', function( e ) {\n                    var percent = e.loaded / e.total;\n                    percent = Math.min( 1, Math.max( 0, percent ) );\n                    return me.trigger( 'progress', percent );\n                });\n\n                xhr.on( 'load', function() {\n                    var status = xhr.exec('getStatus'),\n                        readBody = false,\n                        err = '',\n                        p;\n\n                    xhr.off();\n                    me._xhr = null;\n\n                    if ( status >= 200 && status < 300 ) {\n                        readBody = true;\n                    } else if ( status >= 500 && status < 600 ) {\n                        readBody = true;\n                        err = 'server';\n                    } else {\n                        err = 'http';\n                    }\n\n                    if ( readBody ) {\n                        me._response = xhr.exec('getResponse');\n                        me._response = decodeURIComponent( me._response );\n\n                        // flash 处理可能存在 bug, 没辙只能靠 js 了\n                        // try {\n                        //     me._responseJson = xhr.exec('getResponseAsJson');\n                        // } catch ( error ) {\n\n                        p = window.JSON && window.JSON.parse || function( s ) {\n                            try {\n                                return new Function('return ' + s).call();\n                            } catch ( err ) {\n                                return {};\n                            }\n                        };\n                        me._responseJson  = me._response ? p(me._response) : {};\n\n                        // }\n                    }\n\n                    xhr.destroy();\n                    xhr = null;\n\n                    return err ? me.trigger( 'error', err ) : me.trigger('load');\n                });\n\n                xhr.on( 'error', function() {\n                    xhr.off();\n                    me._xhr = null;\n                    me.trigger( 'error', 'http' );\n                });\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.exec( 'setRequestHeader', key, val );\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/flash/blob',[\n        'runtime/flash/runtime',\n        'lib/blob'\n    ], function( FlashRuntime, Blob ) {\n\n        return FlashRuntime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.flashExec( 'Blob', 'slice', start, end );\n\n                return new Blob( blob.uid, blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Md5 flash实现\n     */\n    define('runtime/flash/md5',[\n        'runtime/flash/runtime'\n    ], function( FlashRuntime ) {\n\n        return FlashRuntime.register( 'Md5', {\n            init: function() {\n                // do nothing.\n            },\n\n            loadFromBlob: function( blob ) {\n                return this.flashExec( 'Md5', 'loadFromBlob', blob.uid );\n            }\n        });\n    });\n    /**\n     * @fileOverview 完全版本。\n     */\n    define('preset/all',[\n        'base',\n\n        // widgets\n        'widgets/filednd',\n        'widgets/filepaste',\n        'widgets/filepicker',\n        'widgets/image',\n        'widgets/queue',\n        'widgets/runtime',\n        'widgets/upload',\n        'widgets/validator',\n        'widgets/md5',\n\n        // runtimes\n        // html5\n        'runtime/html5/blob',\n        'runtime/html5/dnd',\n        'runtime/html5/filepaste',\n        'runtime/html5/filepicker',\n        'runtime/html5/imagemeta/exif',\n        'runtime/html5/androidpatch',\n        'runtime/html5/image',\n        'runtime/html5/transport',\n        'runtime/html5/md5',\n\n        // flash\n        'runtime/flash/filepicker',\n        'runtime/flash/image',\n        'runtime/flash/transport',\n        'runtime/flash/blob',\n        'runtime/flash/md5'\n    ], function( Base ) {\n        return Base;\n    });\n    /**\n     * @fileOverview 日志组件，主要用来收集错误信息，可以帮助 webuploader 更好的定位问题和发展。\n     *\n     * 如果您不想要启用此功能，请在打包的时候去掉 log 模块。\n     *\n     * 或者可以在初始化的时候通过 options.disableWidgets 属性禁用。\n     *\n     * 如：\n     * WebUploader.create({\n     *     ...\n     *\n     *     disableWidgets: 'log',\n     *\n     *     ...\n     * })\n     */\n    define('widgets/log',[\n        'base',\n        'uploader',\n        'widgets/widget'\n    ], function( Base, Uploader ) {\n        var $ = Base.$,\n            logUrl = ' http://static.tieba.baidu.com/tb/pms/img/st.gif??',\n            product = (location.hostname || location.host || 'protected').toLowerCase(),\n\n            // 只针对 baidu 内部产品用户做统计功能。\n            enable = product && /baidu/i.exec(product),\n            base;\n\n        if (!enable) {\n            return;\n        }\n\n        base = {\n            dv: 3,\n            master: 'webuploader',\n            online: /test/.exec(product) ? 0 : 1,\n            module: '',\n            product: product,\n            type: 0\n        };\n\n        function send(data) {\n            var obj = $.extend({}, base, data),\n                url = logUrl.replace(/^(.*)\\?/, '$1' + $.param( obj )),\n                image = new Image();\n\n            image.src = url;\n        }\n\n        return Uploader.register({\n            name: 'log',\n\n            init: function() {\n                var owner = this.owner,\n                    count = 0,\n                    size = 0;\n\n                owner\n                    .on('error', function(code) {\n                        send({\n                            type: 2,\n                            c_error_code: code\n                        });\n                    })\n                    .on('uploadError', function(file, reason) {\n                        send({\n                            type: 2,\n                            c_error_code: 'UPLOAD_ERROR',\n                            c_reason: '' + reason\n                        });\n                    })\n                    .on('uploadComplete', function(file) {\n                        count++;\n                        size += file.size;\n                    }).\n                    on('uploadFinished', function() {\n                        send({\n                            c_count: count,\n                            c_size: size\n                        });\n                        count = size = 0;\n                    });\n\n                send({\n                    c_usage: 1\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('webuploader',[\n        'preset/all',\n        'widgets/log'\n    ], function( preset ) {\n        return preset;\n    });\n    return require('webuploader');\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.noimage.js",
    "content": "/*! WebUploader 0.1.5 */\n\n\n/**\n * @fileOverview 让内部各个部件的代码可以用[amd](https://github.com/amdjs/amdjs-api/wiki/AMD)模块定义方式组织起来。\n *\n * AMD API 内部的简单不完全实现，请忽略。只有当WebUploader被合并成一个文件的时候才会引入。\n */\n(function( root, factory ) {\n    var modules = {},\n\n        // 内部require, 简单不完全实现。\n        // https://github.com/amdjs/amdjs-api/wiki/require\n        _require = function( deps, callback ) {\n            var args, len, i;\n\n            // 如果deps不是数组，则直接返回指定module\n            if ( typeof deps === 'string' ) {\n                return getModule( deps );\n            } else {\n                args = [];\n                for( len = deps.length, i = 0; i < len; i++ ) {\n                    args.push( getModule( deps[ i ] ) );\n                }\n\n                return callback.apply( null, args );\n            }\n        },\n\n        // 内部define，暂时不支持不指定id.\n        _define = function( id, deps, factory ) {\n            if ( arguments.length === 2 ) {\n                factory = deps;\n                deps = null;\n            }\n\n            _require( deps || [], function() {\n                setModule( id, factory, arguments );\n            });\n        },\n\n        // 设置module, 兼容CommonJs写法。\n        setModule = function( id, factory, args ) {\n            var module = {\n                    exports: factory\n                },\n                returned;\n\n            if ( typeof factory === 'function' ) {\n                args.length || (args = [ _require, module.exports, module ]);\n                returned = factory.apply( null, args );\n                returned !== undefined && (module.exports = returned);\n            }\n\n            modules[ id ] = module.exports;\n        },\n\n        // 根据id获取module\n        getModule = function( id ) {\n            var module = modules[ id ] || root[ id ];\n\n            if ( !module ) {\n                throw new Error( '`' + id + '` is undefined' );\n            }\n\n            return module;\n        },\n\n        // 将所有modules，将路径ids装换成对象。\n        exportsTo = function( obj ) {\n            var key, host, parts, part, last, ucFirst;\n\n            // make the first character upper case.\n            ucFirst = function( str ) {\n                return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 ));\n            };\n\n            for ( key in modules ) {\n                host = obj;\n\n                if ( !modules.hasOwnProperty( key ) ) {\n                    continue;\n                }\n\n                parts = key.split('/');\n                last = ucFirst( parts.pop() );\n\n                while( (part = ucFirst( parts.shift() )) ) {\n                    host[ part ] = host[ part ] || {};\n                    host = host[ part ];\n                }\n\n                host[ last ] = modules[ key ];\n            }\n\n            return obj;\n        },\n\n        makeExport = function( dollar ) {\n            root.__dollar = dollar;\n\n            // exports every module.\n            return exportsTo( factory( root, _define, _require ) );\n        },\n\n        origin;\n\n    if ( typeof module === 'object' && typeof module.exports === 'object' ) {\n\n        // For CommonJS and CommonJS-like environments where a proper window is present,\n        module.exports = makeExport();\n    } else if ( typeof define === 'function' && define.amd ) {\n\n        // Allow using this built library as an AMD module\n        // in another project. That other project will only\n        // see this AMD call, not the internal modules in\n        // the closure below.\n        define([ 'jquery' ], makeExport );\n    } else {\n\n        // Browser globals case. Just assign the\n        // result to a property on the global.\n        origin = root.WebUploader;\n        root.WebUploader = makeExport();\n        root.WebUploader.noConflict = function() {\n            root.WebUploader = origin;\n        };\n    }\n})( window, function( window, define, require ) {\n\n\n    /**\n     * @fileOverview jQuery or Zepto\n     */\n    define('dollar-third',[],function() {\n        var $ = window.__dollar || window.jQuery || window.Zepto;\n\n        if ( !$ ) {\n            throw new Error('jQuery or Zepto not found!');\n        }\n\n        return $;\n    });\n    /**\n     * @fileOverview Dom 操作相关\n     */\n    define('dollar',[\n        'dollar-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 使用jQuery的Promise\n     */\n    define('promise-third',[\n        'dollar'\n    ], function( $ ) {\n        return {\n            Deferred: $.Deferred,\n            when: $.when,\n\n            isPromise: function( anything ) {\n                return anything && typeof anything.then === 'function';\n            }\n        };\n    });\n    /**\n     * @fileOverview Promise/A+\n     */\n    define('promise',[\n        'promise-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 基础类方法。\n     */\n\n    /**\n     * Web Uploader内部类的详细说明，以下提及的功能类，都可以在`WebUploader`这个变量中访问到。\n     *\n     * As you know, Web Uploader的每个文件都是用过[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)规范中的`define`组织起来的, 每个Module都会有个module id.\n     * 默认module id为该文件的路径，而此路径将会转化成名字空间存放在WebUploader中。如：\n     *\n     * * module `base`：WebUploader.Base\n     * * module `file`: WebUploader.File\n     * * module `lib/dnd`: WebUploader.Lib.Dnd\n     * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd\n     *\n     *\n     * 以下文档中对类的使用可能省略掉了`WebUploader`前缀。\n     * @module WebUploader\n     * @title WebUploader API文档\n     */\n    define('base',[\n        'dollar',\n        'promise'\n    ], function( $, promise ) {\n\n        var noop = function() {},\n            call = Function.call;\n\n        // http://jsperf.com/uncurrythis\n        // 反科里化\n        function uncurryThis( fn ) {\n            return function() {\n                return call.apply( fn, arguments );\n            };\n        }\n\n        function bindFn( fn, context ) {\n            return function() {\n                return fn.apply( context, arguments );\n            };\n        }\n\n        function createObject( proto ) {\n            var f;\n\n            if ( Object.create ) {\n                return Object.create( proto );\n            } else {\n                f = function() {};\n                f.prototype = proto;\n                return new f();\n            }\n        }\n\n\n        /**\n         * 基础类，提供一些简单常用的方法。\n         * @class Base\n         */\n        return {\n\n            /**\n             * @property {String} version 当前版本号。\n             */\n            version: '0.1.5',\n\n            /**\n             * @property {jQuery|Zepto} $ 引用依赖的jQuery或者Zepto对象。\n             */\n            $: $,\n\n            Deferred: promise.Deferred,\n\n            isPromise: promise.isPromise,\n\n            when: promise.when,\n\n            /**\n             * @description  简单的浏览器检查结果。\n             *\n             * * `webkit`  webkit版本号，如果浏览器为非webkit内核，此属性为`undefined`。\n             * * `chrome`  chrome浏览器版本号，如果浏览器为chrome，此属性为`undefined`。\n             * * `ie`  ie浏览器版本号，如果浏览器为非ie，此属性为`undefined`。**暂不支持ie10+**\n             * * `firefox`  firefox浏览器版本号，如果浏览器为非firefox，此属性为`undefined`。\n             * * `safari`  safari浏览器版本号，如果浏览器为非safari，此属性为`undefined`。\n             * * `opera`  opera浏览器版本号，如果浏览器为非opera，此属性为`undefined`。\n             *\n             * @property {Object} [browser]\n             */\n            browser: (function( ua ) {\n                var ret = {},\n                    webkit = ua.match( /WebKit\\/([\\d.]+)/ ),\n                    chrome = ua.match( /Chrome\\/([\\d.]+)/ ) ||\n                        ua.match( /CriOS\\/([\\d.]+)/ ),\n\n                    ie = ua.match( /MSIE\\s([\\d\\.]+)/ ) ||\n                        ua.match( /(?:trident)(?:.*rv:([\\w.]+))?/i ),\n                    firefox = ua.match( /Firefox\\/([\\d.]+)/ ),\n                    safari = ua.match( /Safari\\/([\\d.]+)/ ),\n                    opera = ua.match( /OPR\\/([\\d.]+)/ );\n\n                webkit && (ret.webkit = parseFloat( webkit[ 1 ] ));\n                chrome && (ret.chrome = parseFloat( chrome[ 1 ] ));\n                ie && (ret.ie = parseFloat( ie[ 1 ] ));\n                firefox && (ret.firefox = parseFloat( firefox[ 1 ] ));\n                safari && (ret.safari = parseFloat( safari[ 1 ] ));\n                opera && (ret.opera = parseFloat( opera[ 1 ] ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * @description  操作系统检查结果。\n             *\n             * * `android`  如果在android浏览器环境下，此值为对应的android版本号，否则为`undefined`。\n             * * `ios` 如果在ios浏览器环境下，此值为对应的ios版本号，否则为`undefined`。\n             * @property {Object} [os]\n             */\n            os: (function( ua ) {\n                var ret = {},\n\n                    // osx = !!ua.match( /\\(Macintosh\\; Intel / ),\n                    android = ua.match( /(?:Android);?[\\s\\/]+([\\d.]+)?/ ),\n                    ios = ua.match( /(?:iPad|iPod|iPhone).*OS\\s([\\d_]+)/ );\n\n                // osx && (ret.osx = true);\n                android && (ret.android = parseFloat( android[ 1 ] ));\n                ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * 实现类与类之间的继承。\n             * @method inherits\n             * @grammar Base.inherits( super ) => child\n             * @grammar Base.inherits( super, protos ) => child\n             * @grammar Base.inherits( super, protos, statics ) => child\n             * @param  {Class} super 父类\n             * @param  {Object | Function} [protos] 子类或者对象。如果对象中包含constructor，子类将是用此属性值。\n             * @param  {Function} [protos.constructor] 子类构造器，不指定的话将创建个临时的直接执行父类构造器的方法。\n             * @param  {Object} [statics] 静态属性或方法。\n             * @return {Class} 返回子类。\n             * @example\n             * function Person() {\n             *     console.log( 'Super' );\n             * }\n             * Person.prototype.hello = function() {\n             *     console.log( 'hello' );\n             * };\n             *\n             * var Manager = Base.inherits( Person, {\n             *     world: function() {\n             *         console.log( 'World' );\n             *     }\n             * });\n             *\n             * // 因为没有指定构造器，父类的构造器将会执行。\n             * var instance = new Manager();    // => Super\n             *\n             * // 继承子父类的方法\n             * instance.hello();    // => hello\n             * instance.world();    // => World\n             *\n             * // 子类的__super__属性指向父类\n             * console.log( Manager.__super__ === Person );    // => true\n             */\n            inherits: function( Super, protos, staticProtos ) {\n                var child;\n\n                if ( typeof protos === 'function' ) {\n                    child = protos;\n                    protos = null;\n                } else if ( protos && protos.hasOwnProperty('constructor') ) {\n                    child = protos.constructor;\n                } else {\n                    child = function() {\n                        return Super.apply( this, arguments );\n                    };\n                }\n\n                // 复制静态方法\n                $.extend( true, child, Super, staticProtos || {} );\n\n                /* jshint camelcase: false */\n\n                // 让子类的__super__属性指向父类。\n                child.__super__ = Super.prototype;\n\n                // 构建原型，添加原型方法或属性。\n                // 暂时用Object.create实现。\n                child.prototype = createObject( Super.prototype );\n                protos && $.extend( true, child.prototype, protos );\n\n                return child;\n            },\n\n            /**\n             * 一个不做任何事情的方法。可以用来赋值给默认的callback.\n             * @method noop\n             */\n            noop: noop,\n\n            /**\n             * 返回一个新的方法，此方法将已指定的`context`来执行。\n             * @grammar Base.bindFn( fn, context ) => Function\n             * @method bindFn\n             * @example\n             * var doSomething = function() {\n             *         console.log( this.name );\n             *     },\n             *     obj = {\n             *         name: 'Object Name'\n             *     },\n             *     aliasFn = Base.bind( doSomething, obj );\n             *\n             *  aliasFn();    // => Object Name\n             *\n             */\n            bindFn: bindFn,\n\n            /**\n             * 引用Console.log如果存在的话，否则引用一个[空函数noop](#WebUploader:Base.noop)。\n             * @grammar Base.log( args... ) => undefined\n             * @method log\n             */\n            log: (function() {\n                if ( window.console ) {\n                    return bindFn( console.log, console );\n                }\n                return noop;\n            })(),\n\n            nextTick: (function() {\n\n                return function( cb ) {\n                    setTimeout( cb, 1 );\n                };\n\n                // @bug 当浏览器不在当前窗口时就停了。\n                // var next = window.requestAnimationFrame ||\n                //     window.webkitRequestAnimationFrame ||\n                //     window.mozRequestAnimationFrame ||\n                //     function( cb ) {\n                //         window.setTimeout( cb, 1000 / 60 );\n                //     };\n\n                // // fix: Uncaught TypeError: Illegal invocation\n                // return bindFn( next, window );\n            })(),\n\n            /**\n             * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的数组slice方法。\n             * 将用来将非数组对象转化成数组对象。\n             * @grammar Base.slice( target, start[, end] ) => Array\n             * @method slice\n             * @example\n             * function doSomthing() {\n             *     var args = Base.slice( arguments, 1 );\n             *     console.log( args );\n             * }\n             *\n             * doSomthing( 'ignored', 'arg2', 'arg3' );    // => Array [\"arg2\", \"arg3\"]\n             */\n            slice: uncurryThis( [].slice ),\n\n            /**\n             * 生成唯一的ID\n             * @method guid\n             * @grammar Base.guid() => String\n             * @grammar Base.guid( prefx ) => String\n             */\n            guid: (function() {\n                var counter = 0;\n\n                return function( prefix ) {\n                    var guid = (+new Date()).toString( 32 ),\n                        i = 0;\n\n                    for ( ; i < 5; i++ ) {\n                        guid += Math.floor( Math.random() * 65535 ).toString( 32 );\n                    }\n\n                    return (prefix || 'wu_') + guid + (counter++).toString( 32 );\n                };\n            })(),\n\n            /**\n             * 格式化文件大小, 输出成带单位的字符串\n             * @method formatSize\n             * @grammar Base.formatSize( size ) => String\n             * @grammar Base.formatSize( size, pointLength ) => String\n             * @grammar Base.formatSize( size, pointLength, units ) => String\n             * @param {Number} size 文件大小\n             * @param {Number} [pointLength=2] 精确到的小数点数。\n             * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 单位数组。从字节，到千字节，一直往上指定。如果单位数组里面只指定了到了K(千字节)，同时文件大小大于M, 此方法的输出将还是显示成多少K.\n             * @example\n             * console.log( Base.formatSize( 100 ) );    // => 100B\n             * console.log( Base.formatSize( 1024 ) );    // => 1.00K\n             * console.log( Base.formatSize( 1024, 0 ) );    // => 1K\n             * console.log( Base.formatSize( 1024 * 1024 ) );    // => 1.00M\n             * console.log( Base.formatSize( 1024 * 1024 * 1024 ) );    // => 1.00G\n             * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) );    // => 1024MB\n             */\n            formatSize: function( size, pointLength, units ) {\n                var unit;\n\n                units = units || [ 'B', 'K', 'M', 'G', 'TB' ];\n\n                while ( (unit = units.shift()) && size > 1024 ) {\n                    size = size / 1024;\n                }\n\n                return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) +\n                        unit;\n            }\n        };\n    });\n    /**\n     * 事件处理类，可以独立使用，也可以扩展给对象使用。\n     * @fileOverview Mediator\n     */\n    define('mediator',[\n        'base'\n    ], function( Base ) {\n        var $ = Base.$,\n            slice = [].slice,\n            separator = /\\s+/,\n            protos;\n\n        // 根据条件过滤出事件handlers.\n        function findHandlers( arr, name, callback, context ) {\n            return $.grep( arr, function( handler ) {\n                return handler &&\n                        (!name || handler.e === name) &&\n                        (!callback || handler.cb === callback ||\n                        handler.cb._cb === callback) &&\n                        (!context || handler.ctx === context);\n            });\n        }\n\n        function eachEvent( events, callback, iterator ) {\n            // 不支持对象，只支持多个event用空格隔开\n            $.each( (events || '').split( separator ), function( _, key ) {\n                iterator( key, callback );\n            });\n        }\n\n        function triggerHanders( events, args ) {\n            var stoped = false,\n                i = -1,\n                len = events.length,\n                handler;\n\n            while ( ++i < len ) {\n                handler = events[ i ];\n\n                if ( handler.cb.apply( handler.ctx2, args ) === false ) {\n                    stoped = true;\n                    break;\n                }\n            }\n\n            return !stoped;\n        }\n\n        protos = {\n\n            /**\n             * 绑定事件。\n             *\n             * `callback`方法在执行时，arguments将会来源于trigger的时候携带的参数。如\n             * ```javascript\n             * var obj = {};\n             *\n             * // 使得obj有事件行为\n             * Mediator.installTo( obj );\n             *\n             * obj.on( 'testa', function( arg1, arg2 ) {\n             *     console.log( arg1, arg2 ); // => 'arg1', 'arg2'\n             * });\n             *\n             * obj.trigger( 'testa', 'arg1', 'arg2' );\n             * ```\n             *\n             * 如果`callback`中，某一个方法`return false`了，则后续的其他`callback`都不会被执行到。\n             * 切会影响到`trigger`方法的返回值，为`false`。\n             *\n             * `on`还可以用来添加一个特殊事件`all`, 这样所有的事件触发都会响应到。同时此类`callback`中的arguments有一个不同处，\n             * 就是第一个参数为`type`，记录当前是什么事件在触发。此类`callback`的优先级比脚低，会再正常`callback`执行完后触发。\n             * ```javascript\n             * obj.on( 'all', function( type, arg1, arg2 ) {\n             *     console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2'\n             * });\n             * ```\n             *\n             * @method on\n             * @grammar on( name, callback[, context] ) => self\n             * @param  {String}   name     事件名，支持多个事件用空格隔开\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             * @class Mediator\n             */\n            on: function( name, callback, context ) {\n                var me = this,\n                    set;\n\n                if ( !callback ) {\n                    return this;\n                }\n\n                set = this._events || (this._events = []);\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var handler = { e: name };\n\n                    handler.cb = callback;\n                    handler.ctx = context;\n                    handler.ctx2 = context || me;\n                    handler.id = set.length;\n\n                    set.push( handler );\n                });\n\n                return this;\n            },\n\n            /**\n             * 绑定事件，且当handler执行完后，自动解除绑定。\n             * @method once\n             * @grammar once( name, callback[, context] ) => self\n             * @param  {String}   name     事件名\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            once: function( name, callback, context ) {\n                var me = this;\n\n                if ( !callback ) {\n                    return me;\n                }\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var once = function() {\n                            me.off( name, once );\n                            return callback.apply( context || me, arguments );\n                        };\n\n                    once._cb = callback;\n                    me.on( name, once, context );\n                });\n\n                return me;\n            },\n\n            /**\n             * 解除事件绑定\n             * @method off\n             * @grammar off( [name[, callback[, context] ] ] ) => self\n             * @param  {String}   [name]     事件名\n             * @param  {Function} [callback] 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            off: function( name, cb, ctx ) {\n                var events = this._events;\n\n                if ( !events ) {\n                    return this;\n                }\n\n                if ( !name && !cb && !ctx ) {\n                    this._events = [];\n                    return this;\n                }\n\n                eachEvent( name, cb, function( name, cb ) {\n                    $.each( findHandlers( events, name, cb, ctx ), function() {\n                        delete events[ this.id ];\n                    });\n                });\n\n                return this;\n            },\n\n            /**\n             * 触发事件\n             * @method trigger\n             * @grammar trigger( name[, args...] ) => self\n             * @param  {String}   type     事件名\n             * @param  {*} [...] 任意参数\n             * @return {Boolean} 如果handler中return false了，则返回false, 否则返回true\n             */\n            trigger: function( type ) {\n                var args, events, allEvents;\n\n                if ( !this._events || !type ) {\n                    return this;\n                }\n\n                args = slice.call( arguments, 1 );\n                events = findHandlers( this._events, type );\n                allEvents = findHandlers( this._events, 'all' );\n\n                return triggerHanders( events, args ) &&\n                        triggerHanders( allEvents, arguments );\n            }\n        };\n\n        /**\n         * 中介者，它本身是个单例，但可以通过[installTo](#WebUploader:Mediator:installTo)方法，使任何对象具备事件行为。\n         * 主要目的是负责模块与模块之间的合作，降低耦合度。\n         *\n         * @class Mediator\n         */\n        return $.extend({\n\n            /**\n             * 可以通过这个接口，使任何对象具备事件功能。\n             * @method installTo\n             * @param  {Object} obj 需要具备事件行为的对象。\n             * @return {Object} 返回obj.\n             */\n            installTo: function( obj ) {\n                return $.extend( obj, protos );\n            }\n\n        }, protos );\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('uploader',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$;\n\n        /**\n         * 上传入口类。\n         * @class Uploader\n         * @constructor\n         * @grammar new Uploader( opts ) => Uploader\n         * @example\n         * var uploader = WebUploader.Uploader({\n         *     swf: 'path_of_swf/Uploader.swf',\n         *\n         *     // 开起分片上传。\n         *     chunked: true\n         * });\n         */\n        function Uploader( opts ) {\n            this.options = $.extend( true, {}, Uploader.options, opts );\n            this._init( this.options );\n        }\n\n        // default Options\n        // widgets中有相应扩展\n        Uploader.options = {};\n        Mediator.installTo( Uploader.prototype );\n\n        // 批量添加纯命令式方法。\n        $.each({\n            upload: 'start-upload',\n            stop: 'stop-upload',\n            getFile: 'get-file',\n            getFiles: 'get-files',\n            addFile: 'add-file',\n            addFiles: 'add-file',\n            sort: 'sort-files',\n            removeFile: 'remove-file',\n            cancelFile: 'cancel-file',\n            skipFile: 'skip-file',\n            retry: 'retry',\n            isInProgress: 'is-in-progress',\n            makeThumb: 'make-thumb',\n            md5File: 'md5-file',\n            getDimension: 'get-dimension',\n            addButton: 'add-btn',\n            predictRuntimeType: 'predict-runtime-type',\n            refresh: 'refresh',\n            disable: 'disable',\n            enable: 'enable',\n            reset: 'reset'\n        }, function( fn, command ) {\n            Uploader.prototype[ fn ] = function() {\n                return this.request( command, arguments );\n            };\n        });\n\n        $.extend( Uploader.prototype, {\n            state: 'pending',\n\n            _init: function( opts ) {\n                var me = this;\n\n                me.request( 'init', opts, function() {\n                    me.state = 'ready';\n                    me.trigger('ready');\n                });\n            },\n\n            /**\n             * 获取或者设置Uploader配置项。\n             * @method option\n             * @grammar option( key ) => *\n             * @grammar option( key, val ) => self\n             * @example\n             *\n             * // 初始状态图片上传前不会压缩\n             * var uploader = new WebUploader.Uploader({\n             *     compress: null;\n             * });\n             *\n             * // 修改后图片上传前，尝试将图片压缩到1600 * 1600\n             * uploader.option( 'compress', {\n             *     width: 1600,\n             *     height: 1600\n             * });\n             */\n            option: function( key, val ) {\n                var opts = this.options;\n\n                // setter\n                if ( arguments.length > 1 ) {\n\n                    if ( $.isPlainObject( val ) &&\n                            $.isPlainObject( opts[ key ] ) ) {\n                        $.extend( opts[ key ], val );\n                    } else {\n                        opts[ key ] = val;\n                    }\n\n                } else {    // getter\n                    return key ? opts[ key ] : opts;\n                }\n            },\n\n            /**\n             * 获取文件统计信息。返回一个包含一下信息的对象。\n             * * `successNum` 上传成功的文件数\n             * * `progressNum` 上传中的文件数\n             * * `cancelNum` 被删除的文件数\n             * * `invalidNum` 无效的文件数\n             * * `uploadFailNum` 上传失败的文件数\n             * * `queueNum` 还在队列中的文件数\n             * * `interruptNum` 被暂停的文件数\n             * @method getStats\n             * @grammar getStats() => Object\n             */\n            getStats: function() {\n                // return this._mgr.getStats.apply( this._mgr, arguments );\n                var stats = this.request('get-stats');\n\n                return stats ? {\n                    successNum: stats.numOfSuccess,\n                    progressNum: stats.numOfProgress,\n\n                    // who care?\n                    // queueFailNum: 0,\n                    cancelNum: stats.numOfCancel,\n                    invalidNum: stats.numOfInvalid,\n                    uploadFailNum: stats.numOfUploadFailed,\n                    queueNum: stats.numOfQueue,\n                    interruptNum: stats.numofInterrupt\n                } : {};\n            },\n\n            // 需要重写此方法来来支持opts.onEvent和instance.onEvent的处理器\n            trigger: function( type/*, args...*/ ) {\n                var args = [].slice.call( arguments, 1 ),\n                    opts = this.options,\n                    name = 'on' + type.substring( 0, 1 ).toUpperCase() +\n                        type.substring( 1 );\n\n                if (\n                        // 调用通过on方法注册的handler.\n                        Mediator.trigger.apply( this, arguments ) === false ||\n\n                        // 调用opts.onEvent\n                        $.isFunction( opts[ name ] ) &&\n                        opts[ name ].apply( this, args ) === false ||\n\n                        // 调用this.onEvent\n                        $.isFunction( this[ name ] ) &&\n                        this[ name ].apply( this, args ) === false ||\n\n                        // 广播所有uploader的事件。\n                        Mediator.trigger.apply( Mediator,\n                        [ this, type ].concat( args ) ) === false ) {\n\n                    return false;\n                }\n\n                return true;\n            },\n\n            /**\n             * 销毁 webuploader 实例\n             * @method destroy\n             * @grammar destroy() => undefined\n             */\n            destroy: function() {\n                this.request( 'destroy', arguments );\n                this.off();\n            },\n\n            // widgets/widget.js将补充此方法的详细文档。\n            request: Base.noop\n        });\n\n        /**\n         * 创建Uploader实例，等同于new Uploader( opts );\n         * @method create\n         * @class Base\n         * @static\n         * @grammar Base.create( opts ) => Uploader\n         */\n        Base.create = Uploader.create = function( opts ) {\n            return new Uploader( opts );\n        };\n\n        // 暴露Uploader，可以通过它来扩展业务逻辑。\n        Base.Uploader = Uploader;\n\n        return Uploader;\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/runtime',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            factories = {},\n\n            // 获取对象的第一个key\n            getFirstKey = function( obj ) {\n                for ( var key in obj ) {\n                    if ( obj.hasOwnProperty( key ) ) {\n                        return key;\n                    }\n                }\n                return null;\n            };\n\n        // 接口类。\n        function Runtime( options ) {\n            this.options = $.extend({\n                container: document.body\n            }, options );\n            this.uid = Base.guid('rt_');\n        }\n\n        $.extend( Runtime.prototype, {\n\n            getContainer: function() {\n                var opts = this.options,\n                    parent, container;\n\n                if ( this._container ) {\n                    return this._container;\n                }\n\n                parent = $( opts.container || document.body );\n                container = $( document.createElement('div') );\n\n                container.attr( 'id', 'rt_' + this.uid );\n                container.css({\n                    position: 'absolute',\n                    top: '0px',\n                    left: '0px',\n                    width: '1px',\n                    height: '1px',\n                    overflow: 'hidden'\n                });\n\n                parent.append( container );\n                parent.addClass('webuploader-container');\n                this._container = container;\n                this._parent = parent;\n                return container;\n            },\n\n            init: Base.noop,\n            exec: Base.noop,\n\n            destroy: function() {\n                this._container && this._container.remove();\n                this._parent && this._parent.removeClass('webuploader-container');\n                this.off();\n            }\n        });\n\n        Runtime.orders = 'html5,flash';\n\n\n        /**\n         * 添加Runtime实现。\n         * @param {String} type    类型\n         * @param {Runtime} factory 具体Runtime实现。\n         */\n        Runtime.addRuntime = function( type, factory ) {\n            factories[ type ] = factory;\n        };\n\n        Runtime.hasRuntime = function( type ) {\n            return !!(type ? factories[ type ] : getFirstKey( factories ));\n        };\n\n        Runtime.create = function( opts, orders ) {\n            var type, runtime;\n\n            orders = orders || Runtime.orders;\n            $.each( orders.split( /\\s*,\\s*/g ), function() {\n                if ( factories[ this ] ) {\n                    type = this;\n                    return false;\n                }\n            });\n\n            type = type || getFirstKey( factories );\n\n            if ( !type ) {\n                throw new Error('Runtime Error');\n            }\n\n            runtime = new factories[ type ]( opts );\n            return runtime;\n        };\n\n        Mediator.installTo( Runtime.prototype );\n        return Runtime;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/client',[\n        'base',\n        'mediator',\n        'runtime/runtime'\n    ], function( Base, Mediator, Runtime ) {\n\n        var cache;\n\n        cache = (function() {\n            var obj = {};\n\n            return {\n                add: function( runtime ) {\n                    obj[ runtime.uid ] = runtime;\n                },\n\n                get: function( ruid, standalone ) {\n                    var i;\n\n                    if ( ruid ) {\n                        return obj[ ruid ];\n                    }\n\n                    for ( i in obj ) {\n                        // 有些类型不能重用，比如filepicker.\n                        if ( standalone && obj[ i ].__standalone ) {\n                            continue;\n                        }\n\n                        return obj[ i ];\n                    }\n\n                    return null;\n                },\n\n                remove: function( runtime ) {\n                    delete obj[ runtime.uid ];\n                }\n            };\n        })();\n\n        function RuntimeClient( component, standalone ) {\n            var deferred = Base.Deferred(),\n                runtime;\n\n            this.uid = Base.guid('client_');\n\n            // 允许runtime没有初始化之前，注册一些方法在初始化后执行。\n            this.runtimeReady = function( cb ) {\n                return deferred.done( cb );\n            };\n\n            this.connectRuntime = function( opts, cb ) {\n\n                // already connected.\n                if ( runtime ) {\n                    throw new Error('already connected!');\n                }\n\n                deferred.done( cb );\n\n                if ( typeof opts === 'string' && cache.get( opts ) ) {\n                    runtime = cache.get( opts );\n                }\n\n                // 像filePicker只能独立存在，不能公用。\n                runtime = runtime || cache.get( null, standalone );\n\n                // 需要创建\n                if ( !runtime ) {\n                    runtime = Runtime.create( opts, opts.runtimeOrder );\n                    runtime.__promise = deferred.promise();\n                    runtime.once( 'ready', deferred.resolve );\n                    runtime.init();\n                    cache.add( runtime );\n                    runtime.__client = 1;\n                } else {\n                    // 来自cache\n                    Base.$.extend( runtime.options, opts );\n                    runtime.__promise.then( deferred.resolve );\n                    runtime.__client++;\n                }\n\n                standalone && (runtime.__standalone = standalone);\n                return runtime;\n            };\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.disconnectRuntime = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                runtime.__client--;\n\n                if ( runtime.__client <= 0 ) {\n                    cache.remove( runtime );\n                    delete runtime.__promise;\n                    runtime.destroy();\n                }\n\n                runtime = null;\n            };\n\n            this.exec = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                var args = Base.slice( arguments );\n                component && args.unshift( component );\n\n                return runtime.exec.apply( this, args );\n            };\n\n            this.getRuid = function() {\n                return runtime && runtime.uid;\n            };\n\n            this.destroy = (function( destroy ) {\n                return function() {\n                    destroy && destroy.apply( this, arguments );\n                    this.trigger('destroy');\n                    this.off();\n                    this.exec('destroy');\n                    this.disconnectRuntime();\n                };\n            })( this.destroy );\n        }\n\n        Mediator.installTo( RuntimeClient.prototype );\n        return RuntimeClient;\n    });\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/dnd',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function DragAndDrop( opts ) {\n            opts = this.options = $.extend({}, DragAndDrop.options, opts );\n\n            opts.container = $( opts.container );\n\n            if ( !opts.container.length ) {\n                return;\n            }\n\n            RuntimeClent.call( this, 'DragAndDrop' );\n        }\n\n        DragAndDrop.options = {\n            accept: null,\n            disableGlobalDnd: false\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: DragAndDrop,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( DragAndDrop.prototype );\n\n        return DragAndDrop;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/widget',[\n        'base',\n        'uploader'\n    ], function( Base, Uploader ) {\n\n        var $ = Base.$,\n            _init = Uploader.prototype._init,\n            _destroy = Uploader.prototype.destroy,\n            IGNORE = {},\n            widgetClass = [];\n\n        function isArrayLike( obj ) {\n            if ( !obj ) {\n                return false;\n            }\n\n            var length = obj.length,\n                type = $.type( obj );\n\n            if ( obj.nodeType === 1 && length ) {\n                return true;\n            }\n\n            return type === 'array' || type !== 'function' && type !== 'string' &&\n                    (length === 0 || typeof length === 'number' && length > 0 &&\n                    (length - 1) in obj);\n        }\n\n        function Widget( uploader ) {\n            this.owner = uploader;\n            this.options = uploader.options;\n        }\n\n        $.extend( Widget.prototype, {\n\n            init: Base.noop,\n\n            // 类Backbone的事件监听声明，监听uploader实例上的事件\n            // widget直接无法监听事件，事件只能通过uploader来传递\n            invoke: function( apiName, args ) {\n\n                /*\n                    {\n                        'make-thumb': 'makeThumb'\n                    }\n                 */\n                var map = this.responseMap;\n\n                // 如果无API响应声明则忽略\n                if ( !map || !(apiName in map) || !(map[ apiName ] in this) ||\n                        !$.isFunction( this[ map[ apiName ] ] ) ) {\n\n                    return IGNORE;\n                }\n\n                return this[ map[ apiName ] ].apply( this, args );\n\n            },\n\n            /**\n             * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。\n             * @method request\n             * @grammar request( command, args ) => * | Promise\n             * @grammar request( command, args, callback ) => Promise\n             * @for  Uploader\n             */\n            request: function() {\n                return this.owner.request.apply( this.owner, arguments );\n            }\n        });\n\n        // 扩展Uploader.\n        $.extend( Uploader.prototype, {\n\n            /**\n             * @property {String | Array} [disableWidgets=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。\n             */\n\n            // 覆写_init用来初始化widgets\n            _init: function() {\n                var me = this,\n                    widgets = me._widgets = [],\n                    deactives = me.options.disableWidgets || '';\n\n                $.each( widgetClass, function( _, klass ) {\n                    (!deactives || !~deactives.indexOf( klass._name )) &&\n                        widgets.push( new klass( me ) );\n                });\n\n                return _init.apply( me, arguments );\n            },\n\n            request: function( apiName, args, callback ) {\n                var i = 0,\n                    widgets = this._widgets,\n                    len = widgets && widgets.length,\n                    rlts = [],\n                    dfds = [],\n                    widget, rlt, promise, key;\n\n                args = isArrayLike( args ) ? args : [ args ];\n\n                for ( ; i < len; i++ ) {\n                    widget = widgets[ i ];\n                    rlt = widget.invoke( apiName, args );\n\n                    if ( rlt !== IGNORE ) {\n\n                        // Deferred对象\n                        if ( Base.isPromise( rlt ) ) {\n                            dfds.push( rlt );\n                        } else {\n                            rlts.push( rlt );\n                        }\n                    }\n                }\n\n                // 如果有callback，则用异步方式。\n                if ( callback || dfds.length ) {\n                    promise = Base.when.apply( Base, dfds );\n                    key = promise.pipe ? 'pipe' : 'then';\n\n                    // 很重要不能删除。删除了会死循环。\n                    // 保证执行顺序。让callback总是在下一个 tick 中执行。\n                    return promise[ key ](function() {\n                                var deferred = Base.Deferred(),\n                                    args = arguments;\n\n                                if ( args.length === 1 ) {\n                                    args = args[ 0 ];\n                                }\n\n                                setTimeout(function() {\n                                    deferred.resolve( args );\n                                }, 1 );\n\n                                return deferred.promise();\n                            })[ callback ? key : 'done' ]( callback || Base.noop );\n                } else {\n                    return rlts[ 0 ];\n                }\n            },\n\n            destroy: function() {\n                _destroy.apply( this, arguments );\n                this._widgets = null;\n            }\n        });\n\n        /**\n         * 添加组件\n         * @grammar Uploader.register(proto);\n         * @grammar Uploader.register(map, proto);\n         * @param  {object} responseMap API 名称与函数实现的映射\n         * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义\n         * @method Uploader.register\n         * @for Uploader\n         * @example\n         * Uploader.register({\n         *     'make-thumb': 'makeThumb'\n         * }, {\n         *     init: function( options ) {},\n         *     makeThumb: function() {}\n         * });\n         *\n         * Uploader.register({\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         */\n        Uploader.register = Widget.register = function( responseMap, widgetProto ) {\n            var map = { init: 'init', destroy: 'destroy', name: 'anonymous' },\n                klass;\n\n            if ( arguments.length === 1 ) {\n                widgetProto = responseMap;\n\n                // 自动生成 map 表。\n                $.each(widgetProto, function(key) {\n                    if ( key[0] === '_' || key === 'name' ) {\n                        key === 'name' && (map.name = widgetProto.name);\n                        return;\n                    }\n\n                    map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;\n                });\n\n            } else {\n                map = $.extend( map, responseMap );\n            }\n\n            widgetProto.responseMap = map;\n            klass = Base.inherits( Widget, widgetProto );\n            klass._name = map.name;\n            widgetClass.push( klass );\n\n            return klass;\n        };\n\n        /**\n         * 删除插件，只有在注册时指定了名字的才能被删除。\n         * @grammar Uploader.unRegister(name);\n         * @param  {string} name 组件名字\n         * @method Uploader.unRegister\n         * @for Uploader\n         * @example\n         *\n         * Uploader.register({\n         *     name: 'custom',\n         *\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         *\n         * Uploader.unRegister('custom');\n         */\n        Uploader.unRegister = Widget.unRegister = function( name ) {\n            if ( !name || name === 'anonymous' ) {\n                return;\n            }\n\n            // 删除指定的插件。\n            for ( var i = widgetClass.length; i--; ) {\n                if ( widgetClass[i]._name === name ) {\n                    widgetClass.splice(i, 1)\n                }\n            }\n        };\n\n        return Widget;\n    });\n    /**\n     * @fileOverview DragAndDrop Widget。\n     */\n    define('widgets/filednd',[\n        'base',\n        'uploader',\n        'lib/dnd',\n        'widgets/widget'\n    ], function( Base, Uploader, Dnd ) {\n        var $ = Base.$;\n\n        Uploader.options.dnd = '';\n\n        /**\n         * @property {Selector} [dnd=undefined]  指定Drag And Drop拖拽的容器，如果不指定，则不启动。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @property {Selector} [disableGlobalDnd=false]  是否禁掉整个页面的拖拽功能，如果不禁用，图片拖进来的时候会默认被浏览器打开。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @event dndAccept\n         * @param {DataTransferItemList} items DataTransferItem\n         * @description 阻止此事件可以拒绝某些类型的文件拖入进来。目前只有 chrome 提供这样的 API，且只能通过 mime-type 验证。\n         * @for  Uploader\n         */\n        return Uploader.register({\n            name: 'dnd',\n\n            init: function( opts ) {\n\n                if ( !opts.dnd ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        disableGlobalDnd: opts.disableGlobalDnd,\n                        container: opts.dnd,\n                        accept: opts.accept\n                    }),\n                    dnd;\n\n                this.dnd = dnd = new Dnd( options );\n\n                dnd.once( 'ready', deferred.resolve );\n                dnd.on( 'drop', function( files ) {\n                    me.request( 'add-file', [ files ]);\n                });\n\n                // 检测文件是否全部允许添加。\n                dnd.on( 'accept', function( items ) {\n                    return me.owner.trigger( 'dndAccept', items );\n                });\n\n                dnd.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.dnd && this.dnd.destroy();\n            }\n        });\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepaste',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function FilePaste( opts ) {\n            opts = this.options = $.extend({}, opts );\n            opts.container = $( opts.container || document.body );\n            RuntimeClent.call( this, 'FilePaste' );\n        }\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePaste,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( FilePaste.prototype );\n\n        return FilePaste;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/filepaste',[\n        'base',\n        'uploader',\n        'lib/filepaste',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePaste ) {\n        var $ = Base.$;\n\n        /**\n         * @property {Selector} [paste=undefined]  指定监听paste事件的容器，如果不指定，不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为`document.body`.\n         * @namespace options\n         * @for Uploader\n         */\n        return Uploader.register({\n            name: 'paste',\n\n            init: function( opts ) {\n\n                if ( !opts.paste ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        container: opts.paste,\n                        accept: opts.accept\n                    }),\n                    paste;\n\n                this.paste = paste = new FilePaste( options );\n\n                paste.once( 'ready', deferred.resolve );\n                paste.on( 'paste', function( files ) {\n                    me.owner.request( 'add-file', [ files ]);\n                });\n                paste.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.paste && this.paste.destroy();\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob\n     */\n    define('lib/blob',[\n        'base',\n        'runtime/client'\n    ], function( Base, RuntimeClient ) {\n\n        function Blob( ruid, source ) {\n            var me = this;\n\n            me.source = source;\n            me.ruid = ruid;\n            this.size = source.size || 0;\n\n            // 如果没有指定 mimetype, 但是知道文件后缀。\n            if ( !source.type && this.ext &&\n                    ~'jpg,jpeg,png,gif,bmp'.indexOf( this.ext ) ) {\n                this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);\n            } else {\n                this.type = source.type || 'application/octet-stream';\n            }\n\n            RuntimeClient.call( me, 'Blob' );\n            this.uid = source.uid || this.uid;\n\n            if ( ruid ) {\n                me.connectRuntime( ruid );\n            }\n        }\n\n        Base.inherits( RuntimeClient, {\n            constructor: Blob,\n\n            slice: function( start, end ) {\n                return this.exec( 'slice', start, end );\n            },\n\n            getSource: function() {\n                return this.source;\n            }\n        });\n\n        return Blob;\n    });\n    /**\n     * 为了统一化Flash的File和HTML5的File而存在。\n     * 以至于要调用Flash里面的File，也可以像调用HTML5版本的File一下。\n     * @fileOverview File\n     */\n    define('lib/file',[\n        'base',\n        'lib/blob'\n    ], function( Base, Blob ) {\n\n        var uid = 1,\n            rExt = /\\.([^.]+)$/;\n\n        function File( ruid, file ) {\n            var ext;\n\n            this.name = file.name || ('untitled' + uid++);\n            ext = rExt.exec( file.name ) ? RegExp.$1.toLowerCase() : '';\n\n            // todo 支持其他类型文件的转换。\n            // 如果有 mimetype, 但是文件名里面没有找出后缀规律\n            if ( !ext && file.type ) {\n                ext = /\\/(jpg|jpeg|png|gif|bmp)$/i.exec( file.type ) ?\n                        RegExp.$1.toLowerCase() : '';\n                this.name += '.' + ext;\n            }\n\n            this.ext = ext;\n            this.lastModifiedDate = file.lastModifiedDate ||\n                    (new Date()).toLocaleString();\n\n            Blob.apply( this, arguments );\n        }\n\n        return Base.inherits( Blob, File );\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepicker',[\n        'base',\n        'runtime/client',\n        'lib/file'\n    ], function( Base, RuntimeClent, File ) {\n\n        var $ = Base.$;\n\n        function FilePicker( opts ) {\n            opts = this.options = $.extend({}, FilePicker.options, opts );\n\n            opts.container = $( opts.id );\n\n            if ( !opts.container.length ) {\n                throw new Error('按钮指定错误');\n            }\n\n            opts.innerHTML = opts.innerHTML || opts.label ||\n                    opts.container.html() || '';\n\n            opts.button = $( opts.button || document.createElement('div') );\n            opts.button.html( opts.innerHTML );\n            opts.container.html( opts.button );\n\n            RuntimeClent.call( this, 'FilePicker', true );\n        }\n\n        FilePicker.options = {\n            button: null,\n            container: null,\n            label: null,\n            innerHTML: null,\n            multiple: true,\n            accept: null,\n            name: 'file'\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePicker,\n\n            init: function() {\n                var me = this,\n                    opts = me.options,\n                    button = opts.button;\n\n                button.addClass('webuploader-pick');\n\n                me.on( 'all', function( type ) {\n                    var files;\n\n                    switch ( type ) {\n                        case 'mouseenter':\n                            button.addClass('webuploader-pick-hover');\n                            break;\n\n                        case 'mouseleave':\n                            button.removeClass('webuploader-pick-hover');\n                            break;\n\n                        case 'change':\n                            files = me.exec('getFiles');\n                            me.trigger( 'select', $.map( files, function( file ) {\n                                file = new File( me.getRuid(), file );\n\n                                // 记录来源。\n                                file._refer = opts.container;\n                                return file;\n                            }), opts.container );\n                            break;\n                    }\n                });\n\n                me.connectRuntime( opts, function() {\n                    me.refresh();\n                    me.exec( 'init', opts );\n                    me.trigger('ready');\n                });\n\n                this._resizeHandler = Base.bindFn( this.refresh, this );\n                $( window ).on( 'resize', this._resizeHandler );\n            },\n\n            refresh: function() {\n                var shimContainer = this.getRuntime().getContainer(),\n                    button = this.options.button,\n                    width = button.outerWidth ?\n                            button.outerWidth() : button.width(),\n\n                    height = button.outerHeight ?\n                            button.outerHeight() : button.height(),\n\n                    pos = button.offset();\n\n                width && height && shimContainer.css({\n                    bottom: 'auto',\n                    right: 'auto',\n                    width: width + 'px',\n                    height: height + 'px'\n                }).offset( pos );\n            },\n\n            enable: function() {\n                var btn = this.options.button;\n\n                btn.removeClass('webuploader-pick-disable');\n                this.refresh();\n            },\n\n            disable: function() {\n                var btn = this.options.button;\n\n                this.getRuntime().getContainer().css({\n                    top: '-99999px'\n                });\n\n                btn.addClass('webuploader-pick-disable');\n            },\n\n            destroy: function() {\n                var btn = this.options.button;\n                $( window ).off( 'resize', this._resizeHandler );\n                btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +\n                    'webuploader-pick');\n            }\n        });\n\n        return FilePicker;\n    });\n\n    /**\n     * @fileOverview 文件选择相关\n     */\n    define('widgets/filepicker',[\n        'base',\n        'uploader',\n        'lib/filepicker',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePicker ) {\n        var $ = Base.$;\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Selector | Object} [pick=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 指定选择文件的按钮容器，不指定则不创建按钮。\n             *\n             * * `id` {Seletor|dom} 指定选择文件的按钮容器，不指定则不创建按钮。**注意** 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。\n             * * `label` {String} 请采用 `innerHTML` 代替\n             * * `innerHTML` {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。\n             * * `multiple` {Boolean} 是否开起同时选择多个文件能力。\n             */\n            pick: null,\n\n            /**\n             * @property {Arroy} [accept=null]\n             * @namespace options\n             * @for Uploader\n             * @description 指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。\n             *\n             * * `title` {String} 文字描述\n             * * `extensions` {String} 允许的文件后缀，不带点，多个用逗号分割。\n             * * `mimeTypes` {String} 多个用逗号分割。\n             *\n             * 如：\n             *\n             * ```\n             * {\n             *     title: 'Images',\n             *     extensions: 'gif,jpg,jpeg,bmp,png',\n             *     mimeTypes: 'image/*'\n             * }\n             * ```\n             */\n            accept: null/*{\n                title: 'Images',\n                extensions: 'gif,jpg,jpeg,bmp,png',\n                mimeTypes: 'image/*'\n            }*/\n        });\n\n        return Uploader.register({\n            name: 'picker',\n\n            init: function( opts ) {\n                this.pickers = [];\n                return opts.pick && this.addBtn( opts.pick );\n            },\n\n            refresh: function() {\n                $.each( this.pickers, function() {\n                    this.refresh();\n                });\n            },\n\n            /**\n             * @method addButton\n             * @for Uploader\n             * @grammar addButton( pick ) => Promise\n             * @description\n             * 添加文件选择按钮，如果一个按钮不够，需要调用此方法来添加。参数跟[options.pick](#WebUploader:Uploader:options)一致。\n             * @example\n             * uploader.addButton({\n             *     id: '#btnContainer',\n             *     innerHTML: '选择文件'\n             * });\n             */\n            addBtn: function( pick ) {\n                var me = this,\n                    opts = me.options,\n                    accept = opts.accept,\n                    promises = [];\n\n                if ( !pick ) {\n                    return;\n                }\n\n                $.isPlainObject( pick ) || (pick = {\n                    id: pick\n                });\n\n                $( pick.id ).each(function() {\n                    var options, picker, deferred;\n\n                    deferred = Base.Deferred();\n\n                    options = $.extend({}, pick, {\n                        accept: $.isPlainObject( accept ) ? [ accept ] : accept,\n                        swf: opts.swf,\n                        runtimeOrder: opts.runtimeOrder,\n                        id: this\n                    });\n\n                    picker = new FilePicker( options );\n\n                    picker.once( 'ready', deferred.resolve );\n                    picker.on( 'select', function( files ) {\n                        me.owner.request( 'add-file', [ files ]);\n                    });\n                    picker.init();\n\n                    me.pickers.push( picker );\n\n                    promises.push( deferred.promise() );\n                });\n\n                return Base.when.apply( Base, promises );\n            },\n\n            disable: function() {\n                $.each( this.pickers, function() {\n                    this.disable();\n                });\n            },\n\n            enable: function() {\n                $.each( this.pickers, function() {\n                    this.enable();\n                });\n            },\n\n            destroy: function() {\n                $.each( this.pickers, function() {\n                    this.destroy();\n                });\n                this.pickers = null;\n            }\n        });\n    });\n    /**\n     * @fileOverview 文件属性封装\n     */\n    define('file',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            idPrefix = 'WU_FILE_',\n            idSuffix = 0,\n            rExt = /\\.([^.]+)$/,\n            statusMap = {};\n\n        function gid() {\n            return idPrefix + idSuffix++;\n        }\n\n        /**\n         * 文件类\n         * @class File\n         * @constructor 构造函数\n         * @grammar new File( source ) => File\n         * @param {Lib.File} source [lib.File](#Lib.File)实例, 此source对象是带有Runtime信息的。\n         */\n        function WUFile( source ) {\n\n            /**\n             * 文件名，包括扩展名（后缀）\n             * @property name\n             * @type {string}\n             */\n            this.name = source.name || 'Untitled';\n\n            /**\n             * 文件体积（字节）\n             * @property size\n             * @type {uint}\n             * @default 0\n             */\n            this.size = source.size || 0;\n\n            /**\n             * 文件MIMETYPE类型，与文件类型的对应关系请参考[http://t.cn/z8ZnFny](http://t.cn/z8ZnFny)\n             * @property type\n             * @type {string}\n             * @default 'application/octet-stream'\n             */\n            this.type = source.type || 'application/octet-stream';\n\n            /**\n             * 文件最后修改日期\n             * @property lastModifiedDate\n             * @type {int}\n             * @default 当前时间戳\n             */\n            this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);\n\n            /**\n             * 文件ID，每个对象具有唯一ID，与文件名无关\n             * @property id\n             * @type {string}\n             */\n            this.id = gid();\n\n            /**\n             * 文件扩展名，通过文件名获取，例如test.png的扩展名为png\n             * @property ext\n             * @type {string}\n             */\n            this.ext = rExt.exec( this.name ) ? RegExp.$1 : '';\n\n\n            /**\n             * 状态文字说明。在不同的status语境下有不同的用途。\n             * @property statusText\n             * @type {string}\n             */\n            this.statusText = '';\n\n            // 存储文件状态，防止通过属性直接修改\n            statusMap[ this.id ] = WUFile.Status.INITED;\n\n            this.source = source;\n            this.loaded = 0;\n\n            this.on( 'error', function( msg ) {\n                this.setStatus( WUFile.Status.ERROR, msg );\n            });\n        }\n\n        $.extend( WUFile.prototype, {\n\n            /**\n             * 设置状态，状态变化时会触发`change`事件。\n             * @method setStatus\n             * @grammar setStatus( status[, statusText] );\n             * @param {File.Status|String} status [文件状态值](#WebUploader:File:File.Status)\n             * @param {String} [statusText=''] 状态说明，常在error时使用，用http, abort,server等来标记是由于什么原因导致文件错误。\n             */\n            setStatus: function( status, text ) {\n\n                var prevStatus = statusMap[ this.id ];\n\n                typeof text !== 'undefined' && (this.statusText = text);\n\n                if ( status !== prevStatus ) {\n                    statusMap[ this.id ] = status;\n                    /**\n                     * 文件状态变化\n                     * @event statuschange\n                     */\n                    this.trigger( 'statuschange', status, prevStatus );\n                }\n\n            },\n\n            /**\n             * 获取文件状态\n             * @return {File.Status}\n             * @example\n                     文件状态具体包括以下几种类型：\n                     {\n                         // 初始化\n                        INITED:     0,\n                        // 已入队列\n                        QUEUED:     1,\n                        // 正在上传\n                        PROGRESS:     2,\n                        // 上传出错\n                        ERROR:         3,\n                        // 上传成功\n                        COMPLETE:     4,\n                        // 上传取消\n                        CANCELLED:     5\n                    }\n             */\n            getStatus: function() {\n                return statusMap[ this.id ];\n            },\n\n            /**\n             * 获取文件原始信息。\n             * @return {*}\n             */\n            getSource: function() {\n                return this.source;\n            },\n\n            destroy: function() {\n                this.off();\n                delete statusMap[ this.id ];\n            }\n        });\n\n        Mediator.installTo( WUFile.prototype );\n\n        /**\n         * 文件状态值，具体包括以下几种类型：\n         * * `inited` 初始状态\n         * * `queued` 已经进入队列, 等待上传\n         * * `progress` 上传中\n         * * `complete` 上传完成。\n         * * `error` 上传出错，可重试\n         * * `interrupt` 上传中断，可续传。\n         * * `invalid` 文件不合格，不能重试上传。会自动从队列中移除。\n         * * `cancelled` 文件被移除。\n         * @property {Object} Status\n         * @namespace File\n         * @class File\n         * @static\n         */\n        WUFile.Status = {\n            INITED:     'inited',    // 初始状态\n            QUEUED:     'queued',    // 已经进入队列, 等待上传\n            PROGRESS:   'progress',    // 上传中\n            ERROR:      'error',    // 上传出错，可重试\n            COMPLETE:   'complete',    // 上传完成。\n            CANCELLED:  'cancelled',    // 上传取消。\n            INTERRUPT:  'interrupt',    // 上传中断，可续传。\n            INVALID:    'invalid'    // 文件不合格，不能重试上传。\n        };\n\n        return WUFile;\n    });\n\n    /**\n     * @fileOverview 文件队列\n     */\n    define('queue',[\n        'base',\n        'mediator',\n        'file'\n    ], function( Base, Mediator, WUFile ) {\n\n        var $ = Base.$,\n            STATUS = WUFile.Status;\n\n        /**\n         * 文件队列, 用来存储各个状态中的文件。\n         * @class Queue\n         * @extends Mediator\n         */\n        function Queue() {\n\n            /**\n             * 统计文件数。\n             * * `numOfQueue` 队列中的文件数。\n             * * `numOfSuccess` 上传成功的文件数\n             * * `numOfCancel` 被取消的文件数\n             * * `numOfProgress` 正在上传中的文件数\n             * * `numOfUploadFailed` 上传错误的文件数。\n             * * `numOfInvalid` 无效的文件数。\n             * * `numofDeleted` 被移除的文件数。\n             * @property {Object} stats\n             */\n            this.stats = {\n                numOfQueue: 0,\n                numOfSuccess: 0,\n                numOfCancel: 0,\n                numOfProgress: 0,\n                numOfUploadFailed: 0,\n                numOfInvalid: 0,\n                numofDeleted: 0,\n                numofInterrupt: 0\n            };\n\n            // 上传队列，仅包括等待上传的文件\n            this._queue = [];\n\n            // 存储所有文件\n            this._map = {};\n        }\n\n        $.extend( Queue.prototype, {\n\n            /**\n             * 将新文件加入对队列尾部\n             *\n             * @method append\n             * @param  {File} file   文件对象\n             */\n            append: function( file ) {\n                this._queue.push( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 将新文件加入对队列头部\n             *\n             * @method prepend\n             * @param  {File} file   文件对象\n             */\n            prepend: function( file ) {\n                this._queue.unshift( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 获取文件对象\n             *\n             * @method getFile\n             * @param  {String} fileId   文件ID\n             * @return {File}\n             */\n            getFile: function( fileId ) {\n                if ( typeof fileId !== 'string' ) {\n                    return fileId;\n                }\n                return this._map[ fileId ];\n            },\n\n            /**\n             * 从队列中取出一个指定状态的文件。\n             * @grammar fetch( status ) => File\n             * @method fetch\n             * @param {String} status [文件状态值](#WebUploader:File:File.Status)\n             * @return {File} [File](#WebUploader:File)\n             */\n            fetch: function( status ) {\n                var len = this._queue.length,\n                    i, file;\n\n                status = status || STATUS.QUEUED;\n\n                for ( i = 0; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( status === file.getStatus() ) {\n                        return file;\n                    }\n                }\n\n                return null;\n            },\n\n            /**\n             * 对队列进行排序，能够控制文件上传顺序。\n             * @grammar sort( fn ) => undefined\n             * @method sort\n             * @param {Function} fn 排序方法\n             */\n            sort: function( fn ) {\n                if ( typeof fn === 'function' ) {\n                    this._queue.sort( fn );\n                }\n            },\n\n            /**\n             * 获取指定类型的文件列表, 列表中每一个成员为[File](#WebUploader:File)对象。\n             * @grammar getFiles( [status1[, status2 ...]] ) => Array\n             * @method getFiles\n             * @param {String} [status] [文件状态值](#WebUploader:File:File.Status)\n             */\n            getFiles: function() {\n                var sts = [].slice.call( arguments, 0 ),\n                    ret = [],\n                    i = 0,\n                    len = this._queue.length,\n                    file;\n\n                for ( ; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( sts.length && !~$.inArray( file.getStatus(), sts ) ) {\n                        continue;\n                    }\n\n                    ret.push( file );\n                }\n\n                return ret;\n            },\n\n            /**\n             * 在队列中删除文件。\n             * @grammar removeFile( file ) => Array\n             * @method removeFile\n             * @param {File} 文件对象。\n             */\n            removeFile: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( existing ) {\n                    delete this._map[ file.id ];\n                    file.destroy();\n                    this.stats.numofDeleted++;\n                }\n            },\n\n            _fileAdded: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( !existing ) {\n                    this._map[ file.id ] = file;\n\n                    file.on( 'statuschange', function( cur, pre ) {\n                        me._onFileStatusChange( cur, pre );\n                    });\n                }\n            },\n\n            _onFileStatusChange: function( curStatus, preStatus ) {\n                var stats = this.stats;\n\n                switch ( preStatus ) {\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress--;\n                        break;\n\n                    case STATUS.QUEUED:\n                        stats.numOfQueue --;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed--;\n                        break;\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid--;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt--;\n                        break;\n                }\n\n                switch ( curStatus ) {\n                    case STATUS.QUEUED:\n                        stats.numOfQueue++;\n                        break;\n\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress++;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed++;\n                        break;\n\n                    case STATUS.COMPLETE:\n                        stats.numOfSuccess++;\n                        break;\n\n                    case STATUS.CANCELLED:\n                        stats.numOfCancel++;\n                        break;\n\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid++;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt++;\n                        break;\n                }\n            }\n\n        });\n\n        Mediator.installTo( Queue.prototype );\n\n        return Queue;\n    });\n    /**\n     * @fileOverview 队列\n     */\n    define('widgets/queue',[\n        'base',\n        'uploader',\n        'queue',\n        'file',\n        'lib/file',\n        'runtime/client',\n        'widgets/widget'\n    ], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {\n\n        var $ = Base.$,\n            rExt = /\\.\\w+$/,\n            Status = WUFile.Status;\n\n        return Uploader.register({\n            name: 'queue',\n\n            init: function( opts ) {\n                var me = this,\n                    deferred, len, i, item, arr, accept, runtime;\n\n                if ( $.isPlainObject( opts.accept ) ) {\n                    opts.accept = [ opts.accept ];\n                }\n\n                // accept中的中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].extensions;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = '\\\\.' + arr.join(',')\n                                .replace( /,/g, '$|\\\\.' )\n                                .replace( /\\*/g, '.*' ) + '$';\n                    }\n\n                    me.accept = new RegExp( accept, 'i' );\n                }\n\n                me.queue = new Queue();\n                me.stats = me.queue.stats;\n\n                // 如果当前不是html5运行时，那就算了。\n                // 不执行后续操作\n                if ( this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                // 创建一个 html5 运行时的 placeholder\n                // 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。\n                deferred = Base.Deferred();\n                this.placeholder = runtime = new RuntimeClient('Placeholder');\n                runtime.connectRuntime({\n                    runtimeOrder: 'html5'\n                }, function() {\n                    me._ruid = runtime.getRuid();\n                    deferred.resolve();\n                });\n                return deferred.promise();\n            },\n\n\n            // 为了支持外部直接添加一个原生File对象。\n            _wrapFile: function( file ) {\n                if ( !(file instanceof WUFile) ) {\n\n                    if ( !(file instanceof File) ) {\n                        if ( !this._ruid ) {\n                            throw new Error('Can\\'t add external files.');\n                        }\n                        file = new File( this._ruid, file );\n                    }\n\n                    file = new WUFile( file );\n                }\n\n                return file;\n            },\n\n            // 判断文件是否可以被加入队列\n            acceptFile: function( file ) {\n                var invalid = !file || !file.size || this.accept &&\n\n                        // 如果名字中有后缀，才做后缀白名单处理。\n                        rExt.exec( file.name ) && !this.accept.test( file.name );\n\n                return !invalid;\n            },\n\n\n            /**\n             * @event beforeFileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列之前触发，此事件的handler返回值为`false`，则此文件不会被添加进入队列。\n             * @for  Uploader\n             */\n\n            /**\n             * @event fileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列以后触发。\n             * @for  Uploader\n             */\n\n            _addFile: function( file ) {\n                var me = this;\n\n                file = me._wrapFile( file );\n\n                // 不过类型判断允许不允许，先派送 `beforeFileQueued`\n                if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {\n                    return;\n                }\n\n                // 类型不匹配，则派送错误事件，并返回。\n                if ( !me.acceptFile( file ) ) {\n                    me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );\n                    return;\n                }\n\n                me.queue.append( file );\n                me.owner.trigger( 'fileQueued', file );\n                return file;\n            },\n\n            getFile: function( fileId ) {\n                return this.queue.getFile( fileId );\n            },\n\n            /**\n             * @event filesQueued\n             * @param {File} files 数组，内容为原始File(lib/File）对象。\n             * @description 当一批文件添加进队列以后触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @property {Boolean} [auto=false]\n             * @namespace options\n             * @for Uploader\n             * @description 设置为 true 后，不需要手动调用上传，有文件选择即开始上传。\n             *\n             */\n\n            /**\n             * @method addFiles\n             * @grammar addFiles( file ) => undefined\n             * @grammar addFiles( [file1, file2 ...] ) => undefined\n             * @param {Array of File or File} [files] Files 对象 数组\n             * @description 添加文件到队列\n             * @for  Uploader\n             */\n            addFile: function( files ) {\n                var me = this;\n\n                if ( !files.length ) {\n                    files = [ files ];\n                }\n\n                files = $.map( files, function( file ) {\n                    return me._addFile( file );\n                });\n\n                me.owner.trigger( 'filesQueued', files );\n\n                if ( me.options.auto ) {\n                    setTimeout(function() {\n                        me.request('start-upload');\n                    }, 20 );\n                }\n            },\n\n            getStats: function() {\n                return this.stats;\n            },\n\n            /**\n             * @event fileDequeued\n             * @param {File} file File对象\n             * @description 当文件被移除队列后触发。\n             * @for  Uploader\n             */\n\n             /**\n             * @method removeFile\n             * @grammar removeFile( file ) => undefined\n             * @grammar removeFile( id ) => undefined\n             * @grammar removeFile( file, true ) => undefined\n             * @grammar removeFile( id, true ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 移除某一文件, 默认只会标记文件状态为已取消，如果第二个参数为 `true` 则会从 queue 中移除。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.removeFile( file );\n             * })\n             */\n            removeFile: function( file, remove ) {\n                var me = this;\n\n                file = file.id ? file : me.queue.getFile( file );\n\n                this.request( 'cancel-file', file );\n\n                if ( remove ) {\n                    this.queue.removeFile( file );\n                }\n            },\n\n            /**\n             * @method getFiles\n             * @grammar getFiles() => Array\n             * @grammar getFiles( status1, status2, status... ) => Array\n             * @description 返回指定状态的文件集合，不传参数将返回所有状态的文件。\n             * @for  Uploader\n             * @example\n             * console.log( uploader.getFiles() );    // => all files\n             * console.log( uploader.getFiles('error') )    // => all error files.\n             */\n            getFiles: function() {\n                return this.queue.getFiles.apply( this.queue, arguments );\n            },\n\n            fetchFile: function() {\n                return this.queue.fetch.apply( this.queue, arguments );\n            },\n\n            /**\n             * @method retry\n             * @grammar retry() => undefined\n             * @grammar retry( file ) => undefined\n             * @description 重试上传，重试指定文件，或者从出错的文件开始重新上传。\n             * @for  Uploader\n             * @example\n             * function retry() {\n             *     uploader.retry();\n             * }\n             */\n            retry: function( file, noForceStart ) {\n                var me = this,\n                    files, i, len;\n\n                if ( file ) {\n                    file = file.id ? file : me.queue.getFile( file );\n                    file.setStatus( Status.QUEUED );\n                    noForceStart || me.request('start-upload');\n                    return;\n                }\n\n                files = me.queue.getFiles( Status.ERROR );\n                i = 0;\n                len = files.length;\n\n                for ( ; i < len; i++ ) {\n                    file = files[ i ];\n                    file.setStatus( Status.QUEUED );\n                }\n\n                me.request('start-upload');\n            },\n\n            /**\n             * @method sort\n             * @grammar sort( fn ) => undefined\n             * @description 排序队列中的文件，在上传之前调整可以控制上传顺序。\n             * @for  Uploader\n             */\n            sortFiles: function() {\n                return this.queue.sort.apply( this.queue, arguments );\n            },\n\n            /**\n             * @event reset\n             * @description 当 uploader 被重置的时候触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @method reset\n             * @grammar reset() => undefined\n             * @description 重置uploader。目前只重置了队列。\n             * @for  Uploader\n             * @example\n             * uploader.reset();\n             */\n            reset: function() {\n                this.owner.trigger('reset');\n                this.queue = new Queue();\n                this.stats = this.queue.stats;\n            },\n\n            destroy: function() {\n                this.reset();\n                this.placeholder && this.placeholder.destroy();\n            }\n        });\n\n    });\n    /**\n     * @fileOverview 添加获取Runtime相关信息的方法。\n     */\n    define('widgets/runtime',[\n        'uploader',\n        'runtime/runtime',\n        'widgets/widget'\n    ], function( Uploader, Runtime ) {\n\n        Uploader.support = function() {\n            return Runtime.hasRuntime.apply( Runtime, arguments );\n        };\n\n        /**\n         * @property {Object} [runtimeOrder=html5,flash]\n         * @namespace options\n         * @for Uploader\n         * @description 指定运行时启动顺序。默认会想尝试 html5 是否支持，如果支持则使用 html5, 否则则使用 flash.\n         *\n         * 可以将此值设置成 `flash`，来强制使用 flash 运行时。\n         */\n\n        return Uploader.register({\n            name: 'runtime',\n\n            init: function() {\n                if ( !this.predictRuntimeType() ) {\n                    throw Error('Runtime Error');\n                }\n            },\n\n            /**\n             * 预测Uploader将采用哪个`Runtime`\n             * @grammar predictRuntimeType() => String\n             * @method predictRuntimeType\n             * @for  Uploader\n             */\n            predictRuntimeType: function() {\n                var orders = this.options.runtimeOrder || Runtime.orders,\n                    type = this.type,\n                    i, len;\n\n                if ( !type ) {\n                    orders = orders.split( /\\s*,\\s*/g );\n\n                    for ( i = 0, len = orders.length; i < len; i++ ) {\n                        if ( Runtime.hasRuntime( orders[ i ] ) ) {\n                            this.type = type = orders[ i ];\n                            break;\n                        }\n                    }\n                }\n\n                return type;\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     */\n    define('lib/transport',[\n        'base',\n        'runtime/client',\n        'mediator'\n    ], function( Base, RuntimeClient, Mediator ) {\n\n        var $ = Base.$;\n\n        function Transport( opts ) {\n            var me = this;\n\n            opts = me.options = $.extend( true, {}, Transport.options, opts || {} );\n            RuntimeClient.call( this, 'Transport' );\n\n            this._blob = null;\n            this._formData = opts.formData || {};\n            this._headers = opts.headers || {};\n\n            this.on( 'progress', this._timeout );\n            this.on( 'load error', function() {\n                me.trigger( 'progress', 1 );\n                clearTimeout( me._timer );\n            });\n        }\n\n        Transport.options = {\n            server: '',\n            method: 'POST',\n\n            // 跨域时，是否允许携带cookie, 只有html5 runtime才有效\n            withCredentials: false,\n            fileVal: 'file',\n            timeout: 2 * 60 * 1000,    // 2分钟\n            formData: {},\n            headers: {},\n            sendAsBinary: false\n        };\n\n        $.extend( Transport.prototype, {\n\n            // 添加Blob, 只能添加一次，最后一次有效。\n            appendBlob: function( key, blob, filename ) {\n                var me = this,\n                    opts = me.options;\n\n                if ( me.getRuid() ) {\n                    me.disconnectRuntime();\n                }\n\n                // 连接到blob归属的同一个runtime.\n                me.connectRuntime( blob.ruid, function() {\n                    me.exec('init');\n                });\n\n                me._blob = blob;\n                opts.fileVal = key || opts.fileVal;\n                opts.filename = filename || opts.filename;\n            },\n\n            // 添加其他字段\n            append: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._formData, key );\n                } else {\n                    this._formData[ key ] = value;\n                }\n            },\n\n            setRequestHeader: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._headers, key );\n                } else {\n                    this._headers[ key ] = value;\n                }\n            },\n\n            send: function( method ) {\n                this.exec( 'send', method );\n                this._timeout();\n            },\n\n            abort: function() {\n                clearTimeout( this._timer );\n                return this.exec('abort');\n            },\n\n            destroy: function() {\n                this.trigger('destroy');\n                this.off();\n                this.exec('destroy');\n                this.disconnectRuntime();\n            },\n\n            getResponse: function() {\n                return this.exec('getResponse');\n            },\n\n            getResponseAsJson: function() {\n                return this.exec('getResponseAsJson');\n            },\n\n            getStatus: function() {\n                return this.exec('getStatus');\n            },\n\n            _timeout: function() {\n                var me = this,\n                    duration = me.options.timeout;\n\n                if ( !duration ) {\n                    return;\n                }\n\n                clearTimeout( me._timer );\n                me._timer = setTimeout(function() {\n                    me.abort();\n                    me.trigger( 'error', 'timeout' );\n                }, duration );\n            }\n\n        });\n\n        // 让Transport具备事件功能。\n        Mediator.installTo( Transport.prototype );\n\n        return Transport;\n    });\n    /**\n     * @fileOverview 负责文件上传相关。\n     */\n    define('widgets/upload',[\n        'base',\n        'uploader',\n        'file',\n        'lib/transport',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile, Transport ) {\n\n        var $ = Base.$,\n            isPromise = Base.isPromise,\n            Status = WUFile.Status;\n\n        // 添加默认配置项\n        $.extend( Uploader.options, {\n\n\n            /**\n             * @property {Boolean} [prepareNextFile=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否允许在文件传输时提前把下一个文件准备好。\n             * 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。\n             * 如果能提前在当前文件传输期处理，可以节省总体耗时。\n             */\n            prepareNextFile: false,\n\n            /**\n             * @property {Boolean} [chunked=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否要分片处理大文件上传。\n             */\n            chunked: false,\n\n            /**\n             * @property {Boolean} [chunkSize=5242880]\n             * @namespace options\n             * @for Uploader\n             * @description 如果要分片，分多大一片？ 默认大小为5M.\n             */\n            chunkSize: 5 * 1024 * 1024,\n\n            /**\n             * @property {Boolean} [chunkRetry=2]\n             * @namespace options\n             * @for Uploader\n             * @description 如果某个分片由于网络问题出错，允许自动重传多少次？\n             */\n            chunkRetry: 2,\n\n            /**\n             * @property {Boolean} [threads=3]\n             * @namespace options\n             * @for Uploader\n             * @description 上传并发数。允许同时最大上传进程数。\n             */\n            threads: 3,\n\n\n            /**\n             * @property {Object} [formData={}]\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传请求的参数表，每次发送都会发送此对象中的参数。\n             */\n            formData: {}\n\n            /**\n             * @property {Object} [fileVal='file']\n             * @namespace options\n             * @for Uploader\n             * @description 设置文件上传域的name。\n             */\n\n            /**\n             * @property {Object} [method='POST']\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传方式，`POST`或者`GET`。\n             */\n\n            /**\n             * @property {Object} [sendAsBinary=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否已二进制的流的方式发送文件，这样整个上传内容`php://input`都为文件内容，\n             * 其他参数在$_GET数组中。\n             */\n        });\n\n        // 负责将文件切片。\n        function CuteFile( file, chunkSize ) {\n            var pending = [],\n                blob = file.source,\n                total = blob.size,\n                chunks = chunkSize ? Math.ceil( total / chunkSize ) : 1,\n                start = 0,\n                index = 0,\n                len, api;\n\n            api = {\n                file: file,\n\n                has: function() {\n                    return !!pending.length;\n                },\n\n                shift: function() {\n                    return pending.shift();\n                },\n\n                unshift: function( block ) {\n                    pending.unshift( block );\n                }\n            };\n\n            while ( index < chunks ) {\n                len = Math.min( chunkSize, total - start );\n\n                pending.push({\n                    file: file,\n                    start: start,\n                    end: chunkSize ? (start + len) : total,\n                    total: total,\n                    chunks: chunks,\n                    chunk: index++,\n                    cuted: api\n                });\n                start += len;\n            }\n\n            file.blocks = pending.concat();\n            file.remaning = pending.length;\n\n            return api;\n        }\n\n        Uploader.register({\n            name: 'upload',\n\n            init: function() {\n                var owner = this.owner,\n                    me = this;\n\n                this.runing = false;\n                this.progress = false;\n\n                owner\n                    .on( 'startUpload', function() {\n                        me.progress = true;\n                    })\n                    .on( 'uploadFinished', function() {\n                        me.progress = false;\n                    });\n\n                // 记录当前正在传的数据，跟threads相关\n                this.pool = [];\n\n                // 缓存分好片的文件。\n                this.stack = [];\n\n                // 缓存即将上传的文件。\n                this.pending = [];\n\n                // 跟踪还有多少分片在上传中但是没有完成上传。\n                this.remaning = 0;\n                this.__tick = Base.bindFn( this._tick, this );\n\n                owner.on( 'uploadComplete', function( file ) {\n\n                    // 把其他块取消了。\n                    file.blocks && $.each( file.blocks, function( _, v ) {\n                        v.transport && (v.transport.abort(), v.transport.destroy());\n                        delete v.transport;\n                    });\n\n                    delete file.blocks;\n                    delete file.remaning;\n                });\n            },\n\n            reset: function() {\n                this.request( 'stop-upload', true );\n                this.runing = false;\n                this.pool = [];\n                this.stack = [];\n                this.pending = [];\n                this.remaning = 0;\n                this._trigged = false;\n                this._promise = null;\n            },\n\n            /**\n             * @event startUpload\n             * @description 当开始上传流程时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 开始上传。此方法可以从初始状态调用开始上传流程，也可以从暂停状态调用，继续上传流程。\n             *\n             * 可以指定开始某一个文件。\n             * @grammar upload() => undefined\n             * @grammar upload( file | fileId) => undefined\n             * @method upload\n             * @for  Uploader\n             */\n            startUpload: function(file) {\n                var me = this;\n\n                // 移出invalid的文件\n                $.each( me.request( 'get-files', Status.INVALID ), function() {\n                    me.request( 'remove-file', this );\n                });\n\n                // 如果指定了开始某个文件，则只开始指定文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        $.each( me.pool, function( _, v ) {\n\n                            // 之前暂停过。\n                            if (v.file !== file) {\n                                return;\n                            }\n\n                            v.transport && v.transport.send();\n                        });\n\n                        file.setStatus( Status.QUEUED );\n                    } else if (file.getStatus() === Status.PROGRESS) {\n                        return;\n                    } else {\n                        file.setStatus( Status.QUEUED );\n                    }\n                } else {\n                    $.each( me.request( 'get-files', [ Status.INITED ] ), function() {\n                        this.setStatus( Status.QUEUED );\n                    });\n                }\n\n                if ( me.runing ) {\n                    return;\n                }\n\n                me.runing = true;\n\n                var files = [];\n\n                // 如果有暂停的，则续传\n                $.each( me.pool, function( _, v ) {\n                    var file = v.file;\n\n                    if ( file.getStatus() === Status.INTERRUPT ) {\n                        files.push(file);\n                        me._trigged = false;\n                        v.transport && v.transport.send();\n                    }\n                });\n\n                var file;\n                while ( (file = files.shift()) ) {\n                    file.setStatus( Status.PROGRESS );\n                }\n\n                file || $.each( me.request( 'get-files',\n                        Status.INTERRUPT ), function() {\n                    this.setStatus( Status.PROGRESS );\n                });\n\n                me._trigged = false;\n                Base.nextTick( me.__tick );\n                me.owner.trigger('startUpload');\n            },\n\n            /**\n             * @event stopUpload\n             * @description 当开始上传流程暂停时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 暂停上传。第一个参数为是否中断上传当前正在上传的文件。\n             *\n             * 如果第一个参数是文件，则只暂停指定文件。\n             * @grammar stop() => undefined\n             * @grammar stop( true ) => undefined\n             * @grammar stop( file ) => undefined\n             * @method stop\n             * @for  Uploader\n             */\n            stopUpload: function( file, interrupt ) {\n                var me = this;\n\n                if (file === true) {\n                    interrupt = file;\n                    file = null;\n                }\n\n                if ( me.runing === false ) {\n                    return;\n                }\n\n                // 如果只是暂停某个文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if ( file.getStatus() !== Status.PROGRESS &&\n                            file.getStatus() !== Status.QUEUED ) {\n                        return;\n                    }\n\n                    file.setStatus( Status.INTERRUPT );\n                    $.each( me.pool, function( _, v ) {\n\n                        // 只 abort 指定的文件。\n                        if (v.file !== file) {\n                            return;\n                        }\n\n                        v.transport && v.transport.abort();\n                        me._putback(v);\n                        me._popBlock(v);\n                    });\n\n                    return Base.nextTick( me.__tick );\n                }\n\n                me.runing = false;\n\n                if (this._promise && this._promise.file) {\n                    this._promise.file.setStatus( Status.INTERRUPT );\n                }\n\n                interrupt && $.each( me.pool, function( _, v ) {\n                    v.transport && v.transport.abort();\n                    v.file.setStatus( Status.INTERRUPT );\n                });\n\n                me.owner.trigger('stopUpload');\n            },\n\n            /**\n             * @method cancelFile\n             * @grammar cancelFile( file ) => undefined\n             * @grammar cancelFile( id ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 标记文件状态为已取消, 同时将中断文件传输。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.cancelFile( file );\n             * })\n             */\n            cancelFile: function( file ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                file.setStatus( Status.CANCELLED );\n                this.owner.trigger( 'fileDequeued', file );\n            },\n\n            /**\n             * 判断`Uplaode`r是否正在上传中。\n             * @grammar isInProgress() => Boolean\n             * @method isInProgress\n             * @for  Uploader\n             */\n            isInProgress: function() {\n                return !!this.progress;\n            },\n\n            _getStats: function() {\n                return this.request('get-stats');\n            },\n\n            /**\n             * 掉过一个文件上传，直接标记指定文件为已上传状态。\n             * @grammar skipFile( file ) => undefined\n             * @method skipFile\n             * @for  Uploader\n             */\n            skipFile: function( file, status ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                file.setStatus( status || Status.COMPLETE );\n                file.skipped = true;\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                this.owner.trigger( 'uploadSkip', file );\n            },\n\n            /**\n             * @event uploadFinished\n             * @description 当所有文件上传结束时触发。\n             * @for  Uploader\n             */\n            _tick: function() {\n                var me = this,\n                    opts = me.options,\n                    fn, val;\n\n                // 上一个promise还没有结束，则等待完成后再执行。\n                if ( me._promise ) {\n                    return me._promise.always( me.__tick );\n                }\n\n                // 还有位置，且还有文件要处理的话。\n                if ( me.pool.length < opts.threads && (val = me._nextBlock()) ) {\n                    me._trigged = false;\n\n                    fn = function( val ) {\n                        me._promise = null;\n\n                        // 有可能是reject过来的，所以要检测val的类型。\n                        val && val.file && me._startSend( val );\n                        Base.nextTick( me.__tick );\n                    };\n\n                    me._promise = isPromise( val ) ? val.always( fn ) : fn( val );\n\n                // 没有要上传的了，且没有正在传输的了。\n                } else if ( !me.remaning && !me._getStats().numOfQueue &&\n                    !me._getStats().numofInterrupt ) {\n                    me.runing = false;\n\n                    me._trigged || Base.nextTick(function() {\n                        me.owner.trigger('uploadFinished');\n                    });\n                    me._trigged = true;\n                }\n            },\n\n            _putback: function(block) {\n                var idx;\n\n                block.cuted.unshift(block);\n                idx = this.stack.indexOf(block.cuted);\n\n                if (!~idx) {\n                    this.stack.unshift(block.cuted);\n                }\n            },\n\n            _getStack: function() {\n                var i = 0,\n                    act;\n\n                while ( (act = this.stack[ i++ ]) ) {\n                    if ( act.has() && act.file.getStatus() === Status.PROGRESS ) {\n                        return act;\n                    } else if (!act.has() ||\n                            act.file.getStatus() !== Status.PROGRESS &&\n                            act.file.getStatus() !== Status.INTERRUPT ) {\n\n                        // 把已经处理完了的，或者，状态为非 progress（上传中）、\n                        // interupt（暂停中） 的移除。\n                        this.stack.splice( --i, 1 );\n                    }\n                }\n\n                return null;\n            },\n\n            _nextBlock: function() {\n                var me = this,\n                    opts = me.options,\n                    act, next, done, preparing;\n\n                // 如果当前文件还有没有需要传输的，则直接返回剩下的。\n                if ( (act = this._getStack()) ) {\n\n                    // 是否提前准备下一个文件\n                    if ( opts.prepareNextFile && !me.pending.length ) {\n                        me._prepareNextFile();\n                    }\n\n                    return act.shift();\n\n                // 否则，如果正在运行，则准备下一个文件，并等待完成后返回下个分片。\n                } else if ( me.runing ) {\n\n                    // 如果缓存中有，则直接在缓存中取，没有则去queue中取。\n                    if ( !me.pending.length && me._getStats().numOfQueue ) {\n                        me._prepareNextFile();\n                    }\n\n                    next = me.pending.shift();\n                    done = function( file ) {\n                        if ( !file ) {\n                            return null;\n                        }\n\n                        act = CuteFile( file, opts.chunked ? opts.chunkSize : 0 );\n                        me.stack.push(act);\n                        return act.shift();\n                    };\n\n                    // 文件可能还在prepare中，也有可能已经完全准备好了。\n                    if ( isPromise( next) ) {\n                        preparing = next.file;\n                        next = next[ next.pipe ? 'pipe' : 'then' ]( done );\n                        next.file = preparing;\n                        return next;\n                    }\n\n                    return done( next );\n                }\n            },\n\n\n            /**\n             * @event uploadStart\n             * @param {File} file File对象\n             * @description 某个文件开始上传前触发，一个文件只会触发一次。\n             * @for  Uploader\n             */\n            _prepareNextFile: function() {\n                var me = this,\n                    file = me.request('fetch-file'),\n                    pending = me.pending,\n                    promise;\n\n                if ( file ) {\n                    promise = me.request( 'before-send-file', file, function() {\n\n                        // 有可能文件被skip掉了。文件被skip掉后，状态坑定不是Queued.\n                        if ( file.getStatus() === Status.PROGRESS ||\n                            file.getStatus() === Status.INTERRUPT ) {\n                            return file;\n                        }\n\n                        return me._finishFile( file );\n                    });\n\n                    me.owner.trigger( 'uploadStart', file );\n                    file.setStatus( Status.PROGRESS );\n\n                    promise.file = file;\n\n                    // 如果还在pending中，则替换成文件本身。\n                    promise.done(function() {\n                        var idx = $.inArray( promise, pending );\n\n                        ~idx && pending.splice( idx, 1, file );\n                    });\n\n                    // befeore-send-file的钩子就有错误发生。\n                    promise.fail(function( reason ) {\n                        file.setStatus( Status.ERROR, reason );\n                        me.owner.trigger( 'uploadError', file, reason );\n                        me.owner.trigger( 'uploadComplete', file );\n                    });\n\n                    pending.push( promise );\n                }\n            },\n\n            // 让出位置了，可以让其他分片开始上传\n            _popBlock: function( block ) {\n                var idx = $.inArray( block, this.pool );\n\n                this.pool.splice( idx, 1 );\n                block.file.remaning--;\n                this.remaning--;\n            },\n\n            // 开始上传，可以被掉过。如果promise被reject了，则表示跳过此分片。\n            _startSend: function( block ) {\n                var me = this,\n                    file = block.file,\n                    promise;\n\n                // 有可能在 before-send-file 的 promise 期间改变了文件状态。\n                // 如：暂停，取消\n                // 我们不能中断 promise, 但是可以在 promise 完后，不做上传操作。\n                if ( file.getStatus() !== Status.PROGRESS ) {\n\n                    // 如果是中断，则还需要放回去。\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        me._putback(block);\n                    }\n\n                    return;\n                }\n\n                me.pool.push( block );\n                me.remaning++;\n\n                // 如果没有分片，则直接使用原始的。\n                // 不会丢失content-type信息。\n                block.blob = block.chunks === 1 ? file.source :\n                        file.source.slice( block.start, block.end );\n\n                // hook, 每个分片发送之前可能要做些异步的事情。\n                promise = me.request( 'before-send', block, function() {\n\n                    // 有可能文件已经上传出错了，所以不需要再传输了。\n                    if ( file.getStatus() === Status.PROGRESS ) {\n                        me._doSend( block );\n                    } else {\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n\n                // 如果为fail了，则跳过此分片。\n                promise.fail(function() {\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file ).always(function() {\n                            block.percentage = 1;\n                            me._popBlock( block );\n                            me.owner.trigger( 'uploadComplete', file );\n                            Base.nextTick( me.__tick );\n                        });\n                    } else {\n                        block.percentage = 1;\n                        me.updateFileProgress( file );\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n            },\n\n\n            /**\n             * @event uploadBeforeSend\n             * @param {Object} object\n             * @param {Object} data 默认的上传参数，可以扩展此对象来控制上传参数。\n             * @param {Object} headers 可以扩展此对象来控制上传头部。\n             * @description 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadAccept\n             * @param {Object} object\n             * @param {Object} ret 服务端的返回数据，json格式，如果服务端不是json格式，从ret._raw中取数据，自行解析。\n             * @description 当某个文件上传到服务端响应后，会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为`false`, 则此文件将派送`server`类型的`uploadError`事件。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadProgress\n             * @param {File} file File对象\n             * @param {Number} percentage 上传进度\n             * @description 上传过程中触发，携带上传进度。\n             * @for  Uploader\n             */\n\n\n            /**\n             * @event uploadError\n             * @param {File} file File对象\n             * @param {String} reason 出错的code\n             * @description 当文件上传出错时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadSuccess\n             * @param {File} file File对象\n             * @param {Object} response 服务端返回的数据\n             * @description 当文件上传成功时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadComplete\n             * @param {File} [file] File对象\n             * @description 不管成功或者失败，文件上传完成时触发。\n             * @for  Uploader\n             */\n\n            // 做上传操作。\n            _doSend: function( block ) {\n                var me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    file = block.file,\n                    tr = new Transport( opts ),\n                    data = $.extend({}, opts.formData ),\n                    headers = $.extend({}, opts.headers ),\n                    requestAccept, ret;\n\n                block.transport = tr;\n\n                tr.on( 'destroy', function() {\n                    delete block.transport;\n                    me._popBlock( block );\n                    Base.nextTick( me.__tick );\n                });\n\n                // 广播上传进度。以文件为单位。\n                tr.on( 'progress', function( percentage ) {\n                    block.percentage = percentage;\n                    me.updateFileProgress( file );\n                });\n\n                // 用来询问，是否返回的结果是有错误的。\n                requestAccept = function( reject ) {\n                    var fn;\n\n                    ret = tr.getResponseAsJson() || {};\n                    ret._raw = tr.getResponse();\n                    fn = function( value ) {\n                        reject = value;\n                    };\n\n                    // 服务端响应了，不代表成功了，询问是否响应正确。\n                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {\n                        reject = reject || 'server';\n                    }\n\n                    return reject;\n                };\n\n                // 尝试重试，然后广播文件上传出错。\n                tr.on( 'error', function( type, flag ) {\n                    block.retried = block.retried || 0;\n\n                    // 自动重试\n                    if ( block.chunks > 1 && ~'http,abort'.indexOf( type ) &&\n                            block.retried < opts.chunkRetry ) {\n\n                        block.retried++;\n                        tr.send();\n\n                    } else {\n\n                        // http status 500 ~ 600\n                        if ( !flag && type === 'server' ) {\n                            type = requestAccept( type );\n                        }\n\n                        file.setStatus( Status.ERROR, type );\n                        owner.trigger( 'uploadError', file, type );\n                        owner.trigger( 'uploadComplete', file );\n                    }\n                });\n\n                // 上传成功\n                tr.on( 'load', function() {\n                    var reason;\n\n                    // 如果非预期，转向上传出错。\n                    if ( (reason = requestAccept()) ) {\n                        tr.trigger( 'error', reason, true );\n                        return;\n                    }\n\n                    // 全部上传完成。\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file, ret );\n                    } else {\n                        tr.destroy();\n                    }\n                });\n\n                // 配置默认的上传字段。\n                data = $.extend( data, {\n                    id: file.id,\n                    name: file.name,\n                    type: file.type,\n                    lastModifiedDate: file.lastModifiedDate,\n                    size: file.size\n                });\n\n                block.chunks > 1 && $.extend( data, {\n                    chunks: block.chunks,\n                    chunk: block.chunk\n                });\n\n                // 在发送之间可以添加字段什么的。。。\n                // 如果默认的字段不够使用，可以通过监听此事件来扩展\n                owner.trigger( 'uploadBeforeSend', block, data, headers );\n\n                // 开始发送。\n                tr.appendBlob( opts.fileVal, block.blob, file.name );\n                tr.append( data );\n                tr.setRequestHeader( headers );\n                tr.send();\n            },\n\n            // 完成上传。\n            _finishFile: function( file, ret, hds ) {\n                var owner = this.owner;\n\n                return owner\n                        .request( 'after-send-file', arguments, function() {\n                            file.setStatus( Status.COMPLETE );\n                            owner.trigger( 'uploadSuccess', file, ret, hds );\n                        })\n                        .fail(function( reason ) {\n\n                            // 如果外部已经标记为invalid什么的，不再改状态。\n                            if ( file.getStatus() === Status.PROGRESS ) {\n                                file.setStatus( Status.ERROR, reason );\n                            }\n\n                            owner.trigger( 'uploadError', file, reason );\n                        })\n                        .always(function() {\n                            owner.trigger( 'uploadComplete', file );\n                        });\n            },\n\n            updateFileProgress: function(file) {\n                var totalPercent = 0,\n                    uploaded = 0;\n\n                if (!file.blocks) {\n                    return;\n                }\n\n                $.each( file.blocks, function( _, v ) {\n                    uploaded += (v.percentage || 0) * (v.end - v.start);\n                });\n\n                totalPercent = uploaded / file.size;\n                this.owner.trigger( 'uploadProgress', file, totalPercent || 0 );\n            }\n\n        });\n    });\n    /**\n     * @fileOverview 各种验证，包括文件总大小是否超出、单文件是否超出和文件是否重复。\n     */\n\n    define('widgets/validator',[\n        'base',\n        'uploader',\n        'file',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile ) {\n\n        var $ = Base.$,\n            validators = {},\n            api;\n\n        /**\n         * @event error\n         * @param {String} type 错误类型。\n         * @description 当validate不通过时，会以派送错误事件的形式通知调用者。通过`upload.on('error', handler)`可以捕获到此类错误，目前有以下错误会在特定的情况下派送错来。\n         *\n         * * `Q_EXCEED_NUM_LIMIT` 在设置了`fileNumLimit`且尝试给`uploader`添加的文件数量超出这个值时派送。\n         * * `Q_EXCEED_SIZE_LIMIT` 在设置了`Q_EXCEED_SIZE_LIMIT`且尝试给`uploader`添加的文件总大小超出这个值时派送。\n         * * `Q_TYPE_DENIED` 当文件类型不满足时触发。。\n         * @for  Uploader\n         */\n\n        // 暴露给外面的api\n        api = {\n\n            // 添加验证器\n            addValidator: function( type, cb ) {\n                validators[ type ] = cb;\n            },\n\n            // 移除验证器\n            removeValidator: function( type ) {\n                delete validators[ type ];\n            }\n        };\n\n        // 在Uploader初始化的时候启动Validators的初始化\n        Uploader.register({\n            name: 'validator',\n\n            init: function() {\n                var me = this;\n                Base.nextTick(function() {\n                    $.each( validators, function() {\n                        this.call( me.owner );\n                    });\n                });\n            }\n        });\n\n        /**\n         * @property {int} [fileNumLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总数量, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileNumLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileNumLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( count >= max && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_NUM_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return count >= max ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function() {\n                count++;\n            });\n\n            uploader.on( 'fileDequeued', function() {\n                count--;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n\n        /**\n         * @property {int} [fileSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileSizeLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var invalid = count + file.size > max;\n\n                if ( invalid && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_SIZE_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return invalid ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                count += file.size;\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                count -= file.size;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n        /**\n         * @property {int} [fileSingleSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证单个文件大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSingleSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                max = opts.fileSingleSizeLimit;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( file.size > max ) {\n                    file.setStatus( WUFile.Status.INVALID, 'exceed_size' );\n                    this.trigger( 'error', 'F_EXCEED_SIZE', max, file );\n                    return false;\n                }\n\n            });\n\n        });\n\n        /**\n         * @property {Boolean} [duplicate=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 去重， 根据文件名字、文件大小和最后修改时间来生成hash Key.\n         */\n        api.addValidator( 'duplicate', function() {\n            var uploader = this,\n                opts = uploader.options,\n                mapping = {};\n\n            if ( opts.duplicate ) {\n                return;\n            }\n\n            function hashString( str ) {\n                var hash = 0,\n                    i = 0,\n                    len = str.length,\n                    _char;\n\n                for ( ; i < len; i++ ) {\n                    _char = str.charCodeAt( i );\n                    hash = _char + (hash << 6) + (hash << 16) - hash;\n                }\n\n                return hash;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var hash = file.__hash || (file.__hash = hashString( file.name +\n                        file.size + file.lastModifiedDate ));\n\n                // 已经重复了\n                if ( mapping[ hash ] ) {\n                    this.trigger( 'error', 'F_DUPLICATE', file );\n                    return false;\n                }\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (mapping[ hash ] = true);\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (delete mapping[ hash ]);\n            });\n\n            uploader.on( 'reset', function() {\n                mapping = {};\n            });\n        });\n\n        return api;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/compbase',[],function() {\n\n        function CompBase( owner, runtime ) {\n\n            this.owner = owner;\n            this.options = owner.options;\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.getRuid = function() {\n                return runtime.uid;\n            };\n\n            this.trigger = function() {\n                return owner.trigger.apply( owner, arguments );\n            };\n        }\n\n        return CompBase;\n    });\n    /**\n     * @fileOverview Html5Runtime\n     */\n    define('runtime/html5/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var type = 'html5',\n            components = {};\n\n        function Html5Runtime() {\n            var pool = {},\n                me = this,\n                destroy = this.destroy;\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                if ( components[ comp ] ) {\n                    instance = pool[ uid ] = pool[ uid ] ||\n                            new components[ comp ]( client, me );\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n            };\n\n            me.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n        }\n\n        Base.inherits( Runtime, {\n            constructor: Html5Runtime,\n\n            // 不需要连接其他程序，直接执行callback\n            init: function() {\n                var me = this;\n                setTimeout(function() {\n                    me.trigger('ready');\n                }, 1 );\n            }\n\n        });\n\n        // 注册Components\n        Html5Runtime.register = function( name, component ) {\n            var klass = components[ name ] = Base.inherits( CompBase, component );\n            return klass;\n        };\n\n        // 注册html5运行时。\n        // 只有在支持的前提下注册。\n        if ( window.Blob && window.FileReader && window.DataView ) {\n            Runtime.addRuntime( type, Html5Runtime );\n        }\n\n        return Html5Runtime;\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/html5/blob',[\n        'runtime/html5/runtime',\n        'lib/blob'\n    ], function( Html5Runtime, Blob ) {\n\n        return Html5Runtime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.owner.source,\n                    slice = blob.slice || blob.webkitSlice || blob.mozSlice;\n\n                blob = slice.call( blob, start, end );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/dnd',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        var $ = Base.$,\n            prefix = 'webuploader-dnd-';\n\n        return Html5Runtime.register( 'DragAndDrop', {\n            init: function() {\n                var elem = this.elem = this.options.container;\n\n                this.dragEnterHandler = Base.bindFn( this._dragEnterHandler, this );\n                this.dragOverHandler = Base.bindFn( this._dragOverHandler, this );\n                this.dragLeaveHandler = Base.bindFn( this._dragLeaveHandler, this );\n                this.dropHandler = Base.bindFn( this._dropHandler, this );\n                this.dndOver = false;\n\n                elem.on( 'dragenter', this.dragEnterHandler );\n                elem.on( 'dragover', this.dragOverHandler );\n                elem.on( 'dragleave', this.dragLeaveHandler );\n                elem.on( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).on( 'dragover', this.dragOverHandler );\n                    $( document ).on( 'drop', this.dropHandler );\n                }\n            },\n\n            _dragEnterHandler: function( e ) {\n                var me = this,\n                    denied = me._denied || false,\n                    items;\n\n                e = e.originalEvent || e;\n\n                if ( !me.dndOver ) {\n                    me.dndOver = true;\n\n                    // 注意只有 chrome 支持。\n                    items = e.dataTransfer.items;\n\n                    if ( items && items.length ) {\n                        me._denied = denied = !me.trigger( 'accept', items );\n                    }\n\n                    me.elem.addClass( prefix + 'over' );\n                    me.elem[ denied ? 'addClass' :\n                            'removeClass' ]( prefix + 'denied' );\n                }\n\n                e.dataTransfer.dropEffect = denied ? 'none' : 'copy';\n\n                return false;\n            },\n\n            _dragOverHandler: function( e ) {\n                // 只处理框内的。\n                var parentElem = this.elem.parent().get( 0 );\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                clearTimeout( this._leaveTimer );\n                this._dragEnterHandler.call( this, e );\n\n                return false;\n            },\n\n            _dragLeaveHandler: function() {\n                var me = this,\n                    handler;\n\n                handler = function() {\n                    me.dndOver = false;\n                    me.elem.removeClass( prefix + 'over ' + prefix + 'denied' );\n                };\n\n                clearTimeout( me._leaveTimer );\n                me._leaveTimer = setTimeout( handler, 100 );\n                return false;\n            },\n\n            _dropHandler: function( e ) {\n                var me = this,\n                    ruid = me.getRuid(),\n                    parentElem = me.elem.parent().get( 0 ),\n                    dataTransfer, data;\n\n                // 只处理框内的。\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                e = e.originalEvent || e;\n                dataTransfer = e.dataTransfer;\n\n                // 如果是页面内拖拽，还不能处理，不阻止事件。\n                // 此处 ie11 下会报参数错误，\n                try {\n                    data = dataTransfer.getData('text/html');\n                } catch( err ) {\n                }\n\n                if ( data ) {\n                    return;\n                }\n\n                me._getTansferFiles( dataTransfer, function( results ) {\n                    me.trigger( 'drop', $.map( results, function( file ) {\n                        return new File( ruid, file );\n                    }) );\n                });\n\n                me.dndOver = false;\n                me.elem.removeClass( prefix + 'over' );\n                return false;\n            },\n\n            // 如果传入 callback 则去查看文件夹，否则只管当前文件夹。\n            _getTansferFiles: function( dataTransfer, callback ) {\n                var results  = [],\n                    promises = [],\n                    items, files, file, item, i, len, canAccessFolder;\n\n                items = dataTransfer.items;\n                files = dataTransfer.files;\n\n                canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);\n\n                for ( i = 0, len = files.length; i < len; i++ ) {\n                    file = files[ i ];\n                    item = items && items[ i ];\n\n                    if ( canAccessFolder && item.webkitGetAsEntry().isDirectory ) {\n\n                        promises.push( this._traverseDirectoryTree(\n                                item.webkitGetAsEntry(), results ) );\n                    } else {\n                        results.push( file );\n                    }\n                }\n\n                Base.when.apply( Base, promises ).done(function() {\n\n                    if ( !results.length ) {\n                        return;\n                    }\n\n                    callback( results );\n                });\n            },\n\n            _traverseDirectoryTree: function( entry, results ) {\n                var deferred = Base.Deferred(),\n                    me = this;\n\n                if ( entry.isFile ) {\n                    entry.file(function( file ) {\n                        results.push( file );\n                        deferred.resolve();\n                    });\n                } else if ( entry.isDirectory ) {\n                    entry.createReader().readEntries(function( entries ) {\n                        var len = entries.length,\n                            promises = [],\n                            arr = [],    // 为了保证顺序。\n                            i;\n\n                        for ( i = 0; i < len; i++ ) {\n                            promises.push( me._traverseDirectoryTree(\n                                    entries[ i ], arr ) );\n                        }\n\n                        Base.when.apply( Base, promises ).then(function() {\n                            results.push.apply( results, arr );\n                            deferred.resolve();\n                        }, deferred.reject );\n                    });\n                }\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                var elem = this.elem;\n\n                // 还没 init 就调用 destroy\n                if (!elem) {\n                    return;\n                }\n\n                elem.off( 'dragenter', this.dragEnterHandler );\n                elem.off( 'dragover', this.dragOverHandler );\n                elem.off( 'dragleave', this.dragLeaveHandler );\n                elem.off( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).off( 'dragover', this.dragOverHandler );\n                    $( document ).off( 'drop', this.dropHandler );\n                }\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/filepaste',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        return Html5Runtime.register( 'FilePaste', {\n            init: function() {\n                var opts = this.options,\n                    elem = this.elem = opts.container,\n                    accept = '.*',\n                    arr, i, len, item;\n\n                // accetp的mimeTypes中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].mimeTypes;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = arr.join(',');\n                        accept = accept.replace( /,/g, '|' ).replace( /\\*/g, '.*' );\n                    }\n                }\n                this.accept = accept = new RegExp( accept, 'i' );\n                this.hander = Base.bindFn( this._pasteHander, this );\n                elem.on( 'paste', this.hander );\n            },\n\n            _pasteHander: function( e ) {\n                var allowed = [],\n                    ruid = this.getRuid(),\n                    items, item, blob, i, len;\n\n                e = e.originalEvent || e;\n                items = e.clipboardData.items;\n\n                for ( i = 0, len = items.length; i < len; i++ ) {\n                    item = items[ i ];\n\n                    if ( item.kind !== 'file' || !(blob = item.getAsFile()) ) {\n                        continue;\n                    }\n\n                    allowed.push( new File( ruid, blob ) );\n                }\n\n                if ( allowed.length ) {\n                    // 不阻止非文件粘贴（文字粘贴）的事件冒泡\n                    e.preventDefault();\n                    e.stopPropagation();\n                    this.trigger( 'paste', allowed );\n                }\n            },\n\n            destroy: function() {\n                this.elem.off( 'paste', this.hander );\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/html5/filepicker',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var $ = Base.$;\n\n        return Html5Runtime.register( 'FilePicker', {\n            init: function() {\n                var container = this.getRuntime().getContainer(),\n                    me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    label = this.label = $( document.createElement('label') ),\n                    input =  this.input = $( document.createElement('input') ),\n                    arr, i, len, mouseHandler;\n\n                input.attr( 'type', 'file' );\n                input.attr( 'name', opts.name );\n                input.addClass('webuploader-element-invisible');\n\n                label.on( 'click', function() {\n                    input.trigger('click');\n                });\n\n                label.css({\n                    opacity: 0,\n                    width: '100%',\n                    height: '100%',\n                    display: 'block',\n                    cursor: 'pointer',\n                    background: '#ffffff'\n                });\n\n                if ( opts.multiple ) {\n                    input.attr( 'multiple', 'multiple' );\n                }\n\n                // @todo Firefox不支持单独指定后缀\n                if ( opts.accept && opts.accept.length > 0 ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        arr.push( opts.accept[ i ].mimeTypes );\n                    }\n\n                    input.attr( 'accept', arr.join(',') );\n                }\n\n                container.append( input );\n                container.append( label );\n\n                mouseHandler = function( e ) {\n                    owner.trigger( e.type );\n                };\n\n                input.on( 'change', function( e ) {\n                    var fn = arguments.callee,\n                        clone;\n\n                    me.files = e.target.files;\n\n                    // reset input\n                    clone = this.cloneNode( true );\n                    clone.value = null;\n                    this.parentNode.replaceChild( clone, this );\n\n                    input.off();\n                    input = $( clone ).on( 'change', fn )\n                            .on( 'mouseenter mouseleave', mouseHandler );\n\n                    owner.trigger('change');\n                });\n\n                label.on( 'mouseenter mouseleave', mouseHandler );\n\n            },\n\n\n            getFiles: function() {\n                return this.files;\n            },\n\n            destroy: function() {\n                this.input.off();\n                this.label.off();\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     * @todo 支持chunked传输，优势：\n     * 可以将大文件分成小块，挨个传输，可以提高大文件成功率，当失败的时候，也只需要重传那小部分，\n     * 而不需要重头再传一次。另外断点续传也需要用chunked方式。\n     */\n    define('runtime/html5/transport',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var noop = Base.noop,\n            $ = Base.$;\n\n        return Html5Runtime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    formData, binary, fr;\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.getSource();\n                } else {\n                    formData = new FormData();\n                    $.each( owner._formData, function( k, v ) {\n                        formData.append( k, v );\n                    });\n\n                    formData.append( opts.fileVal, blob.getSource(),\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                if ( opts.withCredentials && 'withCredentials' in xhr ) {\n                    xhr.open( opts.method, server, true );\n                    xhr.withCredentials = true;\n                } else {\n                    xhr.open( opts.method, server );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n\n                if ( binary ) {\n                    // 强制设置成 content-type 为文件流。\n                    xhr.overrideMimeType &&\n                            xhr.overrideMimeType('application/octet-stream');\n\n                    // android直接发送blob会导致服务端接收到的是空文件。\n                    // bug详情。\n                    // https://code.google.com/p/android/issues/detail?id=39882\n                    // 所以先用fileReader读取出来再通过arraybuffer的方式发送。\n                    if ( Base.os.android ) {\n                        fr = new FileReader();\n\n                        fr.onload = function() {\n                            xhr.send( this.result );\n                            fr = fr.onload = null;\n                        };\n\n                        fr.readAsArrayBuffer( binary );\n                    } else {\n                        xhr.send( binary );\n                    }\n                } else {\n                    xhr.send( formData );\n                }\n            },\n\n            getResponse: function() {\n                return this._response;\n            },\n\n            getResponseAsJson: function() {\n                return this._parseJson( this._response );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    xhr.abort();\n\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new XMLHttpRequest(),\n                    opts = this.options;\n\n                if ( opts.withCredentials && !('withCredentials' in xhr) &&\n                        typeof XDomainRequest !== 'undefined' ) {\n                    xhr = new XDomainRequest();\n                }\n\n                xhr.upload.onprogress = function( e ) {\n                    var percentage = 0;\n\n                    if ( e.lengthComputable ) {\n                        percentage = e.loaded / e.total;\n                    }\n\n                    return me.trigger( 'progress', percentage );\n                };\n\n                xhr.onreadystatechange = function() {\n\n                    if ( xhr.readyState !== 4 ) {\n                        return;\n                    }\n\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    me._xhr = null;\n                    me._status = xhr.status;\n\n                    if ( xhr.status >= 200 && xhr.status < 300 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger('load');\n                    } else if ( xhr.status >= 500 && xhr.status < 600 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger( 'error', 'server' );\n                    }\n\n\n                    return me.trigger( 'error', me._status ? 'http' : 'abort' );\n                };\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.setRequestHeader( key, val );\n                });\n            },\n\n            _parseJson: function( str ) {\n                var json;\n\n                try {\n                    json = JSON.parse( str );\n                } catch ( ex ) {\n                    json = {};\n                }\n\n                return json;\n            }\n        });\n    });\n    /**\n     * @fileOverview FlashRuntime\n     */\n    define('runtime/flash/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var $ = Base.$,\n            type = 'flash',\n            components = {};\n\n\n        function getFlashVersion() {\n            var version;\n\n            try {\n                version = navigator.plugins[ 'Shockwave Flash' ];\n                version = version.description;\n            } catch ( ex ) {\n                try {\n                    version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')\n                            .GetVariable('$version');\n                } catch ( ex2 ) {\n                    version = '0.0';\n                }\n            }\n            version = version.match( /\\d+/g );\n            return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 );\n        }\n\n        function FlashRuntime() {\n            var pool = {},\n                clients = {},\n                destroy = this.destroy,\n                me = this,\n                jsreciver = Base.guid('webuploader_');\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/ ) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                clients[ uid ] = client;\n\n                if ( components[ comp ] ) {\n                    if ( !pool[ uid ] ) {\n                        pool[ uid ] = new components[ comp ]( client, me );\n                    }\n\n                    instance = pool[ uid ];\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n\n                return me.flashExec.apply( client, arguments );\n            };\n\n            function handler( evt, obj ) {\n                var type = evt.type || evt,\n                    parts, uid;\n\n                parts = type.split('::');\n                uid = parts[ 0 ];\n                type = parts[ 1 ];\n\n                // console.log.apply( console, arguments );\n\n                if ( type === 'Ready' && uid === me.uid ) {\n                    me.trigger('ready');\n                } else if ( clients[ uid ] ) {\n                    clients[ uid ].trigger( type.toLowerCase(), evt, obj );\n                }\n\n                // Base.log( evt, obj );\n            }\n\n            // flash的接受器。\n            window[ jsreciver ] = function() {\n                var args = arguments;\n\n                // 为了能捕获得到。\n                setTimeout(function() {\n                    handler.apply( null, args );\n                }, 1 );\n            };\n\n            this.jsreciver = jsreciver;\n\n            this.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n\n            this.flashExec = function( comp, fn ) {\n                var flash = me.getFlash(),\n                    args = Base.slice( arguments, 2 );\n\n                return flash.exec( this.uid, comp, fn, args );\n            };\n\n            // @todo\n        }\n\n        Base.inherits( Runtime, {\n            constructor: FlashRuntime,\n\n            init: function() {\n                var container = this.getContainer(),\n                    opts = this.options,\n                    html;\n\n                // if not the minimal height, shims are not initialized\n                // in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)\n                container.css({\n                    position: 'absolute',\n                    top: '-8px',\n                    left: '-8px',\n                    width: '9px',\n                    height: '9px',\n                    overflow: 'hidden'\n                });\n\n                // insert flash object\n                html = '<object id=\"' + this.uid + '\" type=\"application/' +\n                        'x-shockwave-flash\" data=\"' +  opts.swf + '\" ';\n\n                if ( Base.browser.ie ) {\n                    html += 'classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" ';\n                }\n\n                html += 'width=\"100%\" height=\"100%\" style=\"outline:0\">'  +\n                    '<param name=\"movie\" value=\"' + opts.swf + '\" />' +\n                    '<param name=\"flashvars\" value=\"uid=' + this.uid +\n                    '&jsreciver=' + this.jsreciver + '\" />' +\n                    '<param name=\"wmode\" value=\"transparent\" />' +\n                    '<param name=\"allowscriptaccess\" value=\"always\" />' +\n                '</object>';\n\n                container.html( html );\n            },\n\n            getFlash: function() {\n                if ( this._flash ) {\n                    return this._flash;\n                }\n\n                this._flash = $( '#' + this.uid ).get( 0 );\n                return this._flash;\n            }\n\n        });\n\n        FlashRuntime.register = function( name, component ) {\n            component = components[ name ] = Base.inherits( CompBase, $.extend({\n\n                // @todo fix this later\n                flashExec: function() {\n                    var owner = this.owner,\n                        runtime = this.getRuntime();\n\n                    return runtime.flashExec.apply( owner, arguments );\n                }\n            }, component ) );\n\n            return component;\n        };\n\n        if ( getFlashVersion() >= 11.4 ) {\n            Runtime.addRuntime( type, FlashRuntime );\n        }\n\n        return FlashRuntime;\n    });\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/flash/filepicker',[\n        'base',\n        'runtime/flash/runtime'\n    ], function( Base, FlashRuntime ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'FilePicker', {\n            init: function( opts ) {\n                var copy = $.extend({}, opts ),\n                    len, i;\n\n                // 修复Flash再没有设置title的情况下无法弹出flash文件选择框的bug.\n                len = copy.accept && copy.accept.length;\n                for (  i = 0; i < len; i++ ) {\n                    if ( !copy.accept[ i ].title ) {\n                        copy.accept[ i ].title = 'Files';\n                    }\n                }\n\n                delete copy.button;\n                delete copy.id;\n                delete copy.container;\n\n                this.flashExec( 'FilePicker', 'init', copy );\n            },\n\n            destroy: function() {\n                this.flashExec( 'FilePicker', 'destroy' );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/flash/transport',[\n        'base',\n        'runtime/flash/runtime',\n        'runtime/client'\n    ], function( Base, FlashRuntime, RuntimeClient ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n                this._responseJson = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    binary;\n\n                xhr.connectRuntime( blob.ruid );\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.uid;\n                } else {\n                    $.each( owner._formData, function( k, v ) {\n                        xhr.exec( 'append', k, v );\n                    });\n\n                    xhr.exec( 'appendBlob', opts.fileVal, blob.uid,\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n                xhr.exec( 'send', {\n                    method: opts.method,\n                    url: server,\n                    forceURLStream: opts.forceURLStream,\n                    mimeType: 'application/octet-stream'\n                }, binary );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            getResponse: function() {\n                return this._response || '';\n            },\n\n            getResponseAsJson: function() {\n                return this._responseJson;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.exec('abort');\n                    xhr.destroy();\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new RuntimeClient('XMLHttpRequest');\n\n                xhr.on( 'uploadprogress progress', function( e ) {\n                    var percent = e.loaded / e.total;\n                    percent = Math.min( 1, Math.max( 0, percent ) );\n                    return me.trigger( 'progress', percent );\n                });\n\n                xhr.on( 'load', function() {\n                    var status = xhr.exec('getStatus'),\n                        readBody = false,\n                        err = '',\n                        p;\n\n                    xhr.off();\n                    me._xhr = null;\n\n                    if ( status >= 200 && status < 300 ) {\n                        readBody = true;\n                    } else if ( status >= 500 && status < 600 ) {\n                        readBody = true;\n                        err = 'server';\n                    } else {\n                        err = 'http';\n                    }\n\n                    if ( readBody ) {\n                        me._response = xhr.exec('getResponse');\n                        me._response = decodeURIComponent( me._response );\n\n                        // flash 处理可能存在 bug, 没辙只能靠 js 了\n                        // try {\n                        //     me._responseJson = xhr.exec('getResponseAsJson');\n                        // } catch ( error ) {\n\n                        p = window.JSON && window.JSON.parse || function( s ) {\n                            try {\n                                return new Function('return ' + s).call();\n                            } catch ( err ) {\n                                return {};\n                            }\n                        };\n                        me._responseJson  = me._response ? p(me._response) : {};\n\n                        // }\n                    }\n\n                    xhr.destroy();\n                    xhr = null;\n\n                    return err ? me.trigger( 'error', err ) : me.trigger('load');\n                });\n\n                xhr.on( 'error', function() {\n                    xhr.off();\n                    me._xhr = null;\n                    me.trigger( 'error', 'http' );\n                });\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.exec( 'setRequestHeader', key, val );\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/flash/blob',[\n        'runtime/flash/runtime',\n        'lib/blob'\n    ], function( FlashRuntime, Blob ) {\n\n        return FlashRuntime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.flashExec( 'Blob', 'slice', start, end );\n\n                return new Blob( blob.uid, blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview 没有图像处理的版本。\n     */\n    define('preset/withoutimage',[\n        'base',\n\n        // widgets\n        'widgets/filednd',\n        'widgets/filepaste',\n        'widgets/filepicker',\n        'widgets/queue',\n        'widgets/runtime',\n        'widgets/upload',\n        'widgets/validator',\n\n        // runtimes\n        // html5\n        'runtime/html5/blob',\n        'runtime/html5/dnd',\n        'runtime/html5/filepaste',\n        'runtime/html5/filepicker',\n        'runtime/html5/transport',\n\n        // flash\n        'runtime/flash/filepicker',\n        'runtime/flash/transport',\n        'runtime/flash/blob'\n    ], function( Base ) {\n        return Base;\n    });\n    define('webuploader',[\n        'preset/withoutimage'\n    ], function( preset ) {\n        return preset;\n    });\n    return require('webuploader');\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.nolog.js",
    "content": "/*! WebUploader 0.1.5 */\n\n\n/**\n * @fileOverview 让内部各个部件的代码可以用[amd](https://github.com/amdjs/amdjs-api/wiki/AMD)模块定义方式组织起来。\n *\n * AMD API 内部的简单不完全实现，请忽略。只有当WebUploader被合并成一个文件的时候才会引入。\n */\n(function( root, factory ) {\n    var modules = {},\n\n        // 内部require, 简单不完全实现。\n        // https://github.com/amdjs/amdjs-api/wiki/require\n        _require = function( deps, callback ) {\n            var args, len, i;\n\n            // 如果deps不是数组，则直接返回指定module\n            if ( typeof deps === 'string' ) {\n                return getModule( deps );\n            } else {\n                args = [];\n                for( len = deps.length, i = 0; i < len; i++ ) {\n                    args.push( getModule( deps[ i ] ) );\n                }\n\n                return callback.apply( null, args );\n            }\n        },\n\n        // 内部define，暂时不支持不指定id.\n        _define = function( id, deps, factory ) {\n            if ( arguments.length === 2 ) {\n                factory = deps;\n                deps = null;\n            }\n\n            _require( deps || [], function() {\n                setModule( id, factory, arguments );\n            });\n        },\n\n        // 设置module, 兼容CommonJs写法。\n        setModule = function( id, factory, args ) {\n            var module = {\n                    exports: factory\n                },\n                returned;\n\n            if ( typeof factory === 'function' ) {\n                args.length || (args = [ _require, module.exports, module ]);\n                returned = factory.apply( null, args );\n                returned !== undefined && (module.exports = returned);\n            }\n\n            modules[ id ] = module.exports;\n        },\n\n        // 根据id获取module\n        getModule = function( id ) {\n            var module = modules[ id ] || root[ id ];\n\n            if ( !module ) {\n                throw new Error( '`' + id + '` is undefined' );\n            }\n\n            return module;\n        },\n\n        // 将所有modules，将路径ids装换成对象。\n        exportsTo = function( obj ) {\n            var key, host, parts, part, last, ucFirst;\n\n            // make the first character upper case.\n            ucFirst = function( str ) {\n                return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 ));\n            };\n\n            for ( key in modules ) {\n                host = obj;\n\n                if ( !modules.hasOwnProperty( key ) ) {\n                    continue;\n                }\n\n                parts = key.split('/');\n                last = ucFirst( parts.pop() );\n\n                while( (part = ucFirst( parts.shift() )) ) {\n                    host[ part ] = host[ part ] || {};\n                    host = host[ part ];\n                }\n\n                host[ last ] = modules[ key ];\n            }\n\n            return obj;\n        },\n\n        makeExport = function( dollar ) {\n            root.__dollar = dollar;\n\n            // exports every module.\n            return exportsTo( factory( root, _define, _require ) );\n        },\n\n        origin;\n\n    if ( typeof module === 'object' && typeof module.exports === 'object' ) {\n\n        // For CommonJS and CommonJS-like environments where a proper window is present,\n        module.exports = makeExport();\n    } else if ( typeof define === 'function' && define.amd ) {\n\n        // Allow using this built library as an AMD module\n        // in another project. That other project will only\n        // see this AMD call, not the internal modules in\n        // the closure below.\n        define([ 'jquery' ], makeExport );\n    } else {\n\n        // Browser globals case. Just assign the\n        // result to a property on the global.\n        origin = root.WebUploader;\n        root.WebUploader = makeExport();\n        root.WebUploader.noConflict = function() {\n            root.WebUploader = origin;\n        };\n    }\n})( window, function( window, define, require ) {\n\n\n    /**\n     * @fileOverview jQuery or Zepto\n     */\n    define('dollar-third',[],function() {\n        var $ = window.__dollar || window.jQuery || window.Zepto;\n\n        if ( !$ ) {\n            throw new Error('jQuery or Zepto not found!');\n        }\n\n        return $;\n    });\n    /**\n     * @fileOverview Dom 操作相关\n     */\n    define('dollar',[\n        'dollar-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 使用jQuery的Promise\n     */\n    define('promise-third',[\n        'dollar'\n    ], function( $ ) {\n        return {\n            Deferred: $.Deferred,\n            when: $.when,\n\n            isPromise: function( anything ) {\n                return anything && typeof anything.then === 'function';\n            }\n        };\n    });\n    /**\n     * @fileOverview Promise/A+\n     */\n    define('promise',[\n        'promise-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 基础类方法。\n     */\n\n    /**\n     * Web Uploader内部类的详细说明，以下提及的功能类，都可以在`WebUploader`这个变量中访问到。\n     *\n     * As you know, Web Uploader的每个文件都是用过[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)规范中的`define`组织起来的, 每个Module都会有个module id.\n     * 默认module id为该文件的路径，而此路径将会转化成名字空间存放在WebUploader中。如：\n     *\n     * * module `base`：WebUploader.Base\n     * * module `file`: WebUploader.File\n     * * module `lib/dnd`: WebUploader.Lib.Dnd\n     * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd\n     *\n     *\n     * 以下文档中对类的使用可能省略掉了`WebUploader`前缀。\n     * @module WebUploader\n     * @title WebUploader API文档\n     */\n    define('base',[\n        'dollar',\n        'promise'\n    ], function( $, promise ) {\n\n        var noop = function() {},\n            call = Function.call;\n\n        // http://jsperf.com/uncurrythis\n        // 反科里化\n        function uncurryThis( fn ) {\n            return function() {\n                return call.apply( fn, arguments );\n            };\n        }\n\n        function bindFn( fn, context ) {\n            return function() {\n                return fn.apply( context, arguments );\n            };\n        }\n\n        function createObject( proto ) {\n            var f;\n\n            if ( Object.create ) {\n                return Object.create( proto );\n            } else {\n                f = function() {};\n                f.prototype = proto;\n                return new f();\n            }\n        }\n\n\n        /**\n         * 基础类，提供一些简单常用的方法。\n         * @class Base\n         */\n        return {\n\n            /**\n             * @property {String} version 当前版本号。\n             */\n            version: '0.1.5',\n\n            /**\n             * @property {jQuery|Zepto} $ 引用依赖的jQuery或者Zepto对象。\n             */\n            $: $,\n\n            Deferred: promise.Deferred,\n\n            isPromise: promise.isPromise,\n\n            when: promise.when,\n\n            /**\n             * @description  简单的浏览器检查结果。\n             *\n             * * `webkit`  webkit版本号，如果浏览器为非webkit内核，此属性为`undefined`。\n             * * `chrome`  chrome浏览器版本号，如果浏览器为chrome，此属性为`undefined`。\n             * * `ie`  ie浏览器版本号，如果浏览器为非ie，此属性为`undefined`。**暂不支持ie10+**\n             * * `firefox`  firefox浏览器版本号，如果浏览器为非firefox，此属性为`undefined`。\n             * * `safari`  safari浏览器版本号，如果浏览器为非safari，此属性为`undefined`。\n             * * `opera`  opera浏览器版本号，如果浏览器为非opera，此属性为`undefined`。\n             *\n             * @property {Object} [browser]\n             */\n            browser: (function( ua ) {\n                var ret = {},\n                    webkit = ua.match( /WebKit\\/([\\d.]+)/ ),\n                    chrome = ua.match( /Chrome\\/([\\d.]+)/ ) ||\n                        ua.match( /CriOS\\/([\\d.]+)/ ),\n\n                    ie = ua.match( /MSIE\\s([\\d\\.]+)/ ) ||\n                        ua.match( /(?:trident)(?:.*rv:([\\w.]+))?/i ),\n                    firefox = ua.match( /Firefox\\/([\\d.]+)/ ),\n                    safari = ua.match( /Safari\\/([\\d.]+)/ ),\n                    opera = ua.match( /OPR\\/([\\d.]+)/ );\n\n                webkit && (ret.webkit = parseFloat( webkit[ 1 ] ));\n                chrome && (ret.chrome = parseFloat( chrome[ 1 ] ));\n                ie && (ret.ie = parseFloat( ie[ 1 ] ));\n                firefox && (ret.firefox = parseFloat( firefox[ 1 ] ));\n                safari && (ret.safari = parseFloat( safari[ 1 ] ));\n                opera && (ret.opera = parseFloat( opera[ 1 ] ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * @description  操作系统检查结果。\n             *\n             * * `android`  如果在android浏览器环境下，此值为对应的android版本号，否则为`undefined`。\n             * * `ios` 如果在ios浏览器环境下，此值为对应的ios版本号，否则为`undefined`。\n             * @property {Object} [os]\n             */\n            os: (function( ua ) {\n                var ret = {},\n\n                    // osx = !!ua.match( /\\(Macintosh\\; Intel / ),\n                    android = ua.match( /(?:Android);?[\\s\\/]+([\\d.]+)?/ ),\n                    ios = ua.match( /(?:iPad|iPod|iPhone).*OS\\s([\\d_]+)/ );\n\n                // osx && (ret.osx = true);\n                android && (ret.android = parseFloat( android[ 1 ] ));\n                ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * 实现类与类之间的继承。\n             * @method inherits\n             * @grammar Base.inherits( super ) => child\n             * @grammar Base.inherits( super, protos ) => child\n             * @grammar Base.inherits( super, protos, statics ) => child\n             * @param  {Class} super 父类\n             * @param  {Object | Function} [protos] 子类或者对象。如果对象中包含constructor，子类将是用此属性值。\n             * @param  {Function} [protos.constructor] 子类构造器，不指定的话将创建个临时的直接执行父类构造器的方法。\n             * @param  {Object} [statics] 静态属性或方法。\n             * @return {Class} 返回子类。\n             * @example\n             * function Person() {\n             *     console.log( 'Super' );\n             * }\n             * Person.prototype.hello = function() {\n             *     console.log( 'hello' );\n             * };\n             *\n             * var Manager = Base.inherits( Person, {\n             *     world: function() {\n             *         console.log( 'World' );\n             *     }\n             * });\n             *\n             * // 因为没有指定构造器，父类的构造器将会执行。\n             * var instance = new Manager();    // => Super\n             *\n             * // 继承子父类的方法\n             * instance.hello();    // => hello\n             * instance.world();    // => World\n             *\n             * // 子类的__super__属性指向父类\n             * console.log( Manager.__super__ === Person );    // => true\n             */\n            inherits: function( Super, protos, staticProtos ) {\n                var child;\n\n                if ( typeof protos === 'function' ) {\n                    child = protos;\n                    protos = null;\n                } else if ( protos && protos.hasOwnProperty('constructor') ) {\n                    child = protos.constructor;\n                } else {\n                    child = function() {\n                        return Super.apply( this, arguments );\n                    };\n                }\n\n                // 复制静态方法\n                $.extend( true, child, Super, staticProtos || {} );\n\n                /* jshint camelcase: false */\n\n                // 让子类的__super__属性指向父类。\n                child.__super__ = Super.prototype;\n\n                // 构建原型，添加原型方法或属性。\n                // 暂时用Object.create实现。\n                child.prototype = createObject( Super.prototype );\n                protos && $.extend( true, child.prototype, protos );\n\n                return child;\n            },\n\n            /**\n             * 一个不做任何事情的方法。可以用来赋值给默认的callback.\n             * @method noop\n             */\n            noop: noop,\n\n            /**\n             * 返回一个新的方法，此方法将已指定的`context`来执行。\n             * @grammar Base.bindFn( fn, context ) => Function\n             * @method bindFn\n             * @example\n             * var doSomething = function() {\n             *         console.log( this.name );\n             *     },\n             *     obj = {\n             *         name: 'Object Name'\n             *     },\n             *     aliasFn = Base.bind( doSomething, obj );\n             *\n             *  aliasFn();    // => Object Name\n             *\n             */\n            bindFn: bindFn,\n\n            /**\n             * 引用Console.log如果存在的话，否则引用一个[空函数noop](#WebUploader:Base.noop)。\n             * @grammar Base.log( args... ) => undefined\n             * @method log\n             */\n            log: (function() {\n                if ( window.console ) {\n                    return bindFn( console.log, console );\n                }\n                return noop;\n            })(),\n\n            nextTick: (function() {\n\n                return function( cb ) {\n                    setTimeout( cb, 1 );\n                };\n\n                // @bug 当浏览器不在当前窗口时就停了。\n                // var next = window.requestAnimationFrame ||\n                //     window.webkitRequestAnimationFrame ||\n                //     window.mozRequestAnimationFrame ||\n                //     function( cb ) {\n                //         window.setTimeout( cb, 1000 / 60 );\n                //     };\n\n                // // fix: Uncaught TypeError: Illegal invocation\n                // return bindFn( next, window );\n            })(),\n\n            /**\n             * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的数组slice方法。\n             * 将用来将非数组对象转化成数组对象。\n             * @grammar Base.slice( target, start[, end] ) => Array\n             * @method slice\n             * @example\n             * function doSomthing() {\n             *     var args = Base.slice( arguments, 1 );\n             *     console.log( args );\n             * }\n             *\n             * doSomthing( 'ignored', 'arg2', 'arg3' );    // => Array [\"arg2\", \"arg3\"]\n             */\n            slice: uncurryThis( [].slice ),\n\n            /**\n             * 生成唯一的ID\n             * @method guid\n             * @grammar Base.guid() => String\n             * @grammar Base.guid( prefx ) => String\n             */\n            guid: (function() {\n                var counter = 0;\n\n                return function( prefix ) {\n                    var guid = (+new Date()).toString( 32 ),\n                        i = 0;\n\n                    for ( ; i < 5; i++ ) {\n                        guid += Math.floor( Math.random() * 65535 ).toString( 32 );\n                    }\n\n                    return (prefix || 'wu_') + guid + (counter++).toString( 32 );\n                };\n            })(),\n\n            /**\n             * 格式化文件大小, 输出成带单位的字符串\n             * @method formatSize\n             * @grammar Base.formatSize( size ) => String\n             * @grammar Base.formatSize( size, pointLength ) => String\n             * @grammar Base.formatSize( size, pointLength, units ) => String\n             * @param {Number} size 文件大小\n             * @param {Number} [pointLength=2] 精确到的小数点数。\n             * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 单位数组。从字节，到千字节，一直往上指定。如果单位数组里面只指定了到了K(千字节)，同时文件大小大于M, 此方法的输出将还是显示成多少K.\n             * @example\n             * console.log( Base.formatSize( 100 ) );    // => 100B\n             * console.log( Base.formatSize( 1024 ) );    // => 1.00K\n             * console.log( Base.formatSize( 1024, 0 ) );    // => 1K\n             * console.log( Base.formatSize( 1024 * 1024 ) );    // => 1.00M\n             * console.log( Base.formatSize( 1024 * 1024 * 1024 ) );    // => 1.00G\n             * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) );    // => 1024MB\n             */\n            formatSize: function( size, pointLength, units ) {\n                var unit;\n\n                units = units || [ 'B', 'K', 'M', 'G', 'TB' ];\n\n                while ( (unit = units.shift()) && size > 1024 ) {\n                    size = size / 1024;\n                }\n\n                return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) +\n                        unit;\n            }\n        };\n    });\n    /**\n     * 事件处理类，可以独立使用，也可以扩展给对象使用。\n     * @fileOverview Mediator\n     */\n    define('mediator',[\n        'base'\n    ], function( Base ) {\n        var $ = Base.$,\n            slice = [].slice,\n            separator = /\\s+/,\n            protos;\n\n        // 根据条件过滤出事件handlers.\n        function findHandlers( arr, name, callback, context ) {\n            return $.grep( arr, function( handler ) {\n                return handler &&\n                        (!name || handler.e === name) &&\n                        (!callback || handler.cb === callback ||\n                        handler.cb._cb === callback) &&\n                        (!context || handler.ctx === context);\n            });\n        }\n\n        function eachEvent( events, callback, iterator ) {\n            // 不支持对象，只支持多个event用空格隔开\n            $.each( (events || '').split( separator ), function( _, key ) {\n                iterator( key, callback );\n            });\n        }\n\n        function triggerHanders( events, args ) {\n            var stoped = false,\n                i = -1,\n                len = events.length,\n                handler;\n\n            while ( ++i < len ) {\n                handler = events[ i ];\n\n                if ( handler.cb.apply( handler.ctx2, args ) === false ) {\n                    stoped = true;\n                    break;\n                }\n            }\n\n            return !stoped;\n        }\n\n        protos = {\n\n            /**\n             * 绑定事件。\n             *\n             * `callback`方法在执行时，arguments将会来源于trigger的时候携带的参数。如\n             * ```javascript\n             * var obj = {};\n             *\n             * // 使得obj有事件行为\n             * Mediator.installTo( obj );\n             *\n             * obj.on( 'testa', function( arg1, arg2 ) {\n             *     console.log( arg1, arg2 ); // => 'arg1', 'arg2'\n             * });\n             *\n             * obj.trigger( 'testa', 'arg1', 'arg2' );\n             * ```\n             *\n             * 如果`callback`中，某一个方法`return false`了，则后续的其他`callback`都不会被执行到。\n             * 切会影响到`trigger`方法的返回值，为`false`。\n             *\n             * `on`还可以用来添加一个特殊事件`all`, 这样所有的事件触发都会响应到。同时此类`callback`中的arguments有一个不同处，\n             * 就是第一个参数为`type`，记录当前是什么事件在触发。此类`callback`的优先级比脚低，会再正常`callback`执行完后触发。\n             * ```javascript\n             * obj.on( 'all', function( type, arg1, arg2 ) {\n             *     console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2'\n             * });\n             * ```\n             *\n             * @method on\n             * @grammar on( name, callback[, context] ) => self\n             * @param  {String}   name     事件名，支持多个事件用空格隔开\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             * @class Mediator\n             */\n            on: function( name, callback, context ) {\n                var me = this,\n                    set;\n\n                if ( !callback ) {\n                    return this;\n                }\n\n                set = this._events || (this._events = []);\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var handler = { e: name };\n\n                    handler.cb = callback;\n                    handler.ctx = context;\n                    handler.ctx2 = context || me;\n                    handler.id = set.length;\n\n                    set.push( handler );\n                });\n\n                return this;\n            },\n\n            /**\n             * 绑定事件，且当handler执行完后，自动解除绑定。\n             * @method once\n             * @grammar once( name, callback[, context] ) => self\n             * @param  {String}   name     事件名\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            once: function( name, callback, context ) {\n                var me = this;\n\n                if ( !callback ) {\n                    return me;\n                }\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var once = function() {\n                            me.off( name, once );\n                            return callback.apply( context || me, arguments );\n                        };\n\n                    once._cb = callback;\n                    me.on( name, once, context );\n                });\n\n                return me;\n            },\n\n            /**\n             * 解除事件绑定\n             * @method off\n             * @grammar off( [name[, callback[, context] ] ] ) => self\n             * @param  {String}   [name]     事件名\n             * @param  {Function} [callback] 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            off: function( name, cb, ctx ) {\n                var events = this._events;\n\n                if ( !events ) {\n                    return this;\n                }\n\n                if ( !name && !cb && !ctx ) {\n                    this._events = [];\n                    return this;\n                }\n\n                eachEvent( name, cb, function( name, cb ) {\n                    $.each( findHandlers( events, name, cb, ctx ), function() {\n                        delete events[ this.id ];\n                    });\n                });\n\n                return this;\n            },\n\n            /**\n             * 触发事件\n             * @method trigger\n             * @grammar trigger( name[, args...] ) => self\n             * @param  {String}   type     事件名\n             * @param  {*} [...] 任意参数\n             * @return {Boolean} 如果handler中return false了，则返回false, 否则返回true\n             */\n            trigger: function( type ) {\n                var args, events, allEvents;\n\n                if ( !this._events || !type ) {\n                    return this;\n                }\n\n                args = slice.call( arguments, 1 );\n                events = findHandlers( this._events, type );\n                allEvents = findHandlers( this._events, 'all' );\n\n                return triggerHanders( events, args ) &&\n                        triggerHanders( allEvents, arguments );\n            }\n        };\n\n        /**\n         * 中介者，它本身是个单例，但可以通过[installTo](#WebUploader:Mediator:installTo)方法，使任何对象具备事件行为。\n         * 主要目的是负责模块与模块之间的合作，降低耦合度。\n         *\n         * @class Mediator\n         */\n        return $.extend({\n\n            /**\n             * 可以通过这个接口，使任何对象具备事件功能。\n             * @method installTo\n             * @param  {Object} obj 需要具备事件行为的对象。\n             * @return {Object} 返回obj.\n             */\n            installTo: function( obj ) {\n                return $.extend( obj, protos );\n            }\n\n        }, protos );\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('uploader',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$;\n\n        /**\n         * 上传入口类。\n         * @class Uploader\n         * @constructor\n         * @grammar new Uploader( opts ) => Uploader\n         * @example\n         * var uploader = WebUploader.Uploader({\n         *     swf: 'path_of_swf/Uploader.swf',\n         *\n         *     // 开起分片上传。\n         *     chunked: true\n         * });\n         */\n        function Uploader( opts ) {\n            this.options = $.extend( true, {}, Uploader.options, opts );\n            this._init( this.options );\n        }\n\n        // default Options\n        // widgets中有相应扩展\n        Uploader.options = {};\n        Mediator.installTo( Uploader.prototype );\n\n        // 批量添加纯命令式方法。\n        $.each({\n            upload: 'start-upload',\n            stop: 'stop-upload',\n            getFile: 'get-file',\n            getFiles: 'get-files',\n            addFile: 'add-file',\n            addFiles: 'add-file',\n            sort: 'sort-files',\n            removeFile: 'remove-file',\n            cancelFile: 'cancel-file',\n            skipFile: 'skip-file',\n            retry: 'retry',\n            isInProgress: 'is-in-progress',\n            makeThumb: 'make-thumb',\n            md5File: 'md5-file',\n            getDimension: 'get-dimension',\n            addButton: 'add-btn',\n            predictRuntimeType: 'predict-runtime-type',\n            refresh: 'refresh',\n            disable: 'disable',\n            enable: 'enable',\n            reset: 'reset'\n        }, function( fn, command ) {\n            Uploader.prototype[ fn ] = function() {\n                return this.request( command, arguments );\n            };\n        });\n\n        $.extend( Uploader.prototype, {\n            state: 'pending',\n\n            _init: function( opts ) {\n                var me = this;\n\n                me.request( 'init', opts, function() {\n                    me.state = 'ready';\n                    me.trigger('ready');\n                });\n            },\n\n            /**\n             * 获取或者设置Uploader配置项。\n             * @method option\n             * @grammar option( key ) => *\n             * @grammar option( key, val ) => self\n             * @example\n             *\n             * // 初始状态图片上传前不会压缩\n             * var uploader = new WebUploader.Uploader({\n             *     compress: null;\n             * });\n             *\n             * // 修改后图片上传前，尝试将图片压缩到1600 * 1600\n             * uploader.option( 'compress', {\n             *     width: 1600,\n             *     height: 1600\n             * });\n             */\n            option: function( key, val ) {\n                var opts = this.options;\n\n                // setter\n                if ( arguments.length > 1 ) {\n\n                    if ( $.isPlainObject( val ) &&\n                            $.isPlainObject( opts[ key ] ) ) {\n                        $.extend( opts[ key ], val );\n                    } else {\n                        opts[ key ] = val;\n                    }\n\n                } else {    // getter\n                    return key ? opts[ key ] : opts;\n                }\n            },\n\n            /**\n             * 获取文件统计信息。返回一个包含一下信息的对象。\n             * * `successNum` 上传成功的文件数\n             * * `progressNum` 上传中的文件数\n             * * `cancelNum` 被删除的文件数\n             * * `invalidNum` 无效的文件数\n             * * `uploadFailNum` 上传失败的文件数\n             * * `queueNum` 还在队列中的文件数\n             * * `interruptNum` 被暂停的文件数\n             * @method getStats\n             * @grammar getStats() => Object\n             */\n            getStats: function() {\n                // return this._mgr.getStats.apply( this._mgr, arguments );\n                var stats = this.request('get-stats');\n\n                return stats ? {\n                    successNum: stats.numOfSuccess,\n                    progressNum: stats.numOfProgress,\n\n                    // who care?\n                    // queueFailNum: 0,\n                    cancelNum: stats.numOfCancel,\n                    invalidNum: stats.numOfInvalid,\n                    uploadFailNum: stats.numOfUploadFailed,\n                    queueNum: stats.numOfQueue,\n                    interruptNum: stats.numofInterrupt\n                } : {};\n            },\n\n            // 需要重写此方法来来支持opts.onEvent和instance.onEvent的处理器\n            trigger: function( type/*, args...*/ ) {\n                var args = [].slice.call( arguments, 1 ),\n                    opts = this.options,\n                    name = 'on' + type.substring( 0, 1 ).toUpperCase() +\n                        type.substring( 1 );\n\n                if (\n                        // 调用通过on方法注册的handler.\n                        Mediator.trigger.apply( this, arguments ) === false ||\n\n                        // 调用opts.onEvent\n                        $.isFunction( opts[ name ] ) &&\n                        opts[ name ].apply( this, args ) === false ||\n\n                        // 调用this.onEvent\n                        $.isFunction( this[ name ] ) &&\n                        this[ name ].apply( this, args ) === false ||\n\n                        // 广播所有uploader的事件。\n                        Mediator.trigger.apply( Mediator,\n                        [ this, type ].concat( args ) ) === false ) {\n\n                    return false;\n                }\n\n                return true;\n            },\n\n            /**\n             * 销毁 webuploader 实例\n             * @method destroy\n             * @grammar destroy() => undefined\n             */\n            destroy: function() {\n                this.request( 'destroy', arguments );\n                this.off();\n            },\n\n            // widgets/widget.js将补充此方法的详细文档。\n            request: Base.noop\n        });\n\n        /**\n         * 创建Uploader实例，等同于new Uploader( opts );\n         * @method create\n         * @class Base\n         * @static\n         * @grammar Base.create( opts ) => Uploader\n         */\n        Base.create = Uploader.create = function( opts ) {\n            return new Uploader( opts );\n        };\n\n        // 暴露Uploader，可以通过它来扩展业务逻辑。\n        Base.Uploader = Uploader;\n\n        return Uploader;\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/runtime',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            factories = {},\n\n            // 获取对象的第一个key\n            getFirstKey = function( obj ) {\n                for ( var key in obj ) {\n                    if ( obj.hasOwnProperty( key ) ) {\n                        return key;\n                    }\n                }\n                return null;\n            };\n\n        // 接口类。\n        function Runtime( options ) {\n            this.options = $.extend({\n                container: document.body\n            }, options );\n            this.uid = Base.guid('rt_');\n        }\n\n        $.extend( Runtime.prototype, {\n\n            getContainer: function() {\n                var opts = this.options,\n                    parent, container;\n\n                if ( this._container ) {\n                    return this._container;\n                }\n\n                parent = $( opts.container || document.body );\n                container = $( document.createElement('div') );\n\n                container.attr( 'id', 'rt_' + this.uid );\n                container.css({\n                    position: 'absolute',\n                    top: '0px',\n                    left: '0px',\n                    width: '1px',\n                    height: '1px',\n                    overflow: 'hidden'\n                });\n\n                parent.append( container );\n                parent.addClass('webuploader-container');\n                this._container = container;\n                this._parent = parent;\n                return container;\n            },\n\n            init: Base.noop,\n            exec: Base.noop,\n\n            destroy: function() {\n                this._container && this._container.remove();\n                this._parent && this._parent.removeClass('webuploader-container');\n                this.off();\n            }\n        });\n\n        Runtime.orders = 'html5,flash';\n\n\n        /**\n         * 添加Runtime实现。\n         * @param {String} type    类型\n         * @param {Runtime} factory 具体Runtime实现。\n         */\n        Runtime.addRuntime = function( type, factory ) {\n            factories[ type ] = factory;\n        };\n\n        Runtime.hasRuntime = function( type ) {\n            return !!(type ? factories[ type ] : getFirstKey( factories ));\n        };\n\n        Runtime.create = function( opts, orders ) {\n            var type, runtime;\n\n            orders = orders || Runtime.orders;\n            $.each( orders.split( /\\s*,\\s*/g ), function() {\n                if ( factories[ this ] ) {\n                    type = this;\n                    return false;\n                }\n            });\n\n            type = type || getFirstKey( factories );\n\n            if ( !type ) {\n                throw new Error('Runtime Error');\n            }\n\n            runtime = new factories[ type ]( opts );\n            return runtime;\n        };\n\n        Mediator.installTo( Runtime.prototype );\n        return Runtime;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/client',[\n        'base',\n        'mediator',\n        'runtime/runtime'\n    ], function( Base, Mediator, Runtime ) {\n\n        var cache;\n\n        cache = (function() {\n            var obj = {};\n\n            return {\n                add: function( runtime ) {\n                    obj[ runtime.uid ] = runtime;\n                },\n\n                get: function( ruid, standalone ) {\n                    var i;\n\n                    if ( ruid ) {\n                        return obj[ ruid ];\n                    }\n\n                    for ( i in obj ) {\n                        // 有些类型不能重用，比如filepicker.\n                        if ( standalone && obj[ i ].__standalone ) {\n                            continue;\n                        }\n\n                        return obj[ i ];\n                    }\n\n                    return null;\n                },\n\n                remove: function( runtime ) {\n                    delete obj[ runtime.uid ];\n                }\n            };\n        })();\n\n        function RuntimeClient( component, standalone ) {\n            var deferred = Base.Deferred(),\n                runtime;\n\n            this.uid = Base.guid('client_');\n\n            // 允许runtime没有初始化之前，注册一些方法在初始化后执行。\n            this.runtimeReady = function( cb ) {\n                return deferred.done( cb );\n            };\n\n            this.connectRuntime = function( opts, cb ) {\n\n                // already connected.\n                if ( runtime ) {\n                    throw new Error('already connected!');\n                }\n\n                deferred.done( cb );\n\n                if ( typeof opts === 'string' && cache.get( opts ) ) {\n                    runtime = cache.get( opts );\n                }\n\n                // 像filePicker只能独立存在，不能公用。\n                runtime = runtime || cache.get( null, standalone );\n\n                // 需要创建\n                if ( !runtime ) {\n                    runtime = Runtime.create( opts, opts.runtimeOrder );\n                    runtime.__promise = deferred.promise();\n                    runtime.once( 'ready', deferred.resolve );\n                    runtime.init();\n                    cache.add( runtime );\n                    runtime.__client = 1;\n                } else {\n                    // 来自cache\n                    Base.$.extend( runtime.options, opts );\n                    runtime.__promise.then( deferred.resolve );\n                    runtime.__client++;\n                }\n\n                standalone && (runtime.__standalone = standalone);\n                return runtime;\n            };\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.disconnectRuntime = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                runtime.__client--;\n\n                if ( runtime.__client <= 0 ) {\n                    cache.remove( runtime );\n                    delete runtime.__promise;\n                    runtime.destroy();\n                }\n\n                runtime = null;\n            };\n\n            this.exec = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                var args = Base.slice( arguments );\n                component && args.unshift( component );\n\n                return runtime.exec.apply( this, args );\n            };\n\n            this.getRuid = function() {\n                return runtime && runtime.uid;\n            };\n\n            this.destroy = (function( destroy ) {\n                return function() {\n                    destroy && destroy.apply( this, arguments );\n                    this.trigger('destroy');\n                    this.off();\n                    this.exec('destroy');\n                    this.disconnectRuntime();\n                };\n            })( this.destroy );\n        }\n\n        Mediator.installTo( RuntimeClient.prototype );\n        return RuntimeClient;\n    });\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/dnd',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function DragAndDrop( opts ) {\n            opts = this.options = $.extend({}, DragAndDrop.options, opts );\n\n            opts.container = $( opts.container );\n\n            if ( !opts.container.length ) {\n                return;\n            }\n\n            RuntimeClent.call( this, 'DragAndDrop' );\n        }\n\n        DragAndDrop.options = {\n            accept: null,\n            disableGlobalDnd: false\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: DragAndDrop,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( DragAndDrop.prototype );\n\n        return DragAndDrop;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/widget',[\n        'base',\n        'uploader'\n    ], function( Base, Uploader ) {\n\n        var $ = Base.$,\n            _init = Uploader.prototype._init,\n            _destroy = Uploader.prototype.destroy,\n            IGNORE = {},\n            widgetClass = [];\n\n        function isArrayLike( obj ) {\n            if ( !obj ) {\n                return false;\n            }\n\n            var length = obj.length,\n                type = $.type( obj );\n\n            if ( obj.nodeType === 1 && length ) {\n                return true;\n            }\n\n            return type === 'array' || type !== 'function' && type !== 'string' &&\n                    (length === 0 || typeof length === 'number' && length > 0 &&\n                    (length - 1) in obj);\n        }\n\n        function Widget( uploader ) {\n            this.owner = uploader;\n            this.options = uploader.options;\n        }\n\n        $.extend( Widget.prototype, {\n\n            init: Base.noop,\n\n            // 类Backbone的事件监听声明，监听uploader实例上的事件\n            // widget直接无法监听事件，事件只能通过uploader来传递\n            invoke: function( apiName, args ) {\n\n                /*\n                    {\n                        'make-thumb': 'makeThumb'\n                    }\n                 */\n                var map = this.responseMap;\n\n                // 如果无API响应声明则忽略\n                if ( !map || !(apiName in map) || !(map[ apiName ] in this) ||\n                        !$.isFunction( this[ map[ apiName ] ] ) ) {\n\n                    return IGNORE;\n                }\n\n                return this[ map[ apiName ] ].apply( this, args );\n\n            },\n\n            /**\n             * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。\n             * @method request\n             * @grammar request( command, args ) => * | Promise\n             * @grammar request( command, args, callback ) => Promise\n             * @for  Uploader\n             */\n            request: function() {\n                return this.owner.request.apply( this.owner, arguments );\n            }\n        });\n\n        // 扩展Uploader.\n        $.extend( Uploader.prototype, {\n\n            /**\n             * @property {String | Array} [disableWidgets=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。\n             */\n\n            // 覆写_init用来初始化widgets\n            _init: function() {\n                var me = this,\n                    widgets = me._widgets = [],\n                    deactives = me.options.disableWidgets || '';\n\n                $.each( widgetClass, function( _, klass ) {\n                    (!deactives || !~deactives.indexOf( klass._name )) &&\n                        widgets.push( new klass( me ) );\n                });\n\n                return _init.apply( me, arguments );\n            },\n\n            request: function( apiName, args, callback ) {\n                var i = 0,\n                    widgets = this._widgets,\n                    len = widgets && widgets.length,\n                    rlts = [],\n                    dfds = [],\n                    widget, rlt, promise, key;\n\n                args = isArrayLike( args ) ? args : [ args ];\n\n                for ( ; i < len; i++ ) {\n                    widget = widgets[ i ];\n                    rlt = widget.invoke( apiName, args );\n\n                    if ( rlt !== IGNORE ) {\n\n                        // Deferred对象\n                        if ( Base.isPromise( rlt ) ) {\n                            dfds.push( rlt );\n                        } else {\n                            rlts.push( rlt );\n                        }\n                    }\n                }\n\n                // 如果有callback，则用异步方式。\n                if ( callback || dfds.length ) {\n                    promise = Base.when.apply( Base, dfds );\n                    key = promise.pipe ? 'pipe' : 'then';\n\n                    // 很重要不能删除。删除了会死循环。\n                    // 保证执行顺序。让callback总是在下一个 tick 中执行。\n                    return promise[ key ](function() {\n                                var deferred = Base.Deferred(),\n                                    args = arguments;\n\n                                if ( args.length === 1 ) {\n                                    args = args[ 0 ];\n                                }\n\n                                setTimeout(function() {\n                                    deferred.resolve( args );\n                                }, 1 );\n\n                                return deferred.promise();\n                            })[ callback ? key : 'done' ]( callback || Base.noop );\n                } else {\n                    return rlts[ 0 ];\n                }\n            },\n\n            destroy: function() {\n                _destroy.apply( this, arguments );\n                this._widgets = null;\n            }\n        });\n\n        /**\n         * 添加组件\n         * @grammar Uploader.register(proto);\n         * @grammar Uploader.register(map, proto);\n         * @param  {object} responseMap API 名称与函数实现的映射\n         * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义\n         * @method Uploader.register\n         * @for Uploader\n         * @example\n         * Uploader.register({\n         *     'make-thumb': 'makeThumb'\n         * }, {\n         *     init: function( options ) {},\n         *     makeThumb: function() {}\n         * });\n         *\n         * Uploader.register({\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         */\n        Uploader.register = Widget.register = function( responseMap, widgetProto ) {\n            var map = { init: 'init', destroy: 'destroy', name: 'anonymous' },\n                klass;\n\n            if ( arguments.length === 1 ) {\n                widgetProto = responseMap;\n\n                // 自动生成 map 表。\n                $.each(widgetProto, function(key) {\n                    if ( key[0] === '_' || key === 'name' ) {\n                        key === 'name' && (map.name = widgetProto.name);\n                        return;\n                    }\n\n                    map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;\n                });\n\n            } else {\n                map = $.extend( map, responseMap );\n            }\n\n            widgetProto.responseMap = map;\n            klass = Base.inherits( Widget, widgetProto );\n            klass._name = map.name;\n            widgetClass.push( klass );\n\n            return klass;\n        };\n\n        /**\n         * 删除插件，只有在注册时指定了名字的才能被删除。\n         * @grammar Uploader.unRegister(name);\n         * @param  {string} name 组件名字\n         * @method Uploader.unRegister\n         * @for Uploader\n         * @example\n         *\n         * Uploader.register({\n         *     name: 'custom',\n         *\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         *\n         * Uploader.unRegister('custom');\n         */\n        Uploader.unRegister = Widget.unRegister = function( name ) {\n            if ( !name || name === 'anonymous' ) {\n                return;\n            }\n\n            // 删除指定的插件。\n            for ( var i = widgetClass.length; i--; ) {\n                if ( widgetClass[i]._name === name ) {\n                    widgetClass.splice(i, 1)\n                }\n            }\n        };\n\n        return Widget;\n    });\n    /**\n     * @fileOverview DragAndDrop Widget。\n     */\n    define('widgets/filednd',[\n        'base',\n        'uploader',\n        'lib/dnd',\n        'widgets/widget'\n    ], function( Base, Uploader, Dnd ) {\n        var $ = Base.$;\n\n        Uploader.options.dnd = '';\n\n        /**\n         * @property {Selector} [dnd=undefined]  指定Drag And Drop拖拽的容器，如果不指定，则不启动。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @property {Selector} [disableGlobalDnd=false]  是否禁掉整个页面的拖拽功能，如果不禁用，图片拖进来的时候会默认被浏览器打开。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @event dndAccept\n         * @param {DataTransferItemList} items DataTransferItem\n         * @description 阻止此事件可以拒绝某些类型的文件拖入进来。目前只有 chrome 提供这样的 API，且只能通过 mime-type 验证。\n         * @for  Uploader\n         */\n        return Uploader.register({\n            name: 'dnd',\n\n            init: function( opts ) {\n\n                if ( !opts.dnd ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        disableGlobalDnd: opts.disableGlobalDnd,\n                        container: opts.dnd,\n                        accept: opts.accept\n                    }),\n                    dnd;\n\n                this.dnd = dnd = new Dnd( options );\n\n                dnd.once( 'ready', deferred.resolve );\n                dnd.on( 'drop', function( files ) {\n                    me.request( 'add-file', [ files ]);\n                });\n\n                // 检测文件是否全部允许添加。\n                dnd.on( 'accept', function( items ) {\n                    return me.owner.trigger( 'dndAccept', items );\n                });\n\n                dnd.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.dnd && this.dnd.destroy();\n            }\n        });\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepaste',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function FilePaste( opts ) {\n            opts = this.options = $.extend({}, opts );\n            opts.container = $( opts.container || document.body );\n            RuntimeClent.call( this, 'FilePaste' );\n        }\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePaste,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( FilePaste.prototype );\n\n        return FilePaste;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/filepaste',[\n        'base',\n        'uploader',\n        'lib/filepaste',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePaste ) {\n        var $ = Base.$;\n\n        /**\n         * @property {Selector} [paste=undefined]  指定监听paste事件的容器，如果不指定，不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为`document.body`.\n         * @namespace options\n         * @for Uploader\n         */\n        return Uploader.register({\n            name: 'paste',\n\n            init: function( opts ) {\n\n                if ( !opts.paste ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        container: opts.paste,\n                        accept: opts.accept\n                    }),\n                    paste;\n\n                this.paste = paste = new FilePaste( options );\n\n                paste.once( 'ready', deferred.resolve );\n                paste.on( 'paste', function( files ) {\n                    me.owner.request( 'add-file', [ files ]);\n                });\n                paste.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.paste && this.paste.destroy();\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob\n     */\n    define('lib/blob',[\n        'base',\n        'runtime/client'\n    ], function( Base, RuntimeClient ) {\n\n        function Blob( ruid, source ) {\n            var me = this;\n\n            me.source = source;\n            me.ruid = ruid;\n            this.size = source.size || 0;\n\n            // 如果没有指定 mimetype, 但是知道文件后缀。\n            if ( !source.type && this.ext &&\n                    ~'jpg,jpeg,png,gif,bmp'.indexOf( this.ext ) ) {\n                this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);\n            } else {\n                this.type = source.type || 'application/octet-stream';\n            }\n\n            RuntimeClient.call( me, 'Blob' );\n            this.uid = source.uid || this.uid;\n\n            if ( ruid ) {\n                me.connectRuntime( ruid );\n            }\n        }\n\n        Base.inherits( RuntimeClient, {\n            constructor: Blob,\n\n            slice: function( start, end ) {\n                return this.exec( 'slice', start, end );\n            },\n\n            getSource: function() {\n                return this.source;\n            }\n        });\n\n        return Blob;\n    });\n    /**\n     * 为了统一化Flash的File和HTML5的File而存在。\n     * 以至于要调用Flash里面的File，也可以像调用HTML5版本的File一下。\n     * @fileOverview File\n     */\n    define('lib/file',[\n        'base',\n        'lib/blob'\n    ], function( Base, Blob ) {\n\n        var uid = 1,\n            rExt = /\\.([^.]+)$/;\n\n        function File( ruid, file ) {\n            var ext;\n\n            this.name = file.name || ('untitled' + uid++);\n            ext = rExt.exec( file.name ) ? RegExp.$1.toLowerCase() : '';\n\n            // todo 支持其他类型文件的转换。\n            // 如果有 mimetype, 但是文件名里面没有找出后缀规律\n            if ( !ext && file.type ) {\n                ext = /\\/(jpg|jpeg|png|gif|bmp)$/i.exec( file.type ) ?\n                        RegExp.$1.toLowerCase() : '';\n                this.name += '.' + ext;\n            }\n\n            this.ext = ext;\n            this.lastModifiedDate = file.lastModifiedDate ||\n                    (new Date()).toLocaleString();\n\n            Blob.apply( this, arguments );\n        }\n\n        return Base.inherits( Blob, File );\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepicker',[\n        'base',\n        'runtime/client',\n        'lib/file'\n    ], function( Base, RuntimeClent, File ) {\n\n        var $ = Base.$;\n\n        function FilePicker( opts ) {\n            opts = this.options = $.extend({}, FilePicker.options, opts );\n\n            opts.container = $( opts.id );\n\n            if ( !opts.container.length ) {\n                throw new Error('按钮指定错误');\n            }\n\n            opts.innerHTML = opts.innerHTML || opts.label ||\n                    opts.container.html() || '';\n\n            opts.button = $( opts.button || document.createElement('div') );\n            opts.button.html( opts.innerHTML );\n            opts.container.html( opts.button );\n\n            RuntimeClent.call( this, 'FilePicker', true );\n        }\n\n        FilePicker.options = {\n            button: null,\n            container: null,\n            label: null,\n            innerHTML: null,\n            multiple: true,\n            accept: null,\n            name: 'file'\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePicker,\n\n            init: function() {\n                var me = this,\n                    opts = me.options,\n                    button = opts.button;\n\n                button.addClass('webuploader-pick');\n\n                me.on( 'all', function( type ) {\n                    var files;\n\n                    switch ( type ) {\n                        case 'mouseenter':\n                            button.addClass('webuploader-pick-hover');\n                            break;\n\n                        case 'mouseleave':\n                            button.removeClass('webuploader-pick-hover');\n                            break;\n\n                        case 'change':\n                            files = me.exec('getFiles');\n                            me.trigger( 'select', $.map( files, function( file ) {\n                                file = new File( me.getRuid(), file );\n\n                                // 记录来源。\n                                file._refer = opts.container;\n                                return file;\n                            }), opts.container );\n                            break;\n                    }\n                });\n\n                me.connectRuntime( opts, function() {\n                    me.refresh();\n                    me.exec( 'init', opts );\n                    me.trigger('ready');\n                });\n\n                this._resizeHandler = Base.bindFn( this.refresh, this );\n                $( window ).on( 'resize', this._resizeHandler );\n            },\n\n            refresh: function() {\n                var shimContainer = this.getRuntime().getContainer(),\n                    button = this.options.button,\n                    width = button.outerWidth ?\n                            button.outerWidth() : button.width(),\n\n                    height = button.outerHeight ?\n                            button.outerHeight() : button.height(),\n\n                    pos = button.offset();\n\n                width && height && shimContainer.css({\n                    bottom: 'auto',\n                    right: 'auto',\n                    width: width + 'px',\n                    height: height + 'px'\n                }).offset( pos );\n            },\n\n            enable: function() {\n                var btn = this.options.button;\n\n                btn.removeClass('webuploader-pick-disable');\n                this.refresh();\n            },\n\n            disable: function() {\n                var btn = this.options.button;\n\n                this.getRuntime().getContainer().css({\n                    top: '-99999px'\n                });\n\n                btn.addClass('webuploader-pick-disable');\n            },\n\n            destroy: function() {\n                var btn = this.options.button;\n                $( window ).off( 'resize', this._resizeHandler );\n                btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +\n                    'webuploader-pick');\n            }\n        });\n\n        return FilePicker;\n    });\n\n    /**\n     * @fileOverview 文件选择相关\n     */\n    define('widgets/filepicker',[\n        'base',\n        'uploader',\n        'lib/filepicker',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePicker ) {\n        var $ = Base.$;\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Selector | Object} [pick=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 指定选择文件的按钮容器，不指定则不创建按钮。\n             *\n             * * `id` {Seletor|dom} 指定选择文件的按钮容器，不指定则不创建按钮。**注意** 这里虽然写的是 id, 但是不是只支持 id, 还支持 class, 或者 dom 节点。\n             * * `label` {String} 请采用 `innerHTML` 代替\n             * * `innerHTML` {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。\n             * * `multiple` {Boolean} 是否开起同时选择多个文件能力。\n             */\n            pick: null,\n\n            /**\n             * @property {Arroy} [accept=null]\n             * @namespace options\n             * @for Uploader\n             * @description 指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。\n             *\n             * * `title` {String} 文字描述\n             * * `extensions` {String} 允许的文件后缀，不带点，多个用逗号分割。\n             * * `mimeTypes` {String} 多个用逗号分割。\n             *\n             * 如：\n             *\n             * ```\n             * {\n             *     title: 'Images',\n             *     extensions: 'gif,jpg,jpeg,bmp,png',\n             *     mimeTypes: 'image/*'\n             * }\n             * ```\n             */\n            accept: null/*{\n                title: 'Images',\n                extensions: 'gif,jpg,jpeg,bmp,png',\n                mimeTypes: 'image/*'\n            }*/\n        });\n\n        return Uploader.register({\n            name: 'picker',\n\n            init: function( opts ) {\n                this.pickers = [];\n                return opts.pick && this.addBtn( opts.pick );\n            },\n\n            refresh: function() {\n                $.each( this.pickers, function() {\n                    this.refresh();\n                });\n            },\n\n            /**\n             * @method addButton\n             * @for Uploader\n             * @grammar addButton( pick ) => Promise\n             * @description\n             * 添加文件选择按钮，如果一个按钮不够，需要调用此方法来添加。参数跟[options.pick](#WebUploader:Uploader:options)一致。\n             * @example\n             * uploader.addButton({\n             *     id: '#btnContainer',\n             *     innerHTML: '选择文件'\n             * });\n             */\n            addBtn: function( pick ) {\n                var me = this,\n                    opts = me.options,\n                    accept = opts.accept,\n                    promises = [];\n\n                if ( !pick ) {\n                    return;\n                }\n\n                $.isPlainObject( pick ) || (pick = {\n                    id: pick\n                });\n\n                $( pick.id ).each(function() {\n                    var options, picker, deferred;\n\n                    deferred = Base.Deferred();\n\n                    options = $.extend({}, pick, {\n                        accept: $.isPlainObject( accept ) ? [ accept ] : accept,\n                        swf: opts.swf,\n                        runtimeOrder: opts.runtimeOrder,\n                        id: this\n                    });\n\n                    picker = new FilePicker( options );\n\n                    picker.once( 'ready', deferred.resolve );\n                    picker.on( 'select', function( files ) {\n                        me.owner.request( 'add-file', [ files ]);\n                    });\n                    picker.init();\n\n                    me.pickers.push( picker );\n\n                    promises.push( deferred.promise() );\n                });\n\n                return Base.when.apply( Base, promises );\n            },\n\n            disable: function() {\n                $.each( this.pickers, function() {\n                    this.disable();\n                });\n            },\n\n            enable: function() {\n                $.each( this.pickers, function() {\n                    this.enable();\n                });\n            },\n\n            destroy: function() {\n                $.each( this.pickers, function() {\n                    this.destroy();\n                });\n                this.pickers = null;\n            }\n        });\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('lib/image',[\n        'base',\n        'runtime/client',\n        'lib/blob'\n    ], function( Base, RuntimeClient, Blob ) {\n        var $ = Base.$;\n\n        // 构造器。\n        function Image( opts ) {\n            this.options = $.extend({}, Image.options, opts );\n            RuntimeClient.call( this, 'Image' );\n\n            this.on( 'load', function() {\n                this._info = this.exec('info');\n                this._meta = this.exec('meta');\n            });\n        }\n\n        // 默认选项。\n        Image.options = {\n\n            // 默认的图片处理质量\n            quality: 90,\n\n            // 是否裁剪\n            crop: false,\n\n            // 是否保留头部信息\n            preserveHeaders: false,\n\n            // 是否允许放大。\n            allowMagnify: false\n        };\n\n        // 继承RuntimeClient.\n        Base.inherits( RuntimeClient, {\n            constructor: Image,\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    ruid = blob.getRuid();\n\n                this.connectRuntime( ruid, function() {\n                    me.exec( 'init', me.options );\n                    me.exec( 'loadFromBlob', blob );\n                });\n            },\n\n            resize: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'resize' ].concat( args ) );\n            },\n\n            crop: function() {\n                var args = Base.slice( arguments );\n                return this.exec.apply( this, [ 'crop' ].concat( args ) );\n            },\n\n            getAsDataUrl: function( type ) {\n                return this.exec( 'getAsDataUrl', type );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this.exec( 'getAsBlob', type );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n\n        return Image;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/image',[\n        'base',\n        'uploader',\n        'lib/image',\n        'widgets/widget'\n    ], function( Base, Uploader, Image ) {\n\n        var $ = Base.$,\n            throttle;\n\n        // 根据要处理的文件大小来节流，一次不能处理太多，会卡。\n        throttle = (function( max ) {\n            var occupied = 0,\n                waiting = [],\n                tick = function() {\n                    var item;\n\n                    while ( waiting.length && occupied < max ) {\n                        item = waiting.shift();\n                        occupied += item[ 0 ];\n                        item[ 1 ]();\n                    }\n                };\n\n            return function( emiter, size, cb ) {\n                waiting.push([ size, cb ]);\n                emiter.once( 'destroy', function() {\n                    occupied -= size;\n                    setTimeout( tick, 1 );\n                });\n                setTimeout( tick, 1 );\n            };\n        })( 5 * 1024 * 1024 );\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Object} [thumb]\n             * @namespace options\n             * @for Uploader\n             * @description 配置生成缩略图的选项。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 110,\n             *     height: 110,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 70,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: true,\n             *\n             *     // 是否允许裁剪。\n             *     crop: true,\n             *\n             *     // 为空的话则保留原有图片格式。\n             *     // 否则强制转换成指定的类型。\n             *     type: 'image/jpeg'\n             * }\n             * ```\n             */\n            thumb: {\n                width: 110,\n                height: 110,\n                quality: 70,\n                allowMagnify: true,\n                crop: true,\n                preserveHeaders: false,\n\n                // 为空的话则保留原有图片格式。\n                // 否则强制转换成指定的类型。\n                // IE 8下面 base64 大小不能超过 32K 否则预览失败，而非 jpeg 编码的图片很可\n                // 能会超过 32k, 所以这里设置成预览的时候都是 image/jpeg\n                type: 'image/jpeg'\n            },\n\n            /**\n             * @property {Object} [compress]\n             * @namespace options\n             * @for Uploader\n             * @description 配置压缩的图片的选项。如果此选项为`false`, 则图片在上传前不进行压缩。\n             *\n             * 默认为：\n             *\n             * ```javascript\n             * {\n             *     width: 1600,\n             *     height: 1600,\n             *\n             *     // 图片质量，只有type为`image/jpeg`的时候才有效。\n             *     quality: 90,\n             *\n             *     // 是否允许放大，如果想要生成小图的时候不失真，此选项应该设置为false.\n             *     allowMagnify: false,\n             *\n             *     // 是否允许裁剪。\n             *     crop: false,\n             *\n             *     // 是否保留头部meta信息。\n             *     preserveHeaders: true,\n             *\n             *     // 如果发现压缩后文件大小比原来还大，则使用原来图片\n             *     // 此属性可能会影响图片自动纠正功能\n             *     noCompressIfLarger: false,\n             *\n             *     // 单位字节，如果图片大小小于此值，不会采用压缩。\n             *     compressSize: 0\n             * }\n             * ```\n             */\n            compress: {\n                width: 1600,\n                height: 1600,\n                quality: 90,\n                allowMagnify: false,\n                crop: false,\n                preserveHeaders: true\n            }\n        });\n\n        return Uploader.register({\n\n            name: 'image',\n\n\n            /**\n             * 生成缩略图，此过程为异步，所以需要传入`callback`。\n             * 通常情况在图片加入队里后调用此方法来生成预览图以增强交互效果。\n             *\n             * 当 width 或者 height 的值介于 0 - 1 时，被当成百分比使用。\n             *\n             * `callback`中可以接收到两个参数。\n             * * 第一个为error，如果生成缩略图有错误，此error将为真。\n             * * 第二个为ret, 缩略图的Data URL值。\n             *\n             * **注意**\n             * Date URL在IE6/7中不支持，所以不用调用此方法了，直接显示一张暂不支持预览图片好了。\n             * 也可以借助服务端，将 base64 数据传给服务端，生成一个临时文件供预览。\n             *\n             * @method makeThumb\n             * @grammar makeThumb( file, callback ) => undefined\n             * @grammar makeThumb( file, callback, width, height ) => undefined\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.makeThumb( file, function( error, ret ) {\n             *         if ( error ) {\n             *             $li.text('预览错误');\n             *         } else {\n             *             $li.append('<img alt=\"\" src=\"' + ret + '\" />');\n             *         }\n             *     });\n             *\n             * });\n             */\n            makeThumb: function( file, cb, width, height ) {\n                var opts, image;\n\n                file = this.request( 'get-file', file );\n\n                // 只预览图片格式。\n                if ( !file.type.match( /^image/ ) ) {\n                    cb( true );\n                    return;\n                }\n\n                opts = $.extend({}, this.options.thumb );\n\n                // 如果传入的是object.\n                if ( $.isPlainObject( width ) ) {\n                    opts = $.extend( opts, width );\n                    width = null;\n                }\n\n                width = width || opts.width;\n                height = height || opts.height;\n\n                image = new Image( opts );\n\n                image.once( 'load', function() {\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                // 当 resize 完后\n                image.once( 'complete', function() {\n                    cb( false, image.getAsDataUrl( opts.type ) );\n                    image.destroy();\n                });\n\n                image.once( 'error', function( reason ) {\n                    cb( reason || true );\n                    image.destroy();\n                });\n\n                throttle( image, file.source.size, function() {\n                    file._info && image.info( file._info );\n                    file._meta && image.meta( file._meta );\n                    image.loadFromBlob( file.source );\n                });\n            },\n\n            beforeSendFile: function( file ) {\n                var opts = this.options.compress || this.options.resize,\n                    compressSize = opts && opts.compressSize || 0,\n                    noCompressIfLarger = opts && opts.noCompressIfLarger || false,\n                    image, deferred;\n\n                file = this.request( 'get-file', file );\n\n                // 只压缩 jpeg 图片格式。\n                // gif 可能会丢失针\n                // bmp png 基本上尺寸都不大，且压缩比比较小。\n                if ( !opts || !~'image/jpeg,image/jpg'.indexOf( file.type ) ||\n                        file.size < compressSize ||\n                        file._compressed ) {\n                    return;\n                }\n\n                opts = $.extend({}, opts );\n                deferred = Base.Deferred();\n\n                image = new Image( opts );\n\n                deferred.always(function() {\n                    image.destroy();\n                    image = null;\n                });\n                image.once( 'error', deferred.reject );\n                image.once( 'load', function() {\n                    var width = opts.width,\n                        height = opts.height;\n\n                    file._info = file._info || image.info();\n                    file._meta = file._meta || image.meta();\n\n                    // 如果 width 的值介于 0 - 1\n                    // 说明设置的是百分比。\n                    if ( width <= 1 && width > 0 ) {\n                        width = file._info.width * width;\n                    }\n\n                    // 同样的规则应用于 height\n                    if ( height <= 1 && height > 0 ) {\n                        height = file._info.height * height;\n                    }\n\n                    image.resize( width, height );\n                });\n\n                image.once( 'complete', function() {\n                    var blob, size;\n\n                    // 移动端 UC / qq 浏览器的无图模式下\n                    // ctx.getImageData 处理大图的时候会报 Exception\n                    // INDEX_SIZE_ERR: DOM Exception 1\n                    try {\n                        blob = image.getAsBlob( opts.type );\n\n                        size = file.size;\n\n                        // 如果压缩后，比原来还大则不用压缩后的。\n                        if ( !noCompressIfLarger || blob.size < size ) {\n                            // file.source.destroy && file.source.destroy();\n                            file.source = blob;\n                            file.size = blob.size;\n\n                            file.trigger( 'resize', blob.size, size );\n                        }\n\n                        // 标记，避免重复压缩。\n                        file._compressed = true;\n                        deferred.resolve();\n                    } catch ( e ) {\n                        // 出错了直接继续，让其上传原始图片\n                        deferred.resolve();\n                    }\n                });\n\n                file._info && image.info( file._info );\n                file._meta && image.meta( file._meta );\n\n                image.loadFromBlob( file.source );\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview 文件属性封装\n     */\n    define('file',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            idPrefix = 'WU_FILE_',\n            idSuffix = 0,\n            rExt = /\\.([^.]+)$/,\n            statusMap = {};\n\n        function gid() {\n            return idPrefix + idSuffix++;\n        }\n\n        /**\n         * 文件类\n         * @class File\n         * @constructor 构造函数\n         * @grammar new File( source ) => File\n         * @param {Lib.File} source [lib.File](#Lib.File)实例, 此source对象是带有Runtime信息的。\n         */\n        function WUFile( source ) {\n\n            /**\n             * 文件名，包括扩展名（后缀）\n             * @property name\n             * @type {string}\n             */\n            this.name = source.name || 'Untitled';\n\n            /**\n             * 文件体积（字节）\n             * @property size\n             * @type {uint}\n             * @default 0\n             */\n            this.size = source.size || 0;\n\n            /**\n             * 文件MIMETYPE类型，与文件类型的对应关系请参考[http://t.cn/z8ZnFny](http://t.cn/z8ZnFny)\n             * @property type\n             * @type {string}\n             * @default 'application/octet-stream'\n             */\n            this.type = source.type || 'application/octet-stream';\n\n            /**\n             * 文件最后修改日期\n             * @property lastModifiedDate\n             * @type {int}\n             * @default 当前时间戳\n             */\n            this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);\n\n            /**\n             * 文件ID，每个对象具有唯一ID，与文件名无关\n             * @property id\n             * @type {string}\n             */\n            this.id = gid();\n\n            /**\n             * 文件扩展名，通过文件名获取，例如test.png的扩展名为png\n             * @property ext\n             * @type {string}\n             */\n            this.ext = rExt.exec( this.name ) ? RegExp.$1 : '';\n\n\n            /**\n             * 状态文字说明。在不同的status语境下有不同的用途。\n             * @property statusText\n             * @type {string}\n             */\n            this.statusText = '';\n\n            // 存储文件状态，防止通过属性直接修改\n            statusMap[ this.id ] = WUFile.Status.INITED;\n\n            this.source = source;\n            this.loaded = 0;\n\n            this.on( 'error', function( msg ) {\n                this.setStatus( WUFile.Status.ERROR, msg );\n            });\n        }\n\n        $.extend( WUFile.prototype, {\n\n            /**\n             * 设置状态，状态变化时会触发`change`事件。\n             * @method setStatus\n             * @grammar setStatus( status[, statusText] );\n             * @param {File.Status|String} status [文件状态值](#WebUploader:File:File.Status)\n             * @param {String} [statusText=''] 状态说明，常在error时使用，用http, abort,server等来标记是由于什么原因导致文件错误。\n             */\n            setStatus: function( status, text ) {\n\n                var prevStatus = statusMap[ this.id ];\n\n                typeof text !== 'undefined' && (this.statusText = text);\n\n                if ( status !== prevStatus ) {\n                    statusMap[ this.id ] = status;\n                    /**\n                     * 文件状态变化\n                     * @event statuschange\n                     */\n                    this.trigger( 'statuschange', status, prevStatus );\n                }\n\n            },\n\n            /**\n             * 获取文件状态\n             * @return {File.Status}\n             * @example\n                     文件状态具体包括以下几种类型：\n                     {\n                         // 初始化\n                        INITED:     0,\n                        // 已入队列\n                        QUEUED:     1,\n                        // 正在上传\n                        PROGRESS:     2,\n                        // 上传出错\n                        ERROR:         3,\n                        // 上传成功\n                        COMPLETE:     4,\n                        // 上传取消\n                        CANCELLED:     5\n                    }\n             */\n            getStatus: function() {\n                return statusMap[ this.id ];\n            },\n\n            /**\n             * 获取文件原始信息。\n             * @return {*}\n             */\n            getSource: function() {\n                return this.source;\n            },\n\n            destroy: function() {\n                this.off();\n                delete statusMap[ this.id ];\n            }\n        });\n\n        Mediator.installTo( WUFile.prototype );\n\n        /**\n         * 文件状态值，具体包括以下几种类型：\n         * * `inited` 初始状态\n         * * `queued` 已经进入队列, 等待上传\n         * * `progress` 上传中\n         * * `complete` 上传完成。\n         * * `error` 上传出错，可重试\n         * * `interrupt` 上传中断，可续传。\n         * * `invalid` 文件不合格，不能重试上传。会自动从队列中移除。\n         * * `cancelled` 文件被移除。\n         * @property {Object} Status\n         * @namespace File\n         * @class File\n         * @static\n         */\n        WUFile.Status = {\n            INITED:     'inited',    // 初始状态\n            QUEUED:     'queued',    // 已经进入队列, 等待上传\n            PROGRESS:   'progress',    // 上传中\n            ERROR:      'error',    // 上传出错，可重试\n            COMPLETE:   'complete',    // 上传完成。\n            CANCELLED:  'cancelled',    // 上传取消。\n            INTERRUPT:  'interrupt',    // 上传中断，可续传。\n            INVALID:    'invalid'    // 文件不合格，不能重试上传。\n        };\n\n        return WUFile;\n    });\n\n    /**\n     * @fileOverview 文件队列\n     */\n    define('queue',[\n        'base',\n        'mediator',\n        'file'\n    ], function( Base, Mediator, WUFile ) {\n\n        var $ = Base.$,\n            STATUS = WUFile.Status;\n\n        /**\n         * 文件队列, 用来存储各个状态中的文件。\n         * @class Queue\n         * @extends Mediator\n         */\n        function Queue() {\n\n            /**\n             * 统计文件数。\n             * * `numOfQueue` 队列中的文件数。\n             * * `numOfSuccess` 上传成功的文件数\n             * * `numOfCancel` 被取消的文件数\n             * * `numOfProgress` 正在上传中的文件数\n             * * `numOfUploadFailed` 上传错误的文件数。\n             * * `numOfInvalid` 无效的文件数。\n             * * `numofDeleted` 被移除的文件数。\n             * @property {Object} stats\n             */\n            this.stats = {\n                numOfQueue: 0,\n                numOfSuccess: 0,\n                numOfCancel: 0,\n                numOfProgress: 0,\n                numOfUploadFailed: 0,\n                numOfInvalid: 0,\n                numofDeleted: 0,\n                numofInterrupt: 0\n            };\n\n            // 上传队列，仅包括等待上传的文件\n            this._queue = [];\n\n            // 存储所有文件\n            this._map = {};\n        }\n\n        $.extend( Queue.prototype, {\n\n            /**\n             * 将新文件加入对队列尾部\n             *\n             * @method append\n             * @param  {File} file   文件对象\n             */\n            append: function( file ) {\n                this._queue.push( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 将新文件加入对队列头部\n             *\n             * @method prepend\n             * @param  {File} file   文件对象\n             */\n            prepend: function( file ) {\n                this._queue.unshift( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 获取文件对象\n             *\n             * @method getFile\n             * @param  {String} fileId   文件ID\n             * @return {File}\n             */\n            getFile: function( fileId ) {\n                if ( typeof fileId !== 'string' ) {\n                    return fileId;\n                }\n                return this._map[ fileId ];\n            },\n\n            /**\n             * 从队列中取出一个指定状态的文件。\n             * @grammar fetch( status ) => File\n             * @method fetch\n             * @param {String} status [文件状态值](#WebUploader:File:File.Status)\n             * @return {File} [File](#WebUploader:File)\n             */\n            fetch: function( status ) {\n                var len = this._queue.length,\n                    i, file;\n\n                status = status || STATUS.QUEUED;\n\n                for ( i = 0; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( status === file.getStatus() ) {\n                        return file;\n                    }\n                }\n\n                return null;\n            },\n\n            /**\n             * 对队列进行排序，能够控制文件上传顺序。\n             * @grammar sort( fn ) => undefined\n             * @method sort\n             * @param {Function} fn 排序方法\n             */\n            sort: function( fn ) {\n                if ( typeof fn === 'function' ) {\n                    this._queue.sort( fn );\n                }\n            },\n\n            /**\n             * 获取指定类型的文件列表, 列表中每一个成员为[File](#WebUploader:File)对象。\n             * @grammar getFiles( [status1[, status2 ...]] ) => Array\n             * @method getFiles\n             * @param {String} [status] [文件状态值](#WebUploader:File:File.Status)\n             */\n            getFiles: function() {\n                var sts = [].slice.call( arguments, 0 ),\n                    ret = [],\n                    i = 0,\n                    len = this._queue.length,\n                    file;\n\n                for ( ; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( sts.length && !~$.inArray( file.getStatus(), sts ) ) {\n                        continue;\n                    }\n\n                    ret.push( file );\n                }\n\n                return ret;\n            },\n\n            /**\n             * 在队列中删除文件。\n             * @grammar removeFile( file ) => Array\n             * @method removeFile\n             * @param {File} 文件对象。\n             */\n            removeFile: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( existing ) {\n                    delete this._map[ file.id ];\n                    file.destroy();\n                    this.stats.numofDeleted++;\n                }\n            },\n\n            _fileAdded: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( !existing ) {\n                    this._map[ file.id ] = file;\n\n                    file.on( 'statuschange', function( cur, pre ) {\n                        me._onFileStatusChange( cur, pre );\n                    });\n                }\n            },\n\n            _onFileStatusChange: function( curStatus, preStatus ) {\n                var stats = this.stats;\n\n                switch ( preStatus ) {\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress--;\n                        break;\n\n                    case STATUS.QUEUED:\n                        stats.numOfQueue --;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed--;\n                        break;\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid--;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt--;\n                        break;\n                }\n\n                switch ( curStatus ) {\n                    case STATUS.QUEUED:\n                        stats.numOfQueue++;\n                        break;\n\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress++;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed++;\n                        break;\n\n                    case STATUS.COMPLETE:\n                        stats.numOfSuccess++;\n                        break;\n\n                    case STATUS.CANCELLED:\n                        stats.numOfCancel++;\n                        break;\n\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid++;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt++;\n                        break;\n                }\n            }\n\n        });\n\n        Mediator.installTo( Queue.prototype );\n\n        return Queue;\n    });\n    /**\n     * @fileOverview 队列\n     */\n    define('widgets/queue',[\n        'base',\n        'uploader',\n        'queue',\n        'file',\n        'lib/file',\n        'runtime/client',\n        'widgets/widget'\n    ], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {\n\n        var $ = Base.$,\n            rExt = /\\.\\w+$/,\n            Status = WUFile.Status;\n\n        return Uploader.register({\n            name: 'queue',\n\n            init: function( opts ) {\n                var me = this,\n                    deferred, len, i, item, arr, accept, runtime;\n\n                if ( $.isPlainObject( opts.accept ) ) {\n                    opts.accept = [ opts.accept ];\n                }\n\n                // accept中的中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].extensions;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = '\\\\.' + arr.join(',')\n                                .replace( /,/g, '$|\\\\.' )\n                                .replace( /\\*/g, '.*' ) + '$';\n                    }\n\n                    me.accept = new RegExp( accept, 'i' );\n                }\n\n                me.queue = new Queue();\n                me.stats = me.queue.stats;\n\n                // 如果当前不是html5运行时，那就算了。\n                // 不执行后续操作\n                if ( this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                // 创建一个 html5 运行时的 placeholder\n                // 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。\n                deferred = Base.Deferred();\n                this.placeholder = runtime = new RuntimeClient('Placeholder');\n                runtime.connectRuntime({\n                    runtimeOrder: 'html5'\n                }, function() {\n                    me._ruid = runtime.getRuid();\n                    deferred.resolve();\n                });\n                return deferred.promise();\n            },\n\n\n            // 为了支持外部直接添加一个原生File对象。\n            _wrapFile: function( file ) {\n                if ( !(file instanceof WUFile) ) {\n\n                    if ( !(file instanceof File) ) {\n                        if ( !this._ruid ) {\n                            throw new Error('Can\\'t add external files.');\n                        }\n                        file = new File( this._ruid, file );\n                    }\n\n                    file = new WUFile( file );\n                }\n\n                return file;\n            },\n\n            // 判断文件是否可以被加入队列\n            acceptFile: function( file ) {\n                var invalid = !file || !file.size || this.accept &&\n\n                        // 如果名字中有后缀，才做后缀白名单处理。\n                        rExt.exec( file.name ) && !this.accept.test( file.name );\n\n                return !invalid;\n            },\n\n\n            /**\n             * @event beforeFileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列之前触发，此事件的handler返回值为`false`，则此文件不会被添加进入队列。\n             * @for  Uploader\n             */\n\n            /**\n             * @event fileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列以后触发。\n             * @for  Uploader\n             */\n\n            _addFile: function( file ) {\n                var me = this;\n\n                file = me._wrapFile( file );\n\n                // 不过类型判断允许不允许，先派送 `beforeFileQueued`\n                if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {\n                    return;\n                }\n\n                // 类型不匹配，则派送错误事件，并返回。\n                if ( !me.acceptFile( file ) ) {\n                    me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );\n                    return;\n                }\n\n                me.queue.append( file );\n                me.owner.trigger( 'fileQueued', file );\n                return file;\n            },\n\n            getFile: function( fileId ) {\n                return this.queue.getFile( fileId );\n            },\n\n            /**\n             * @event filesQueued\n             * @param {File} files 数组，内容为原始File(lib/File）对象。\n             * @description 当一批文件添加进队列以后触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @property {Boolean} [auto=false]\n             * @namespace options\n             * @for Uploader\n             * @description 设置为 true 后，不需要手动调用上传，有文件选择即开始上传。\n             *\n             */\n\n            /**\n             * @method addFiles\n             * @grammar addFiles( file ) => undefined\n             * @grammar addFiles( [file1, file2 ...] ) => undefined\n             * @param {Array of File or File} [files] Files 对象 数组\n             * @description 添加文件到队列\n             * @for  Uploader\n             */\n            addFile: function( files ) {\n                var me = this;\n\n                if ( !files.length ) {\n                    files = [ files ];\n                }\n\n                files = $.map( files, function( file ) {\n                    return me._addFile( file );\n                });\n\n                me.owner.trigger( 'filesQueued', files );\n\n                if ( me.options.auto ) {\n                    setTimeout(function() {\n                        me.request('start-upload');\n                    }, 20 );\n                }\n            },\n\n            getStats: function() {\n                return this.stats;\n            },\n\n            /**\n             * @event fileDequeued\n             * @param {File} file File对象\n             * @description 当文件被移除队列后触发。\n             * @for  Uploader\n             */\n\n             /**\n             * @method removeFile\n             * @grammar removeFile( file ) => undefined\n             * @grammar removeFile( id ) => undefined\n             * @grammar removeFile( file, true ) => undefined\n             * @grammar removeFile( id, true ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 移除某一文件, 默认只会标记文件状态为已取消，如果第二个参数为 `true` 则会从 queue 中移除。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.removeFile( file );\n             * })\n             */\n            removeFile: function( file, remove ) {\n                var me = this;\n\n                file = file.id ? file : me.queue.getFile( file );\n\n                this.request( 'cancel-file', file );\n\n                if ( remove ) {\n                    this.queue.removeFile( file );\n                }\n            },\n\n            /**\n             * @method getFiles\n             * @grammar getFiles() => Array\n             * @grammar getFiles( status1, status2, status... ) => Array\n             * @description 返回指定状态的文件集合，不传参数将返回所有状态的文件。\n             * @for  Uploader\n             * @example\n             * console.log( uploader.getFiles() );    // => all files\n             * console.log( uploader.getFiles('error') )    // => all error files.\n             */\n            getFiles: function() {\n                return this.queue.getFiles.apply( this.queue, arguments );\n            },\n\n            fetchFile: function() {\n                return this.queue.fetch.apply( this.queue, arguments );\n            },\n\n            /**\n             * @method retry\n             * @grammar retry() => undefined\n             * @grammar retry( file ) => undefined\n             * @description 重试上传，重试指定文件，或者从出错的文件开始重新上传。\n             * @for  Uploader\n             * @example\n             * function retry() {\n             *     uploader.retry();\n             * }\n             */\n            retry: function( file, noForceStart ) {\n                var me = this,\n                    files, i, len;\n\n                if ( file ) {\n                    file = file.id ? file : me.queue.getFile( file );\n                    file.setStatus( Status.QUEUED );\n                    noForceStart || me.request('start-upload');\n                    return;\n                }\n\n                files = me.queue.getFiles( Status.ERROR );\n                i = 0;\n                len = files.length;\n\n                for ( ; i < len; i++ ) {\n                    file = files[ i ];\n                    file.setStatus( Status.QUEUED );\n                }\n\n                me.request('start-upload');\n            },\n\n            /**\n             * @method sort\n             * @grammar sort( fn ) => undefined\n             * @description 排序队列中的文件，在上传之前调整可以控制上传顺序。\n             * @for  Uploader\n             */\n            sortFiles: function() {\n                return this.queue.sort.apply( this.queue, arguments );\n            },\n\n            /**\n             * @event reset\n             * @description 当 uploader 被重置的时候触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @method reset\n             * @grammar reset() => undefined\n             * @description 重置uploader。目前只重置了队列。\n             * @for  Uploader\n             * @example\n             * uploader.reset();\n             */\n            reset: function() {\n                this.owner.trigger('reset');\n                this.queue = new Queue();\n                this.stats = this.queue.stats;\n            },\n\n            destroy: function() {\n                this.reset();\n                this.placeholder && this.placeholder.destroy();\n            }\n        });\n\n    });\n    /**\n     * @fileOverview 添加获取Runtime相关信息的方法。\n     */\n    define('widgets/runtime',[\n        'uploader',\n        'runtime/runtime',\n        'widgets/widget'\n    ], function( Uploader, Runtime ) {\n\n        Uploader.support = function() {\n            return Runtime.hasRuntime.apply( Runtime, arguments );\n        };\n\n        /**\n         * @property {Object} [runtimeOrder=html5,flash]\n         * @namespace options\n         * @for Uploader\n         * @description 指定运行时启动顺序。默认会想尝试 html5 是否支持，如果支持则使用 html5, 否则则使用 flash.\n         *\n         * 可以将此值设置成 `flash`，来强制使用 flash 运行时。\n         */\n\n        return Uploader.register({\n            name: 'runtime',\n\n            init: function() {\n                if ( !this.predictRuntimeType() ) {\n                    throw Error('Runtime Error');\n                }\n            },\n\n            /**\n             * 预测Uploader将采用哪个`Runtime`\n             * @grammar predictRuntimeType() => String\n             * @method predictRuntimeType\n             * @for  Uploader\n             */\n            predictRuntimeType: function() {\n                var orders = this.options.runtimeOrder || Runtime.orders,\n                    type = this.type,\n                    i, len;\n\n                if ( !type ) {\n                    orders = orders.split( /\\s*,\\s*/g );\n\n                    for ( i = 0, len = orders.length; i < len; i++ ) {\n                        if ( Runtime.hasRuntime( orders[ i ] ) ) {\n                            this.type = type = orders[ i ];\n                            break;\n                        }\n                    }\n                }\n\n                return type;\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     */\n    define('lib/transport',[\n        'base',\n        'runtime/client',\n        'mediator'\n    ], function( Base, RuntimeClient, Mediator ) {\n\n        var $ = Base.$;\n\n        function Transport( opts ) {\n            var me = this;\n\n            opts = me.options = $.extend( true, {}, Transport.options, opts || {} );\n            RuntimeClient.call( this, 'Transport' );\n\n            this._blob = null;\n            this._formData = opts.formData || {};\n            this._headers = opts.headers || {};\n\n            this.on( 'progress', this._timeout );\n            this.on( 'load error', function() {\n                me.trigger( 'progress', 1 );\n                clearTimeout( me._timer );\n            });\n        }\n\n        Transport.options = {\n            server: '',\n            method: 'POST',\n\n            // 跨域时，是否允许携带cookie, 只有html5 runtime才有效\n            withCredentials: false,\n            fileVal: 'file',\n            timeout: 2 * 60 * 1000,    // 2分钟\n            formData: {},\n            headers: {},\n            sendAsBinary: false\n        };\n\n        $.extend( Transport.prototype, {\n\n            // 添加Blob, 只能添加一次，最后一次有效。\n            appendBlob: function( key, blob, filename ) {\n                var me = this,\n                    opts = me.options;\n\n                if ( me.getRuid() ) {\n                    me.disconnectRuntime();\n                }\n\n                // 连接到blob归属的同一个runtime.\n                me.connectRuntime( blob.ruid, function() {\n                    me.exec('init');\n                });\n\n                me._blob = blob;\n                opts.fileVal = key || opts.fileVal;\n                opts.filename = filename || opts.filename;\n            },\n\n            // 添加其他字段\n            append: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._formData, key );\n                } else {\n                    this._formData[ key ] = value;\n                }\n            },\n\n            setRequestHeader: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._headers, key );\n                } else {\n                    this._headers[ key ] = value;\n                }\n            },\n\n            send: function( method ) {\n                this.exec( 'send', method );\n                this._timeout();\n            },\n\n            abort: function() {\n                clearTimeout( this._timer );\n                return this.exec('abort');\n            },\n\n            destroy: function() {\n                this.trigger('destroy');\n                this.off();\n                this.exec('destroy');\n                this.disconnectRuntime();\n            },\n\n            getResponse: function() {\n                return this.exec('getResponse');\n            },\n\n            getResponseAsJson: function() {\n                return this.exec('getResponseAsJson');\n            },\n\n            getStatus: function() {\n                return this.exec('getStatus');\n            },\n\n            _timeout: function() {\n                var me = this,\n                    duration = me.options.timeout;\n\n                if ( !duration ) {\n                    return;\n                }\n\n                clearTimeout( me._timer );\n                me._timer = setTimeout(function() {\n                    me.abort();\n                    me.trigger( 'error', 'timeout' );\n                }, duration );\n            }\n\n        });\n\n        // 让Transport具备事件功能。\n        Mediator.installTo( Transport.prototype );\n\n        return Transport;\n    });\n    /**\n     * @fileOverview 负责文件上传相关。\n     */\n    define('widgets/upload',[\n        'base',\n        'uploader',\n        'file',\n        'lib/transport',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile, Transport ) {\n\n        var $ = Base.$,\n            isPromise = Base.isPromise,\n            Status = WUFile.Status;\n\n        // 添加默认配置项\n        $.extend( Uploader.options, {\n\n\n            /**\n             * @property {Boolean} [prepareNextFile=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否允许在文件传输时提前把下一个文件准备好。\n             * 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。\n             * 如果能提前在当前文件传输期处理，可以节省总体耗时。\n             */\n            prepareNextFile: false,\n\n            /**\n             * @property {Boolean} [chunked=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否要分片处理大文件上传。\n             */\n            chunked: false,\n\n            /**\n             * @property {Boolean} [chunkSize=5242880]\n             * @namespace options\n             * @for Uploader\n             * @description 如果要分片，分多大一片？ 默认大小为5M.\n             */\n            chunkSize: 5 * 1024 * 1024,\n\n            /**\n             * @property {Boolean} [chunkRetry=2]\n             * @namespace options\n             * @for Uploader\n             * @description 如果某个分片由于网络问题出错，允许自动重传多少次？\n             */\n            chunkRetry: 2,\n\n            /**\n             * @property {Boolean} [threads=3]\n             * @namespace options\n             * @for Uploader\n             * @description 上传并发数。允许同时最大上传进程数。\n             */\n            threads: 3,\n\n\n            /**\n             * @property {Object} [formData={}]\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传请求的参数表，每次发送都会发送此对象中的参数。\n             */\n            formData: {}\n\n            /**\n             * @property {Object} [fileVal='file']\n             * @namespace options\n             * @for Uploader\n             * @description 设置文件上传域的name。\n             */\n\n            /**\n             * @property {Object} [method='POST']\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传方式，`POST`或者`GET`。\n             */\n\n            /**\n             * @property {Object} [sendAsBinary=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否已二进制的流的方式发送文件，这样整个上传内容`php://input`都为文件内容，\n             * 其他参数在$_GET数组中。\n             */\n        });\n\n        // 负责将文件切片。\n        function CuteFile( file, chunkSize ) {\n            var pending = [],\n                blob = file.source,\n                total = blob.size,\n                chunks = chunkSize ? Math.ceil( total / chunkSize ) : 1,\n                start = 0,\n                index = 0,\n                len, api;\n\n            api = {\n                file: file,\n\n                has: function() {\n                    return !!pending.length;\n                },\n\n                shift: function() {\n                    return pending.shift();\n                },\n\n                unshift: function( block ) {\n                    pending.unshift( block );\n                }\n            };\n\n            while ( index < chunks ) {\n                len = Math.min( chunkSize, total - start );\n\n                pending.push({\n                    file: file,\n                    start: start,\n                    end: chunkSize ? (start + len) : total,\n                    total: total,\n                    chunks: chunks,\n                    chunk: index++,\n                    cuted: api\n                });\n                start += len;\n            }\n\n            file.blocks = pending.concat();\n            file.remaning = pending.length;\n\n            return api;\n        }\n\n        Uploader.register({\n            name: 'upload',\n\n            init: function() {\n                var owner = this.owner,\n                    me = this;\n\n                this.runing = false;\n                this.progress = false;\n\n                owner\n                    .on( 'startUpload', function() {\n                        me.progress = true;\n                    })\n                    .on( 'uploadFinished', function() {\n                        me.progress = false;\n                    });\n\n                // 记录当前正在传的数据，跟threads相关\n                this.pool = [];\n\n                // 缓存分好片的文件。\n                this.stack = [];\n\n                // 缓存即将上传的文件。\n                this.pending = [];\n\n                // 跟踪还有多少分片在上传中但是没有完成上传。\n                this.remaning = 0;\n                this.__tick = Base.bindFn( this._tick, this );\n\n                owner.on( 'uploadComplete', function( file ) {\n\n                    // 把其他块取消了。\n                    file.blocks && $.each( file.blocks, function( _, v ) {\n                        v.transport && (v.transport.abort(), v.transport.destroy());\n                        delete v.transport;\n                    });\n\n                    delete file.blocks;\n                    delete file.remaning;\n                });\n            },\n\n            reset: function() {\n                this.request( 'stop-upload', true );\n                this.runing = false;\n                this.pool = [];\n                this.stack = [];\n                this.pending = [];\n                this.remaning = 0;\n                this._trigged = false;\n                this._promise = null;\n            },\n\n            /**\n             * @event startUpload\n             * @description 当开始上传流程时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 开始上传。此方法可以从初始状态调用开始上传流程，也可以从暂停状态调用，继续上传流程。\n             *\n             * 可以指定开始某一个文件。\n             * @grammar upload() => undefined\n             * @grammar upload( file | fileId) => undefined\n             * @method upload\n             * @for  Uploader\n             */\n            startUpload: function(file) {\n                var me = this;\n\n                // 移出invalid的文件\n                $.each( me.request( 'get-files', Status.INVALID ), function() {\n                    me.request( 'remove-file', this );\n                });\n\n                // 如果指定了开始某个文件，则只开始指定文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        $.each( me.pool, function( _, v ) {\n\n                            // 之前暂停过。\n                            if (v.file !== file) {\n                                return;\n                            }\n\n                            v.transport && v.transport.send();\n                        });\n\n                        file.setStatus( Status.QUEUED );\n                    } else if (file.getStatus() === Status.PROGRESS) {\n                        return;\n                    } else {\n                        file.setStatus( Status.QUEUED );\n                    }\n                } else {\n                    $.each( me.request( 'get-files', [ Status.INITED ] ), function() {\n                        this.setStatus( Status.QUEUED );\n                    });\n                }\n\n                if ( me.runing ) {\n                    return;\n                }\n\n                me.runing = true;\n\n                var files = [];\n\n                // 如果有暂停的，则续传\n                $.each( me.pool, function( _, v ) {\n                    var file = v.file;\n\n                    if ( file.getStatus() === Status.INTERRUPT ) {\n                        files.push(file);\n                        me._trigged = false;\n                        v.transport && v.transport.send();\n                    }\n                });\n\n                var file;\n                while ( (file = files.shift()) ) {\n                    file.setStatus( Status.PROGRESS );\n                }\n\n                file || $.each( me.request( 'get-files',\n                        Status.INTERRUPT ), function() {\n                    this.setStatus( Status.PROGRESS );\n                });\n\n                me._trigged = false;\n                Base.nextTick( me.__tick );\n                me.owner.trigger('startUpload');\n            },\n\n            /**\n             * @event stopUpload\n             * @description 当开始上传流程暂停时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 暂停上传。第一个参数为是否中断上传当前正在上传的文件。\n             *\n             * 如果第一个参数是文件，则只暂停指定文件。\n             * @grammar stop() => undefined\n             * @grammar stop( true ) => undefined\n             * @grammar stop( file ) => undefined\n             * @method stop\n             * @for  Uploader\n             */\n            stopUpload: function( file, interrupt ) {\n                var me = this;\n\n                if (file === true) {\n                    interrupt = file;\n                    file = null;\n                }\n\n                if ( me.runing === false ) {\n                    return;\n                }\n\n                // 如果只是暂停某个文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if ( file.getStatus() !== Status.PROGRESS &&\n                            file.getStatus() !== Status.QUEUED ) {\n                        return;\n                    }\n\n                    file.setStatus( Status.INTERRUPT );\n                    $.each( me.pool, function( _, v ) {\n\n                        // 只 abort 指定的文件。\n                        if (v.file !== file) {\n                            return;\n                        }\n\n                        v.transport && v.transport.abort();\n                        me._putback(v);\n                        me._popBlock(v);\n                    });\n\n                    return Base.nextTick( me.__tick );\n                }\n\n                me.runing = false;\n\n                if (this._promise && this._promise.file) {\n                    this._promise.file.setStatus( Status.INTERRUPT );\n                }\n\n                interrupt && $.each( me.pool, function( _, v ) {\n                    v.transport && v.transport.abort();\n                    v.file.setStatus( Status.INTERRUPT );\n                });\n\n                me.owner.trigger('stopUpload');\n            },\n\n            /**\n             * @method cancelFile\n             * @grammar cancelFile( file ) => undefined\n             * @grammar cancelFile( id ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 标记文件状态为已取消, 同时将中断文件传输。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.cancelFile( file );\n             * })\n             */\n            cancelFile: function( file ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                file.setStatus( Status.CANCELLED );\n                this.owner.trigger( 'fileDequeued', file );\n            },\n\n            /**\n             * 判断`Uplaode`r是否正在上传中。\n             * @grammar isInProgress() => Boolean\n             * @method isInProgress\n             * @for  Uploader\n             */\n            isInProgress: function() {\n                return !!this.progress;\n            },\n\n            _getStats: function() {\n                return this.request('get-stats');\n            },\n\n            /**\n             * 掉过一个文件上传，直接标记指定文件为已上传状态。\n             * @grammar skipFile( file ) => undefined\n             * @method skipFile\n             * @for  Uploader\n             */\n            skipFile: function( file, status ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                file.setStatus( status || Status.COMPLETE );\n                file.skipped = true;\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                this.owner.trigger( 'uploadSkip', file );\n            },\n\n            /**\n             * @event uploadFinished\n             * @description 当所有文件上传结束时触发。\n             * @for  Uploader\n             */\n            _tick: function() {\n                var me = this,\n                    opts = me.options,\n                    fn, val;\n\n                // 上一个promise还没有结束，则等待完成后再执行。\n                if ( me._promise ) {\n                    return me._promise.always( me.__tick );\n                }\n\n                // 还有位置，且还有文件要处理的话。\n                if ( me.pool.length < opts.threads && (val = me._nextBlock()) ) {\n                    me._trigged = false;\n\n                    fn = function( val ) {\n                        me._promise = null;\n\n                        // 有可能是reject过来的，所以要检测val的类型。\n                        val && val.file && me._startSend( val );\n                        Base.nextTick( me.__tick );\n                    };\n\n                    me._promise = isPromise( val ) ? val.always( fn ) : fn( val );\n\n                // 没有要上传的了，且没有正在传输的了。\n                } else if ( !me.remaning && !me._getStats().numOfQueue &&\n                    !me._getStats().numofInterrupt ) {\n                    me.runing = false;\n\n                    me._trigged || Base.nextTick(function() {\n                        me.owner.trigger('uploadFinished');\n                    });\n                    me._trigged = true;\n                }\n            },\n\n            _putback: function(block) {\n                var idx;\n\n                block.cuted.unshift(block);\n                idx = this.stack.indexOf(block.cuted);\n\n                if (!~idx) {\n                    this.stack.unshift(block.cuted);\n                }\n            },\n\n            _getStack: function() {\n                var i = 0,\n                    act;\n\n                while ( (act = this.stack[ i++ ]) ) {\n                    if ( act.has() && act.file.getStatus() === Status.PROGRESS ) {\n                        return act;\n                    } else if (!act.has() ||\n                            act.file.getStatus() !== Status.PROGRESS &&\n                            act.file.getStatus() !== Status.INTERRUPT ) {\n\n                        // 把已经处理完了的，或者，状态为非 progress（上传中）、\n                        // interupt（暂停中） 的移除。\n                        this.stack.splice( --i, 1 );\n                    }\n                }\n\n                return null;\n            },\n\n            _nextBlock: function() {\n                var me = this,\n                    opts = me.options,\n                    act, next, done, preparing;\n\n                // 如果当前文件还有没有需要传输的，则直接返回剩下的。\n                if ( (act = this._getStack()) ) {\n\n                    // 是否提前准备下一个文件\n                    if ( opts.prepareNextFile && !me.pending.length ) {\n                        me._prepareNextFile();\n                    }\n\n                    return act.shift();\n\n                // 否则，如果正在运行，则准备下一个文件，并等待完成后返回下个分片。\n                } else if ( me.runing ) {\n\n                    // 如果缓存中有，则直接在缓存中取，没有则去queue中取。\n                    if ( !me.pending.length && me._getStats().numOfQueue ) {\n                        me._prepareNextFile();\n                    }\n\n                    next = me.pending.shift();\n                    done = function( file ) {\n                        if ( !file ) {\n                            return null;\n                        }\n\n                        act = CuteFile( file, opts.chunked ? opts.chunkSize : 0 );\n                        me.stack.push(act);\n                        return act.shift();\n                    };\n\n                    // 文件可能还在prepare中，也有可能已经完全准备好了。\n                    if ( isPromise( next) ) {\n                        preparing = next.file;\n                        next = next[ next.pipe ? 'pipe' : 'then' ]( done );\n                        next.file = preparing;\n                        return next;\n                    }\n\n                    return done( next );\n                }\n            },\n\n\n            /**\n             * @event uploadStart\n             * @param {File} file File对象\n             * @description 某个文件开始上传前触发，一个文件只会触发一次。\n             * @for  Uploader\n             */\n            _prepareNextFile: function() {\n                var me = this,\n                    file = me.request('fetch-file'),\n                    pending = me.pending,\n                    promise;\n\n                if ( file ) {\n                    promise = me.request( 'before-send-file', file, function() {\n\n                        // 有可能文件被skip掉了。文件被skip掉后，状态坑定不是Queued.\n                        if ( file.getStatus() === Status.PROGRESS ||\n                            file.getStatus() === Status.INTERRUPT ) {\n                            return file;\n                        }\n\n                        return me._finishFile( file );\n                    });\n\n                    me.owner.trigger( 'uploadStart', file );\n                    file.setStatus( Status.PROGRESS );\n\n                    promise.file = file;\n\n                    // 如果还在pending中，则替换成文件本身。\n                    promise.done(function() {\n                        var idx = $.inArray( promise, pending );\n\n                        ~idx && pending.splice( idx, 1, file );\n                    });\n\n                    // befeore-send-file的钩子就有错误发生。\n                    promise.fail(function( reason ) {\n                        file.setStatus( Status.ERROR, reason );\n                        me.owner.trigger( 'uploadError', file, reason );\n                        me.owner.trigger( 'uploadComplete', file );\n                    });\n\n                    pending.push( promise );\n                }\n            },\n\n            // 让出位置了，可以让其他分片开始上传\n            _popBlock: function( block ) {\n                var idx = $.inArray( block, this.pool );\n\n                this.pool.splice( idx, 1 );\n                block.file.remaning--;\n                this.remaning--;\n            },\n\n            // 开始上传，可以被掉过。如果promise被reject了，则表示跳过此分片。\n            _startSend: function( block ) {\n                var me = this,\n                    file = block.file,\n                    promise;\n\n                // 有可能在 before-send-file 的 promise 期间改变了文件状态。\n                // 如：暂停，取消\n                // 我们不能中断 promise, 但是可以在 promise 完后，不做上传操作。\n                if ( file.getStatus() !== Status.PROGRESS ) {\n\n                    // 如果是中断，则还需要放回去。\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        me._putback(block);\n                    }\n\n                    return;\n                }\n\n                me.pool.push( block );\n                me.remaning++;\n\n                // 如果没有分片，则直接使用原始的。\n                // 不会丢失content-type信息。\n                block.blob = block.chunks === 1 ? file.source :\n                        file.source.slice( block.start, block.end );\n\n                // hook, 每个分片发送之前可能要做些异步的事情。\n                promise = me.request( 'before-send', block, function() {\n\n                    // 有可能文件已经上传出错了，所以不需要再传输了。\n                    if ( file.getStatus() === Status.PROGRESS ) {\n                        me._doSend( block );\n                    } else {\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n\n                // 如果为fail了，则跳过此分片。\n                promise.fail(function() {\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file ).always(function() {\n                            block.percentage = 1;\n                            me._popBlock( block );\n                            me.owner.trigger( 'uploadComplete', file );\n                            Base.nextTick( me.__tick );\n                        });\n                    } else {\n                        block.percentage = 1;\n                        me.updateFileProgress( file );\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n            },\n\n\n            /**\n             * @event uploadBeforeSend\n             * @param {Object} object\n             * @param {Object} data 默认的上传参数，可以扩展此对象来控制上传参数。\n             * @param {Object} headers 可以扩展此对象来控制上传头部。\n             * @description 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadAccept\n             * @param {Object} object\n             * @param {Object} ret 服务端的返回数据，json格式，如果服务端不是json格式，从ret._raw中取数据，自行解析。\n             * @description 当某个文件上传到服务端响应后，会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为`false`, 则此文件将派送`server`类型的`uploadError`事件。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadProgress\n             * @param {File} file File对象\n             * @param {Number} percentage 上传进度\n             * @description 上传过程中触发，携带上传进度。\n             * @for  Uploader\n             */\n\n\n            /**\n             * @event uploadError\n             * @param {File} file File对象\n             * @param {String} reason 出错的code\n             * @description 当文件上传出错时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadSuccess\n             * @param {File} file File对象\n             * @param {Object} response 服务端返回的数据\n             * @description 当文件上传成功时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadComplete\n             * @param {File} [file] File对象\n             * @description 不管成功或者失败，文件上传完成时触发。\n             * @for  Uploader\n             */\n\n            // 做上传操作。\n            _doSend: function( block ) {\n                var me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    file = block.file,\n                    tr = new Transport( opts ),\n                    data = $.extend({}, opts.formData ),\n                    headers = $.extend({}, opts.headers ),\n                    requestAccept, ret;\n\n                block.transport = tr;\n\n                tr.on( 'destroy', function() {\n                    delete block.transport;\n                    me._popBlock( block );\n                    Base.nextTick( me.__tick );\n                });\n\n                // 广播上传进度。以文件为单位。\n                tr.on( 'progress', function( percentage ) {\n                    block.percentage = percentage;\n                    me.updateFileProgress( file );\n                });\n\n                // 用来询问，是否返回的结果是有错误的。\n                requestAccept = function( reject ) {\n                    var fn;\n\n                    ret = tr.getResponseAsJson() || {};\n                    ret._raw = tr.getResponse();\n                    fn = function( value ) {\n                        reject = value;\n                    };\n\n                    // 服务端响应了，不代表成功了，询问是否响应正确。\n                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {\n                        reject = reject || 'server';\n                    }\n\n                    return reject;\n                };\n\n                // 尝试重试，然后广播文件上传出错。\n                tr.on( 'error', function( type, flag ) {\n                    block.retried = block.retried || 0;\n\n                    // 自动重试\n                    if ( block.chunks > 1 && ~'http,abort'.indexOf( type ) &&\n                            block.retried < opts.chunkRetry ) {\n\n                        block.retried++;\n                        tr.send();\n\n                    } else {\n\n                        // http status 500 ~ 600\n                        if ( !flag && type === 'server' ) {\n                            type = requestAccept( type );\n                        }\n\n                        file.setStatus( Status.ERROR, type );\n                        owner.trigger( 'uploadError', file, type );\n                        owner.trigger( 'uploadComplete', file );\n                    }\n                });\n\n                // 上传成功\n                tr.on( 'load', function() {\n                    var reason;\n\n                    // 如果非预期，转向上传出错。\n                    if ( (reason = requestAccept()) ) {\n                        tr.trigger( 'error', reason, true );\n                        return;\n                    }\n\n                    // 全部上传完成。\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file, ret );\n                    } else {\n                        tr.destroy();\n                    }\n                });\n\n                // 配置默认的上传字段。\n                data = $.extend( data, {\n                    id: file.id,\n                    name: file.name,\n                    type: file.type,\n                    lastModifiedDate: file.lastModifiedDate,\n                    size: file.size\n                });\n\n                block.chunks > 1 && $.extend( data, {\n                    chunks: block.chunks,\n                    chunk: block.chunk\n                });\n\n                // 在发送之间可以添加字段什么的。。。\n                // 如果默认的字段不够使用，可以通过监听此事件来扩展\n                owner.trigger( 'uploadBeforeSend', block, data, headers );\n\n                // 开始发送。\n                tr.appendBlob( opts.fileVal, block.blob, file.name );\n                tr.append( data );\n                tr.setRequestHeader( headers );\n                tr.send();\n            },\n\n            // 完成上传。\n            _finishFile: function( file, ret, hds ) {\n                var owner = this.owner;\n\n                return owner\n                        .request( 'after-send-file', arguments, function() {\n                            file.setStatus( Status.COMPLETE );\n                            owner.trigger( 'uploadSuccess', file, ret, hds );\n                        })\n                        .fail(function( reason ) {\n\n                            // 如果外部已经标记为invalid什么的，不再改状态。\n                            if ( file.getStatus() === Status.PROGRESS ) {\n                                file.setStatus( Status.ERROR, reason );\n                            }\n\n                            owner.trigger( 'uploadError', file, reason );\n                        })\n                        .always(function() {\n                            owner.trigger( 'uploadComplete', file );\n                        });\n            },\n\n            updateFileProgress: function(file) {\n                var totalPercent = 0,\n                    uploaded = 0;\n\n                if (!file.blocks) {\n                    return;\n                }\n\n                $.each( file.blocks, function( _, v ) {\n                    uploaded += (v.percentage || 0) * (v.end - v.start);\n                });\n\n                totalPercent = uploaded / file.size;\n                this.owner.trigger( 'uploadProgress', file, totalPercent || 0 );\n            }\n\n        });\n    });\n    /**\n     * @fileOverview 各种验证，包括文件总大小是否超出、单文件是否超出和文件是否重复。\n     */\n\n    define('widgets/validator',[\n        'base',\n        'uploader',\n        'file',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile ) {\n\n        var $ = Base.$,\n            validators = {},\n            api;\n\n        /**\n         * @event error\n         * @param {String} type 错误类型。\n         * @description 当validate不通过时，会以派送错误事件的形式通知调用者。通过`upload.on('error', handler)`可以捕获到此类错误，目前有以下错误会在特定的情况下派送错来。\n         *\n         * * `Q_EXCEED_NUM_LIMIT` 在设置了`fileNumLimit`且尝试给`uploader`添加的文件数量超出这个值时派送。\n         * * `Q_EXCEED_SIZE_LIMIT` 在设置了`Q_EXCEED_SIZE_LIMIT`且尝试给`uploader`添加的文件总大小超出这个值时派送。\n         * * `Q_TYPE_DENIED` 当文件类型不满足时触发。。\n         * @for  Uploader\n         */\n\n        // 暴露给外面的api\n        api = {\n\n            // 添加验证器\n            addValidator: function( type, cb ) {\n                validators[ type ] = cb;\n            },\n\n            // 移除验证器\n            removeValidator: function( type ) {\n                delete validators[ type ];\n            }\n        };\n\n        // 在Uploader初始化的时候启动Validators的初始化\n        Uploader.register({\n            name: 'validator',\n\n            init: function() {\n                var me = this;\n                Base.nextTick(function() {\n                    $.each( validators, function() {\n                        this.call( me.owner );\n                    });\n                });\n            }\n        });\n\n        /**\n         * @property {int} [fileNumLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总数量, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileNumLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileNumLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( count >= max && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_NUM_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return count >= max ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function() {\n                count++;\n            });\n\n            uploader.on( 'fileDequeued', function() {\n                count--;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n\n        /**\n         * @property {int} [fileSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileSizeLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var invalid = count + file.size > max;\n\n                if ( invalid && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_SIZE_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return invalid ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                count += file.size;\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                count -= file.size;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n        /**\n         * @property {int} [fileSingleSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证单个文件大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSingleSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                max = opts.fileSingleSizeLimit;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( file.size > max ) {\n                    file.setStatus( WUFile.Status.INVALID, 'exceed_size' );\n                    this.trigger( 'error', 'F_EXCEED_SIZE', max, file );\n                    return false;\n                }\n\n            });\n\n        });\n\n        /**\n         * @property {Boolean} [duplicate=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 去重， 根据文件名字、文件大小和最后修改时间来生成hash Key.\n         */\n        api.addValidator( 'duplicate', function() {\n            var uploader = this,\n                opts = uploader.options,\n                mapping = {};\n\n            if ( opts.duplicate ) {\n                return;\n            }\n\n            function hashString( str ) {\n                var hash = 0,\n                    i = 0,\n                    len = str.length,\n                    _char;\n\n                for ( ; i < len; i++ ) {\n                    _char = str.charCodeAt( i );\n                    hash = _char + (hash << 6) + (hash << 16) - hash;\n                }\n\n                return hash;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var hash = file.__hash || (file.__hash = hashString( file.name +\n                        file.size + file.lastModifiedDate ));\n\n                // 已经重复了\n                if ( mapping[ hash ] ) {\n                    this.trigger( 'error', 'F_DUPLICATE', file );\n                    return false;\n                }\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (mapping[ hash ] = true);\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (delete mapping[ hash ]);\n            });\n\n            uploader.on( 'reset', function() {\n                mapping = {};\n            });\n        });\n\n        return api;\n    });\n\n    /**\n     * @fileOverview Md5\n     */\n    define('lib/md5',[\n        'runtime/client',\n        'mediator'\n    ], function( RuntimeClient, Mediator ) {\n\n        function Md5() {\n            RuntimeClient.call( this, 'Md5' );\n        }\n\n        // 让 Md5 具备事件功能。\n        Mediator.installTo( Md5.prototype );\n\n        Md5.prototype.loadFromBlob = function( blob ) {\n            var me = this;\n\n            if ( me.getRuid() ) {\n                me.disconnectRuntime();\n            }\n\n            // 连接到blob归属的同一个runtime.\n            me.connectRuntime( blob.ruid, function() {\n                me.exec('init');\n                me.exec( 'loadFromBlob', blob );\n            });\n        };\n\n        Md5.prototype.getResult = function() {\n            return this.exec('getResult');\n        };\n\n        return Md5;\n    });\n    /**\n     * @fileOverview 图片操作, 负责预览图片和上传前压缩图片\n     */\n    define('widgets/md5',[\n        'base',\n        'uploader',\n        'lib/md5',\n        'lib/blob',\n        'widgets/widget'\n    ], function( Base, Uploader, Md5, Blob ) {\n\n        return Uploader.register({\n            name: 'md5',\n\n\n            /**\n             * 计算文件 md5 值，返回一个 promise 对象，可以监听 progress 进度。\n             *\n             *\n             * @method md5File\n             * @grammar md5File( file[, start[, end]] ) => promise\n             * @for Uploader\n             * @example\n             *\n             * uploader.on( 'fileQueued', function( file ) {\n             *     var $li = ...;\n             *\n             *     uploader.md5File( file )\n             *\n             *         // 及时显示进度\n             *         .progress(function(percentage) {\n             *             console.log('Percentage:', percentage);\n             *         })\n             *\n             *         // 完成\n             *         .then(function(val) {\n             *             console.log('md5 result:', val);\n             *         });\n             *\n             * });\n             */\n            md5File: function( file, start, end ) {\n                var md5 = new Md5(),\n                    deferred = Base.Deferred(),\n                    blob = (file instanceof Blob) ? file :\n                        this.request( 'get-file', file ).source;\n\n                md5.on( 'progress load', function( e ) {\n                    e = e || {};\n                    deferred.notify( e.total ? e.loaded / e.total : 1 );\n                });\n\n                md5.on( 'complete', function() {\n                    deferred.resolve( md5.getResult() );\n                });\n\n                md5.on( 'error', function( reason ) {\n                    deferred.reject( reason );\n                });\n\n                if ( arguments.length > 1 ) {\n                    start = start || 0;\n                    end = end || 0;\n                    start < 0 && (start = blob.size + start);\n                    end < 0 && (end = blob.size + end);\n                    end = Math.min( end, blob.size );\n                    blob = blob.slice( start, end );\n                }\n\n                md5.loadFromBlob( blob );\n\n                return deferred.promise();\n            }\n        });\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/compbase',[],function() {\n\n        function CompBase( owner, runtime ) {\n\n            this.owner = owner;\n            this.options = owner.options;\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.getRuid = function() {\n                return runtime.uid;\n            };\n\n            this.trigger = function() {\n                return owner.trigger.apply( owner, arguments );\n            };\n        }\n\n        return CompBase;\n    });\n    /**\n     * @fileOverview Html5Runtime\n     */\n    define('runtime/html5/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var type = 'html5',\n            components = {};\n\n        function Html5Runtime() {\n            var pool = {},\n                me = this,\n                destroy = this.destroy;\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                if ( components[ comp ] ) {\n                    instance = pool[ uid ] = pool[ uid ] ||\n                            new components[ comp ]( client, me );\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n            };\n\n            me.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n        }\n\n        Base.inherits( Runtime, {\n            constructor: Html5Runtime,\n\n            // 不需要连接其他程序，直接执行callback\n            init: function() {\n                var me = this;\n                setTimeout(function() {\n                    me.trigger('ready');\n                }, 1 );\n            }\n\n        });\n\n        // 注册Components\n        Html5Runtime.register = function( name, component ) {\n            var klass = components[ name ] = Base.inherits( CompBase, component );\n            return klass;\n        };\n\n        // 注册html5运行时。\n        // 只有在支持的前提下注册。\n        if ( window.Blob && window.FileReader && window.DataView ) {\n            Runtime.addRuntime( type, Html5Runtime );\n        }\n\n        return Html5Runtime;\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/html5/blob',[\n        'runtime/html5/runtime',\n        'lib/blob'\n    ], function( Html5Runtime, Blob ) {\n\n        return Html5Runtime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.owner.source,\n                    slice = blob.slice || blob.webkitSlice || blob.mozSlice;\n\n                blob = slice.call( blob, start, end );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/dnd',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        var $ = Base.$,\n            prefix = 'webuploader-dnd-';\n\n        return Html5Runtime.register( 'DragAndDrop', {\n            init: function() {\n                var elem = this.elem = this.options.container;\n\n                this.dragEnterHandler = Base.bindFn( this._dragEnterHandler, this );\n                this.dragOverHandler = Base.bindFn( this._dragOverHandler, this );\n                this.dragLeaveHandler = Base.bindFn( this._dragLeaveHandler, this );\n                this.dropHandler = Base.bindFn( this._dropHandler, this );\n                this.dndOver = false;\n\n                elem.on( 'dragenter', this.dragEnterHandler );\n                elem.on( 'dragover', this.dragOverHandler );\n                elem.on( 'dragleave', this.dragLeaveHandler );\n                elem.on( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).on( 'dragover', this.dragOverHandler );\n                    $( document ).on( 'drop', this.dropHandler );\n                }\n            },\n\n            _dragEnterHandler: function( e ) {\n                var me = this,\n                    denied = me._denied || false,\n                    items;\n\n                e = e.originalEvent || e;\n\n                if ( !me.dndOver ) {\n                    me.dndOver = true;\n\n                    // 注意只有 chrome 支持。\n                    items = e.dataTransfer.items;\n\n                    if ( items && items.length ) {\n                        me._denied = denied = !me.trigger( 'accept', items );\n                    }\n\n                    me.elem.addClass( prefix + 'over' );\n                    me.elem[ denied ? 'addClass' :\n                            'removeClass' ]( prefix + 'denied' );\n                }\n\n                e.dataTransfer.dropEffect = denied ? 'none' : 'copy';\n\n                return false;\n            },\n\n            _dragOverHandler: function( e ) {\n                // 只处理框内的。\n                var parentElem = this.elem.parent().get( 0 );\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                clearTimeout( this._leaveTimer );\n                this._dragEnterHandler.call( this, e );\n\n                return false;\n            },\n\n            _dragLeaveHandler: function() {\n                var me = this,\n                    handler;\n\n                handler = function() {\n                    me.dndOver = false;\n                    me.elem.removeClass( prefix + 'over ' + prefix + 'denied' );\n                };\n\n                clearTimeout( me._leaveTimer );\n                me._leaveTimer = setTimeout( handler, 100 );\n                return false;\n            },\n\n            _dropHandler: function( e ) {\n                var me = this,\n                    ruid = me.getRuid(),\n                    parentElem = me.elem.parent().get( 0 ),\n                    dataTransfer, data;\n\n                // 只处理框内的。\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                e = e.originalEvent || e;\n                dataTransfer = e.dataTransfer;\n\n                // 如果是页面内拖拽，还不能处理，不阻止事件。\n                // 此处 ie11 下会报参数错误，\n                try {\n                    data = dataTransfer.getData('text/html');\n                } catch( err ) {\n                }\n\n                if ( data ) {\n                    return;\n                }\n\n                me._getTansferFiles( dataTransfer, function( results ) {\n                    me.trigger( 'drop', $.map( results, function( file ) {\n                        return new File( ruid, file );\n                    }) );\n                });\n\n                me.dndOver = false;\n                me.elem.removeClass( prefix + 'over' );\n                return false;\n            },\n\n            // 如果传入 callback 则去查看文件夹，否则只管当前文件夹。\n            _getTansferFiles: function( dataTransfer, callback ) {\n                var results  = [],\n                    promises = [],\n                    items, files, file, item, i, len, canAccessFolder;\n\n                items = dataTransfer.items;\n                files = dataTransfer.files;\n\n                canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);\n\n                for ( i = 0, len = files.length; i < len; i++ ) {\n                    file = files[ i ];\n                    item = items && items[ i ];\n\n                    if ( canAccessFolder && item.webkitGetAsEntry().isDirectory ) {\n\n                        promises.push( this._traverseDirectoryTree(\n                                item.webkitGetAsEntry(), results ) );\n                    } else {\n                        results.push( file );\n                    }\n                }\n\n                Base.when.apply( Base, promises ).done(function() {\n\n                    if ( !results.length ) {\n                        return;\n                    }\n\n                    callback( results );\n                });\n            },\n\n            _traverseDirectoryTree: function( entry, results ) {\n                var deferred = Base.Deferred(),\n                    me = this;\n\n                if ( entry.isFile ) {\n                    entry.file(function( file ) {\n                        results.push( file );\n                        deferred.resolve();\n                    });\n                } else if ( entry.isDirectory ) {\n                    entry.createReader().readEntries(function( entries ) {\n                        var len = entries.length,\n                            promises = [],\n                            arr = [],    // 为了保证顺序。\n                            i;\n\n                        for ( i = 0; i < len; i++ ) {\n                            promises.push( me._traverseDirectoryTree(\n                                    entries[ i ], arr ) );\n                        }\n\n                        Base.when.apply( Base, promises ).then(function() {\n                            results.push.apply( results, arr );\n                            deferred.resolve();\n                        }, deferred.reject );\n                    });\n                }\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                var elem = this.elem;\n\n                // 还没 init 就调用 destroy\n                if (!elem) {\n                    return;\n                }\n\n                elem.off( 'dragenter', this.dragEnterHandler );\n                elem.off( 'dragover', this.dragOverHandler );\n                elem.off( 'dragleave', this.dragLeaveHandler );\n                elem.off( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).off( 'dragover', this.dragOverHandler );\n                    $( document ).off( 'drop', this.dropHandler );\n                }\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/filepaste',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        return Html5Runtime.register( 'FilePaste', {\n            init: function() {\n                var opts = this.options,\n                    elem = this.elem = opts.container,\n                    accept = '.*',\n                    arr, i, len, item;\n\n                // accetp的mimeTypes中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].mimeTypes;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = arr.join(',');\n                        accept = accept.replace( /,/g, '|' ).replace( /\\*/g, '.*' );\n                    }\n                }\n                this.accept = accept = new RegExp( accept, 'i' );\n                this.hander = Base.bindFn( this._pasteHander, this );\n                elem.on( 'paste', this.hander );\n            },\n\n            _pasteHander: function( e ) {\n                var allowed = [],\n                    ruid = this.getRuid(),\n                    items, item, blob, i, len;\n\n                e = e.originalEvent || e;\n                items = e.clipboardData.items;\n\n                for ( i = 0, len = items.length; i < len; i++ ) {\n                    item = items[ i ];\n\n                    if ( item.kind !== 'file' || !(blob = item.getAsFile()) ) {\n                        continue;\n                    }\n\n                    allowed.push( new File( ruid, blob ) );\n                }\n\n                if ( allowed.length ) {\n                    // 不阻止非文件粘贴（文字粘贴）的事件冒泡\n                    e.preventDefault();\n                    e.stopPropagation();\n                    this.trigger( 'paste', allowed );\n                }\n            },\n\n            destroy: function() {\n                this.elem.off( 'paste', this.hander );\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/html5/filepicker',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var $ = Base.$;\n\n        return Html5Runtime.register( 'FilePicker', {\n            init: function() {\n                var container = this.getRuntime().getContainer(),\n                    me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    label = this.label = $( document.createElement('label') ),\n                    input =  this.input = $( document.createElement('input') ),\n                    arr, i, len, mouseHandler;\n\n                input.attr( 'type', 'file' );\n                input.attr( 'name', opts.name );\n                input.addClass('webuploader-element-invisible');\n\n                label.on( 'click', function() {\n                    input.trigger('click');\n                });\n\n                label.css({\n                    opacity: 0,\n                    width: '100%',\n                    height: '100%',\n                    display: 'block',\n                    cursor: 'pointer',\n                    background: '#ffffff'\n                });\n\n                if ( opts.multiple ) {\n                    input.attr( 'multiple', 'multiple' );\n                }\n\n                // @todo Firefox不支持单独指定后缀\n                if ( opts.accept && opts.accept.length > 0 ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        arr.push( opts.accept[ i ].mimeTypes );\n                    }\n\n                    input.attr( 'accept', arr.join(',') );\n                }\n\n                container.append( input );\n                container.append( label );\n\n                mouseHandler = function( e ) {\n                    owner.trigger( e.type );\n                };\n\n                input.on( 'change', function( e ) {\n                    var fn = arguments.callee,\n                        clone;\n\n                    me.files = e.target.files;\n\n                    // reset input\n                    clone = this.cloneNode( true );\n                    clone.value = null;\n                    this.parentNode.replaceChild( clone, this );\n\n                    input.off();\n                    input = $( clone ).on( 'change', fn )\n                            .on( 'mouseenter mouseleave', mouseHandler );\n\n                    owner.trigger('change');\n                });\n\n                label.on( 'mouseenter mouseleave', mouseHandler );\n\n            },\n\n\n            getFiles: function() {\n                return this.files;\n            },\n\n            destroy: function() {\n                this.input.off();\n                this.label.off();\n            }\n        });\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/util',[\n        'base'\n    ], function( Base ) {\n\n        var urlAPI = window.createObjectURL && window ||\n                window.URL && URL.revokeObjectURL && URL ||\n                window.webkitURL,\n            createObjectURL = Base.noop,\n            revokeObjectURL = createObjectURL;\n\n        if ( urlAPI ) {\n\n            // 更安全的方式调用，比如android里面就能把context改成其他的对象。\n            createObjectURL = function() {\n                return urlAPI.createObjectURL.apply( urlAPI, arguments );\n            };\n\n            revokeObjectURL = function() {\n                return urlAPI.revokeObjectURL.apply( urlAPI, arguments );\n            };\n        }\n\n        return {\n            createObjectURL: createObjectURL,\n            revokeObjectURL: revokeObjectURL,\n\n            dataURL2Blob: function( dataURI ) {\n                var byteStr, intArray, ab, i, mimetype, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                ab = new ArrayBuffer( byteStr.length );\n                intArray = new Uint8Array( ab );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                mimetype = parts[ 0 ].split(':')[ 1 ].split(';')[ 0 ];\n\n                return this.arrayBufferToBlob( ab, mimetype );\n            },\n\n            dataURL2ArrayBuffer: function( dataURI ) {\n                var byteStr, intArray, i, parts;\n\n                parts = dataURI.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    byteStr = atob( parts[ 1 ] );\n                } else {\n                    byteStr = decodeURIComponent( parts[ 1 ] );\n                }\n\n                intArray = new Uint8Array( byteStr.length );\n\n                for ( i = 0; i < byteStr.length; i++ ) {\n                    intArray[ i ] = byteStr.charCodeAt( i );\n                }\n\n                return intArray.buffer;\n            },\n\n            arrayBufferToBlob: function( buffer, type ) {\n                var builder = window.BlobBuilder || window.WebKitBlobBuilder,\n                    bb;\n\n                // android不支持直接new Blob, 只能借助blobbuilder.\n                if ( builder ) {\n                    bb = new builder();\n                    bb.append( buffer );\n                    return bb.getBlob( type );\n                }\n\n                return new Blob([ buffer ], type ? { type: type } : {} );\n            },\n\n            // 抽出来主要是为了解决android下面canvas.toDataUrl不支持jpeg.\n            // 你得到的结果是png.\n            canvasToDataUrl: function( canvas, type, quality ) {\n                return canvas.toDataURL( type, quality / 100 );\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            parseMeta: function( blob, callback ) {\n                callback( false, {});\n            },\n\n            // imagemeat会复写这个方法，如果用户选择加载那个文件了的话。\n            updateImageHead: function( data ) {\n                return data;\n            }\n        };\n    });\n    /**\n     * Terms:\n     *\n     * Uint8Array, FileReader, BlobBuilder, atob, ArrayBuffer\n     * @fileOverview Image控件\n     */\n    define('runtime/html5/imagemeta',[\n        'runtime/html5/util'\n    ], function( Util ) {\n\n        var api;\n\n        api = {\n            parsers: {\n                0xffe1: []\n            },\n\n            maxMetaDataSize: 262144,\n\n            parse: function( blob, cb ) {\n                var me = this,\n                    fr = new FileReader();\n\n                fr.onload = function() {\n                    cb( false, me._parse( this.result ) );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                fr.onerror = function( e ) {\n                    cb( e.message );\n                    fr = fr.onload = fr.onerror = null;\n                };\n\n                blob = blob.slice( 0, me.maxMetaDataSize );\n                fr.readAsArrayBuffer( blob.getSource() );\n            },\n\n            _parse: function( buffer, noParse ) {\n                if ( buffer.byteLength < 6 ) {\n                    return;\n                }\n\n                var dataview = new DataView( buffer ),\n                    offset = 2,\n                    maxOffset = dataview.byteLength - 4,\n                    headLength = offset,\n                    ret = {},\n                    markerBytes, markerLength, parsers, i;\n\n                if ( dataview.getUint16( 0 ) === 0xffd8 ) {\n\n                    while ( offset < maxOffset ) {\n                        markerBytes = dataview.getUint16( offset );\n\n                        if ( markerBytes >= 0xffe0 && markerBytes <= 0xffef ||\n                                markerBytes === 0xfffe ) {\n\n                            markerLength = dataview.getUint16( offset + 2 ) + 2;\n\n                            if ( offset + markerLength > dataview.byteLength ) {\n                                break;\n                            }\n\n                            parsers = api.parsers[ markerBytes ];\n\n                            if ( !noParse && parsers ) {\n                                for ( i = 0; i < parsers.length; i += 1 ) {\n                                    parsers[ i ].call( api, dataview, offset,\n                                            markerLength, ret );\n                                }\n                            }\n\n                            offset += markerLength;\n                            headLength = offset;\n                        } else {\n                            break;\n                        }\n                    }\n\n                    if ( headLength > 6 ) {\n                        if ( buffer.slice ) {\n                            ret.imageHead = buffer.slice( 2, headLength );\n                        } else {\n                            // Workaround for IE10, which does not yet\n                            // support ArrayBuffer.slice:\n                            ret.imageHead = new Uint8Array( buffer )\n                                    .subarray( 2, headLength );\n                        }\n                    }\n                }\n\n                return ret;\n            },\n\n            updateImageHead: function( buffer, head ) {\n                var data = this._parse( buffer, true ),\n                    buf1, buf2, bodyoffset;\n\n\n                bodyoffset = 2;\n                if ( data.imageHead ) {\n                    bodyoffset = 2 + data.imageHead.byteLength;\n                }\n\n                if ( buffer.slice ) {\n                    buf2 = buffer.slice( bodyoffset );\n                } else {\n                    buf2 = new Uint8Array( buffer ).subarray( bodyoffset );\n                }\n\n                buf1 = new Uint8Array( head.byteLength + 2 + buf2.byteLength );\n\n                buf1[ 0 ] = 0xFF;\n                buf1[ 1 ] = 0xD8;\n                buf1.set( new Uint8Array( head ), 2 );\n                buf1.set( new Uint8Array( buf2 ), head.byteLength + 2 );\n\n                return buf1.buffer;\n            }\n        };\n\n        Util.parseMeta = function() {\n            return api.parse.apply( api, arguments );\n        };\n\n        Util.updateImageHead = function() {\n            return api.updateImageHead.apply( api, arguments );\n        };\n\n        return api;\n    });\n    /**\n     * 代码来自于：https://github.com/blueimp/JavaScript-Load-Image\n     * 暂时项目中只用了orientation.\n     *\n     * 去除了 Exif Sub IFD Pointer, GPS Info IFD Pointer, Exif Thumbnail.\n     * @fileOverview EXIF解析\n     */\n\n    // Sample\n    // ====================================\n    // Make : Apple\n    // Model : iPhone 4S\n    // Orientation : 1\n    // XResolution : 72 [72/1]\n    // YResolution : 72 [72/1]\n    // ResolutionUnit : 2\n    // Software : QuickTime 7.7.1\n    // DateTime : 2013:09:01 22:53:55\n    // ExifIFDPointer : 190\n    // ExposureTime : 0.058823529411764705 [1/17]\n    // FNumber : 2.4 [12/5]\n    // ExposureProgram : Normal program\n    // ISOSpeedRatings : 800\n    // ExifVersion : 0220\n    // DateTimeOriginal : 2013:09:01 22:52:51\n    // DateTimeDigitized : 2013:09:01 22:52:51\n    // ComponentsConfiguration : YCbCr\n    // ShutterSpeedValue : 4.058893515764426\n    // ApertureValue : 2.5260688216892597 [4845/1918]\n    // BrightnessValue : -0.3126686601998395\n    // MeteringMode : Pattern\n    // Flash : Flash did not fire, compulsory flash mode\n    // FocalLength : 4.28 [107/25]\n    // SubjectArea : [4 values]\n    // FlashpixVersion : 0100\n    // ColorSpace : 1\n    // PixelXDimension : 2448\n    // PixelYDimension : 3264\n    // SensingMethod : One-chip color area sensor\n    // ExposureMode : 0\n    // WhiteBalance : Auto white balance\n    // FocalLengthIn35mmFilm : 35\n    // SceneCaptureType : Standard\n    define('runtime/html5/imagemeta/exif',[\n        'base',\n        'runtime/html5/imagemeta'\n    ], function( Base, ImageMeta ) {\n\n        var EXIF = {};\n\n        EXIF.ExifMap = function() {\n            return this;\n        };\n\n        EXIF.ExifMap.prototype.map = {\n            'Orientation': 0x0112\n        };\n\n        EXIF.ExifMap.prototype.get = function( id ) {\n            return this[ id ] || this[ this.map[ id ] ];\n        };\n\n        EXIF.exifTagTypes = {\n            // byte, 8-bit unsigned int:\n            1: {\n                getValue: function( dataView, dataOffset ) {\n                    return dataView.getUint8( dataOffset );\n                },\n                size: 1\n            },\n\n            // ascii, 8-bit byte:\n            2: {\n                getValue: function( dataView, dataOffset ) {\n                    return String.fromCharCode( dataView.getUint8( dataOffset ) );\n                },\n                size: 1,\n                ascii: true\n            },\n\n            // short, 16 bit int:\n            3: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint16( dataOffset, littleEndian );\n                },\n                size: 2\n            },\n\n            // long, 32 bit int:\n            4: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // rational = two long values,\n            // first is numerator, second is denominator:\n            5: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getUint32( dataOffset, littleEndian ) /\n                        dataView.getUint32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            },\n\n            // slong, 32 bit signed int:\n            9: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian );\n                },\n                size: 4\n            },\n\n            // srational, two slongs, first is numerator, second is denominator:\n            10: {\n                getValue: function( dataView, dataOffset, littleEndian ) {\n                    return dataView.getInt32( dataOffset, littleEndian ) /\n                        dataView.getInt32( dataOffset + 4, littleEndian );\n                },\n                size: 8\n            }\n        };\n\n        // undefined, 8-bit byte, value depending on field:\n        EXIF.exifTagTypes[ 7 ] = EXIF.exifTagTypes[ 1 ];\n\n        EXIF.getExifValue = function( dataView, tiffOffset, offset, type, length,\n                littleEndian ) {\n\n            var tagType = EXIF.exifTagTypes[ type ],\n                tagSize, dataOffset, values, i, str, c;\n\n            if ( !tagType ) {\n                Base.log('Invalid Exif data: Invalid tag type.');\n                return;\n            }\n\n            tagSize = tagType.size * length;\n\n            // Determine if the value is contained in the dataOffset bytes,\n            // or if the value at the dataOffset is a pointer to the actual data:\n            dataOffset = tagSize > 4 ? tiffOffset + dataView.getUint32( offset + 8,\n                    littleEndian ) : (offset + 8);\n\n            if ( dataOffset + tagSize > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid data offset.');\n                return;\n            }\n\n            if ( length === 1 ) {\n                return tagType.getValue( dataView, dataOffset, littleEndian );\n            }\n\n            values = [];\n\n            for ( i = 0; i < length; i += 1 ) {\n                values[ i ] = tagType.getValue( dataView,\n                        dataOffset + i * tagType.size, littleEndian );\n            }\n\n            if ( tagType.ascii ) {\n                str = '';\n\n                // Concatenate the chars:\n                for ( i = 0; i < values.length; i += 1 ) {\n                    c = values[ i ];\n\n                    // Ignore the terminating NULL byte(s):\n                    if ( c === '\\u0000' ) {\n                        break;\n                    }\n                    str += c;\n                }\n\n                return str;\n            }\n            return values;\n        };\n\n        EXIF.parseExifTag = function( dataView, tiffOffset, offset, littleEndian,\n                data ) {\n\n            var tag = dataView.getUint16( offset, littleEndian );\n            data.exif[ tag ] = EXIF.getExifValue( dataView, tiffOffset, offset,\n                    dataView.getUint16( offset + 2, littleEndian ),    // tag type\n                    dataView.getUint32( offset + 4, littleEndian ),    // tag length\n                    littleEndian );\n        };\n\n        EXIF.parseExifTags = function( dataView, tiffOffset, dirOffset,\n                littleEndian, data ) {\n\n            var tagsNumber, dirEndOffset, i;\n\n            if ( dirOffset + 6 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory offset.');\n                return;\n            }\n\n            tagsNumber = dataView.getUint16( dirOffset, littleEndian );\n            dirEndOffset = dirOffset + 2 + 12 * tagsNumber;\n\n            if ( dirEndOffset + 4 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid directory size.');\n                return;\n            }\n\n            for ( i = 0; i < tagsNumber; i += 1 ) {\n                this.parseExifTag( dataView, tiffOffset,\n                        dirOffset + 2 + 12 * i,    // tag offset\n                        littleEndian, data );\n            }\n\n            // Return the offset to the next directory:\n            return dataView.getUint32( dirEndOffset, littleEndian );\n        };\n\n        // EXIF.getExifThumbnail = function(dataView, offset, length) {\n        //     var hexData,\n        //         i,\n        //         b;\n        //     if (!length || offset + length > dataView.byteLength) {\n        //         Base.log('Invalid Exif data: Invalid thumbnail data.');\n        //         return;\n        //     }\n        //     hexData = [];\n        //     for (i = 0; i < length; i += 1) {\n        //         b = dataView.getUint8(offset + i);\n        //         hexData.push((b < 16 ? '0' : '') + b.toString(16));\n        //     }\n        //     return 'data:image/jpeg,%' + hexData.join('%');\n        // };\n\n        EXIF.parseExifData = function( dataView, offset, length, data ) {\n\n            var tiffOffset = offset + 10,\n                littleEndian, dirOffset;\n\n            // Check for the ASCII code for \"Exif\" (0x45786966):\n            if ( dataView.getUint32( offset + 4 ) !== 0x45786966 ) {\n                // No Exif data, might be XMP data instead\n                return;\n            }\n            if ( tiffOffset + 8 > dataView.byteLength ) {\n                Base.log('Invalid Exif data: Invalid segment size.');\n                return;\n            }\n\n            // Check for the two null bytes:\n            if ( dataView.getUint16( offset + 8 ) !== 0x0000 ) {\n                Base.log('Invalid Exif data: Missing byte alignment offset.');\n                return;\n            }\n\n            // Check the byte alignment:\n            switch ( dataView.getUint16( tiffOffset ) ) {\n                case 0x4949:\n                    littleEndian = true;\n                    break;\n\n                case 0x4D4D:\n                    littleEndian = false;\n                    break;\n\n                default:\n                    Base.log('Invalid Exif data: Invalid byte alignment marker.');\n                    return;\n            }\n\n            // Check for the TIFF tag marker (0x002A):\n            if ( dataView.getUint16( tiffOffset + 2, littleEndian ) !== 0x002A ) {\n                Base.log('Invalid Exif data: Missing TIFF marker.');\n                return;\n            }\n\n            // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:\n            dirOffset = dataView.getUint32( tiffOffset + 4, littleEndian );\n            // Create the exif object to store the tags:\n            data.exif = new EXIF.ExifMap();\n            // Parse the tags of the main image directory and retrieve the\n            // offset to the next directory, usually the thumbnail directory:\n            dirOffset = EXIF.parseExifTags( dataView, tiffOffset,\n                    tiffOffset + dirOffset, littleEndian, data );\n\n            // 尝试读取缩略图\n            // if ( dirOffset ) {\n            //     thumbnailData = {exif: {}};\n            //     dirOffset = EXIF.parseExifTags(\n            //         dataView,\n            //         tiffOffset,\n            //         tiffOffset + dirOffset,\n            //         littleEndian,\n            //         thumbnailData\n            //     );\n\n            //     // Check for JPEG Thumbnail offset:\n            //     if (thumbnailData.exif[0x0201]) {\n            //         data.exif.Thumbnail = EXIF.getExifThumbnail(\n            //             dataView,\n            //             tiffOffset + thumbnailData.exif[0x0201],\n            //             thumbnailData.exif[0x0202] // Thumbnail data length\n            //         );\n            //     }\n            // }\n        };\n\n        ImageMeta.parsers[ 0xffe1 ].push( EXIF.parseExifData );\n        return EXIF;\n    });\n    /**\n     * 这个方式性能不行，但是可以解决android里面的toDataUrl的bug\n     * android里面toDataUrl('image/jpege')得到的结果却是png.\n     *\n     * 所以这里没辙，只能借助这个工具\n     * @fileOverview jpeg encoder\n     */\n    define('runtime/html5/jpegencoder',[], function( require, exports, module ) {\n\n        /*\n          Copyright (c) 2008, Adobe Systems Incorporated\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\n          met:\n\n          * Redistributions of source code must retain the above copyright notice,\n            this list of conditions and the following disclaimer.\n\n          * Redistributions in binary form must reproduce the above copyright\n            notice, this list of conditions and the following disclaimer in the\n            documentation and/or other materials provided with the distribution.\n\n          * Neither the name of Adobe Systems Incorporated nor the names of its\n            contributors may be used to endorse or promote products derived from\n            this software without specific prior written permission.\n\n          THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n          IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\n          THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n          PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n          CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n          EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n          PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n          PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n          LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n          NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n          SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n        */\n        /*\n        JPEG encoder ported to JavaScript and optimized by Andreas Ritter, www.bytestrom.eu, 11/2009\n\n        Basic GUI blocking jpeg encoder\n        */\n\n        function JPEGEncoder(quality) {\n          var self = this;\n            var fround = Math.round;\n            var ffloor = Math.floor;\n            var YTable = new Array(64);\n            var UVTable = new Array(64);\n            var fdtbl_Y = new Array(64);\n            var fdtbl_UV = new Array(64);\n            var YDC_HT;\n            var UVDC_HT;\n            var YAC_HT;\n            var UVAC_HT;\n\n            var bitcode = new Array(65535);\n            var category = new Array(65535);\n            var outputfDCTQuant = new Array(64);\n            var DU = new Array(64);\n            var byteout = [];\n            var bytenew = 0;\n            var bytepos = 7;\n\n            var YDU = new Array(64);\n            var UDU = new Array(64);\n            var VDU = new Array(64);\n            var clt = new Array(256);\n            var RGB_YUV_TABLE = new Array(2048);\n            var currentQuality;\n\n            var ZigZag = [\n                     0, 1, 5, 6,14,15,27,28,\n                     2, 4, 7,13,16,26,29,42,\n                     3, 8,12,17,25,30,41,43,\n                     9,11,18,24,31,40,44,53,\n                    10,19,23,32,39,45,52,54,\n                    20,22,33,38,46,51,55,60,\n                    21,34,37,47,50,56,59,61,\n                    35,36,48,49,57,58,62,63\n                ];\n\n            var std_dc_luminance_nrcodes = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];\n            var std_dc_luminance_values = [0,1,2,3,4,5,6,7,8,9,10,11];\n            var std_ac_luminance_nrcodes = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];\n            var std_ac_luminance_values = [\n                    0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,\n                    0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,\n                    0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\n                    0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,\n                    0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,\n                    0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\n                    0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,\n                    0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,\n                    0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\n                    0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,\n                    0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,\n                    0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\n                    0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,\n                    0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,\n                    0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\n                    0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,\n                    0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,\n                    0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\n                    0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,\n                    0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\n                    0xf9,0xfa\n                ];\n\n            var std_dc_chrominance_nrcodes = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];\n            var std_dc_chrominance_values = [0,1,2,3,4,5,6,7,8,9,10,11];\n            var std_ac_chrominance_nrcodes = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];\n            var std_ac_chrominance_values = [\n                    0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,\n                    0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,\n                    0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\n                    0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,\n                    0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,\n                    0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\n                    0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,\n                    0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,\n                    0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\n                    0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,\n                    0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,\n                    0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\n                    0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,\n                    0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,\n                    0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\n                    0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,\n                    0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,\n                    0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\n                    0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,\n                    0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\n                    0xf9,0xfa\n                ];\n\n            function initQuantTables(sf){\n                    var YQT = [\n                        16, 11, 10, 16, 24, 40, 51, 61,\n                        12, 12, 14, 19, 26, 58, 60, 55,\n                        14, 13, 16, 24, 40, 57, 69, 56,\n                        14, 17, 22, 29, 51, 87, 80, 62,\n                        18, 22, 37, 56, 68,109,103, 77,\n                        24, 35, 55, 64, 81,104,113, 92,\n                        49, 64, 78, 87,103,121,120,101,\n                        72, 92, 95, 98,112,100,103, 99\n                    ];\n\n                    for (var i = 0; i < 64; i++) {\n                        var t = ffloor((YQT[i]*sf+50)/100);\n                        if (t < 1) {\n                            t = 1;\n                        } else if (t > 255) {\n                            t = 255;\n                        }\n                        YTable[ZigZag[i]] = t;\n                    }\n                    var UVQT = [\n                        17, 18, 24, 47, 99, 99, 99, 99,\n                        18, 21, 26, 66, 99, 99, 99, 99,\n                        24, 26, 56, 99, 99, 99, 99, 99,\n                        47, 66, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99,\n                        99, 99, 99, 99, 99, 99, 99, 99\n                    ];\n                    for (var j = 0; j < 64; j++) {\n                        var u = ffloor((UVQT[j]*sf+50)/100);\n                        if (u < 1) {\n                            u = 1;\n                        } else if (u > 255) {\n                            u = 255;\n                        }\n                        UVTable[ZigZag[j]] = u;\n                    }\n                    var aasf = [\n                        1.0, 1.387039845, 1.306562965, 1.175875602,\n                        1.0, 0.785694958, 0.541196100, 0.275899379\n                    ];\n                    var k = 0;\n                    for (var row = 0; row < 8; row++)\n                    {\n                        for (var col = 0; col < 8; col++)\n                        {\n                            fdtbl_Y[k]  = (1.0 / (YTable [ZigZag[k]] * aasf[row] * aasf[col] * 8.0));\n                            fdtbl_UV[k] = (1.0 / (UVTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0));\n                            k++;\n                        }\n                    }\n                }\n\n                function computeHuffmanTbl(nrcodes, std_table){\n                    var codevalue = 0;\n                    var pos_in_table = 0;\n                    var HT = new Array();\n                    for (var k = 1; k <= 16; k++) {\n                        for (var j = 1; j <= nrcodes[k]; j++) {\n                            HT[std_table[pos_in_table]] = [];\n                            HT[std_table[pos_in_table]][0] = codevalue;\n                            HT[std_table[pos_in_table]][1] = k;\n                            pos_in_table++;\n                            codevalue++;\n                        }\n                        codevalue*=2;\n                    }\n                    return HT;\n                }\n\n                function initHuffmanTbl()\n                {\n                    YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);\n                    UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);\n                    YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);\n                    UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);\n                }\n\n                function initCategoryNumber()\n                {\n                    var nrlower = 1;\n                    var nrupper = 2;\n                    for (var cat = 1; cat <= 15; cat++) {\n                        //Positive numbers\n                        for (var nr = nrlower; nr<nrupper; nr++) {\n                            category[32767+nr] = cat;\n                            bitcode[32767+nr] = [];\n                            bitcode[32767+nr][1] = cat;\n                            bitcode[32767+nr][0] = nr;\n                        }\n                        //Negative numbers\n                        for (var nrneg =-(nrupper-1); nrneg<=-nrlower; nrneg++) {\n                            category[32767+nrneg] = cat;\n                            bitcode[32767+nrneg] = [];\n                            bitcode[32767+nrneg][1] = cat;\n                            bitcode[32767+nrneg][0] = nrupper-1+nrneg;\n                        }\n                        nrlower <<= 1;\n                        nrupper <<= 1;\n                    }\n                }\n\n                function initRGBYUVTable() {\n                    for(var i = 0; i < 256;i++) {\n                        RGB_YUV_TABLE[i]            =  19595 * i;\n                        RGB_YUV_TABLE[(i+ 256)>>0]  =  38470 * i;\n                        RGB_YUV_TABLE[(i+ 512)>>0]  =   7471 * i + 0x8000;\n                        RGB_YUV_TABLE[(i+ 768)>>0]  = -11059 * i;\n                        RGB_YUV_TABLE[(i+1024)>>0]  = -21709 * i;\n                        RGB_YUV_TABLE[(i+1280)>>0]  =  32768 * i + 0x807FFF;\n                        RGB_YUV_TABLE[(i+1536)>>0]  = -27439 * i;\n                        RGB_YUV_TABLE[(i+1792)>>0]  = - 5329 * i;\n                    }\n                }\n\n                // IO functions\n                function writeBits(bs)\n                {\n                    var value = bs[0];\n                    var posval = bs[1]-1;\n                    while ( posval >= 0 ) {\n                        if (value & (1 << posval) ) {\n                            bytenew |= (1 << bytepos);\n                        }\n                        posval--;\n                        bytepos--;\n                        if (bytepos < 0) {\n                            if (bytenew == 0xFF) {\n                                writeByte(0xFF);\n                                writeByte(0);\n                            }\n                            else {\n                                writeByte(bytenew);\n                            }\n                            bytepos=7;\n                            bytenew=0;\n                        }\n                    }\n                }\n\n                function writeByte(value)\n                {\n                    byteout.push(clt[value]); // write char directly instead of converting later\n                }\n\n                function writeWord(value)\n                {\n                    writeByte((value>>8)&0xFF);\n                    writeByte((value   )&0xFF);\n                }\n\n                // DCT & quantization core\n                function fDCTQuant(data, fdtbl)\n                {\n                    var d0, d1, d2, d3, d4, d5, d6, d7;\n                    /* Pass 1: process rows. */\n                    var dataOff=0;\n                    var i;\n                    var I8 = 8;\n                    var I64 = 64;\n                    for (i=0; i<I8; ++i)\n                    {\n                        d0 = data[dataOff];\n                        d1 = data[dataOff+1];\n                        d2 = data[dataOff+2];\n                        d3 = data[dataOff+3];\n                        d4 = data[dataOff+4];\n                        d5 = data[dataOff+5];\n                        d6 = data[dataOff+6];\n                        d7 = data[dataOff+7];\n\n                        var tmp0 = d0 + d7;\n                        var tmp7 = d0 - d7;\n                        var tmp1 = d1 + d6;\n                        var tmp6 = d1 - d6;\n                        var tmp2 = d2 + d5;\n                        var tmp5 = d2 - d5;\n                        var tmp3 = d3 + d4;\n                        var tmp4 = d3 - d4;\n\n                        /* Even part */\n                        var tmp10 = tmp0 + tmp3;    /* phase 2 */\n                        var tmp13 = tmp0 - tmp3;\n                        var tmp11 = tmp1 + tmp2;\n                        var tmp12 = tmp1 - tmp2;\n\n                        data[dataOff] = tmp10 + tmp11; /* phase 3 */\n                        data[dataOff+4] = tmp10 - tmp11;\n\n                        var z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */\n                        data[dataOff+2] = tmp13 + z1; /* phase 5 */\n                        data[dataOff+6] = tmp13 - z1;\n\n                        /* Odd part */\n                        tmp10 = tmp4 + tmp5; /* phase 2 */\n                        tmp11 = tmp5 + tmp6;\n                        tmp12 = tmp6 + tmp7;\n\n                        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n                        var z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */\n                        var z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */\n                        var z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */\n                        var z3 = tmp11 * 0.707106781; /* c4 */\n\n                        var z11 = tmp7 + z3;    /* phase 5 */\n                        var z13 = tmp7 - z3;\n\n                        data[dataOff+5] = z13 + z2; /* phase 6 */\n                        data[dataOff+3] = z13 - z2;\n                        data[dataOff+1] = z11 + z4;\n                        data[dataOff+7] = z11 - z4;\n\n                        dataOff += 8; /* advance pointer to next row */\n                    }\n\n                    /* Pass 2: process columns. */\n                    dataOff = 0;\n                    for (i=0; i<I8; ++i)\n                    {\n                        d0 = data[dataOff];\n                        d1 = data[dataOff + 8];\n                        d2 = data[dataOff + 16];\n                        d3 = data[dataOff + 24];\n                        d4 = data[dataOff + 32];\n                        d5 = data[dataOff + 40];\n                        d6 = data[dataOff + 48];\n                        d7 = data[dataOff + 56];\n\n                        var tmp0p2 = d0 + d7;\n                        var tmp7p2 = d0 - d7;\n                        var tmp1p2 = d1 + d6;\n                        var tmp6p2 = d1 - d6;\n                        var tmp2p2 = d2 + d5;\n                        var tmp5p2 = d2 - d5;\n                        var tmp3p2 = d3 + d4;\n                        var tmp4p2 = d3 - d4;\n\n                        /* Even part */\n                        var tmp10p2 = tmp0p2 + tmp3p2;  /* phase 2 */\n                        var tmp13p2 = tmp0p2 - tmp3p2;\n                        var tmp11p2 = tmp1p2 + tmp2p2;\n                        var tmp12p2 = tmp1p2 - tmp2p2;\n\n                        data[dataOff] = tmp10p2 + tmp11p2; /* phase 3 */\n                        data[dataOff+32] = tmp10p2 - tmp11p2;\n\n                        var z1p2 = (tmp12p2 + tmp13p2) * 0.707106781; /* c4 */\n                        data[dataOff+16] = tmp13p2 + z1p2; /* phase 5 */\n                        data[dataOff+48] = tmp13p2 - z1p2;\n\n                        /* Odd part */\n                        tmp10p2 = tmp4p2 + tmp5p2; /* phase 2 */\n                        tmp11p2 = tmp5p2 + tmp6p2;\n                        tmp12p2 = tmp6p2 + tmp7p2;\n\n                        /* The rotator is modified from fig 4-8 to avoid extra negations. */\n                        var z5p2 = (tmp10p2 - tmp12p2) * 0.382683433; /* c6 */\n                        var z2p2 = 0.541196100 * tmp10p2 + z5p2; /* c2-c6 */\n                        var z4p2 = 1.306562965 * tmp12p2 + z5p2; /* c2+c6 */\n                        var z3p2 = tmp11p2 * 0.707106781; /* c4 */\n\n                        var z11p2 = tmp7p2 + z3p2;  /* phase 5 */\n                        var z13p2 = tmp7p2 - z3p2;\n\n                        data[dataOff+40] = z13p2 + z2p2; /* phase 6 */\n                        data[dataOff+24] = z13p2 - z2p2;\n                        data[dataOff+ 8] = z11p2 + z4p2;\n                        data[dataOff+56] = z11p2 - z4p2;\n\n                        dataOff++; /* advance pointer to next column */\n                    }\n\n                    // Quantize/descale the coefficients\n                    var fDCTQuant;\n                    for (i=0; i<I64; ++i)\n                    {\n                        // Apply the quantization and scaling factor & Round to nearest integer\n                        fDCTQuant = data[i]*fdtbl[i];\n                        outputfDCTQuant[i] = (fDCTQuant > 0.0) ? ((fDCTQuant + 0.5)|0) : ((fDCTQuant - 0.5)|0);\n                        //outputfDCTQuant[i] = fround(fDCTQuant);\n\n                    }\n                    return outputfDCTQuant;\n                }\n\n                function writeAPP0()\n                {\n                    writeWord(0xFFE0); // marker\n                    writeWord(16); // length\n                    writeByte(0x4A); // J\n                    writeByte(0x46); // F\n                    writeByte(0x49); // I\n                    writeByte(0x46); // F\n                    writeByte(0); // = \"JFIF\",'\\0'\n                    writeByte(1); // versionhi\n                    writeByte(1); // versionlo\n                    writeByte(0); // xyunits\n                    writeWord(1); // xdensity\n                    writeWord(1); // ydensity\n                    writeByte(0); // thumbnwidth\n                    writeByte(0); // thumbnheight\n                }\n\n                function writeSOF0(width, height)\n                {\n                    writeWord(0xFFC0); // marker\n                    writeWord(17);   // length, truecolor YUV JPG\n                    writeByte(8);    // precision\n                    writeWord(height);\n                    writeWord(width);\n                    writeByte(3);    // nrofcomponents\n                    writeByte(1);    // IdY\n                    writeByte(0x11); // HVY\n                    writeByte(0);    // QTY\n                    writeByte(2);    // IdU\n                    writeByte(0x11); // HVU\n                    writeByte(1);    // QTU\n                    writeByte(3);    // IdV\n                    writeByte(0x11); // HVV\n                    writeByte(1);    // QTV\n                }\n\n                function writeDQT()\n                {\n                    writeWord(0xFFDB); // marker\n                    writeWord(132);    // length\n                    writeByte(0);\n                    for (var i=0; i<64; i++) {\n                        writeByte(YTable[i]);\n                    }\n                    writeByte(1);\n                    for (var j=0; j<64; j++) {\n                        writeByte(UVTable[j]);\n                    }\n                }\n\n                function writeDHT()\n                {\n                    writeWord(0xFFC4); // marker\n                    writeWord(0x01A2); // length\n\n                    writeByte(0); // HTYDCinfo\n                    for (var i=0; i<16; i++) {\n                        writeByte(std_dc_luminance_nrcodes[i+1]);\n                    }\n                    for (var j=0; j<=11; j++) {\n                        writeByte(std_dc_luminance_values[j]);\n                    }\n\n                    writeByte(0x10); // HTYACinfo\n                    for (var k=0; k<16; k++) {\n                        writeByte(std_ac_luminance_nrcodes[k+1]);\n                    }\n                    for (var l=0; l<=161; l++) {\n                        writeByte(std_ac_luminance_values[l]);\n                    }\n\n                    writeByte(1); // HTUDCinfo\n                    for (var m=0; m<16; m++) {\n                        writeByte(std_dc_chrominance_nrcodes[m+1]);\n                    }\n                    for (var n=0; n<=11; n++) {\n                        writeByte(std_dc_chrominance_values[n]);\n                    }\n\n                    writeByte(0x11); // HTUACinfo\n                    for (var o=0; o<16; o++) {\n                        writeByte(std_ac_chrominance_nrcodes[o+1]);\n                    }\n                    for (var p=0; p<=161; p++) {\n                        writeByte(std_ac_chrominance_values[p]);\n                    }\n                }\n\n                function writeSOS()\n                {\n                    writeWord(0xFFDA); // marker\n                    writeWord(12); // length\n                    writeByte(3); // nrofcomponents\n                    writeByte(1); // IdY\n                    writeByte(0); // HTY\n                    writeByte(2); // IdU\n                    writeByte(0x11); // HTU\n                    writeByte(3); // IdV\n                    writeByte(0x11); // HTV\n                    writeByte(0); // Ss\n                    writeByte(0x3f); // Se\n                    writeByte(0); // Bf\n                }\n\n                function processDU(CDU, fdtbl, DC, HTDC, HTAC){\n                    var EOB = HTAC[0x00];\n                    var M16zeroes = HTAC[0xF0];\n                    var pos;\n                    var I16 = 16;\n                    var I63 = 63;\n                    var I64 = 64;\n                    var DU_DCT = fDCTQuant(CDU, fdtbl);\n                    //ZigZag reorder\n                    for (var j=0;j<I64;++j) {\n                        DU[ZigZag[j]]=DU_DCT[j];\n                    }\n                    var Diff = DU[0] - DC; DC = DU[0];\n                    //Encode DC\n                    if (Diff==0) {\n                        writeBits(HTDC[0]); // Diff might be 0\n                    } else {\n                        pos = 32767+Diff;\n                        writeBits(HTDC[category[pos]]);\n                        writeBits(bitcode[pos]);\n                    }\n                    //Encode ACs\n                    var end0pos = 63; // was const... which is crazy\n                    for (; (end0pos>0)&&(DU[end0pos]==0); end0pos--) {};\n                    //end0pos = first element in reverse order !=0\n                    if ( end0pos == 0) {\n                        writeBits(EOB);\n                        return DC;\n                    }\n                    var i = 1;\n                    var lng;\n                    while ( i <= end0pos ) {\n                        var startpos = i;\n                        for (; (DU[i]==0) && (i<=end0pos); ++i) {}\n                        var nrzeroes = i-startpos;\n                        if ( nrzeroes >= I16 ) {\n                            lng = nrzeroes>>4;\n                            for (var nrmarker=1; nrmarker <= lng; ++nrmarker)\n                                writeBits(M16zeroes);\n                            nrzeroes = nrzeroes&0xF;\n                        }\n                        pos = 32767+DU[i];\n                        writeBits(HTAC[(nrzeroes<<4)+category[pos]]);\n                        writeBits(bitcode[pos]);\n                        i++;\n                    }\n                    if ( end0pos != I63 ) {\n                        writeBits(EOB);\n                    }\n                    return DC;\n                }\n\n                function initCharLookupTable(){\n                    var sfcc = String.fromCharCode;\n                    for(var i=0; i < 256; i++){ ///// ACHTUNG // 255\n                        clt[i] = sfcc(i);\n                    }\n                }\n\n                this.encode = function(image,quality) // image data object\n                {\n                    // var time_start = new Date().getTime();\n\n                    if(quality) setQuality(quality);\n\n                    // Initialize bit writer\n                    byteout = new Array();\n                    bytenew=0;\n                    bytepos=7;\n\n                    // Add JPEG headers\n                    writeWord(0xFFD8); // SOI\n                    writeAPP0();\n                    writeDQT();\n                    writeSOF0(image.width,image.height);\n                    writeDHT();\n                    writeSOS();\n\n\n                    // Encode 8x8 macroblocks\n                    var DCY=0;\n                    var DCU=0;\n                    var DCV=0;\n\n                    bytenew=0;\n                    bytepos=7;\n\n\n                    this.encode.displayName = \"_encode_\";\n\n                    var imageData = image.data;\n                    var width = image.width;\n                    var height = image.height;\n\n                    var quadWidth = width*4;\n                    var tripleWidth = width*3;\n\n                    var x, y = 0;\n                    var r, g, b;\n                    var start,p, col,row,pos;\n                    while(y < height){\n                        x = 0;\n                        while(x < quadWidth){\n                        start = quadWidth * y + x;\n                        p = start;\n                        col = -1;\n                        row = 0;\n\n                        for(pos=0; pos < 64; pos++){\n                            row = pos >> 3;// /8\n                            col = ( pos & 7 ) * 4; // %8\n                            p = start + ( row * quadWidth ) + col;\n\n                            if(y+row >= height){ // padding bottom\n                                p-= (quadWidth*(y+1+row-height));\n                            }\n\n                            if(x+col >= quadWidth){ // padding right\n                                p-= ((x+col) - quadWidth +4)\n                            }\n\n                            r = imageData[ p++ ];\n                            g = imageData[ p++ ];\n                            b = imageData[ p++ ];\n\n\n                            /* // calculate YUV values dynamically\n                            YDU[pos]=((( 0.29900)*r+( 0.58700)*g+( 0.11400)*b))-128; //-0x80\n                            UDU[pos]=(((-0.16874)*r+(-0.33126)*g+( 0.50000)*b));\n                            VDU[pos]=((( 0.50000)*r+(-0.41869)*g+(-0.08131)*b));\n                            */\n\n                            // use lookup table (slightly faster)\n                            YDU[pos] = ((RGB_YUV_TABLE[r]             + RGB_YUV_TABLE[(g +  256)>>0] + RGB_YUV_TABLE[(b +  512)>>0]) >> 16)-128;\n                            UDU[pos] = ((RGB_YUV_TABLE[(r +  768)>>0] + RGB_YUV_TABLE[(g + 1024)>>0] + RGB_YUV_TABLE[(b + 1280)>>0]) >> 16)-128;\n                            VDU[pos] = ((RGB_YUV_TABLE[(r + 1280)>>0] + RGB_YUV_TABLE[(g + 1536)>>0] + RGB_YUV_TABLE[(b + 1792)>>0]) >> 16)-128;\n\n                        }\n\n                        DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n                        DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n                        DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n                        x+=32;\n                        }\n                        y+=8;\n                    }\n\n\n                    ////////////////////////////////////////////////////////////////\n\n                    // Do the bit alignment of the EOI marker\n                    if ( bytepos >= 0 ) {\n                        var fillbits = [];\n                        fillbits[1] = bytepos+1;\n                        fillbits[0] = (1<<(bytepos+1))-1;\n                        writeBits(fillbits);\n                    }\n\n                    writeWord(0xFFD9); //EOI\n\n                    var jpegDataUri = 'data:image/jpeg;base64,' + btoa(byteout.join(''));\n\n                    byteout = [];\n\n                    // benchmarking\n                    // var duration = new Date().getTime() - time_start;\n                    // console.log('Encoding time: '+ currentQuality + 'ms');\n                    //\n\n                    return jpegDataUri\n            }\n\n            function setQuality(quality){\n                if (quality <= 0) {\n                    quality = 1;\n                }\n                if (quality > 100) {\n                    quality = 100;\n                }\n\n                if(currentQuality == quality) return // don't recalc if unchanged\n\n                var sf = 0;\n                if (quality < 50) {\n                    sf = Math.floor(5000 / quality);\n                } else {\n                    sf = Math.floor(200 - quality*2);\n                }\n\n                initQuantTables(sf);\n                currentQuality = quality;\n                // console.log('Quality set to: '+quality +'%');\n            }\n\n            function init(){\n                // var time_start = new Date().getTime();\n                if(!quality) quality = 50;\n                // Create tables\n                initCharLookupTable()\n                initHuffmanTbl();\n                initCategoryNumber();\n                initRGBYUVTable();\n\n                setQuality(quality);\n                // var duration = new Date().getTime() - time_start;\n                // console.log('Initialization '+ duration + 'ms');\n            }\n\n            init();\n\n        };\n\n        JPEGEncoder.encode = function( data, quality ) {\n            var encoder = new JPEGEncoder( quality );\n\n            return encoder.encode( data );\n        }\n\n        return JPEGEncoder;\n    });\n    /**\n     * @fileOverview Fix android canvas.toDataUrl bug.\n     */\n    define('runtime/html5/androidpatch',[\n        'runtime/html5/util',\n        'runtime/html5/jpegencoder',\n        'base'\n    ], function( Util, encoder, Base ) {\n        var origin = Util.canvasToDataUrl,\n            supportJpeg;\n\n        Util.canvasToDataUrl = function( canvas, type, quality ) {\n            var ctx, w, h, fragement, parts;\n\n            // 非android手机直接跳过。\n            if ( !Base.os.android ) {\n                return origin.apply( null, arguments );\n            }\n\n            // 检测是否canvas支持jpeg导出，根据数据格式来判断。\n            // JPEG 前两位分别是：255, 216\n            if ( type === 'image/jpeg' && typeof supportJpeg === 'undefined' ) {\n                fragement = origin.apply( null, arguments );\n\n                parts = fragement.split(',');\n\n                if ( ~parts[ 0 ].indexOf('base64') ) {\n                    fragement = atob( parts[ 1 ] );\n                } else {\n                    fragement = decodeURIComponent( parts[ 1 ] );\n                }\n\n                fragement = fragement.substring( 0, 2 );\n\n                supportJpeg = fragement.charCodeAt( 0 ) === 255 &&\n                        fragement.charCodeAt( 1 ) === 216;\n            }\n\n            // 只有在android环境下才修复\n            if ( type === 'image/jpeg' && !supportJpeg ) {\n                w = canvas.width;\n                h = canvas.height;\n                ctx = canvas.getContext('2d');\n\n                return encoder.encode( ctx.getImageData( 0, 0, w, h ), quality );\n            }\n\n            return origin.apply( null, arguments );\n        };\n    });\n    /**\n     * @fileOverview Image\n     */\n    define('runtime/html5/image',[\n        'base',\n        'runtime/html5/runtime',\n        'runtime/html5/util'\n    ], function( Base, Html5Runtime, Util ) {\n\n        var BLANK = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs%3D';\n\n        return Html5Runtime.register( 'Image', {\n\n            // flag: 标记是否被修改过。\n            modified: false,\n\n            init: function() {\n                var me = this,\n                    img = new Image();\n\n                img.onload = function() {\n\n                    me._info = {\n                        type: me.type,\n                        width: this.width,\n                        height: this.height\n                    };\n\n                    // 读取meta信息。\n                    if ( !me._metas && 'image/jpeg' === me.type ) {\n                        Util.parseMeta( me._blob, function( error, ret ) {\n                            me._metas = ret;\n                            me.owner.trigger('load');\n                        });\n                    } else {\n                        me.owner.trigger('load');\n                    }\n                };\n\n                img.onerror = function() {\n                    me.owner.trigger('error');\n                };\n\n                me._img = img;\n            },\n\n            loadFromBlob: function( blob ) {\n                var me = this,\n                    img = me._img;\n\n                me._blob = blob;\n                me.type = blob.type;\n                img.src = Util.createObjectURL( blob.getSource() );\n                me.owner.once( 'load', function() {\n                    Util.revokeObjectURL( img.src );\n                });\n            },\n\n            resize: function( width, height ) {\n                var canvas = this._canvas ||\n                        (this._canvas = document.createElement('canvas'));\n\n                this._resize( this._img, canvas, width, height );\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'resize' );\n            },\n\n            crop: function( x, y, w, h, s ) {\n                var cvs = this._canvas ||\n                        (this._canvas = document.createElement('canvas')),\n                    opts = this.options,\n                    img = this._img,\n                    iw = img.naturalWidth,\n                    ih = img.naturalHeight,\n                    orientation = this.getOrientation();\n\n                s = s || 1;\n\n                // todo 解决 orientation 的问题。\n                // values that require 90 degree rotation\n                // if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                //     switch ( orientation ) {\n                //         case 6:\n                //             tmp = x;\n                //             x = y;\n                //             y = iw * s - tmp - w;\n                //             console.log(ih * s, tmp, w)\n                //             break;\n                //     }\n\n                //     (w ^= h, h ^= w, w ^= h);\n                // }\n\n                cvs.width = w;\n                cvs.height = h;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n                this._renderImageToCanvas( cvs, img, -x, -y, iw * s, ih * s );\n\n                this._blob = null;    // 没用了，可以删掉了。\n                this.modified = true;\n                this.owner.trigger( 'complete', 'crop' );\n            },\n\n            getAsBlob: function( type ) {\n                var blob = this._blob,\n                    opts = this.options,\n                    canvas;\n\n                type = type || this.type;\n\n                // blob需要重新生成。\n                if ( this.modified || this.type !== type ) {\n                    canvas = this._canvas;\n\n                    if ( type === 'image/jpeg' ) {\n\n                        blob = Util.canvasToDataUrl( canvas, type, opts.quality );\n\n                        if ( opts.preserveHeaders && this._metas &&\n                                this._metas.imageHead ) {\n\n                            blob = Util.dataURL2ArrayBuffer( blob );\n                            blob = Util.updateImageHead( blob,\n                                    this._metas.imageHead );\n                            blob = Util.arrayBufferToBlob( blob, type );\n                            return blob;\n                        }\n                    } else {\n                        blob = Util.canvasToDataUrl( canvas, type );\n                    }\n\n                    blob = Util.dataURL2Blob( blob );\n                }\n\n                return blob;\n            },\n\n            getAsDataUrl: function( type ) {\n                var opts = this.options;\n\n                type = type || this.type;\n\n                if ( type === 'image/jpeg' ) {\n                    return Util.canvasToDataUrl( this._canvas, type, opts.quality );\n                } else {\n                    return this._canvas.toDataURL( type );\n                }\n            },\n\n            getOrientation: function() {\n                return this._metas && this._metas.exif &&\n                        this._metas.exif.get('Orientation') || 1;\n            },\n\n            info: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._info = val;\n                    return this;\n                }\n\n                // getter\n                return this._info;\n            },\n\n            meta: function( val ) {\n\n                // setter\n                if ( val ) {\n                    this._meta = val;\n                    return this;\n                }\n\n                // getter\n                return this._meta;\n            },\n\n            destroy: function() {\n                var canvas = this._canvas;\n                this._img.onload = null;\n\n                if ( canvas ) {\n                    canvas.getContext('2d')\n                            .clearRect( 0, 0, canvas.width, canvas.height );\n                    canvas.width = canvas.height = 0;\n                    this._canvas = null;\n                }\n\n                // 释放内存。非常重要，否则释放不了image的内存。\n                this._img.src = BLANK;\n                this._img = this._blob = null;\n            },\n\n            _resize: function( img, cvs, width, height ) {\n                var opts = this.options,\n                    naturalWidth = img.width,\n                    naturalHeight = img.height,\n                    orientation = this.getOrientation(),\n                    scale, w, h, x, y;\n\n                // values that require 90 degree rotation\n                if ( ~[ 5, 6, 7, 8 ].indexOf( orientation ) ) {\n\n                    // 交换width, height的值。\n                    width ^= height;\n                    height ^= width;\n                    width ^= height;\n                }\n\n                scale = Math[ opts.crop ? 'max' : 'min' ]( width / naturalWidth,\n                        height / naturalHeight );\n\n                // 不允许放大。\n                opts.allowMagnify || (scale = Math.min( 1, scale ));\n\n                w = naturalWidth * scale;\n                h = naturalHeight * scale;\n\n                if ( opts.crop ) {\n                    cvs.width = width;\n                    cvs.height = height;\n                } else {\n                    cvs.width = w;\n                    cvs.height = h;\n                }\n\n                x = (cvs.width - w) / 2;\n                y = (cvs.height - h) / 2;\n\n                opts.preserveHeaders || this._rotate2Orientaion( cvs, orientation );\n\n                this._renderImageToCanvas( cvs, img, x, y, w, h );\n            },\n\n            _rotate2Orientaion: function( canvas, orientation ) {\n                var width = canvas.width,\n                    height = canvas.height,\n                    ctx = canvas.getContext('2d');\n\n                switch ( orientation ) {\n                    case 5:\n                    case 6:\n                    case 7:\n                    case 8:\n                        canvas.width = height;\n                        canvas.height = width;\n                        break;\n                }\n\n                switch ( orientation ) {\n                    case 2:    // horizontal flip\n                        ctx.translate( width, 0 );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 3:    // 180 rotate left\n                        ctx.translate( width, height );\n                        ctx.rotate( Math.PI );\n                        break;\n\n                    case 4:    // vertical flip\n                        ctx.translate( 0, height );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 5:    // vertical flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.scale( 1, -1 );\n                        break;\n\n                    case 6:    // 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( 0, -height );\n                        break;\n\n                    case 7:    // horizontal flip + 90 rotate right\n                        ctx.rotate( 0.5 * Math.PI );\n                        ctx.translate( width, -height );\n                        ctx.scale( -1, 1 );\n                        break;\n\n                    case 8:    // 90 rotate left\n                        ctx.rotate( -0.5 * Math.PI );\n                        ctx.translate( -width, 0 );\n                        break;\n                }\n            },\n\n            // https://github.com/stomita/ios-imagefile-megapixel/\n            // blob/master/src/megapix-image.js\n            _renderImageToCanvas: (function() {\n\n                // 如果不是ios, 不需要这么复杂！\n                if ( !Base.os.ios ) {\n                    return function( canvas ) {\n                        var args = Base.slice( arguments, 1 ),\n                            ctx = canvas.getContext('2d');\n\n                        ctx.drawImage.apply( ctx, args );\n                    };\n                }\n\n                /**\n                 * Detecting vertical squash in loaded image.\n                 * Fixes a bug which squash image vertically while drawing into\n                 * canvas for some images.\n                 */\n                function detectVerticalSquash( img, iw, ih ) {\n                    var canvas = document.createElement('canvas'),\n                        ctx = canvas.getContext('2d'),\n                        sy = 0,\n                        ey = ih,\n                        py = ih,\n                        data, alpha, ratio;\n\n\n                    canvas.width = 1;\n                    canvas.height = ih;\n                    ctx.drawImage( img, 0, 0 );\n                    data = ctx.getImageData( 0, 0, 1, ih ).data;\n\n                    // search image edge pixel position in case\n                    // it is squashed vertically.\n                    while ( py > sy ) {\n                        alpha = data[ (py - 1) * 4 + 3 ];\n\n                        if ( alpha === 0 ) {\n                            ey = py;\n                        } else {\n                            sy = py;\n                        }\n\n                        py = (ey + sy) >> 1;\n                    }\n\n                    ratio = (py / ih);\n                    return (ratio === 0) ? 1 : ratio;\n                }\n\n                // fix ie7 bug\n                // http://stackoverflow.com/questions/11929099/\n                // html5-canvas-drawimage-ratio-bug-ios\n                if ( Base.os.ios >= 7 ) {\n                    return function( canvas, img, x, y, w, h ) {\n                        var iw = img.naturalWidth,\n                            ih = img.naturalHeight,\n                            vertSquashRatio = detectVerticalSquash( img, iw, ih );\n\n                        return canvas.getContext('2d').drawImage( img, 0, 0,\n                                iw * vertSquashRatio, ih * vertSquashRatio,\n                                x, y, w, h );\n                    };\n                }\n\n                /**\n                 * Detect subsampling in loaded image.\n                 * In iOS, larger images than 2M pixels may be\n                 * subsampled in rendering.\n                 */\n                function detectSubsampling( img ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        canvas, ctx;\n\n                    // subsampling may happen overmegapixel image\n                    if ( iw * ih > 1024 * 1024 ) {\n                        canvas = document.createElement('canvas');\n                        canvas.width = canvas.height = 1;\n                        ctx = canvas.getContext('2d');\n                        ctx.drawImage( img, -iw + 1, 0 );\n\n                        // subsampled image becomes half smaller in rendering size.\n                        // check alpha channel value to confirm image is covering\n                        // edge pixel or not. if alpha value is 0\n                        // image is not covering, hence subsampled.\n                        return ctx.getImageData( 0, 0, 1, 1 ).data[ 3 ] === 0;\n                    } else {\n                        return false;\n                    }\n                }\n\n\n                return function( canvas, img, x, y, width, height ) {\n                    var iw = img.naturalWidth,\n                        ih = img.naturalHeight,\n                        ctx = canvas.getContext('2d'),\n                        subsampled = detectSubsampling( img ),\n                        doSquash = this.type === 'image/jpeg',\n                        d = 1024,\n                        sy = 0,\n                        dy = 0,\n                        tmpCanvas, tmpCtx, vertSquashRatio, dw, dh, sx, dx;\n\n                    if ( subsampled ) {\n                        iw /= 2;\n                        ih /= 2;\n                    }\n\n                    ctx.save();\n                    tmpCanvas = document.createElement('canvas');\n                    tmpCanvas.width = tmpCanvas.height = d;\n\n                    tmpCtx = tmpCanvas.getContext('2d');\n                    vertSquashRatio = doSquash ?\n                            detectVerticalSquash( img, iw, ih ) : 1;\n\n                    dw = Math.ceil( d * width / iw );\n                    dh = Math.ceil( d * height / ih / vertSquashRatio );\n\n                    while ( sy < ih ) {\n                        sx = 0;\n                        dx = 0;\n                        while ( sx < iw ) {\n                            tmpCtx.clearRect( 0, 0, d, d );\n                            tmpCtx.drawImage( img, -sx, -sy );\n                            ctx.drawImage( tmpCanvas, 0, 0, d, d,\n                                    x + dx, y + dy, dw, dh );\n                            sx += d;\n                            dx += dw;\n                        }\n                        sy += d;\n                        dy += dh;\n                    }\n                    ctx.restore();\n                    tmpCanvas = tmpCtx = null;\n                };\n            })()\n        });\n    });\n    /**\n     * @fileOverview Transport\n     * @todo 支持chunked传输，优势：\n     * 可以将大文件分成小块，挨个传输，可以提高大文件成功率，当失败的时候，也只需要重传那小部分，\n     * 而不需要重头再传一次。另外断点续传也需要用chunked方式。\n     */\n    define('runtime/html5/transport',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var noop = Base.noop,\n            $ = Base.$;\n\n        return Html5Runtime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    formData, binary, fr;\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.getSource();\n                } else {\n                    formData = new FormData();\n                    $.each( owner._formData, function( k, v ) {\n                        formData.append( k, v );\n                    });\n\n                    formData.append( opts.fileVal, blob.getSource(),\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                if ( opts.withCredentials && 'withCredentials' in xhr ) {\n                    xhr.open( opts.method, server, true );\n                    xhr.withCredentials = true;\n                } else {\n                    xhr.open( opts.method, server );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n\n                if ( binary ) {\n                    // 强制设置成 content-type 为文件流。\n                    xhr.overrideMimeType &&\n                            xhr.overrideMimeType('application/octet-stream');\n\n                    // android直接发送blob会导致服务端接收到的是空文件。\n                    // bug详情。\n                    // https://code.google.com/p/android/issues/detail?id=39882\n                    // 所以先用fileReader读取出来再通过arraybuffer的方式发送。\n                    if ( Base.os.android ) {\n                        fr = new FileReader();\n\n                        fr.onload = function() {\n                            xhr.send( this.result );\n                            fr = fr.onload = null;\n                        };\n\n                        fr.readAsArrayBuffer( binary );\n                    } else {\n                        xhr.send( binary );\n                    }\n                } else {\n                    xhr.send( formData );\n                }\n            },\n\n            getResponse: function() {\n                return this._response;\n            },\n\n            getResponseAsJson: function() {\n                return this._parseJson( this._response );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    xhr.abort();\n\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new XMLHttpRequest(),\n                    opts = this.options;\n\n                if ( opts.withCredentials && !('withCredentials' in xhr) &&\n                        typeof XDomainRequest !== 'undefined' ) {\n                    xhr = new XDomainRequest();\n                }\n\n                xhr.upload.onprogress = function( e ) {\n                    var percentage = 0;\n\n                    if ( e.lengthComputable ) {\n                        percentage = e.loaded / e.total;\n                    }\n\n                    return me.trigger( 'progress', percentage );\n                };\n\n                xhr.onreadystatechange = function() {\n\n                    if ( xhr.readyState !== 4 ) {\n                        return;\n                    }\n\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    me._xhr = null;\n                    me._status = xhr.status;\n\n                    if ( xhr.status >= 200 && xhr.status < 300 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger('load');\n                    } else if ( xhr.status >= 500 && xhr.status < 600 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger( 'error', 'server' );\n                    }\n\n\n                    return me.trigger( 'error', me._status ? 'http' : 'abort' );\n                };\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.setRequestHeader( key, val );\n                });\n            },\n\n            _parseJson: function( str ) {\n                var json;\n\n                try {\n                    json = JSON.parse( str );\n                } catch ( ex ) {\n                    json = {};\n                }\n\n                return json;\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/html5/md5',[\n        'runtime/html5/runtime'\n    ], function( FlashRuntime ) {\n\n        /*\n         * Fastest md5 implementation around (JKM md5)\n         * Credits: Joseph Myers\n         *\n         * @see http://www.myersdaily.org/joseph/javascript/md5-text.html\n         * @see http://jsperf.com/md5-shootout/7\n         */\n\n        /* this function is much faster,\n          so if possible we use it. Some IEs\n          are the only ones I know of that\n          need the idiotic second function,\n          generated by an if clause.  */\n        var add32 = function (a, b) {\n            return (a + b) & 0xFFFFFFFF;\n        },\n\n        cmn = function (q, a, b, x, s, t) {\n            a = add32(add32(a, q), add32(x, t));\n            return add32((a << s) | (a >>> (32 - s)), b);\n        },\n\n        ff = function (a, b, c, d, x, s, t) {\n            return cmn((b & c) | ((~b) & d), a, b, x, s, t);\n        },\n\n        gg = function (a, b, c, d, x, s, t) {\n            return cmn((b & d) | (c & (~d)), a, b, x, s, t);\n        },\n\n        hh = function (a, b, c, d, x, s, t) {\n            return cmn(b ^ c ^ d, a, b, x, s, t);\n        },\n\n        ii = function (a, b, c, d, x, s, t) {\n            return cmn(c ^ (b | (~d)), a, b, x, s, t);\n        },\n\n        md5cycle = function (x, k) {\n            var a = x[0],\n                b = x[1],\n                c = x[2],\n                d = x[3];\n\n            a = ff(a, b, c, d, k[0], 7, -680876936);\n            d = ff(d, a, b, c, k[1], 12, -389564586);\n            c = ff(c, d, a, b, k[2], 17, 606105819);\n            b = ff(b, c, d, a, k[3], 22, -1044525330);\n            a = ff(a, b, c, d, k[4], 7, -176418897);\n            d = ff(d, a, b, c, k[5], 12, 1200080426);\n            c = ff(c, d, a, b, k[6], 17, -1473231341);\n            b = ff(b, c, d, a, k[7], 22, -45705983);\n            a = ff(a, b, c, d, k[8], 7, 1770035416);\n            d = ff(d, a, b, c, k[9], 12, -1958414417);\n            c = ff(c, d, a, b, k[10], 17, -42063);\n            b = ff(b, c, d, a, k[11], 22, -1990404162);\n            a = ff(a, b, c, d, k[12], 7, 1804603682);\n            d = ff(d, a, b, c, k[13], 12, -40341101);\n            c = ff(c, d, a, b, k[14], 17, -1502002290);\n            b = ff(b, c, d, a, k[15], 22, 1236535329);\n\n            a = gg(a, b, c, d, k[1], 5, -165796510);\n            d = gg(d, a, b, c, k[6], 9, -1069501632);\n            c = gg(c, d, a, b, k[11], 14, 643717713);\n            b = gg(b, c, d, a, k[0], 20, -373897302);\n            a = gg(a, b, c, d, k[5], 5, -701558691);\n            d = gg(d, a, b, c, k[10], 9, 38016083);\n            c = gg(c, d, a, b, k[15], 14, -660478335);\n            b = gg(b, c, d, a, k[4], 20, -405537848);\n            a = gg(a, b, c, d, k[9], 5, 568446438);\n            d = gg(d, a, b, c, k[14], 9, -1019803690);\n            c = gg(c, d, a, b, k[3], 14, -187363961);\n            b = gg(b, c, d, a, k[8], 20, 1163531501);\n            a = gg(a, b, c, d, k[13], 5, -1444681467);\n            d = gg(d, a, b, c, k[2], 9, -51403784);\n            c = gg(c, d, a, b, k[7], 14, 1735328473);\n            b = gg(b, c, d, a, k[12], 20, -1926607734);\n\n            a = hh(a, b, c, d, k[5], 4, -378558);\n            d = hh(d, a, b, c, k[8], 11, -2022574463);\n            c = hh(c, d, a, b, k[11], 16, 1839030562);\n            b = hh(b, c, d, a, k[14], 23, -35309556);\n            a = hh(a, b, c, d, k[1], 4, -1530992060);\n            d = hh(d, a, b, c, k[4], 11, 1272893353);\n            c = hh(c, d, a, b, k[7], 16, -155497632);\n            b = hh(b, c, d, a, k[10], 23, -1094730640);\n            a = hh(a, b, c, d, k[13], 4, 681279174);\n            d = hh(d, a, b, c, k[0], 11, -358537222);\n            c = hh(c, d, a, b, k[3], 16, -722521979);\n            b = hh(b, c, d, a, k[6], 23, 76029189);\n            a = hh(a, b, c, d, k[9], 4, -640364487);\n            d = hh(d, a, b, c, k[12], 11, -421815835);\n            c = hh(c, d, a, b, k[15], 16, 530742520);\n            b = hh(b, c, d, a, k[2], 23, -995338651);\n\n            a = ii(a, b, c, d, k[0], 6, -198630844);\n            d = ii(d, a, b, c, k[7], 10, 1126891415);\n            c = ii(c, d, a, b, k[14], 15, -1416354905);\n            b = ii(b, c, d, a, k[5], 21, -57434055);\n            a = ii(a, b, c, d, k[12], 6, 1700485571);\n            d = ii(d, a, b, c, k[3], 10, -1894986606);\n            c = ii(c, d, a, b, k[10], 15, -1051523);\n            b = ii(b, c, d, a, k[1], 21, -2054922799);\n            a = ii(a, b, c, d, k[8], 6, 1873313359);\n            d = ii(d, a, b, c, k[15], 10, -30611744);\n            c = ii(c, d, a, b, k[6], 15, -1560198380);\n            b = ii(b, c, d, a, k[13], 21, 1309151649);\n            a = ii(a, b, c, d, k[4], 6, -145523070);\n            d = ii(d, a, b, c, k[11], 10, -1120210379);\n            c = ii(c, d, a, b, k[2], 15, 718787259);\n            b = ii(b, c, d, a, k[9], 21, -343485551);\n\n            x[0] = add32(a, x[0]);\n            x[1] = add32(b, x[1]);\n            x[2] = add32(c, x[2]);\n            x[3] = add32(d, x[3]);\n        },\n\n        /* there needs to be support for Unicode here,\n           * unless we pretend that we can redefine the MD-5\n           * algorithm for multi-byte characters (perhaps\n           * by adding every four 16-bit characters and\n           * shortening the sum to 32 bits). Otherwise\n           * I suggest performing MD-5 as if every character\n           * was two bytes--e.g., 0040 0025 = @%--but then\n           * how will an ordinary MD-5 sum be matched?\n           * There is no way to standardize text to something\n           * like UTF-8 before transformation; speed cost is\n           * utterly prohibitive. The JavaScript standard\n           * itself needs to look at this: it should start\n           * providing access to strings as preformed UTF-8\n           * 8-bit unsigned value arrays.\n           */\n        md5blk = function (s) {\n            var md5blks = [],\n                i; /* Andy King said do it this way. */\n\n            for (i = 0; i < 64; i += 4) {\n                md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);\n            }\n            return md5blks;\n        },\n\n        md5blk_array = function (a) {\n            var md5blks = [],\n                i; /* Andy King said do it this way. */\n\n            for (i = 0; i < 64; i += 4) {\n                md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);\n            }\n            return md5blks;\n        },\n\n        md51 = function (s) {\n            var n = s.length,\n                state = [1732584193, -271733879, -1732584194, 271733878],\n                i,\n                length,\n                tail,\n                tmp,\n                lo,\n                hi;\n\n            for (i = 64; i <= n; i += 64) {\n                md5cycle(state, md5blk(s.substring(i - 64, i)));\n            }\n            s = s.substring(i - 64);\n            length = s.length;\n            tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);\n            }\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Beware that the final length might not fit in 32 bits so we take care of that\n            tmp = n * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n\n            md5cycle(state, tail);\n            return state;\n        },\n\n        md51_array = function (a) {\n            var n = a.length,\n                state = [1732584193, -271733879, -1732584194, 271733878],\n                i,\n                length,\n                tail,\n                tmp,\n                lo,\n                hi;\n\n            for (i = 64; i <= n; i += 64) {\n                md5cycle(state, md5blk_array(a.subarray(i - 64, i)));\n            }\n\n            // Not sure if it is a bug, however IE10 will always produce a sub array of length 1\n            // containing the last element of the parent array if the sub array specified starts\n            // beyond the length of the parent array - weird.\n            // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue\n            a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);\n\n            length = a.length;\n            tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= a[i] << ((i % 4) << 3);\n            }\n\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Beware that the final length might not fit in 32 bits so we take care of that\n            tmp = n * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n\n            md5cycle(state, tail);\n\n            return state;\n        },\n\n        hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'],\n\n        rhex = function (n) {\n            var s = '',\n                j;\n            for (j = 0; j < 4; j += 1) {\n                s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];\n            }\n            return s;\n        },\n\n        hex = function (x) {\n            var i;\n            for (i = 0; i < x.length; i += 1) {\n                x[i] = rhex(x[i]);\n            }\n            return x.join('');\n        },\n\n        md5 = function (s) {\n            return hex(md51(s));\n        },\n\n\n\n        ////////////////////////////////////////////////////////////////////////////\n\n        /**\n         * SparkMD5 OOP implementation.\n         *\n         * Use this class to perform an incremental md5, otherwise use the\n         * static methods instead.\n         */\n        SparkMD5 = function () {\n            // call reset to init the instance\n            this.reset();\n        };\n\n\n        // In some cases the fast add32 function cannot be used..\n        if (md5('hello') !== '5d41402abc4b2a76b9719d911017c592') {\n            add32 = function (x, y) {\n                var lsw = (x & 0xFFFF) + (y & 0xFFFF),\n                    msw = (x >> 16) + (y >> 16) + (lsw >> 16);\n                return (msw << 16) | (lsw & 0xFFFF);\n            };\n        }\n\n\n        /**\n         * Appends a string.\n         * A conversion will be applied if an utf8 string is detected.\n         *\n         * @param {String} str The string to be appended\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.append = function (str) {\n            // converts the string to utf8 bytes if necessary\n            if (/[\\u0080-\\uFFFF]/.test(str)) {\n                str = unescape(encodeURIComponent(str));\n            }\n\n            // then append as binary\n            this.appendBinary(str);\n\n            return this;\n        };\n\n        /**\n         * Appends a binary string.\n         *\n         * @param {String} contents The binary string to be appended\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.appendBinary = function (contents) {\n            this._buff += contents;\n            this._length += contents.length;\n\n            var length = this._buff.length,\n                i;\n\n            for (i = 64; i <= length; i += 64) {\n                md5cycle(this._state, md5blk(this._buff.substring(i - 64, i)));\n            }\n\n            this._buff = this._buff.substr(i - 64);\n\n            return this;\n        };\n\n        /**\n         * Finishes the incremental computation, reseting the internal state and\n         * returning the result.\n         * Use the raw parameter to obtain the raw result instead of the hex one.\n         *\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.prototype.end = function (raw) {\n            var buff = this._buff,\n                length = buff.length,\n                i,\n                tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n                ret;\n\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);\n            }\n\n            this._finish(tail, length);\n            ret = !!raw ? this._state : hex(this._state);\n\n            this.reset();\n\n            return ret;\n        };\n\n        /**\n         * Finish the final calculation based on the tail.\n         *\n         * @param {Array}  tail   The tail (will be modified)\n         * @param {Number} length The length of the remaining buffer\n         */\n        SparkMD5.prototype._finish = function (tail, length) {\n            var i = length,\n                tmp,\n                lo,\n                hi;\n\n            tail[i >> 2] |= 0x80 << ((i % 4) << 3);\n            if (i > 55) {\n                md5cycle(this._state, tail);\n                for (i = 0; i < 16; i += 1) {\n                    tail[i] = 0;\n                }\n            }\n\n            // Do the final computation based on the tail and length\n            // Beware that the final length may not fit in 32 bits so we take care of that\n            tmp = this._length * 8;\n            tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);\n            lo = parseInt(tmp[2], 16);\n            hi = parseInt(tmp[1], 16) || 0;\n\n            tail[14] = lo;\n            tail[15] = hi;\n            md5cycle(this._state, tail);\n        };\n\n        /**\n         * Resets the internal state of the computation.\n         *\n         * @return {SparkMD5} The instance itself\n         */\n        SparkMD5.prototype.reset = function () {\n            this._buff = \"\";\n            this._length = 0;\n            this._state = [1732584193, -271733879, -1732584194, 271733878];\n\n            return this;\n        };\n\n        /**\n         * Releases memory used by the incremental buffer and other aditional\n         * resources. If you plan to use the instance again, use reset instead.\n         */\n        SparkMD5.prototype.destroy = function () {\n            delete this._state;\n            delete this._buff;\n            delete this._length;\n        };\n\n\n        /**\n         * Performs the md5 hash on a string.\n         * A conversion will be applied if utf8 string is detected.\n         *\n         * @param {String}  str The string\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.hash = function (str, raw) {\n            // converts the string to utf8 bytes if necessary\n            if (/[\\u0080-\\uFFFF]/.test(str)) {\n                str = unescape(encodeURIComponent(str));\n            }\n\n            var hash = md51(str);\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        /**\n         * Performs the md5 hash on a binary string.\n         *\n         * @param {String}  content The binary string\n         * @param {Boolean} raw     True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.hashBinary = function (content, raw) {\n            var hash = md51(content);\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        /**\n         * SparkMD5 OOP implementation for array buffers.\n         *\n         * Use this class to perform an incremental md5 ONLY for array buffers.\n         */\n        SparkMD5.ArrayBuffer = function () {\n            // call reset to init the instance\n            this.reset();\n        };\n\n        ////////////////////////////////////////////////////////////////////////////\n\n        /**\n         * Appends an array buffer.\n         *\n         * @param {ArrayBuffer} arr The array to be appended\n         *\n         * @return {SparkMD5.ArrayBuffer} The instance itself\n         */\n        SparkMD5.ArrayBuffer.prototype.append = function (arr) {\n            // TODO: we could avoid the concatenation here but the algorithm would be more complex\n            //       if you find yourself needing extra performance, please make a PR.\n            var buff = this._concatArrayBuffer(this._buff, arr),\n                length = buff.length,\n                i;\n\n            this._length += arr.byteLength;\n\n            for (i = 64; i <= length; i += 64) {\n                md5cycle(this._state, md5blk_array(buff.subarray(i - 64, i)));\n            }\n\n            // Avoids IE10 weirdness (documented above)\n            this._buff = (i - 64) < length ? buff.subarray(i - 64) : new Uint8Array(0);\n\n            return this;\n        };\n\n        /**\n         * Finishes the incremental computation, reseting the internal state and\n         * returning the result.\n         * Use the raw parameter to obtain the raw result instead of the hex one.\n         *\n         * @param {Boolean} raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.ArrayBuffer.prototype.end = function (raw) {\n            var buff = this._buff,\n                length = buff.length,\n                tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],\n                i,\n                ret;\n\n            for (i = 0; i < length; i += 1) {\n                tail[i >> 2] |= buff[i] << ((i % 4) << 3);\n            }\n\n            this._finish(tail, length);\n            ret = !!raw ? this._state : hex(this._state);\n\n            this.reset();\n\n            return ret;\n        };\n\n        SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;\n\n        /**\n         * Resets the internal state of the computation.\n         *\n         * @return {SparkMD5.ArrayBuffer} The instance itself\n         */\n        SparkMD5.ArrayBuffer.prototype.reset = function () {\n            this._buff = new Uint8Array(0);\n            this._length = 0;\n            this._state = [1732584193, -271733879, -1732584194, 271733878];\n\n            return this;\n        };\n\n        /**\n         * Releases memory used by the incremental buffer and other aditional\n         * resources. If you plan to use the instance again, use reset instead.\n         */\n        SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;\n\n        /**\n         * Concats two array buffers, returning a new one.\n         *\n         * @param  {ArrayBuffer} first  The first array buffer\n         * @param  {ArrayBuffer} second The second array buffer\n         *\n         * @return {ArrayBuffer} The new array buffer\n         */\n        SparkMD5.ArrayBuffer.prototype._concatArrayBuffer = function (first, second) {\n            var firstLength = first.length,\n                result = new Uint8Array(firstLength + second.byteLength);\n\n            result.set(first);\n            result.set(new Uint8Array(second), firstLength);\n\n            return result;\n        };\n\n        /**\n         * Performs the md5 hash on an array buffer.\n         *\n         * @param {ArrayBuffer} arr The array buffer\n         * @param {Boolean}     raw True to get the raw result, false to get the hex result\n         *\n         * @return {String|Array} The result\n         */\n        SparkMD5.ArrayBuffer.hash = function (arr, raw) {\n            var hash = md51_array(new Uint8Array(arr));\n\n            return !!raw ? hash : hex(hash);\n        };\n\n        return FlashRuntime.register( 'Md5', {\n            init: function() {\n                // do nothing.\n            },\n\n            loadFromBlob: function( file ) {\n                var blob = file.getSource(),\n                    chunkSize = 2 * 1024 * 1024,\n                    chunks = Math.ceil( blob.size / chunkSize ),\n                    chunk = 0,\n                    owner = this.owner,\n                    spark = new SparkMD5.ArrayBuffer(),\n                    me = this,\n                    blobSlice = blob.mozSlice || blob.webkitSlice || blob.slice,\n                    loadNext, fr;\n\n                fr = new FileReader();\n\n                loadNext = function() {\n                    var start, end;\n\n                    start = chunk * chunkSize;\n                    end = Math.min( start + chunkSize, blob.size );\n\n                    fr.onload = function( e ) {\n                        spark.append( e.target.result );\n                        owner.trigger( 'progress', {\n                            total: file.size,\n                            loaded: end\n                        });\n                    };\n\n                    fr.onloadend = function() {\n                        fr.onloadend = fr.onload = null;\n\n                        if ( ++chunk < chunks ) {\n                            setTimeout( loadNext, 1 );\n                        } else {\n                            setTimeout(function(){\n                                owner.trigger('load');\n                                me.result = spark.end();\n                                loadNext = file = blob = spark = null;\n                                owner.trigger('complete');\n                            }, 50 );\n                        }\n                    };\n\n                    fr.readAsArrayBuffer( blobSlice.call( blob, start, end ) );\n                };\n\n                loadNext();\n            },\n\n            getResult: function() {\n                return this.result;\n            }\n        });\n    });\n    /**\n     * @fileOverview FlashRuntime\n     */\n    define('runtime/flash/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var $ = Base.$,\n            type = 'flash',\n            components = {};\n\n\n        function getFlashVersion() {\n            var version;\n\n            try {\n                version = navigator.plugins[ 'Shockwave Flash' ];\n                version = version.description;\n            } catch ( ex ) {\n                try {\n                    version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')\n                            .GetVariable('$version');\n                } catch ( ex2 ) {\n                    version = '0.0';\n                }\n            }\n            version = version.match( /\\d+/g );\n            return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 );\n        }\n\n        function FlashRuntime() {\n            var pool = {},\n                clients = {},\n                destroy = this.destroy,\n                me = this,\n                jsreciver = Base.guid('webuploader_');\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/ ) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                clients[ uid ] = client;\n\n                if ( components[ comp ] ) {\n                    if ( !pool[ uid ] ) {\n                        pool[ uid ] = new components[ comp ]( client, me );\n                    }\n\n                    instance = pool[ uid ];\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n\n                return me.flashExec.apply( client, arguments );\n            };\n\n            function handler( evt, obj ) {\n                var type = evt.type || evt,\n                    parts, uid;\n\n                parts = type.split('::');\n                uid = parts[ 0 ];\n                type = parts[ 1 ];\n\n                // console.log.apply( console, arguments );\n\n                if ( type === 'Ready' && uid === me.uid ) {\n                    me.trigger('ready');\n                } else if ( clients[ uid ] ) {\n                    clients[ uid ].trigger( type.toLowerCase(), evt, obj );\n                }\n\n                // Base.log( evt, obj );\n            }\n\n            // flash的接受器。\n            window[ jsreciver ] = function() {\n                var args = arguments;\n\n                // 为了能捕获得到。\n                setTimeout(function() {\n                    handler.apply( null, args );\n                }, 1 );\n            };\n\n            this.jsreciver = jsreciver;\n\n            this.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n\n            this.flashExec = function( comp, fn ) {\n                var flash = me.getFlash(),\n                    args = Base.slice( arguments, 2 );\n\n                return flash.exec( this.uid, comp, fn, args );\n            };\n\n            // @todo\n        }\n\n        Base.inherits( Runtime, {\n            constructor: FlashRuntime,\n\n            init: function() {\n                var container = this.getContainer(),\n                    opts = this.options,\n                    html;\n\n                // if not the minimal height, shims are not initialized\n                // in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)\n                container.css({\n                    position: 'absolute',\n                    top: '-8px',\n                    left: '-8px',\n                    width: '9px',\n                    height: '9px',\n                    overflow: 'hidden'\n                });\n\n                // insert flash object\n                html = '<object id=\"' + this.uid + '\" type=\"application/' +\n                        'x-shockwave-flash\" data=\"' +  opts.swf + '\" ';\n\n                if ( Base.browser.ie ) {\n                    html += 'classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" ';\n                }\n\n                html += 'width=\"100%\" height=\"100%\" style=\"outline:0\">'  +\n                    '<param name=\"movie\" value=\"' + opts.swf + '\" />' +\n                    '<param name=\"flashvars\" value=\"uid=' + this.uid +\n                    '&jsreciver=' + this.jsreciver + '\" />' +\n                    '<param name=\"wmode\" value=\"transparent\" />' +\n                    '<param name=\"allowscriptaccess\" value=\"always\" />' +\n                '</object>';\n\n                container.html( html );\n            },\n\n            getFlash: function() {\n                if ( this._flash ) {\n                    return this._flash;\n                }\n\n                this._flash = $( '#' + this.uid ).get( 0 );\n                return this._flash;\n            }\n\n        });\n\n        FlashRuntime.register = function( name, component ) {\n            component = components[ name ] = Base.inherits( CompBase, $.extend({\n\n                // @todo fix this later\n                flashExec: function() {\n                    var owner = this.owner,\n                        runtime = this.getRuntime();\n\n                    return runtime.flashExec.apply( owner, arguments );\n                }\n            }, component ) );\n\n            return component;\n        };\n\n        if ( getFlashVersion() >= 11.4 ) {\n            Runtime.addRuntime( type, FlashRuntime );\n        }\n\n        return FlashRuntime;\n    });\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/flash/filepicker',[\n        'base',\n        'runtime/flash/runtime'\n    ], function( Base, FlashRuntime ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'FilePicker', {\n            init: function( opts ) {\n                var copy = $.extend({}, opts ),\n                    len, i;\n\n                // 修复Flash再没有设置title的情况下无法弹出flash文件选择框的bug.\n                len = copy.accept && copy.accept.length;\n                for (  i = 0; i < len; i++ ) {\n                    if ( !copy.accept[ i ].title ) {\n                        copy.accept[ i ].title = 'Files';\n                    }\n                }\n\n                delete copy.button;\n                delete copy.id;\n                delete copy.container;\n\n                this.flashExec( 'FilePicker', 'init', copy );\n            },\n\n            destroy: function() {\n                this.flashExec( 'FilePicker', 'destroy' );\n            }\n        });\n    });\n    /**\n     * @fileOverview 图片压缩\n     */\n    define('runtime/flash/image',[\n        'runtime/flash/runtime'\n    ], function( FlashRuntime ) {\n\n        return FlashRuntime.register( 'Image', {\n            // init: function( options ) {\n            //     var owner = this.owner;\n\n            //     this.flashExec( 'Image', 'init', options );\n            //     owner.on( 'load', function() {\n            //         debugger;\n            //     });\n            // },\n\n            loadFromBlob: function( blob ) {\n                var owner = this.owner;\n\n                owner.info() && this.flashExec( 'Image', 'info', owner.info() );\n                owner.meta() && this.flashExec( 'Image', 'meta', owner.meta() );\n\n                this.flashExec( 'Image', 'loadFromBlob', blob.uid );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/flash/transport',[\n        'base',\n        'runtime/flash/runtime',\n        'runtime/client'\n    ], function( Base, FlashRuntime, RuntimeClient ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n                this._responseJson = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    binary;\n\n                xhr.connectRuntime( blob.ruid );\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.uid;\n                } else {\n                    $.each( owner._formData, function( k, v ) {\n                        xhr.exec( 'append', k, v );\n                    });\n\n                    xhr.exec( 'appendBlob', opts.fileVal, blob.uid,\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n                xhr.exec( 'send', {\n                    method: opts.method,\n                    url: server,\n                    forceURLStream: opts.forceURLStream,\n                    mimeType: 'application/octet-stream'\n                }, binary );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            getResponse: function() {\n                return this._response || '';\n            },\n\n            getResponseAsJson: function() {\n                return this._responseJson;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.exec('abort');\n                    xhr.destroy();\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new RuntimeClient('XMLHttpRequest');\n\n                xhr.on( 'uploadprogress progress', function( e ) {\n                    var percent = e.loaded / e.total;\n                    percent = Math.min( 1, Math.max( 0, percent ) );\n                    return me.trigger( 'progress', percent );\n                });\n\n                xhr.on( 'load', function() {\n                    var status = xhr.exec('getStatus'),\n                        readBody = false,\n                        err = '',\n                        p;\n\n                    xhr.off();\n                    me._xhr = null;\n\n                    if ( status >= 200 && status < 300 ) {\n                        readBody = true;\n                    } else if ( status >= 500 && status < 600 ) {\n                        readBody = true;\n                        err = 'server';\n                    } else {\n                        err = 'http';\n                    }\n\n                    if ( readBody ) {\n                        me._response = xhr.exec('getResponse');\n                        me._response = decodeURIComponent( me._response );\n\n                        // flash 处理可能存在 bug, 没辙只能靠 js 了\n                        // try {\n                        //     me._responseJson = xhr.exec('getResponseAsJson');\n                        // } catch ( error ) {\n\n                        p = window.JSON && window.JSON.parse || function( s ) {\n                            try {\n                                return new Function('return ' + s).call();\n                            } catch ( err ) {\n                                return {};\n                            }\n                        };\n                        me._responseJson  = me._response ? p(me._response) : {};\n\n                        // }\n                    }\n\n                    xhr.destroy();\n                    xhr = null;\n\n                    return err ? me.trigger( 'error', err ) : me.trigger('load');\n                });\n\n                xhr.on( 'error', function() {\n                    xhr.off();\n                    me._xhr = null;\n                    me.trigger( 'error', 'http' );\n                });\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.exec( 'setRequestHeader', key, val );\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/flash/blob',[\n        'runtime/flash/runtime',\n        'lib/blob'\n    ], function( FlashRuntime, Blob ) {\n\n        return FlashRuntime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.flashExec( 'Blob', 'slice', start, end );\n\n                return new Blob( blob.uid, blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Md5 flash实现\n     */\n    define('runtime/flash/md5',[\n        'runtime/flash/runtime'\n    ], function( FlashRuntime ) {\n\n        return FlashRuntime.register( 'Md5', {\n            init: function() {\n                // do nothing.\n            },\n\n            loadFromBlob: function( blob ) {\n                return this.flashExec( 'Md5', 'loadFromBlob', blob.uid );\n            }\n        });\n    });\n    /**\n     * @fileOverview 完全版本。\n     */\n    define('preset/all',[\n        'base',\n\n        // widgets\n        'widgets/filednd',\n        'widgets/filepaste',\n        'widgets/filepicker',\n        'widgets/image',\n        'widgets/queue',\n        'widgets/runtime',\n        'widgets/upload',\n        'widgets/validator',\n        'widgets/md5',\n\n        // runtimes\n        // html5\n        'runtime/html5/blob',\n        'runtime/html5/dnd',\n        'runtime/html5/filepaste',\n        'runtime/html5/filepicker',\n        'runtime/html5/imagemeta/exif',\n        'runtime/html5/androidpatch',\n        'runtime/html5/image',\n        'runtime/html5/transport',\n        'runtime/html5/md5',\n\n        // flash\n        'runtime/flash/filepicker',\n        'runtime/flash/image',\n        'runtime/flash/transport',\n        'runtime/flash/blob',\n        'runtime/flash/md5'\n    ], function( Base ) {\n        return Base;\n    });\n    define('webuploader',[\n        'preset/all'\n    ], function( preset ) {\n        return preset;\n    });\n    return require('webuploader');\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/plugins/webuploader/webuploader.withoutimage.js",
    "content": "/*! WebUploader 0.1.5 */\n\n\n/**\n * @fileOverview 让内部各个部件的代码可以用[amd](https://github.com/amdjs/amdjs-api/wiki/AMD)模块定义方式组织起来。\n *\n * AMD API 内部的简单不完全实现，请忽略。只有当WebUploader被合并成一个文件的时候才会引入。\n */\n(function( root, factory ) {\n    var modules = {},\n\n        // 内部require, 简单不完全实现。\n        // https://github.com/amdjs/amdjs-api/wiki/require\n        _require = function( deps, callback ) {\n            var args, len, i;\n\n            // 如果deps不是数组，则直接返回指定module\n            if ( typeof deps === 'string' ) {\n                return getModule( deps );\n            } else {\n                args = [];\n                for( len = deps.length, i = 0; i < len; i++ ) {\n                    args.push( getModule( deps[ i ] ) );\n                }\n\n                return callback.apply( null, args );\n            }\n        },\n\n        // 内部define，暂时不支持不指定id.\n        _define = function( id, deps, factory ) {\n            if ( arguments.length === 2 ) {\n                factory = deps;\n                deps = null;\n            }\n\n            _require( deps || [], function() {\n                setModule( id, factory, arguments );\n            });\n        },\n\n        // 设置module, 兼容CommonJs写法。\n        setModule = function( id, factory, args ) {\n            var module = {\n                    exports: factory\n                },\n                returned;\n\n            if ( typeof factory === 'function' ) {\n                args.length || (args = [ _require, module.exports, module ]);\n                returned = factory.apply( null, args );\n                returned !== undefined && (module.exports = returned);\n            }\n\n            modules[ id ] = module.exports;\n        },\n\n        // 根据id获取module\n        getModule = function( id ) {\n            var module = modules[ id ] || root[ id ];\n\n            if ( !module ) {\n                throw new Error( '`' + id + '` is undefined' );\n            }\n\n            return module;\n        },\n\n        // 将所有modules，将路径ids装换成对象。\n        exportsTo = function( obj ) {\n            var key, host, parts, part, last, ucFirst;\n\n            // make the first character upper case.\n            ucFirst = function( str ) {\n                return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 ));\n            };\n\n            for ( key in modules ) {\n                host = obj;\n\n                if ( !modules.hasOwnProperty( key ) ) {\n                    continue;\n                }\n\n                parts = key.split('/');\n                last = ucFirst( parts.pop() );\n\n                while( (part = ucFirst( parts.shift() )) ) {\n                    host[ part ] = host[ part ] || {};\n                    host = host[ part ];\n                }\n\n                host[ last ] = modules[ key ];\n            }\n\n            return obj;\n        },\n\n        makeExport = function( dollar ) {\n            root.__dollar = dollar;\n\n            // exports every module.\n            return exportsTo( factory( root, _define, _require ) );\n        },\n\n        origin;\n\n    if ( typeof module === 'object' && typeof module.exports === 'object' ) {\n\n        // For CommonJS and CommonJS-like environments where a proper window is present,\n        module.exports = makeExport();\n    } else if ( typeof define === 'function' && define.amd ) {\n\n        // Allow using this built library as an AMD module\n        // in another project. That other project will only\n        // see this AMD call, not the internal modules in\n        // the closure below.\n        define([ 'jquery' ], makeExport );\n    } else {\n\n        // Browser globals case. Just assign the\n        // result to a property on the global.\n        origin = root.WebUploader;\n        root.WebUploader = makeExport();\n        root.WebUploader.noConflict = function() {\n            root.WebUploader = origin;\n        };\n    }\n})( window, function( window, define, require ) {\n\n\n    /**\n     * @fileOverview jQuery or Zepto\n     */\n    define('dollar-third',[],function() {\n        var $ = window.__dollar || window.jQuery || window.Zepto;\n\n        if ( !$ ) {\n            throw new Error('jQuery or Zepto not found!');\n        }\n\n        return $;\n    });\n    /**\n     * @fileOverview Dom 操作相关\n     */\n    define('dollar',[\n        'dollar-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 使用jQuery的Promise\n     */\n    define('promise-third',[\n        'dollar'\n    ], function( $ ) {\n        return {\n            Deferred: $.Deferred,\n            when: $.when,\n\n            isPromise: function( anything ) {\n                return anything && typeof anything.then === 'function';\n            }\n        };\n    });\n    /**\n     * @fileOverview Promise/A+\n     */\n    define('promise',[\n        'promise-third'\n    ], function( _ ) {\n        return _;\n    });\n    /**\n     * @fileOverview 基础类方法。\n     */\n\n    /**\n     * Web Uploader内部类的详细说明，以下提及的功能类，都可以在`WebUploader`这个变量中访问到。\n     *\n     * As you know, Web Uploader的每个文件都是用过[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)规范中的`define`组织起来的, 每个Module都会有个module id.\n     * 默认module id为该文件的路径，而此路径将会转化成名字空间存放在WebUploader中。如：\n     *\n     * * module `base`：WebUploader.Base\n     * * module `file`: WebUploader.File\n     * * module `lib/dnd`: WebUploader.Lib.Dnd\n     * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd\n     *\n     *\n     * 以下文档中对类的使用可能省略掉了`WebUploader`前缀。\n     * @module WebUploader\n     * @title WebUploader API文档\n     */\n    define('base',[\n        'dollar',\n        'promise'\n    ], function( $, promise ) {\n\n        var noop = function() {},\n            call = Function.call;\n\n        // http://jsperf.com/uncurrythis\n        // 反科里化\n        function uncurryThis( fn ) {\n            return function() {\n                return call.apply( fn, arguments );\n            };\n        }\n\n        function bindFn( fn, context ) {\n            return function() {\n                return fn.apply( context, arguments );\n            };\n        }\n\n        function createObject( proto ) {\n            var f;\n\n            if ( Object.create ) {\n                return Object.create( proto );\n            } else {\n                f = function() {};\n                f.prototype = proto;\n                return new f();\n            }\n        }\n\n\n        /**\n         * 基础类，提供一些简单常用的方法。\n         * @class Base\n         */\n        return {\n\n            /**\n             * @property {String} version 当前版本号。\n             */\n            version: '0.1.5',\n\n            /**\n             * @property {jQuery|Zepto} $ 引用依赖的jQuery或者Zepto对象。\n             */\n            $: $,\n\n            Deferred: promise.Deferred,\n\n            isPromise: promise.isPromise,\n\n            when: promise.when,\n\n            /**\n             * @description  简单的浏览器检查结果。\n             *\n             * * `webkit`  webkit版本号，如果浏览器为非webkit内核，此属性为`undefined`。\n             * * `chrome`  chrome浏览器版本号，如果浏览器为chrome，此属性为`undefined`。\n             * * `ie`  ie浏览器版本号，如果浏览器为非ie，此属性为`undefined`。**暂不支持ie10+**\n             * * `firefox`  firefox浏览器版本号，如果浏览器为非firefox，此属性为`undefined`。\n             * * `safari`  safari浏览器版本号，如果浏览器为非safari，此属性为`undefined`。\n             * * `opera`  opera浏览器版本号，如果浏览器为非opera，此属性为`undefined`。\n             *\n             * @property {Object} [browser]\n             */\n            browser: (function( ua ) {\n                var ret = {},\n                    webkit = ua.match( /WebKit\\/([\\d.]+)/ ),\n                    chrome = ua.match( /Chrome\\/([\\d.]+)/ ) ||\n                        ua.match( /CriOS\\/([\\d.]+)/ ),\n\n                    ie = ua.match( /MSIE\\s([\\d\\.]+)/ ) ||\n                        ua.match( /(?:trident)(?:.*rv:([\\w.]+))?/i ),\n                    firefox = ua.match( /Firefox\\/([\\d.]+)/ ),\n                    safari = ua.match( /Safari\\/([\\d.]+)/ ),\n                    opera = ua.match( /OPR\\/([\\d.]+)/ );\n\n                webkit && (ret.webkit = parseFloat( webkit[ 1 ] ));\n                chrome && (ret.chrome = parseFloat( chrome[ 1 ] ));\n                ie && (ret.ie = parseFloat( ie[ 1 ] ));\n                firefox && (ret.firefox = parseFloat( firefox[ 1 ] ));\n                safari && (ret.safari = parseFloat( safari[ 1 ] ));\n                opera && (ret.opera = parseFloat( opera[ 1 ] ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * @description  操作系统检查结果。\n             *\n             * * `android`  如果在android浏览器环境下，此值为对应的android版本号，否则为`undefined`。\n             * * `ios` 如果在ios浏览器环境下，此值为对应的ios版本号，否则为`undefined`。\n             * @property {Object} [os]\n             */\n            os: (function( ua ) {\n                var ret = {},\n\n                    // osx = !!ua.match( /\\(Macintosh\\; Intel / ),\n                    android = ua.match( /(?:Android);?[\\s\\/]+([\\d.]+)?/ ),\n                    ios = ua.match( /(?:iPad|iPod|iPhone).*OS\\s([\\d_]+)/ );\n\n                // osx && (ret.osx = true);\n                android && (ret.android = parseFloat( android[ 1 ] ));\n                ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) ));\n\n                return ret;\n            })( navigator.userAgent ),\n\n            /**\n             * 实现类与类之间的继承。\n             * @method inherits\n             * @grammar Base.inherits( super ) => child\n             * @grammar Base.inherits( super, protos ) => child\n             * @grammar Base.inherits( super, protos, statics ) => child\n             * @param  {Class} super 父类\n             * @param  {Object | Function} [protos] 子类或者对象。如果对象中包含constructor，子类将是用此属性值。\n             * @param  {Function} [protos.constructor] 子类构造器，不指定的话将创建个临时的直接执行父类构造器的方法。\n             * @param  {Object} [statics] 静态属性或方法。\n             * @return {Class} 返回子类。\n             * @example\n             * function Person() {\n             *     console.log( 'Super' );\n             * }\n             * Person.prototype.hello = function() {\n             *     console.log( 'hello' );\n             * };\n             *\n             * var Manager = Base.inherits( Person, {\n             *     world: function() {\n             *         console.log( 'World' );\n             *     }\n             * });\n             *\n             * // 因为没有指定构造器，父类的构造器将会执行。\n             * var instance = new Manager();    // => Super\n             *\n             * // 继承子父类的方法\n             * instance.hello();    // => hello\n             * instance.world();    // => World\n             *\n             * // 子类的__super__属性指向父类\n             * console.log( Manager.__super__ === Person );    // => true\n             */\n            inherits: function( Super, protos, staticProtos ) {\n                var child;\n\n                if ( typeof protos === 'function' ) {\n                    child = protos;\n                    protos = null;\n                } else if ( protos && protos.hasOwnProperty('constructor') ) {\n                    child = protos.constructor;\n                } else {\n                    child = function() {\n                        return Super.apply( this, arguments );\n                    };\n                }\n\n                // 复制静态方法\n                $.extend( true, child, Super, staticProtos || {} );\n\n                /* jshint camelcase: false */\n\n                // 让子类的__super__属性指向父类。\n                child.__super__ = Super.prototype;\n\n                // 构建原型，添加原型方法或属性。\n                // 暂时用Object.create实现。\n                child.prototype = createObject( Super.prototype );\n                protos && $.extend( true, child.prototype, protos );\n\n                return child;\n            },\n\n            /**\n             * 一个不做任何事情的方法。可以用来赋值给默认的callback.\n             * @method noop\n             */\n            noop: noop,\n\n            /**\n             * 返回一个新的方法，此方法将已指定的`context`来执行。\n             * @grammar Base.bindFn( fn, context ) => Function\n             * @method bindFn\n             * @example\n             * var doSomething = function() {\n             *         console.log( this.name );\n             *     },\n             *     obj = {\n             *         name: 'Object Name'\n             *     },\n             *     aliasFn = Base.bind( doSomething, obj );\n             *\n             *  aliasFn();    // => Object Name\n             *\n             */\n            bindFn: bindFn,\n\n            /**\n             * 引用Console.log如果存在的话，否则引用一个[空函数noop](#WebUploader:Base.noop)。\n             * @grammar Base.log( args... ) => undefined\n             * @method log\n             */\n            log: (function() {\n                if ( window.console ) {\n                    return bindFn( console.log, console );\n                }\n                return noop;\n            })(),\n\n            nextTick: (function() {\n\n                return function( cb ) {\n                    setTimeout( cb, 1 );\n                };\n\n                // @bug 当浏览器不在当前窗口时就停了。\n                // var next = window.requestAnimationFrame ||\n                //     window.webkitRequestAnimationFrame ||\n                //     window.mozRequestAnimationFrame ||\n                //     function( cb ) {\n                //         window.setTimeout( cb, 1000 / 60 );\n                //     };\n\n                // // fix: Uncaught TypeError: Illegal invocation\n                // return bindFn( next, window );\n            })(),\n\n            /**\n             * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的数组slice方法。\n             * 将用来将非数组对象转化成数组对象。\n             * @grammar Base.slice( target, start[, end] ) => Array\n             * @method slice\n             * @example\n             * function doSomthing() {\n             *     var args = Base.slice( arguments, 1 );\n             *     console.log( args );\n             * }\n             *\n             * doSomthing( 'ignored', 'arg2', 'arg3' );    // => Array [\"arg2\", \"arg3\"]\n             */\n            slice: uncurryThis( [].slice ),\n\n            /**\n             * 生成唯一的ID\n             * @method guid\n             * @grammar Base.guid() => String\n             * @grammar Base.guid( prefx ) => String\n             */\n            guid: (function() {\n                var counter = 0;\n\n                return function( prefix ) {\n                    var guid = (+new Date()).toString( 32 ),\n                        i = 0;\n\n                    for ( ; i < 5; i++ ) {\n                        guid += Math.floor( Math.random() * 65535 ).toString( 32 );\n                    }\n\n                    return (prefix || 'wu_') + guid + (counter++).toString( 32 );\n                };\n            })(),\n\n            /**\n             * 格式化文件大小, 输出成带单位的字符串\n             * @method formatSize\n             * @grammar Base.formatSize( size ) => String\n             * @grammar Base.formatSize( size, pointLength ) => String\n             * @grammar Base.formatSize( size, pointLength, units ) => String\n             * @param {Number} size 文件大小\n             * @param {Number} [pointLength=2] 精确到的小数点数。\n             * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 单位数组。从字节，到千字节，一直往上指定。如果单位数组里面只指定了到了K(千字节)，同时文件大小大于M, 此方法的输出将还是显示成多少K.\n             * @example\n             * console.log( Base.formatSize( 100 ) );    // => 100B\n             * console.log( Base.formatSize( 1024 ) );    // => 1.00K\n             * console.log( Base.formatSize( 1024, 0 ) );    // => 1K\n             * console.log( Base.formatSize( 1024 * 1024 ) );    // => 1.00M\n             * console.log( Base.formatSize( 1024 * 1024 * 1024 ) );    // => 1.00G\n             * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) );    // => 1024MB\n             */\n            formatSize: function( size, pointLength, units ) {\n                var unit;\n\n                units = units || [ 'B', 'K', 'M', 'G', 'TB' ];\n\n                while ( (unit = units.shift()) && size > 1024 ) {\n                    size = size / 1024;\n                }\n\n                return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) +\n                        unit;\n            }\n        };\n    });\n    /**\n     * 事件处理类，可以独立使用，也可以扩展给对象使用。\n     * @fileOverview Mediator\n     */\n    define('mediator',[\n        'base'\n    ], function( Base ) {\n        var $ = Base.$,\n            slice = [].slice,\n            separator = /\\s+/,\n            protos;\n\n        // 根据条件过滤出事件handlers.\n        function findHandlers( arr, name, callback, context ) {\n            return $.grep( arr, function( handler ) {\n                return handler &&\n                        (!name || handler.e === name) &&\n                        (!callback || handler.cb === callback ||\n                        handler.cb._cb === callback) &&\n                        (!context || handler.ctx === context);\n            });\n        }\n\n        function eachEvent( events, callback, iterator ) {\n            // 不支持对象，只支持多个event用空格隔开\n            $.each( (events || '').split( separator ), function( _, key ) {\n                iterator( key, callback );\n            });\n        }\n\n        function triggerHanders( events, args ) {\n            var stoped = false,\n                i = -1,\n                len = events.length,\n                handler;\n\n            while ( ++i < len ) {\n                handler = events[ i ];\n\n                if ( handler.cb.apply( handler.ctx2, args ) === false ) {\n                    stoped = true;\n                    break;\n                }\n            }\n\n            return !stoped;\n        }\n\n        protos = {\n\n            /**\n             * 绑定事件。\n             *\n             * `callback`方法在执行时，arguments将会来源于trigger的时候携带的参数。如\n             * ```javascript\n             * var obj = {};\n             *\n             * // 使得obj有事件行为\n             * Mediator.installTo( obj );\n             *\n             * obj.on( 'testa', function( arg1, arg2 ) {\n             *     console.log( arg1, arg2 ); // => 'arg1', 'arg2'\n             * });\n             *\n             * obj.trigger( 'testa', 'arg1', 'arg2' );\n             * ```\n             *\n             * 如果`callback`中，某一个方法`return false`了，则后续的其他`callback`都不会被执行到。\n             * 切会影响到`trigger`方法的返回值，为`false`。\n             *\n             * `on`还可以用来添加一个特殊事件`all`, 这样所有的事件触发都会响应到。同时此类`callback`中的arguments有一个不同处，\n             * 就是第一个参数为`type`，记录当前是什么事件在触发。此类`callback`的优先级比脚低，会再正常`callback`执行完后触发。\n             * ```javascript\n             * obj.on( 'all', function( type, arg1, arg2 ) {\n             *     console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2'\n             * });\n             * ```\n             *\n             * @method on\n             * @grammar on( name, callback[, context] ) => self\n             * @param  {String}   name     事件名，支持多个事件用空格隔开\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             * @class Mediator\n             */\n            on: function( name, callback, context ) {\n                var me = this,\n                    set;\n\n                if ( !callback ) {\n                    return this;\n                }\n\n                set = this._events || (this._events = []);\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var handler = { e: name };\n\n                    handler.cb = callback;\n                    handler.ctx = context;\n                    handler.ctx2 = context || me;\n                    handler.id = set.length;\n\n                    set.push( handler );\n                });\n\n                return this;\n            },\n\n            /**\n             * 绑定事件，且当handler执行完后，自动解除绑定。\n             * @method once\n             * @grammar once( name, callback[, context] ) => self\n             * @param  {String}   name     事件名\n             * @param  {Function} callback 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            once: function( name, callback, context ) {\n                var me = this;\n\n                if ( !callback ) {\n                    return me;\n                }\n\n                eachEvent( name, callback, function( name, callback ) {\n                    var once = function() {\n                            me.off( name, once );\n                            return callback.apply( context || me, arguments );\n                        };\n\n                    once._cb = callback;\n                    me.on( name, once, context );\n                });\n\n                return me;\n            },\n\n            /**\n             * 解除事件绑定\n             * @method off\n             * @grammar off( [name[, callback[, context] ] ] ) => self\n             * @param  {String}   [name]     事件名\n             * @param  {Function} [callback] 事件处理器\n             * @param  {Object}   [context]  事件处理器的上下文。\n             * @return {self} 返回自身，方便链式\n             * @chainable\n             */\n            off: function( name, cb, ctx ) {\n                var events = this._events;\n\n                if ( !events ) {\n                    return this;\n                }\n\n                if ( !name && !cb && !ctx ) {\n                    this._events = [];\n                    return this;\n                }\n\n                eachEvent( name, cb, function( name, cb ) {\n                    $.each( findHandlers( events, name, cb, ctx ), function() {\n                        delete events[ this.id ];\n                    });\n                });\n\n                return this;\n            },\n\n            /**\n             * 触发事件\n             * @method trigger\n             * @grammar trigger( name[, args...] ) => self\n             * @param  {String}   type     事件名\n             * @param  {*} [...] 任意参数\n             * @return {Boolean} 如果handler中return false了，则返回false, 否则返回true\n             */\n            trigger: function( type ) {\n                var args, events, allEvents;\n\n                if ( !this._events || !type ) {\n                    return this;\n                }\n\n                args = slice.call( arguments, 1 );\n                events = findHandlers( this._events, type );\n                allEvents = findHandlers( this._events, 'all' );\n\n                return triggerHanders( events, args ) &&\n                        triggerHanders( allEvents, arguments );\n            }\n        };\n\n        /**\n         * 中介者，它本身是个单例，但可以通过[installTo](#WebUploader:Mediator:installTo)方法，使任何对象具备事件行为。\n         * 主要目的是负责模块与模块之间的合作，降低耦合度。\n         *\n         * @class Mediator\n         */\n        return $.extend({\n\n            /**\n             * 可以通过这个接口，使任何对象具备事件功能。\n             * @method installTo\n             * @param  {Object} obj 需要具备事件行为的对象。\n             * @return {Object} 返回obj.\n             */\n            installTo: function( obj ) {\n                return $.extend( obj, protos );\n            }\n\n        }, protos );\n    });\n    /**\n     * @fileOverview Uploader上传类\n     */\n    define('uploader',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$;\n\n        /**\n         * 上传入口类。\n         * @class Uploader\n         * @constructor\n         * @grammar new Uploader( opts ) => Uploader\n         * @example\n         * var uploader = WebUploader.Uploader({\n         *     swf: 'path_of_swf/Uploader.swf',\n         *\n         *     // 开起分片上传。\n         *     chunked: true\n         * });\n         */\n        function Uploader( opts ) {\n            this.options = $.extend( true, {}, Uploader.options, opts );\n            this._init( this.options );\n        }\n\n        // default Options\n        // widgets中有相应扩展\n        Uploader.options = {};\n        Mediator.installTo( Uploader.prototype );\n\n        // 批量添加纯命令式方法。\n        $.each({\n            upload: 'start-upload',\n            stop: 'stop-upload',\n            getFile: 'get-file',\n            getFiles: 'get-files',\n            addFile: 'add-file',\n            addFiles: 'add-file',\n            sort: 'sort-files',\n            removeFile: 'remove-file',\n            cancelFile: 'cancel-file',\n            skipFile: 'skip-file',\n            retry: 'retry',\n            isInProgress: 'is-in-progress',\n            makeThumb: 'make-thumb',\n            md5File: 'md5-file',\n            getDimension: 'get-dimension',\n            addButton: 'add-btn',\n            predictRuntimeType: 'predict-runtime-type',\n            refresh: 'refresh',\n            disable: 'disable',\n            enable: 'enable',\n            reset: 'reset'\n        }, function( fn, command ) {\n            Uploader.prototype[ fn ] = function() {\n                return this.request( command, arguments );\n            };\n        });\n\n        $.extend( Uploader.prototype, {\n            state: 'pending',\n\n            _init: function( opts ) {\n                var me = this;\n\n                me.request( 'init', opts, function() {\n                    me.state = 'ready';\n                    me.trigger('ready');\n                });\n            },\n\n            /**\n             * 获取或者设置Uploader配置项。\n             * @method option\n             * @grammar option( key ) => *\n             * @grammar option( key, val ) => self\n             * @example\n             *\n             * // 初始状态图片上传前不会压缩\n             * var uploader = new WebUploader.Uploader({\n             *     compress: null;\n             * });\n             *\n             * // 修改后图片上传前，尝试将图片压缩到1600 * 1600\n             * uploader.option( 'compress', {\n             *     width: 1600,\n             *     height: 1600\n             * });\n             */\n            option: function( key, val ) {\n                var opts = this.options;\n\n                // setter\n                if ( arguments.length > 1 ) {\n\n                    if ( $.isPlainObject( val ) &&\n                            $.isPlainObject( opts[ key ] ) ) {\n                        $.extend( opts[ key ], val );\n                    } else {\n                        opts[ key ] = val;\n                    }\n\n                } else {    // getter\n                    return key ? opts[ key ] : opts;\n                }\n            },\n\n            /**\n             * 获取文件统计信息。返回一个包含一下信息的对象。\n             * * `successNum` 上传成功的文件数\n             * * `progressNum` 上传中的文件数\n             * * `cancelNum` 被删除的文件数\n             * * `invalidNum` 无效的文件数\n             * * `uploadFailNum` 上传失败的文件数\n             * * `queueNum` 还在队列中的文件数\n             * * `interruptNum` 被暂停的文件数\n             * @method getStats\n             * @grammar getStats() => Object\n             */\n            getStats: function() {\n                // return this._mgr.getStats.apply( this._mgr, arguments );\n                var stats = this.request('get-stats');\n\n                return stats ? {\n                    successNum: stats.numOfSuccess,\n                    progressNum: stats.numOfProgress,\n\n                    // who care?\n                    // queueFailNum: 0,\n                    cancelNum: stats.numOfCancel,\n                    invalidNum: stats.numOfInvalid,\n                    uploadFailNum: stats.numOfUploadFailed,\n                    queueNum: stats.numOfQueue,\n                    interruptNum: stats.numofInterrupt\n                } : {};\n            },\n\n            // 需要重写此方法来来支持opts.onEvent和instance.onEvent的处理器\n            trigger: function( type/*, args...*/ ) {\n                var args = [].slice.call( arguments, 1 ),\n                    opts = this.options,\n                    name = 'on' + type.substring( 0, 1 ).toUpperCase() +\n                        type.substring( 1 );\n\n                if (\n                        // 调用通过on方法注册的handler.\n                        Mediator.trigger.apply( this, arguments ) === false ||\n\n                        // 调用opts.onEvent\n                        $.isFunction( opts[ name ] ) &&\n                        opts[ name ].apply( this, args ) === false ||\n\n                        // 调用this.onEvent\n                        $.isFunction( this[ name ] ) &&\n                        this[ name ].apply( this, args ) === false ||\n\n                        // 广播所有uploader的事件。\n                        Mediator.trigger.apply( Mediator,\n                        [ this, type ].concat( args ) ) === false ) {\n\n                    return false;\n                }\n\n                return true;\n            },\n\n            /**\n             * 销毁 webuploader 实例\n             * @method destroy\n             * @grammar destroy() => undefined\n             */\n            destroy: function() {\n                this.request( 'destroy', arguments );\n                this.off();\n            },\n\n            // widgets/widget.js将补充此方法的详细文档。\n            request: Base.noop\n        });\n\n        /**\n         * 创建Uploader实例，等同于new Uploader( opts );\n         * @method create\n         * @class Base\n         * @static\n         * @grammar Base.create( opts ) => Uploader\n         */\n        Base.create = Uploader.create = function( opts ) {\n            return new Uploader( opts );\n        };\n\n        // 暴露Uploader，可以通过它来扩展业务逻辑。\n        Base.Uploader = Uploader;\n\n        return Uploader;\n    });\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/runtime',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            factories = {},\n\n            // 获取对象的第一个key\n            getFirstKey = function( obj ) {\n                for ( var key in obj ) {\n                    if ( obj.hasOwnProperty( key ) ) {\n                        return key;\n                    }\n                }\n                return null;\n            };\n\n        // 接口类。\n        function Runtime( options ) {\n            this.options = $.extend({\n                container: document.body\n            }, options );\n            this.uid = Base.guid('rt_');\n        }\n\n        $.extend( Runtime.prototype, {\n\n            getContainer: function() {\n                var opts = this.options,\n                    parent, container;\n\n                if ( this._container ) {\n                    return this._container;\n                }\n\n                parent = $( opts.container || document.body );\n                container = $( document.createElement('div') );\n\n                container.attr( 'id', 'rt_' + this.uid );\n                container.css({\n                    position: 'absolute',\n                    top: '0px',\n                    left: '0px',\n                    width: '1px',\n                    height: '1px',\n                    overflow: 'hidden'\n                });\n\n                parent.append( container );\n                parent.addClass('webuploader-container');\n                this._container = container;\n                this._parent = parent;\n                return container;\n            },\n\n            init: Base.noop,\n            exec: Base.noop,\n\n            destroy: function() {\n                this._container && this._container.remove();\n                this._parent && this._parent.removeClass('webuploader-container');\n                this.off();\n            }\n        });\n\n        Runtime.orders = 'html5,flash';\n\n\n        /**\n         * 添加Runtime实现。\n         * @param {String} type    类型\n         * @param {Runtime} factory 具体Runtime实现。\n         */\n        Runtime.addRuntime = function( type, factory ) {\n            factories[ type ] = factory;\n        };\n\n        Runtime.hasRuntime = function( type ) {\n            return !!(type ? factories[ type ] : getFirstKey( factories ));\n        };\n\n        Runtime.create = function( opts, orders ) {\n            var type, runtime;\n\n            orders = orders || Runtime.orders;\n            $.each( orders.split( /\\s*,\\s*/g ), function() {\n                if ( factories[ this ] ) {\n                    type = this;\n                    return false;\n                }\n            });\n\n            type = type || getFirstKey( factories );\n\n            if ( !type ) {\n                throw new Error('Runtime Error');\n            }\n\n            runtime = new factories[ type ]( opts );\n            return runtime;\n        };\n\n        Mediator.installTo( Runtime.prototype );\n        return Runtime;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/client',[\n        'base',\n        'mediator',\n        'runtime/runtime'\n    ], function( Base, Mediator, Runtime ) {\n\n        var cache;\n\n        cache = (function() {\n            var obj = {};\n\n            return {\n                add: function( runtime ) {\n                    obj[ runtime.uid ] = runtime;\n                },\n\n                get: function( ruid, standalone ) {\n                    var i;\n\n                    if ( ruid ) {\n                        return obj[ ruid ];\n                    }\n\n                    for ( i in obj ) {\n                        // 有些类型不能重用，比如filepicker.\n                        if ( standalone && obj[ i ].__standalone ) {\n                            continue;\n                        }\n\n                        return obj[ i ];\n                    }\n\n                    return null;\n                },\n\n                remove: function( runtime ) {\n                    delete obj[ runtime.uid ];\n                }\n            };\n        })();\n\n        function RuntimeClient( component, standalone ) {\n            var deferred = Base.Deferred(),\n                runtime;\n\n            this.uid = Base.guid('client_');\n\n            // 允许runtime没有初始化之前，注册一些方法在初始化后执行。\n            this.runtimeReady = function( cb ) {\n                return deferred.done( cb );\n            };\n\n            this.connectRuntime = function( opts, cb ) {\n\n                // already connected.\n                if ( runtime ) {\n                    throw new Error('already connected!');\n                }\n\n                deferred.done( cb );\n\n                if ( typeof opts === 'string' && cache.get( opts ) ) {\n                    runtime = cache.get( opts );\n                }\n\n                // 像filePicker只能独立存在，不能公用。\n                runtime = runtime || cache.get( null, standalone );\n\n                // 需要创建\n                if ( !runtime ) {\n                    runtime = Runtime.create( opts, opts.runtimeOrder );\n                    runtime.__promise = deferred.promise();\n                    runtime.once( 'ready', deferred.resolve );\n                    runtime.init();\n                    cache.add( runtime );\n                    runtime.__client = 1;\n                } else {\n                    // 来自cache\n                    Base.$.extend( runtime.options, opts );\n                    runtime.__promise.then( deferred.resolve );\n                    runtime.__client++;\n                }\n\n                standalone && (runtime.__standalone = standalone);\n                return runtime;\n            };\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.disconnectRuntime = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                runtime.__client--;\n\n                if ( runtime.__client <= 0 ) {\n                    cache.remove( runtime );\n                    delete runtime.__promise;\n                    runtime.destroy();\n                }\n\n                runtime = null;\n            };\n\n            this.exec = function() {\n                if ( !runtime ) {\n                    return;\n                }\n\n                var args = Base.slice( arguments );\n                component && args.unshift( component );\n\n                return runtime.exec.apply( this, args );\n            };\n\n            this.getRuid = function() {\n                return runtime && runtime.uid;\n            };\n\n            this.destroy = (function( destroy ) {\n                return function() {\n                    destroy && destroy.apply( this, arguments );\n                    this.trigger('destroy');\n                    this.off();\n                    this.exec('destroy');\n                    this.disconnectRuntime();\n                };\n            })( this.destroy );\n        }\n\n        Mediator.installTo( RuntimeClient.prototype );\n        return RuntimeClient;\n    });\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/dnd',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function DragAndDrop( opts ) {\n            opts = this.options = $.extend({}, DragAndDrop.options, opts );\n\n            opts.container = $( opts.container );\n\n            if ( !opts.container.length ) {\n                return;\n            }\n\n            RuntimeClent.call( this, 'DragAndDrop' );\n        }\n\n        DragAndDrop.options = {\n            accept: null,\n            disableGlobalDnd: false\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: DragAndDrop,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( DragAndDrop.prototype );\n\n        return DragAndDrop;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/widget',[\n        'base',\n        'uploader'\n    ], function( Base, Uploader ) {\n\n        var $ = Base.$,\n            _init = Uploader.prototype._init,\n            _destroy = Uploader.prototype.destroy,\n            IGNORE = {},\n            widgetClass = [];\n\n        function isArrayLike( obj ) {\n            if ( !obj ) {\n                return false;\n            }\n\n            var length = obj.length,\n                type = $.type( obj );\n\n            if ( obj.nodeType === 1 && length ) {\n                return true;\n            }\n\n            return type === 'array' || type !== 'function' && type !== 'string' &&\n                    (length === 0 || typeof length === 'number' && length > 0 &&\n                    (length - 1) in obj);\n        }\n\n        function Widget( uploader ) {\n            this.owner = uploader;\n            this.options = uploader.options;\n        }\n\n        $.extend( Widget.prototype, {\n\n            init: Base.noop,\n\n            // 类Backbone的事件监听声明，监听uploader实例上的事件\n            // widget直接无法监听事件，事件只能通过uploader来传递\n            invoke: function( apiName, args ) {\n\n                /*\n                    {\n                        'make-thumb': 'makeThumb'\n                    }\n                 */\n                var map = this.responseMap;\n\n                // 如果无API响应声明则忽略\n                if ( !map || !(apiName in map) || !(map[ apiName ] in this) ||\n                        !$.isFunction( this[ map[ apiName ] ] ) ) {\n\n                    return IGNORE;\n                }\n\n                return this[ map[ apiName ] ].apply( this, args );\n\n            },\n\n            /**\n             * 发送命令。当传入`callback`或者`handler`中返回`promise`时。返回一个当所有`handler`中的promise都完成后完成的新`promise`。\n             * @method request\n             * @grammar request( command, args ) => * | Promise\n             * @grammar request( command, args, callback ) => Promise\n             * @for  Uploader\n             */\n            request: function() {\n                return this.owner.request.apply( this.owner, arguments );\n            }\n        });\n\n        // 扩展Uploader.\n        $.extend( Uploader.prototype, {\n\n            /**\n             * @property {String | Array} [disableWidgets=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 默认所有 Uploader.register 了的 widget 都会被加载，如果禁用某一部分，请通过此 option 指定黑名单。\n             */\n\n            // 覆写_init用来初始化widgets\n            _init: function() {\n                var me = this,\n                    widgets = me._widgets = [],\n                    deactives = me.options.disableWidgets || '';\n\n                $.each( widgetClass, function( _, klass ) {\n                    (!deactives || !~deactives.indexOf( klass._name )) &&\n                        widgets.push( new klass( me ) );\n                });\n\n                return _init.apply( me, arguments );\n            },\n\n            request: function( apiName, args, callback ) {\n                var i = 0,\n                    widgets = this._widgets,\n                    len = widgets && widgets.length,\n                    rlts = [],\n                    dfds = [],\n                    widget, rlt, promise, key;\n\n                args = isArrayLike( args ) ? args : [ args ];\n\n                for ( ; i < len; i++ ) {\n                    widget = widgets[ i ];\n                    rlt = widget.invoke( apiName, args );\n\n                    if ( rlt !== IGNORE ) {\n\n                        // Deferred对象\n                        if ( Base.isPromise( rlt ) ) {\n                            dfds.push( rlt );\n                        } else {\n                            rlts.push( rlt );\n                        }\n                    }\n                }\n\n                // 如果有callback，则用异步方式。\n                if ( callback || dfds.length ) {\n                    promise = Base.when.apply( Base, dfds );\n                    key = promise.pipe ? 'pipe' : 'then';\n\n                    // 很重要不能删除。删除了会死循环。\n                    // 保证执行顺序。让callback总是在下一个 tick 中执行。\n                    return promise[ key ](function() {\n                                var deferred = Base.Deferred(),\n                                    args = arguments;\n\n                                if ( args.length === 1 ) {\n                                    args = args[ 0 ];\n                                }\n\n                                setTimeout(function() {\n                                    deferred.resolve( args );\n                                }, 1 );\n\n                                return deferred.promise();\n                            })[ callback ? key : 'done' ]( callback || Base.noop );\n                } else {\n                    return rlts[ 0 ];\n                }\n            },\n\n            destroy: function() {\n                _destroy.apply( this, arguments );\n                this._widgets = null;\n            }\n        });\n\n        /**\n         * 添加组件\n         * @grammar Uploader.register(proto);\n         * @grammar Uploader.register(map, proto);\n         * @param  {object} responseMap API 名称与函数实现的映射\n         * @param  {object} proto 组件原型，构造函数通过 constructor 属性定义\n         * @method Uploader.register\n         * @for Uploader\n         * @example\n         * Uploader.register({\n         *     'make-thumb': 'makeThumb'\n         * }, {\n         *     init: function( options ) {},\n         *     makeThumb: function() {}\n         * });\n         *\n         * Uploader.register({\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         */\n        Uploader.register = Widget.register = function( responseMap, widgetProto ) {\n            var map = { init: 'init', destroy: 'destroy', name: 'anonymous' },\n                klass;\n\n            if ( arguments.length === 1 ) {\n                widgetProto = responseMap;\n\n                // 自动生成 map 表。\n                $.each(widgetProto, function(key) {\n                    if ( key[0] === '_' || key === 'name' ) {\n                        key === 'name' && (map.name = widgetProto.name);\n                        return;\n                    }\n\n                    map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;\n                });\n\n            } else {\n                map = $.extend( map, responseMap );\n            }\n\n            widgetProto.responseMap = map;\n            klass = Base.inherits( Widget, widgetProto );\n            klass._name = map.name;\n            widgetClass.push( klass );\n\n            return klass;\n        };\n\n        /**\n         * 删除插件，只有在注册时指定了名字的才能被删除。\n         * @grammar Uploader.unRegister(name);\n         * @param  {string} name 组件名字\n         * @method Uploader.unRegister\n         * @for Uploader\n         * @example\n         *\n         * Uploader.register({\n         *     name: 'custom',\n         *\n         *     'make-thumb': function() {\n         *\n         *     }\n         * });\n         *\n         * Uploader.unRegister('custom');\n         */\n        Uploader.unRegister = Widget.unRegister = function( name ) {\n            if ( !name || name === 'anonymous' ) {\n                return;\n            }\n\n            // 删除指定的插件。\n            for ( var i = widgetClass.length; i--; ) {\n                if ( widgetClass[i]._name === name ) {\n                    widgetClass.splice(i, 1)\n                }\n            }\n        };\n\n        return Widget;\n    });\n    /**\n     * @fileOverview DragAndDrop Widget。\n     */\n    define('widgets/filednd',[\n        'base',\n        'uploader',\n        'lib/dnd',\n        'widgets/widget'\n    ], function( Base, Uploader, Dnd ) {\n        var $ = Base.$;\n\n        Uploader.options.dnd = '';\n\n        /**\n         * @property {Selector} [dnd=undefined]  指定Drag And Drop拖拽的容器，如果不指定，则不启动。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @property {Selector} [disableGlobalDnd=false]  是否禁掉整个页面的拖拽功能，如果不禁用，图片拖进来的时候会默认被浏览器打开。\n         * @namespace options\n         * @for Uploader\n         */\n\n        /**\n         * @event dndAccept\n         * @param {DataTransferItemList} items DataTransferItem\n         * @description 阻止此事件可以拒绝某些类型的文件拖入进来。目前只有 chrome 提供这样的 API，且只能通过 mime-type 验证。\n         * @for  Uploader\n         */\n        return Uploader.register({\n            name: 'dnd',\n\n            init: function( opts ) {\n\n                if ( !opts.dnd ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        disableGlobalDnd: opts.disableGlobalDnd,\n                        container: opts.dnd,\n                        accept: opts.accept\n                    }),\n                    dnd;\n\n                this.dnd = dnd = new Dnd( options );\n\n                dnd.once( 'ready', deferred.resolve );\n                dnd.on( 'drop', function( files ) {\n                    me.request( 'add-file', [ files ]);\n                });\n\n                // 检测文件是否全部允许添加。\n                dnd.on( 'accept', function( items ) {\n                    return me.owner.trigger( 'dndAccept', items );\n                });\n\n                dnd.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.dnd && this.dnd.destroy();\n            }\n        });\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepaste',[\n        'base',\n        'mediator',\n        'runtime/client'\n    ], function( Base, Mediator, RuntimeClent ) {\n\n        var $ = Base.$;\n\n        function FilePaste( opts ) {\n            opts = this.options = $.extend({}, opts );\n            opts.container = $( opts.container || document.body );\n            RuntimeClent.call( this, 'FilePaste' );\n        }\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePaste,\n\n            init: function() {\n                var me = this;\n\n                me.connectRuntime( me.options, function() {\n                    me.exec('init');\n                    me.trigger('ready');\n                });\n            }\n        });\n\n        Mediator.installTo( FilePaste.prototype );\n\n        return FilePaste;\n    });\n    /**\n     * @fileOverview 组件基类。\n     */\n    define('widgets/filepaste',[\n        'base',\n        'uploader',\n        'lib/filepaste',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePaste ) {\n        var $ = Base.$;\n\n        /**\n         * @property {Selector} [paste=undefined]  指定监听paste事件的容器，如果不指定，不启用此功能。此功能为通过粘贴来添加截屏的图片。建议设置为`document.body`.\n         * @namespace options\n         * @for Uploader\n         */\n        return Uploader.register({\n            name: 'paste',\n\n            init: function( opts ) {\n\n                if ( !opts.paste ||\n                        this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                var me = this,\n                    deferred = Base.Deferred(),\n                    options = $.extend({}, {\n                        container: opts.paste,\n                        accept: opts.accept\n                    }),\n                    paste;\n\n                this.paste = paste = new FilePaste( options );\n\n                paste.once( 'ready', deferred.resolve );\n                paste.on( 'paste', function( files ) {\n                    me.owner.request( 'add-file', [ files ]);\n                });\n                paste.init();\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                this.paste && this.paste.destroy();\n            }\n        });\n    });\n    /**\n     * @fileOverview Blob\n     */\n    define('lib/blob',[\n        'base',\n        'runtime/client'\n    ], function( Base, RuntimeClient ) {\n\n        function Blob( ruid, source ) {\n            var me = this;\n\n            me.source = source;\n            me.ruid = ruid;\n            this.size = source.size || 0;\n\n            // 如果没有指定 mimetype, 但是知道文件后缀。\n            if ( !source.type && this.ext &&\n                    ~'jpg,jpeg,png,gif,bmp'.indexOf( this.ext ) ) {\n                this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);\n            } else {\n                this.type = source.type || 'application/octet-stream';\n            }\n\n            RuntimeClient.call( me, 'Blob' );\n            this.uid = source.uid || this.uid;\n\n            if ( ruid ) {\n                me.connectRuntime( ruid );\n            }\n        }\n\n        Base.inherits( RuntimeClient, {\n            constructor: Blob,\n\n            slice: function( start, end ) {\n                return this.exec( 'slice', start, end );\n            },\n\n            getSource: function() {\n                return this.source;\n            }\n        });\n\n        return Blob;\n    });\n    /**\n     * 为了统一化Flash的File和HTML5的File而存在。\n     * 以至于要调用Flash里面的File，也可以像调用HTML5版本的File一下。\n     * @fileOverview File\n     */\n    define('lib/file',[\n        'base',\n        'lib/blob'\n    ], function( Base, Blob ) {\n\n        var uid = 1,\n            rExt = /\\.([^.]+)$/;\n\n        function File( ruid, file ) {\n            var ext;\n\n            this.name = file.name || ('untitled' + uid++);\n            ext = rExt.exec( file.name ) ? RegExp.$1.toLowerCase() : '';\n\n            // todo 支持其他类型文件的转换。\n            // 如果有 mimetype, 但是文件名里面没有找出后缀规律\n            if ( !ext && file.type ) {\n                ext = /\\/(jpg|jpeg|png|gif|bmp)$/i.exec( file.type ) ?\n                        RegExp.$1.toLowerCase() : '';\n                this.name += '.' + ext;\n            }\n\n            this.ext = ext;\n            this.lastModifiedDate = file.lastModifiedDate ||\n                    (new Date()).toLocaleString();\n\n            Blob.apply( this, arguments );\n        }\n\n        return Base.inherits( Blob, File );\n    });\n\n    /**\n     * @fileOverview 错误信息\n     */\n    define('lib/filepicker',[\n        'base',\n        'runtime/client',\n        'lib/file'\n    ], function( Base, RuntimeClent, File ) {\n\n        var $ = Base.$;\n\n        function FilePicker( opts ) {\n            opts = this.options = $.extend({}, FilePicker.options, opts );\n\n            opts.container = $( opts.id );\n\n            if ( !opts.container.length ) {\n                throw new Error('按钮指定错误');\n            }\n\n            opts.innerHTML = opts.innerHTML || opts.label ||\n                    opts.container.html() || '';\n\n            opts.button = $( opts.button || document.createElement('div') );\n            opts.button.html( opts.innerHTML );\n            opts.container.html( opts.button );\n\n            RuntimeClent.call( this, 'FilePicker', true );\n        }\n\n        FilePicker.options = {\n            button: null,\n            container: null,\n            label: null,\n            innerHTML: null,\n            multiple: true,\n            accept: null,\n            name: 'file'\n        };\n\n        Base.inherits( RuntimeClent, {\n            constructor: FilePicker,\n\n            init: function() {\n                var me = this,\n                    opts = me.options,\n                    button = opts.button;\n\n                button.addClass('webuploader-pick');\n\n                me.on( 'all', function( type ) {\n                    var files;\n\n                    switch ( type ) {\n                        case 'mouseenter':\n                            button.addClass('webuploader-pick-hover');\n                            break;\n\n                        case 'mouseleave':\n                            button.removeClass('webuploader-pick-hover');\n                            break;\n\n                        case 'change':\n                            files = me.exec('getFiles');\n                            me.trigger( 'select', $.map( files, function( file ) {\n                                file = new File( me.getRuid(), file );\n\n                                // 记录来源。\n                                file._refer = opts.container;\n                                return file;\n                            }), opts.container );\n                            break;\n                    }\n                });\n\n                me.connectRuntime( opts, function() {\n                    me.refresh();\n                    me.exec( 'init', opts );\n                    me.trigger('ready');\n                });\n\n                this._resizeHandler = Base.bindFn( this.refresh, this );\n                $( window ).on( 'resize', this._resizeHandler );\n            },\n\n            refresh: function() {\n                var shimContainer = this.getRuntime().getContainer(),\n                    button = this.options.button,\n                    width = button.outerWidth ?\n                            button.outerWidth() : button.width(),\n\n                    height = button.outerHeight ?\n                            button.outerHeight() : button.height(),\n\n                    pos = button.offset();\n\n                width && height && shimContainer.css({\n                    bottom: 'auto',\n                    right: 'auto',\n                    width: width + 'px',\n                    height: height + 'px'\n                }).offset( pos );\n            },\n\n            enable: function() {\n                var btn = this.options.button;\n\n                btn.removeClass('webuploader-pick-disable');\n                this.refresh();\n            },\n\n            disable: function() {\n                var btn = this.options.button;\n\n                this.getRuntime().getContainer().css({\n                    top: '-99999px'\n                });\n\n                btn.addClass('webuploader-pick-disable');\n            },\n\n            destroy: function() {\n                var btn = this.options.button;\n                $( window ).off( 'resize', this._resizeHandler );\n                btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +\n                    'webuploader-pick');\n            }\n        });\n\n        return FilePicker;\n    });\n\n    /**\n     * @fileOverview 文件选择相关\n     */\n    define('widgets/filepicker',[\n        'base',\n        'uploader',\n        'lib/filepicker',\n        'widgets/widget'\n    ], function( Base, Uploader, FilePicker ) {\n        var $ = Base.$;\n\n        $.extend( Uploader.options, {\n\n            /**\n             * @property {Selector | Object} [pick=undefined]\n             * @namespace options\n             * @for Uploader\n             * @description 指定选择文件的按钮容器，不指定则不创建按钮。\n             *\n             * * `id` {Seletor} 指定选择文件的按钮容器，不指定则不创建按钮。\n             * * `label` {String} 请采用 `innerHTML` 代替\n             * * `innerHTML` {String} 指定按钮文字。不指定时优先从指定的容器中看是否自带文字。\n             * * `multiple` {Boolean} 是否开起同时选择多个文件能力。\n             */\n            pick: null,\n\n            /**\n             * @property {Arroy} [accept=null]\n             * @namespace options\n             * @for Uploader\n             * @description 指定接受哪些类型的文件。 由于目前还有ext转mimeType表，所以这里需要分开指定。\n             *\n             * * `title` {String} 文字描述\n             * * `extensions` {String} 允许的文件后缀，不带点，多个用逗号分割。\n             * * `mimeTypes` {String} 多个用逗号分割。\n             *\n             * 如：\n             *\n             * ```\n             * {\n             *     title: 'Images',\n             *     extensions: 'gif,jpg,jpeg,bmp,png',\n             *     mimeTypes: 'image/*'\n             * }\n             * ```\n             */\n            accept: null/*{\n                title: 'Images',\n                extensions: 'gif,jpg,jpeg,bmp,png',\n                mimeTypes: 'image/*'\n            }*/\n        });\n\n        return Uploader.register({\n            name: 'picker',\n\n            init: function( opts ) {\n                this.pickers = [];\n                return opts.pick && this.addBtn( opts.pick );\n            },\n\n            refresh: function() {\n                $.each( this.pickers, function() {\n                    this.refresh();\n                });\n            },\n\n            /**\n             * @method addButton\n             * @for Uploader\n             * @grammar addButton( pick ) => Promise\n             * @description\n             * 添加文件选择按钮，如果一个按钮不够，需要调用此方法来添加。参数跟[options.pick](#WebUploader:Uploader:options)一致。\n             * @example\n             * uploader.addButton({\n             *     id: '#btnContainer',\n             *     innerHTML: '选择文件'\n             * });\n             */\n            addBtn: function( pick ) {\n                var me = this,\n                    opts = me.options,\n                    accept = opts.accept,\n                    promises = [];\n\n                if ( !pick ) {\n                    return;\n                }\n\n                $.isPlainObject( pick ) || (pick = {\n                    id: pick\n                });\n\n                $( pick.id ).each(function() {\n                    var options, picker, deferred;\n\n                    deferred = Base.Deferred();\n\n                    options = $.extend({}, pick, {\n                        accept: $.isPlainObject( accept ) ? [ accept ] : accept,\n                        swf: opts.swf,\n                        runtimeOrder: opts.runtimeOrder,\n                        id: this\n                    });\n\n                    picker = new FilePicker( options );\n\n                    picker.once( 'ready', deferred.resolve );\n                    picker.on( 'select', function( files ) {\n                        me.owner.request( 'add-file', [ files ]);\n                    });\n                    picker.init();\n\n                    me.pickers.push( picker );\n\n                    promises.push( deferred.promise() );\n                });\n\n                return Base.when.apply( Base, promises );\n            },\n\n            disable: function() {\n                $.each( this.pickers, function() {\n                    this.disable();\n                });\n            },\n\n            enable: function() {\n                $.each( this.pickers, function() {\n                    this.enable();\n                });\n            },\n\n            destroy: function() {\n                $.each( this.pickers, function() {\n                    this.destroy();\n                });\n                this.pickers = null;\n            }\n        });\n    });\n    /**\n     * @fileOverview 文件属性封装\n     */\n    define('file',[\n        'base',\n        'mediator'\n    ], function( Base, Mediator ) {\n\n        var $ = Base.$,\n            idPrefix = 'WU_FILE_',\n            idSuffix = 0,\n            rExt = /\\.([^.]+)$/,\n            statusMap = {};\n\n        function gid() {\n            return idPrefix + idSuffix++;\n        }\n\n        /**\n         * 文件类\n         * @class File\n         * @constructor 构造函数\n         * @grammar new File( source ) => File\n         * @param {Lib.File} source [lib.File](#Lib.File)实例, 此source对象是带有Runtime信息的。\n         */\n        function WUFile( source ) {\n\n            /**\n             * 文件名，包括扩展名（后缀）\n             * @property name\n             * @type {string}\n             */\n            this.name = source.name || 'Untitled';\n\n            /**\n             * 文件体积（字节）\n             * @property size\n             * @type {uint}\n             * @default 0\n             */\n            this.size = source.size || 0;\n\n            /**\n             * 文件MIMETYPE类型，与文件类型的对应关系请参考[http://t.cn/z8ZnFny](http://t.cn/z8ZnFny)\n             * @property type\n             * @type {string}\n             * @default 'application/octet-stream'\n             */\n            this.type = source.type || 'application/octet-stream';\n\n            /**\n             * 文件最后修改日期\n             * @property lastModifiedDate\n             * @type {int}\n             * @default 当前时间戳\n             */\n            this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);\n\n            /**\n             * 文件ID，每个对象具有唯一ID，与文件名无关\n             * @property id\n             * @type {string}\n             */\n            this.id = gid();\n\n            /**\n             * 文件扩展名，通过文件名获取，例如test.png的扩展名为png\n             * @property ext\n             * @type {string}\n             */\n            this.ext = rExt.exec( this.name ) ? RegExp.$1 : '';\n\n\n            /**\n             * 状态文字说明。在不同的status语境下有不同的用途。\n             * @property statusText\n             * @type {string}\n             */\n            this.statusText = '';\n\n            // 存储文件状态，防止通过属性直接修改\n            statusMap[ this.id ] = WUFile.Status.INITED;\n\n            this.source = source;\n            this.loaded = 0;\n\n            this.on( 'error', function( msg ) {\n                this.setStatus( WUFile.Status.ERROR, msg );\n            });\n        }\n\n        $.extend( WUFile.prototype, {\n\n            /**\n             * 设置状态，状态变化时会触发`change`事件。\n             * @method setStatus\n             * @grammar setStatus( status[, statusText] );\n             * @param {File.Status|String} status [文件状态值](#WebUploader:File:File.Status)\n             * @param {String} [statusText=''] 状态说明，常在error时使用，用http, abort,server等来标记是由于什么原因导致文件错误。\n             */\n            setStatus: function( status, text ) {\n\n                var prevStatus = statusMap[ this.id ];\n\n                typeof text !== 'undefined' && (this.statusText = text);\n\n                if ( status !== prevStatus ) {\n                    statusMap[ this.id ] = status;\n                    /**\n                     * 文件状态变化\n                     * @event statuschange\n                     */\n                    this.trigger( 'statuschange', status, prevStatus );\n                }\n\n            },\n\n            /**\n             * 获取文件状态\n             * @return {File.Status}\n             * @example\n                     文件状态具体包括以下几种类型：\n                     {\n                         // 初始化\n                        INITED:     0,\n                        // 已入队列\n                        QUEUED:     1,\n                        // 正在上传\n                        PROGRESS:     2,\n                        // 上传出错\n                        ERROR:         3,\n                        // 上传成功\n                        COMPLETE:     4,\n                        // 上传取消\n                        CANCELLED:     5\n                    }\n             */\n            getStatus: function() {\n                return statusMap[ this.id ];\n            },\n\n            /**\n             * 获取文件原始信息。\n             * @return {*}\n             */\n            getSource: function() {\n                return this.source;\n            },\n\n            destroy: function() {\n                this.off();\n                delete statusMap[ this.id ];\n            }\n        });\n\n        Mediator.installTo( WUFile.prototype );\n\n        /**\n         * 文件状态值，具体包括以下几种类型：\n         * * `inited` 初始状态\n         * * `queued` 已经进入队列, 等待上传\n         * * `progress` 上传中\n         * * `complete` 上传完成。\n         * * `error` 上传出错，可重试\n         * * `interrupt` 上传中断，可续传。\n         * * `invalid` 文件不合格，不能重试上传。会自动从队列中移除。\n         * * `cancelled` 文件被移除。\n         * @property {Object} Status\n         * @namespace File\n         * @class File\n         * @static\n         */\n        WUFile.Status = {\n            INITED:     'inited',    // 初始状态\n            QUEUED:     'queued',    // 已经进入队列, 等待上传\n            PROGRESS:   'progress',    // 上传中\n            ERROR:      'error',    // 上传出错，可重试\n            COMPLETE:   'complete',    // 上传完成。\n            CANCELLED:  'cancelled',    // 上传取消。\n            INTERRUPT:  'interrupt',    // 上传中断，可续传。\n            INVALID:    'invalid'    // 文件不合格，不能重试上传。\n        };\n\n        return WUFile;\n    });\n\n    /**\n     * @fileOverview 文件队列\n     */\n    define('queue',[\n        'base',\n        'mediator',\n        'file'\n    ], function( Base, Mediator, WUFile ) {\n\n        var $ = Base.$,\n            STATUS = WUFile.Status;\n\n        /**\n         * 文件队列, 用来存储各个状态中的文件。\n         * @class Queue\n         * @extends Mediator\n         */\n        function Queue() {\n\n            /**\n             * 统计文件数。\n             * * `numOfQueue` 队列中的文件数。\n             * * `numOfSuccess` 上传成功的文件数\n             * * `numOfCancel` 被取消的文件数\n             * * `numOfProgress` 正在上传中的文件数\n             * * `numOfUploadFailed` 上传错误的文件数。\n             * * `numOfInvalid` 无效的文件数。\n             * * `numofDeleted` 被移除的文件数。\n             * @property {Object} stats\n             */\n            this.stats = {\n                numOfQueue: 0,\n                numOfSuccess: 0,\n                numOfCancel: 0,\n                numOfProgress: 0,\n                numOfUploadFailed: 0,\n                numOfInvalid: 0,\n                numofDeleted: 0,\n                numofInterrupt: 0,\n            };\n\n            // 上传队列，仅包括等待上传的文件\n            this._queue = [];\n\n            // 存储所有文件\n            this._map = {};\n        }\n\n        $.extend( Queue.prototype, {\n\n            /**\n             * 将新文件加入对队列尾部\n             *\n             * @method append\n             * @param  {File} file   文件对象\n             */\n            append: function( file ) {\n                this._queue.push( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 将新文件加入对队列头部\n             *\n             * @method prepend\n             * @param  {File} file   文件对象\n             */\n            prepend: function( file ) {\n                this._queue.unshift( file );\n                this._fileAdded( file );\n                return this;\n            },\n\n            /**\n             * 获取文件对象\n             *\n             * @method getFile\n             * @param  {String} fileId   文件ID\n             * @return {File}\n             */\n            getFile: function( fileId ) {\n                if ( typeof fileId !== 'string' ) {\n                    return fileId;\n                }\n                return this._map[ fileId ];\n            },\n\n            /**\n             * 从队列中取出一个指定状态的文件。\n             * @grammar fetch( status ) => File\n             * @method fetch\n             * @param {String} status [文件状态值](#WebUploader:File:File.Status)\n             * @return {File} [File](#WebUploader:File)\n             */\n            fetch: function( status ) {\n                var len = this._queue.length,\n                    i, file;\n\n                status = status || STATUS.QUEUED;\n\n                for ( i = 0; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( status === file.getStatus() ) {\n                        return file;\n                    }\n                }\n\n                return null;\n            },\n\n            /**\n             * 对队列进行排序，能够控制文件上传顺序。\n             * @grammar sort( fn ) => undefined\n             * @method sort\n             * @param {Function} fn 排序方法\n             */\n            sort: function( fn ) {\n                if ( typeof fn === 'function' ) {\n                    this._queue.sort( fn );\n                }\n            },\n\n            /**\n             * 获取指定类型的文件列表, 列表中每一个成员为[File](#WebUploader:File)对象。\n             * @grammar getFiles( [status1[, status2 ...]] ) => Array\n             * @method getFiles\n             * @param {String} [status] [文件状态值](#WebUploader:File:File.Status)\n             */\n            getFiles: function() {\n                var sts = [].slice.call( arguments, 0 ),\n                    ret = [],\n                    i = 0,\n                    len = this._queue.length,\n                    file;\n\n                for ( ; i < len; i++ ) {\n                    file = this._queue[ i ];\n\n                    if ( sts.length && !~$.inArray( file.getStatus(), sts ) ) {\n                        continue;\n                    }\n\n                    ret.push( file );\n                }\n\n                return ret;\n            },\n\n            /**\n             * 在队列中删除文件。\n             * @grammar removeFile( file ) => Array\n             * @method removeFile\n             * @param {File} 文件对象。\n             */\n            removeFile: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( existing ) {\n                    delete this._map[ file.id ];\n                    file.destroy();\n                    this.stats.numofDeleted++;\n                }\n            },\n\n            _fileAdded: function( file ) {\n                var me = this,\n                    existing = this._map[ file.id ];\n\n                if ( !existing ) {\n                    this._map[ file.id ] = file;\n\n                    file.on( 'statuschange', function( cur, pre ) {\n                        me._onFileStatusChange( cur, pre );\n                    });\n                }\n            },\n\n            _onFileStatusChange: function( curStatus, preStatus ) {\n                var stats = this.stats;\n\n                switch ( preStatus ) {\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress--;\n                        break;\n\n                    case STATUS.QUEUED:\n                        stats.numOfQueue --;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed--;\n                        break;\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid--;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt--;\n                        break;\n                }\n\n                switch ( curStatus ) {\n                    case STATUS.QUEUED:\n                        stats.numOfQueue++;\n                        break;\n\n                    case STATUS.PROGRESS:\n                        stats.numOfProgress++;\n                        break;\n\n                    case STATUS.ERROR:\n                        stats.numOfUploadFailed++;\n                        break;\n\n                    case STATUS.COMPLETE:\n                        stats.numOfSuccess++;\n                        break;\n\n                    case STATUS.CANCELLED:\n                        stats.numOfCancel++;\n                        break;\n\n\n                    case STATUS.INVALID:\n                        stats.numOfInvalid++;\n                        break;\n\n                    case STATUS.INTERRUPT:\n                        stats.numofInterrupt++;\n                        break;\n                }\n            }\n\n        });\n\n        Mediator.installTo( Queue.prototype );\n\n        return Queue;\n    });\n    /**\n     * @fileOverview 队列\n     */\n    define('widgets/queue',[\n        'base',\n        'uploader',\n        'queue',\n        'file',\n        'lib/file',\n        'runtime/client',\n        'widgets/widget'\n    ], function( Base, Uploader, Queue, WUFile, File, RuntimeClient ) {\n\n        var $ = Base.$,\n            rExt = /\\.\\w+$/,\n            Status = WUFile.Status;\n\n        return Uploader.register({\n            name: 'queue',\n\n            init: function( opts ) {\n                var me = this,\n                    deferred, len, i, item, arr, accept, runtime;\n\n                if ( $.isPlainObject( opts.accept ) ) {\n                    opts.accept = [ opts.accept ];\n                }\n\n                // accept中的中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].extensions;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = '\\\\.' + arr.join(',')\n                                .replace( /,/g, '$|\\\\.' )\n                                .replace( /\\*/g, '.*' ) + '$';\n                    }\n\n                    me.accept = new RegExp( accept, 'i' );\n                }\n\n                me.queue = new Queue();\n                me.stats = me.queue.stats;\n\n                // 如果当前不是html5运行时，那就算了。\n                // 不执行后续操作\n                if ( this.request('predict-runtime-type') !== 'html5' ) {\n                    return;\n                }\n\n                // 创建一个 html5 运行时的 placeholder\n                // 以至于外部添加原生 File 对象的时候能正确包裹一下供 webuploader 使用。\n                deferred = Base.Deferred();\n                this.placeholder = runtime = new RuntimeClient('Placeholder');\n                runtime.connectRuntime({\n                    runtimeOrder: 'html5'\n                }, function() {\n                    me._ruid = runtime.getRuid();\n                    deferred.resolve();\n                });\n                return deferred.promise();\n            },\n\n\n            // 为了支持外部直接添加一个原生File对象。\n            _wrapFile: function( file ) {\n                if ( !(file instanceof WUFile) ) {\n\n                    if ( !(file instanceof File) ) {\n                        if ( !this._ruid ) {\n                            throw new Error('Can\\'t add external files.');\n                        }\n                        file = new File( this._ruid, file );\n                    }\n\n                    file = new WUFile( file );\n                }\n\n                return file;\n            },\n\n            // 判断文件是否可以被加入队列\n            acceptFile: function( file ) {\n                var invalid = !file || !file.size || this.accept &&\n\n                        // 如果名字中有后缀，才做后缀白名单处理。\n                        rExt.exec( file.name ) && !this.accept.test( file.name );\n\n                return !invalid;\n            },\n\n\n            /**\n             * @event beforeFileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列之前触发，此事件的handler返回值为`false`，则此文件不会被添加进入队列。\n             * @for  Uploader\n             */\n\n            /**\n             * @event fileQueued\n             * @param {File} file File对象\n             * @description 当文件被加入队列以后触发。\n             * @for  Uploader\n             */\n\n            _addFile: function( file ) {\n                var me = this;\n\n                file = me._wrapFile( file );\n\n                // 不过类型判断允许不允许，先派送 `beforeFileQueued`\n                if ( !me.owner.trigger( 'beforeFileQueued', file ) ) {\n                    return;\n                }\n\n                // 类型不匹配，则派送错误事件，并返回。\n                if ( !me.acceptFile( file ) ) {\n                    me.owner.trigger( 'error', 'Q_TYPE_DENIED', file );\n                    return;\n                }\n\n                me.queue.append( file );\n                me.owner.trigger( 'fileQueued', file );\n                return file;\n            },\n\n            getFile: function( fileId ) {\n                return this.queue.getFile( fileId );\n            },\n\n            /**\n             * @event filesQueued\n             * @param {File} files 数组，内容为原始File(lib/File）对象。\n             * @description 当一批文件添加进队列以后触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @property {Boolean} [auto=false]\n             * @namespace options\n             * @for Uploader\n             * @description 设置为 true 后，不需要手动调用上传，有文件选择即开始上传。\n             *\n             */\n\n            /**\n             * @method addFiles\n             * @grammar addFiles( file ) => undefined\n             * @grammar addFiles( [file1, file2 ...] ) => undefined\n             * @param {Array of File or File} [files] Files 对象 数组\n             * @description 添加文件到队列\n             * @for  Uploader\n             */\n            addFile: function( files ) {\n                var me = this;\n\n                if ( !files.length ) {\n                    files = [ files ];\n                }\n\n                files = $.map( files, function( file ) {\n                    return me._addFile( file );\n                });\n\n                me.owner.trigger( 'filesQueued', files );\n\n                if ( me.options.auto ) {\n                    setTimeout(function() {\n                        me.request('start-upload');\n                    }, 20 );\n                }\n            },\n\n            getStats: function() {\n                return this.stats;\n            },\n\n            /**\n             * @event fileDequeued\n             * @param {File} file File对象\n             * @description 当文件被移除队列后触发。\n             * @for  Uploader\n             */\n\n             /**\n             * @method removeFile\n             * @grammar removeFile( file ) => undefined\n             * @grammar removeFile( id ) => undefined\n             * @grammar removeFile( file, true ) => undefined\n             * @grammar removeFile( id, true ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 移除某一文件, 默认只会标记文件状态为已取消，如果第二个参数为 `true` 则会从 queue 中移除。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.removeFile( file );\n             * })\n             */\n            removeFile: function( file, remove ) {\n                var me = this;\n\n                file = file.id ? file : me.queue.getFile( file );\n\n                this.request( 'cancel-file', file );\n\n                if ( remove ) {\n                    this.queue.removeFile( file );\n                }\n            },\n\n            /**\n             * @method getFiles\n             * @grammar getFiles() => Array\n             * @grammar getFiles( status1, status2, status... ) => Array\n             * @description 返回指定状态的文件集合，不传参数将返回所有状态的文件。\n             * @for  Uploader\n             * @example\n             * console.log( uploader.getFiles() );    // => all files\n             * console.log( uploader.getFiles('error') )    // => all error files.\n             */\n            getFiles: function() {\n                return this.queue.getFiles.apply( this.queue, arguments );\n            },\n\n            fetchFile: function() {\n                return this.queue.fetch.apply( this.queue, arguments );\n            },\n\n            /**\n             * @method retry\n             * @grammar retry() => undefined\n             * @grammar retry( file ) => undefined\n             * @description 重试上传，重试指定文件，或者从出错的文件开始重新上传。\n             * @for  Uploader\n             * @example\n             * function retry() {\n             *     uploader.retry();\n             * }\n             */\n            retry: function( file, noForceStart ) {\n                var me = this,\n                    files, i, len;\n\n                if ( file ) {\n                    file = file.id ? file : me.queue.getFile( file );\n                    file.setStatus( Status.QUEUED );\n                    noForceStart || me.request('start-upload');\n                    return;\n                }\n\n                files = me.queue.getFiles( Status.ERROR );\n                i = 0;\n                len = files.length;\n\n                for ( ; i < len; i++ ) {\n                    file = files[ i ];\n                    file.setStatus( Status.QUEUED );\n                }\n\n                me.request('start-upload');\n            },\n\n            /**\n             * @method sort\n             * @grammar sort( fn ) => undefined\n             * @description 排序队列中的文件，在上传之前调整可以控制上传顺序。\n             * @for  Uploader\n             */\n            sortFiles: function() {\n                return this.queue.sort.apply( this.queue, arguments );\n            },\n\n            /**\n             * @event reset\n             * @description 当 uploader 被重置的时候触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @method reset\n             * @grammar reset() => undefined\n             * @description 重置uploader。目前只重置了队列。\n             * @for  Uploader\n             * @example\n             * uploader.reset();\n             */\n            reset: function() {\n                this.owner.trigger('reset');\n                this.queue = new Queue();\n                this.stats = this.queue.stats;\n            },\n\n            destroy: function() {\n                this.reset();\n                this.placeholder && this.placeholder.destroy();\n            }\n        });\n\n    });\n    /**\n     * @fileOverview 添加获取Runtime相关信息的方法。\n     */\n    define('widgets/runtime',[\n        'uploader',\n        'runtime/runtime',\n        'widgets/widget'\n    ], function( Uploader, Runtime ) {\n\n        Uploader.support = function() {\n            return Runtime.hasRuntime.apply( Runtime, arguments );\n        };\n\n        return Uploader.register({\n            name: 'runtime',\n\n            init: function() {\n                if ( !this.predictRuntimeType() ) {\n                    throw Error('Runtime Error');\n                }\n            },\n\n            /**\n             * 预测Uploader将采用哪个`Runtime`\n             * @grammar predictRuntimeType() => String\n             * @method predictRuntimeType\n             * @for  Uploader\n             */\n            predictRuntimeType: function() {\n                var orders = this.options.runtimeOrder || Runtime.orders,\n                    type = this.type,\n                    i, len;\n\n                if ( !type ) {\n                    orders = orders.split( /\\s*,\\s*/g );\n\n                    for ( i = 0, len = orders.length; i < len; i++ ) {\n                        if ( Runtime.hasRuntime( orders[ i ] ) ) {\n                            this.type = type = orders[ i ];\n                            break;\n                        }\n                    }\n                }\n\n                return type;\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     */\n    define('lib/transport',[\n        'base',\n        'runtime/client',\n        'mediator'\n    ], function( Base, RuntimeClient, Mediator ) {\n\n        var $ = Base.$;\n\n        function Transport( opts ) {\n            var me = this;\n\n            opts = me.options = $.extend( true, {}, Transport.options, opts || {} );\n            RuntimeClient.call( this, 'Transport' );\n\n            this._blob = null;\n            this._formData = opts.formData || {};\n            this._headers = opts.headers || {};\n\n            this.on( 'progress', this._timeout );\n            this.on( 'load error', function() {\n                me.trigger( 'progress', 1 );\n                clearTimeout( me._timer );\n            });\n        }\n\n        Transport.options = {\n            server: '',\n            method: 'POST',\n\n            // 跨域时，是否允许携带cookie, 只有html5 runtime才有效\n            withCredentials: false,\n            fileVal: 'file',\n            timeout: 2 * 60 * 1000,    // 2分钟\n            formData: {},\n            headers: {},\n            sendAsBinary: false\n        };\n\n        $.extend( Transport.prototype, {\n\n            // 添加Blob, 只能添加一次，最后一次有效。\n            appendBlob: function( key, blob, filename ) {\n                var me = this,\n                    opts = me.options;\n\n                if ( me.getRuid() ) {\n                    me.disconnectRuntime();\n                }\n\n                // 连接到blob归属的同一个runtime.\n                me.connectRuntime( blob.ruid, function() {\n                    me.exec('init');\n                });\n\n                me._blob = blob;\n                opts.fileVal = key || opts.fileVal;\n                opts.filename = filename || opts.filename;\n            },\n\n            // 添加其他字段\n            append: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._formData, key );\n                } else {\n                    this._formData[ key ] = value;\n                }\n            },\n\n            setRequestHeader: function( key, value ) {\n                if ( typeof key === 'object' ) {\n                    $.extend( this._headers, key );\n                } else {\n                    this._headers[ key ] = value;\n                }\n            },\n\n            send: function( method ) {\n                this.exec( 'send', method );\n                this._timeout();\n            },\n\n            abort: function() {\n                clearTimeout( this._timer );\n                return this.exec('abort');\n            },\n\n            destroy: function() {\n                this.trigger('destroy');\n                this.off();\n                this.exec('destroy');\n                this.disconnectRuntime();\n            },\n\n            getResponse: function() {\n                return this.exec('getResponse');\n            },\n\n            getResponseAsJson: function() {\n                return this.exec('getResponseAsJson');\n            },\n\n            getStatus: function() {\n                return this.exec('getStatus');\n            },\n\n            _timeout: function() {\n                var me = this,\n                    duration = me.options.timeout;\n\n                if ( !duration ) {\n                    return;\n                }\n\n                clearTimeout( me._timer );\n                me._timer = setTimeout(function() {\n                    me.abort();\n                    me.trigger( 'error', 'timeout' );\n                }, duration );\n            }\n\n        });\n\n        // 让Transport具备事件功能。\n        Mediator.installTo( Transport.prototype );\n\n        return Transport;\n    });\n    /**\n     * @fileOverview 负责文件上传相关。\n     */\n    define('widgets/upload',[\n        'base',\n        'uploader',\n        'file',\n        'lib/transport',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile, Transport ) {\n\n        var $ = Base.$,\n            isPromise = Base.isPromise,\n            Status = WUFile.Status;\n\n        // 添加默认配置项\n        $.extend( Uploader.options, {\n\n\n            /**\n             * @property {Boolean} [prepareNextFile=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否允许在文件传输时提前把下一个文件准备好。\n             * 对于一个文件的准备工作比较耗时，比如图片压缩，md5序列化。\n             * 如果能提前在当前文件传输期处理，可以节省总体耗时。\n             */\n            prepareNextFile: false,\n\n            /**\n             * @property {Boolean} [chunked=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否要分片处理大文件上传。\n             */\n            chunked: false,\n\n            /**\n             * @property {Boolean} [chunkSize=5242880]\n             * @namespace options\n             * @for Uploader\n             * @description 如果要分片，分多大一片？ 默认大小为5M.\n             */\n            chunkSize: 5 * 1024 * 1024,\n\n            /**\n             * @property {Boolean} [chunkRetry=2]\n             * @namespace options\n             * @for Uploader\n             * @description 如果某个分片由于网络问题出错，允许自动重传多少次？\n             */\n            chunkRetry: 2,\n\n            /**\n             * @property {Boolean} [threads=3]\n             * @namespace options\n             * @for Uploader\n             * @description 上传并发数。允许同时最大上传进程数。\n             */\n            threads: 3,\n\n\n            /**\n             * @property {Object} [formData={}]\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传请求的参数表，每次发送都会发送此对象中的参数。\n             */\n            formData: {}\n\n            /**\n             * @property {Object} [fileVal='file']\n             * @namespace options\n             * @for Uploader\n             * @description 设置文件上传域的name。\n             */\n\n            /**\n             * @property {Object} [method='POST']\n             * @namespace options\n             * @for Uploader\n             * @description 文件上传方式，`POST`或者`GET`。\n             */\n\n            /**\n             * @property {Object} [sendAsBinary=false]\n             * @namespace options\n             * @for Uploader\n             * @description 是否已二进制的流的方式发送文件，这样整个上传内容`php://input`都为文件内容，\n             * 其他参数在$_GET数组中。\n             */\n        });\n\n        // 负责将文件切片。\n        function CuteFile( file, chunkSize ) {\n            var pending = [],\n                blob = file.source,\n                total = blob.size,\n                chunks = chunkSize ? Math.ceil( total / chunkSize ) : 1,\n                start = 0,\n                index = 0,\n                len, api;\n\n            api = {\n                file: file,\n\n                has: function() {\n                    return !!pending.length;\n                },\n\n                shift: function() {\n                    return pending.shift();\n                },\n\n                unshift: function( block ) {\n                    pending.unshift( block );\n                }\n            };\n\n            while ( index < chunks ) {\n                len = Math.min( chunkSize, total - start );\n\n                pending.push({\n                    file: file,\n                    start: start,\n                    end: chunkSize ? (start + len) : total,\n                    total: total,\n                    chunks: chunks,\n                    chunk: index++,\n                    cuted: api\n                });\n                start += len;\n            }\n\n            file.blocks = pending.concat();\n            file.remaning = pending.length;\n\n            return api;\n        }\n\n        Uploader.register({\n            name: 'upload',\n\n            init: function() {\n                var owner = this.owner,\n                    me = this;\n\n                this.runing = false;\n                this.progress = false;\n\n                owner\n                    .on( 'startUpload', function() {\n                        me.progress = true;\n                    })\n                    .on( 'uploadFinished', function() {\n                        me.progress = false;\n                    });\n\n                // 记录当前正在传的数据，跟threads相关\n                this.pool = [];\n\n                // 缓存分好片的文件。\n                this.stack = [];\n\n                // 缓存即将上传的文件。\n                this.pending = [];\n\n                // 跟踪还有多少分片在上传中但是没有完成上传。\n                this.remaning = 0;\n                this.__tick = Base.bindFn( this._tick, this );\n\n                owner.on( 'uploadComplete', function( file ) {\n\n                    // 把其他块取消了。\n                    file.blocks && $.each( file.blocks, function( _, v ) {\n                        v.transport && (v.transport.abort(), v.transport.destroy());\n                        delete v.transport;\n                    });\n\n                    delete file.blocks;\n                    delete file.remaning;\n                });\n            },\n\n            reset: function() {\n                this.request( 'stop-upload', true );\n                this.runing = false;\n                this.pool = [];\n                this.stack = [];\n                this.pending = [];\n                this.remaning = 0;\n                this._trigged = false;\n                this._promise = null;\n            },\n\n            /**\n             * @event startUpload\n             * @description 当开始上传流程时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 开始上传。此方法可以从初始状态调用开始上传流程，也可以从暂停状态调用，继续上传流程。\n             *\n             * 可以指定开始某一个文件。\n             * @grammar upload() => undefined\n             * @grammar upload( file | fileId) => undefined\n             * @method upload\n             * @for  Uploader\n             */\n            startUpload: function(file) {\n                var me = this;\n\n                // 移出invalid的文件\n                $.each( me.request( 'get-files', Status.INVALID ), function() {\n                    me.request( 'remove-file', this );\n                });\n\n                // 如果指定了开始某个文件，则只开始指定文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        $.each( me.pool, function( _, v ) {\n\n                            // 之前暂停过。\n                            if (v.file !== file) {\n                                return;\n                            }\n\n                            v.transport && v.transport.send();\n                        });\n\n                        file.setStatus( Status.QUEUED );\n                    } else if (file.getStatus() === Status.PROGRESS) {\n                        return;\n                    } else {\n                        file.setStatus( Status.QUEUED );\n                    }\n                } else {\n                    $.each( me.request( 'get-files', [ Status.INITED ] ), function() {\n                        this.setStatus( Status.QUEUED );\n                    });\n                }\n\n                if ( me.runing ) {\n                    return;\n                }\n\n                me.runing = true;\n\n                // 如果有暂停的，则续传\n                $.each( me.pool, function( _, v ) {\n                    var file = v.file;\n\n                    if ( file.getStatus() === Status.INTERRUPT ) {\n                        file.setStatus( Status.PROGRESS );\n                        me._trigged = false;\n                        v.transport && v.transport.send();\n                    }\n                });\n\n                file || $.each( me.request( 'get-files',\n                        Status.INTERRUPT ), function() {\n                    this.setStatus( Status.PROGRESS );\n                });\n\n                me._trigged = false;\n                Base.nextTick( me.__tick );\n                me.owner.trigger('startUpload');\n            },\n\n            /**\n             * @event stopUpload\n             * @description 当开始上传流程暂停时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * 暂停上传。第一个参数为是否中断上传当前正在上传的文件。\n             *\n             * 如果第一个参数是文件，则只暂停指定文件。\n             * @grammar stop() => undefined\n             * @grammar stop( true ) => undefined\n             * @grammar stop( file ) => undefined\n             * @method stop\n             * @for  Uploader\n             */\n            stopUpload: function( file, interrupt ) {\n                var me = this;\n\n                if (file === true) {\n                    interrupt = file;\n                    file = null;\n                }\n\n                if ( me.runing === false ) {\n                    return;\n                }\n\n                // 如果只是暂停某个文件。\n                if ( file ) {\n                    file = file.id ? file : me.request( 'get-file', file );\n\n                    if ( file.getStatus() !== Status.PROGRESS &&\n                            file.getStatus() !== Status.QUEUED ) {\n                        return;\n                    }\n\n                    file.setStatus( Status.INTERRUPT );\n                    $.each( me.pool, function( _, v ) {\n\n                        // 只 abort 指定的文件。\n                        if (v.file !== file) {\n                            return;\n                        }\n\n                        v.transport && v.transport.abort();\n                        me._putback(v);\n                        me._popBlock(v);\n                    });\n\n                    return Base.nextTick( me.__tick );\n                }\n\n                me.runing = false;\n\n                if (this._promise && this._promise.file) {\n                    this._promise.file.setStatus( Status.INTERRUPT );\n                }\n\n                interrupt && $.each( me.pool, function( _, v ) {\n                    v.transport && v.transport.abort();\n                    v.file.setStatus( Status.INTERRUPT );\n                });\n\n                me.owner.trigger('stopUpload');\n            },\n\n            /**\n             * @method cancelFile\n             * @grammar cancelFile( file ) => undefined\n             * @grammar cancelFile( id ) => undefined\n             * @param {File|id} file File对象或这File对象的id\n             * @description 标记文件状态为已取消, 同时将中断文件传输。\n             * @for  Uploader\n             * @example\n             *\n             * $li.on('click', '.remove-this', function() {\n             *     uploader.cancelFile( file );\n             * })\n             */\n            cancelFile: function( file ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                file.setStatus( Status.CANCELLED );\n                this.owner.trigger( 'fileDequeued', file );\n            },\n\n            /**\n             * 判断`Uplaode`r是否正在上传中。\n             * @grammar isInProgress() => Boolean\n             * @method isInProgress\n             * @for  Uploader\n             */\n            isInProgress: function() {\n                return !!this.progress;\n            },\n\n            _getStats: function() {\n                return this.request('get-stats');\n            },\n\n            /**\n             * 掉过一个文件上传，直接标记指定文件为已上传状态。\n             * @grammar skipFile( file ) => undefined\n             * @method skipFile\n             * @for  Uploader\n             */\n            skipFile: function( file, status ) {\n                file = file.id ? file : this.request( 'get-file', file );\n\n                file.setStatus( status || Status.COMPLETE );\n                file.skipped = true;\n\n                // 如果正在上传。\n                file.blocks && $.each( file.blocks, function( _, v ) {\n                    var _tr = v.transport;\n\n                    if ( _tr ) {\n                        _tr.abort();\n                        _tr.destroy();\n                        delete v.transport;\n                    }\n                });\n\n                this.owner.trigger( 'uploadSkip', file );\n            },\n\n            /**\n             * @event uploadFinished\n             * @description 当所有文件上传结束时触发。\n             * @for  Uploader\n             */\n            _tick: function() {\n                var me = this,\n                    opts = me.options,\n                    fn, val;\n\n                // 上一个promise还没有结束，则等待完成后再执行。\n                if ( me._promise ) {\n                    return me._promise.always( me.__tick );\n                }\n\n                // 还有位置，且还有文件要处理的话。\n                if ( me.pool.length < opts.threads && (val = me._nextBlock()) ) {\n                    me._trigged = false;\n\n                    fn = function( val ) {\n                        me._promise = null;\n\n                        // 有可能是reject过来的，所以要检测val的类型。\n                        val && val.file && me._startSend( val );\n                        Base.nextTick( me.__tick );\n                    };\n\n                    me._promise = isPromise( val ) ? val.always( fn ) : fn( val );\n\n                // 没有要上传的了，且没有正在传输的了。\n                } else if ( !me.remaning && !me._getStats().numOfQueue &&\n                    !me._getStats().numofInterrupt ) {\n                    me.runing = false;\n\n                    me._trigged || Base.nextTick(function() {\n                        me.owner.trigger('uploadFinished');\n                    });\n                    me._trigged = true;\n                }\n            },\n\n            _putback: function(block) {\n                var idx;\n\n                block.cuted.unshift(block);\n                idx = this.stack.indexOf(block.cuted);\n\n                if (!~idx) {\n                    this.stack.unshift(block.cuted);\n                }\n            },\n\n            _getStack: function() {\n                var i = 0,\n                    act;\n\n                while ( (act = this.stack[ i++ ]) ) {\n                    if ( act.has() && act.file.getStatus() === Status.PROGRESS ) {\n                        return act;\n                    } else if (!act.has() ||\n                            act.file.getStatus() !== Status.PROGRESS &&\n                            act.file.getStatus() !== Status.INTERRUPT ) {\n\n                        // 把已经处理完了的，或者，状态为非 progress（上传中）、\n                        // interupt（暂停中） 的移除。\n                        this.stack.splice( --i, 1 );\n                    }\n                }\n\n                return null;\n            },\n\n            _nextBlock: function() {\n                var me = this,\n                    opts = me.options,\n                    act, next, done, preparing;\n\n                // 如果当前文件还有没有需要传输的，则直接返回剩下的。\n                if ( (act = this._getStack()) ) {\n\n                    // 是否提前准备下一个文件\n                    if ( opts.prepareNextFile && !me.pending.length ) {\n                        me._prepareNextFile();\n                    }\n\n                    return act.shift();\n\n                // 否则，如果正在运行，则准备下一个文件，并等待完成后返回下个分片。\n                } else if ( me.runing ) {\n\n                    // 如果缓存中有，则直接在缓存中取，没有则去queue中取。\n                    if ( !me.pending.length && me._getStats().numOfQueue ) {\n                        me._prepareNextFile();\n                    }\n\n                    next = me.pending.shift();\n                    done = function( file ) {\n                        if ( !file ) {\n                            return null;\n                        }\n\n                        act = CuteFile( file, opts.chunked ? opts.chunkSize : 0 );\n                        me.stack.push(act);\n                        return act.shift();\n                    };\n\n                    // 文件可能还在prepare中，也有可能已经完全准备好了。\n                    if ( isPromise( next) ) {\n                        preparing = next.file;\n                        next = next[ next.pipe ? 'pipe' : 'then' ]( done );\n                        next.file = preparing;\n                        return next;\n                    }\n\n                    return done( next );\n                }\n            },\n\n\n            /**\n             * @event uploadStart\n             * @param {File} file File对象\n             * @description 某个文件开始上传前触发，一个文件只会触发一次。\n             * @for  Uploader\n             */\n            _prepareNextFile: function() {\n                var me = this,\n                    file = me.request('fetch-file'),\n                    pending = me.pending,\n                    promise;\n\n                if ( file ) {\n                    promise = me.request( 'before-send-file', file, function() {\n\n                        // 有可能文件被skip掉了。文件被skip掉后，状态坑定不是Queued.\n                        if ( file.getStatus() === Status.PROGRESS ||\n                            file.getStatus() === Status.INTERRUPT ) {\n                            return file;\n                        }\n\n                        return me._finishFile( file );\n                    });\n\n                    me.owner.trigger( 'uploadStart', file );\n                    file.setStatus( Status.PROGRESS );\n\n                    promise.file = file;\n\n                    // 如果还在pending中，则替换成文件本身。\n                    promise.done(function() {\n                        var idx = $.inArray( promise, pending );\n\n                        ~idx && pending.splice( idx, 1, file );\n                    });\n\n                    // befeore-send-file的钩子就有错误发生。\n                    promise.fail(function( reason ) {\n                        file.setStatus( Status.ERROR, reason );\n                        me.owner.trigger( 'uploadError', file, reason );\n                        me.owner.trigger( 'uploadComplete', file );\n                    });\n\n                    pending.push( promise );\n                }\n            },\n\n            // 让出位置了，可以让其他分片开始上传\n            _popBlock: function( block ) {\n                var idx = $.inArray( block, this.pool );\n\n                this.pool.splice( idx, 1 );\n                block.file.remaning--;\n                this.remaning--;\n            },\n\n            // 开始上传，可以被掉过。如果promise被reject了，则表示跳过此分片。\n            _startSend: function( block ) {\n                var me = this,\n                    file = block.file,\n                    promise;\n\n                // 有可能在 before-send-file 的 promise 期间改变了文件状态。\n                // 如：暂停，取消\n                // 我们不能中断 promise, 但是可以在 promise 完后，不做上传操作。\n                if ( file.getStatus() !== Status.PROGRESS ) {\n\n                    // 如果是中断，则还需要放回去。\n                    if (file.getStatus() === Status.INTERRUPT) {\n                        me._putback(block);\n                    }\n\n                    return;\n                }\n\n                me.pool.push( block );\n                me.remaning++;\n\n                // 如果没有分片，则直接使用原始的。\n                // 不会丢失content-type信息。\n                block.blob = block.chunks === 1 ? file.source :\n                        file.source.slice( block.start, block.end );\n\n                // hook, 每个分片发送之前可能要做些异步的事情。\n                promise = me.request( 'before-send', block, function() {\n\n                    // 有可能文件已经上传出错了，所以不需要再传输了。\n                    if ( file.getStatus() === Status.PROGRESS ) {\n                        me._doSend( block );\n                    } else {\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n\n                // 如果为fail了，则跳过此分片。\n                promise.fail(function() {\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file ).always(function() {\n                            block.percentage = 1;\n                            me._popBlock( block );\n                            me.owner.trigger( 'uploadComplete', file );\n                            Base.nextTick( me.__tick );\n                        });\n                    } else {\n                        block.percentage = 1;\n                        me._popBlock( block );\n                        Base.nextTick( me.__tick );\n                    }\n                });\n            },\n\n\n            /**\n             * @event uploadBeforeSend\n             * @param {Object} object\n             * @param {Object} data 默认的上传参数，可以扩展此对象来控制上传参数。\n             * @param {Object} headers 可以扩展此对象来控制上传头部。\n             * @description 当某个文件的分块在发送前触发，主要用来询问是否要添加附带参数，大文件在开起分片上传的前提下此事件可能会触发多次。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadAccept\n             * @param {Object} object\n             * @param {Object} ret 服务端的返回数据，json格式，如果服务端不是json格式，从ret._raw中取数据，自行解析。\n             * @description 当某个文件上传到服务端响应后，会派送此事件来询问服务端响应是否有效。如果此事件handler返回值为`false`, 则此文件将派送`server`类型的`uploadError`事件。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadProgress\n             * @param {File} file File对象\n             * @param {Number} percentage 上传进度\n             * @description 上传过程中触发，携带上传进度。\n             * @for  Uploader\n             */\n\n\n            /**\n             * @event uploadError\n             * @param {File} file File对象\n             * @param {String} reason 出错的code\n             * @description 当文件上传出错时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadSuccess\n             * @param {File} file File对象\n             * @param {Object} response 服务端返回的数据\n             * @description 当文件上传成功时触发。\n             * @for  Uploader\n             */\n\n            /**\n             * @event uploadComplete\n             * @param {File} [file] File对象\n             * @description 不管成功或者失败，文件上传完成时触发。\n             * @for  Uploader\n             */\n\n            // 做上传操作。\n            _doSend: function( block ) {\n                var me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    file = block.file,\n                    tr = new Transport( opts ),\n                    data = $.extend({}, opts.formData ),\n                    headers = $.extend({}, opts.headers ),\n                    requestAccept, ret;\n\n                block.transport = tr;\n\n                tr.on( 'destroy', function() {\n                    delete block.transport;\n                    me._popBlock( block );\n                    Base.nextTick( me.__tick );\n                });\n\n                // 广播上传进度。以文件为单位。\n                tr.on( 'progress', function( percentage ) {\n                    var totalPercent = 0,\n                        uploaded = 0;\n\n                    // 可能没有abort掉，progress还是执行进来了。\n                    // if ( !file.blocks ) {\n                    //     return;\n                    // }\n\n                    totalPercent = block.percentage = percentage;\n\n                    if ( block.chunks > 1 ) {    // 计算文件的整体速度。\n                        $.each( file.blocks, function( _, v ) {\n                            uploaded += (v.percentage || 0) * (v.end - v.start);\n                        });\n\n                        totalPercent = uploaded / file.size;\n                    }\n\n                    owner.trigger( 'uploadProgress', file, totalPercent || 0 );\n                });\n\n                // 用来询问，是否返回的结果是有错误的。\n                requestAccept = function( reject ) {\n                    var fn;\n\n                    ret = tr.getResponseAsJson() || {};\n                    ret._raw = tr.getResponse();\n                    fn = function( value ) {\n                        reject = value;\n                    };\n\n                    // 服务端响应了，不代表成功了，询问是否响应正确。\n                    if ( !owner.trigger( 'uploadAccept', block, ret, fn ) ) {\n                        reject = reject || 'server';\n                    }\n\n                    return reject;\n                };\n\n                // 尝试重试，然后广播文件上传出错。\n                tr.on( 'error', function( type, flag ) {\n                    block.retried = block.retried || 0;\n\n                    // 自动重试\n                    if ( block.chunks > 1 && ~'http,abort'.indexOf( type ) &&\n                            block.retried < opts.chunkRetry ) {\n\n                        block.retried++;\n                        tr.send();\n\n                    } else {\n\n                        // http status 500 ~ 600\n                        if ( !flag && type === 'server' ) {\n                            type = requestAccept( type );\n                        }\n\n                        file.setStatus( Status.ERROR, type );\n                        owner.trigger( 'uploadError', file, type );\n                        owner.trigger( 'uploadComplete', file );\n                    }\n                });\n\n                // 上传成功\n                tr.on( 'load', function() {\n                    var reason;\n\n                    // 如果非预期，转向上传出错。\n                    if ( (reason = requestAccept()) ) {\n                        tr.trigger( 'error', reason, true );\n                        return;\n                    }\n\n                    // 全部上传完成。\n                    if ( file.remaning === 1 ) {\n                        me._finishFile( file, ret );\n                    } else {\n                        tr.destroy();\n                    }\n                });\n\n                // 配置默认的上传字段。\n                data = $.extend( data, {\n                    id: file.id,\n                    name: file.name,\n                    type: file.type,\n                    lastModifiedDate: file.lastModifiedDate,\n                    size: file.size\n                });\n\n                block.chunks > 1 && $.extend( data, {\n                    chunks: block.chunks,\n                    chunk: block.chunk\n                });\n\n                // 在发送之间可以添加字段什么的。。。\n                // 如果默认的字段不够使用，可以通过监听此事件来扩展\n                owner.trigger( 'uploadBeforeSend', block, data, headers );\n\n                // 开始发送。\n                tr.appendBlob( opts.fileVal, block.blob, file.name );\n                tr.append( data );\n                tr.setRequestHeader( headers );\n                tr.send();\n            },\n\n            // 完成上传。\n            _finishFile: function( file, ret, hds ) {\n                var owner = this.owner;\n\n                return owner\n                        .request( 'after-send-file', arguments, function() {\n                            file.setStatus( Status.COMPLETE );\n                            owner.trigger( 'uploadSuccess', file, ret, hds );\n                        })\n                        .fail(function( reason ) {\n\n                            // 如果外部已经标记为invalid什么的，不再改状态。\n                            if ( file.getStatus() === Status.PROGRESS ) {\n                                file.setStatus( Status.ERROR, reason );\n                            }\n\n                            owner.trigger( 'uploadError', file, reason );\n                        })\n                        .always(function() {\n                            owner.trigger( 'uploadComplete', file );\n                        });\n            }\n\n        });\n    });\n    /**\n     * @fileOverview 各种验证，包括文件总大小是否超出、单文件是否超出和文件是否重复。\n     */\n\n    define('widgets/validator',[\n        'base',\n        'uploader',\n        'file',\n        'widgets/widget'\n    ], function( Base, Uploader, WUFile ) {\n\n        var $ = Base.$,\n            validators = {},\n            api;\n\n        /**\n         * @event error\n         * @param {String} type 错误类型。\n         * @description 当validate不通过时，会以派送错误事件的形式通知调用者。通过`upload.on('error', handler)`可以捕获到此类错误，目前有以下错误会在特定的情况下派送错来。\n         *\n         * * `Q_EXCEED_NUM_LIMIT` 在设置了`fileNumLimit`且尝试给`uploader`添加的文件数量超出这个值时派送。\n         * * `Q_EXCEED_SIZE_LIMIT` 在设置了`Q_EXCEED_SIZE_LIMIT`且尝试给`uploader`添加的文件总大小超出这个值时派送。\n         * * `Q_TYPE_DENIED` 当文件类型不满足时触发。。\n         * @for  Uploader\n         */\n\n        // 暴露给外面的api\n        api = {\n\n            // 添加验证器\n            addValidator: function( type, cb ) {\n                validators[ type ] = cb;\n            },\n\n            // 移除验证器\n            removeValidator: function( type ) {\n                delete validators[ type ];\n            }\n        };\n\n        // 在Uploader初始化的时候启动Validators的初始化\n        Uploader.register({\n            name: 'validator',\n\n            init: function() {\n                var me = this;\n                Base.nextTick(function() {\n                    $.each( validators, function() {\n                        this.call( me.owner );\n                    });\n                });\n            }\n        });\n\n        /**\n         * @property {int} [fileNumLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总数量, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileNumLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileNumLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( count >= max && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_NUM_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return count >= max ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function() {\n                count++;\n            });\n\n            uploader.on( 'fileDequeued', function() {\n                count--;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n\n        /**\n         * @property {int} [fileSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证文件总大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                count = 0,\n                max = parseInt( opts.fileSizeLimit, 10 ),\n                flag = true;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var invalid = count + file.size > max;\n\n                if ( invalid && flag ) {\n                    flag = false;\n                    this.trigger( 'error', 'Q_EXCEED_SIZE_LIMIT', max, file );\n                    setTimeout(function() {\n                        flag = true;\n                    }, 1 );\n                }\n\n                return invalid ? false : true;\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                count += file.size;\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                count -= file.size;\n            });\n\n            uploader.on( 'reset', function() {\n                count = 0;\n            });\n        });\n\n        /**\n         * @property {int} [fileSingleSizeLimit=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 验证单个文件大小是否超出限制, 超出则不允许加入队列。\n         */\n        api.addValidator( 'fileSingleSizeLimit', function() {\n            var uploader = this,\n                opts = uploader.options,\n                max = opts.fileSingleSizeLimit;\n\n            if ( !max ) {\n                return;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n\n                if ( file.size > max ) {\n                    file.setStatus( WUFile.Status.INVALID, 'exceed_size' );\n                    this.trigger( 'error', 'F_EXCEED_SIZE', max, file );\n                    return false;\n                }\n\n            });\n\n        });\n\n        /**\n         * @property {Boolean} [duplicate=undefined]\n         * @namespace options\n         * @for Uploader\n         * @description 去重， 根据文件名字、文件大小和最后修改时间来生成hash Key.\n         */\n        api.addValidator( 'duplicate', function() {\n            var uploader = this,\n                opts = uploader.options,\n                mapping = {};\n\n            if ( opts.duplicate ) {\n                return;\n            }\n\n            function hashString( str ) {\n                var hash = 0,\n                    i = 0,\n                    len = str.length,\n                    _char;\n\n                for ( ; i < len; i++ ) {\n                    _char = str.charCodeAt( i );\n                    hash = _char + (hash << 6) + (hash << 16) - hash;\n                }\n\n                return hash;\n            }\n\n            uploader.on( 'beforeFileQueued', function( file ) {\n                var hash = file.__hash || (file.__hash = hashString( file.name +\n                        file.size + file.lastModifiedDate ));\n\n                // 已经重复了\n                if ( mapping[ hash ] ) {\n                    this.trigger( 'error', 'F_DUPLICATE', file );\n                    return false;\n                }\n            });\n\n            uploader.on( 'fileQueued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (mapping[ hash ] = true);\n            });\n\n            uploader.on( 'fileDequeued', function( file ) {\n                var hash = file.__hash;\n\n                hash && (delete mapping[ hash ]);\n            });\n\n            uploader.on( 'reset', function() {\n                mapping = {};\n            });\n        });\n\n        return api;\n    });\n\n    /**\n     * @fileOverview Runtime管理器，负责Runtime的选择, 连接\n     */\n    define('runtime/compbase',[],function() {\n\n        function CompBase( owner, runtime ) {\n\n            this.owner = owner;\n            this.options = owner.options;\n\n            this.getRuntime = function() {\n                return runtime;\n            };\n\n            this.getRuid = function() {\n                return runtime.uid;\n            };\n\n            this.trigger = function() {\n                return owner.trigger.apply( owner, arguments );\n            };\n        }\n\n        return CompBase;\n    });\n    /**\n     * @fileOverview Html5Runtime\n     */\n    define('runtime/html5/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var type = 'html5',\n            components = {};\n\n        function Html5Runtime() {\n            var pool = {},\n                me = this,\n                destroy = this.destroy;\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                if ( components[ comp ] ) {\n                    instance = pool[ uid ] = pool[ uid ] ||\n                            new components[ comp ]( client, me );\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n            };\n\n            me.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n        }\n\n        Base.inherits( Runtime, {\n            constructor: Html5Runtime,\n\n            // 不需要连接其他程序，直接执行callback\n            init: function() {\n                var me = this;\n                setTimeout(function() {\n                    me.trigger('ready');\n                }, 1 );\n            }\n\n        });\n\n        // 注册Components\n        Html5Runtime.register = function( name, component ) {\n            var klass = components[ name ] = Base.inherits( CompBase, component );\n            return klass;\n        };\n\n        // 注册html5运行时。\n        // 只有在支持的前提下注册。\n        if ( window.Blob && window.FileReader && window.DataView ) {\n            Runtime.addRuntime( type, Html5Runtime );\n        }\n\n        return Html5Runtime;\n    });\n    /**\n     * @fileOverview Blob Html实现\n     */\n    define('runtime/html5/blob',[\n        'runtime/html5/runtime',\n        'lib/blob'\n    ], function( Html5Runtime, Blob ) {\n\n        return Html5Runtime.register( 'Blob', {\n            slice: function( start, end ) {\n                var blob = this.owner.source,\n                    slice = blob.slice || blob.webkitSlice || blob.mozSlice;\n\n                blob = slice.call( blob, start, end );\n\n                return new Blob( this.getRuid(), blob );\n            }\n        });\n    });\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/dnd',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        var $ = Base.$,\n            prefix = 'webuploader-dnd-';\n\n        return Html5Runtime.register( 'DragAndDrop', {\n            init: function() {\n                var elem = this.elem = this.options.container;\n\n                this.dragEnterHandler = Base.bindFn( this._dragEnterHandler, this );\n                this.dragOverHandler = Base.bindFn( this._dragOverHandler, this );\n                this.dragLeaveHandler = Base.bindFn( this._dragLeaveHandler, this );\n                this.dropHandler = Base.bindFn( this._dropHandler, this );\n                this.dndOver = false;\n\n                elem.on( 'dragenter', this.dragEnterHandler );\n                elem.on( 'dragover', this.dragOverHandler );\n                elem.on( 'dragleave', this.dragLeaveHandler );\n                elem.on( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).on( 'dragover', this.dragOverHandler );\n                    $( document ).on( 'drop', this.dropHandler );\n                }\n            },\n\n            _dragEnterHandler: function( e ) {\n                var me = this,\n                    denied = me._denied || false,\n                    items;\n\n                e = e.originalEvent || e;\n\n                if ( !me.dndOver ) {\n                    me.dndOver = true;\n\n                    // 注意只有 chrome 支持。\n                    items = e.dataTransfer.items;\n\n                    if ( items && items.length ) {\n                        me._denied = denied = !me.trigger( 'accept', items );\n                    }\n\n                    me.elem.addClass( prefix + 'over' );\n                    me.elem[ denied ? 'addClass' :\n                            'removeClass' ]( prefix + 'denied' );\n                }\n\n                e.dataTransfer.dropEffect = denied ? 'none' : 'copy';\n\n                return false;\n            },\n\n            _dragOverHandler: function( e ) {\n                // 只处理框内的。\n                var parentElem = this.elem.parent().get( 0 );\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                clearTimeout( this._leaveTimer );\n                this._dragEnterHandler.call( this, e );\n\n                return false;\n            },\n\n            _dragLeaveHandler: function() {\n                var me = this,\n                    handler;\n\n                handler = function() {\n                    me.dndOver = false;\n                    me.elem.removeClass( prefix + 'over ' + prefix + 'denied' );\n                };\n\n                clearTimeout( me._leaveTimer );\n                me._leaveTimer = setTimeout( handler, 100 );\n                return false;\n            },\n\n            _dropHandler: function( e ) {\n                var me = this,\n                    ruid = me.getRuid(),\n                    parentElem = me.elem.parent().get( 0 ),\n                    dataTransfer, data;\n\n                // 只处理框内的。\n                if ( parentElem && !$.contains( parentElem, e.currentTarget ) ) {\n                    return false;\n                }\n\n                e = e.originalEvent || e;\n                dataTransfer = e.dataTransfer;\n\n                // 如果是页面内拖拽，还不能处理，不阻止事件。\n                // 此处 ie11 下会报参数错误，\n                try {\n                    data = dataTransfer.getData('text/html');\n                } catch( err ) {\n                }\n\n                if ( data ) {\n                    return;\n                }\n\n                me._getTansferFiles( dataTransfer, function( results ) {\n                    me.trigger( 'drop', $.map( results, function( file ) {\n                        return new File( ruid, file );\n                    }) );\n                });\n\n                me.dndOver = false;\n                me.elem.removeClass( prefix + 'over' );\n                return false;\n            },\n\n            // 如果传入 callback 则去查看文件夹，否则只管当前文件夹。\n            _getTansferFiles: function( dataTransfer, callback ) {\n                var results  = [],\n                    promises = [],\n                    items, files, file, item, i, len, canAccessFolder;\n\n                items = dataTransfer.items;\n                files = dataTransfer.files;\n\n                canAccessFolder = !!(items && items[ 0 ].webkitGetAsEntry);\n\n                for ( i = 0, len = files.length; i < len; i++ ) {\n                    file = files[ i ];\n                    item = items && items[ i ];\n\n                    if ( canAccessFolder && item.webkitGetAsEntry().isDirectory ) {\n\n                        promises.push( this._traverseDirectoryTree(\n                                item.webkitGetAsEntry(), results ) );\n                    } else {\n                        results.push( file );\n                    }\n                }\n\n                Base.when.apply( Base, promises ).done(function() {\n\n                    if ( !results.length ) {\n                        return;\n                    }\n\n                    callback( results );\n                });\n            },\n\n            _traverseDirectoryTree: function( entry, results ) {\n                var deferred = Base.Deferred(),\n                    me = this;\n\n                if ( entry.isFile ) {\n                    entry.file(function( file ) {\n                        results.push( file );\n                        deferred.resolve();\n                    });\n                } else if ( entry.isDirectory ) {\n                    entry.createReader().readEntries(function( entries ) {\n                        var len = entries.length,\n                            promises = [],\n                            arr = [],    // 为了保证顺序。\n                            i;\n\n                        for ( i = 0; i < len; i++ ) {\n                            promises.push( me._traverseDirectoryTree(\n                                    entries[ i ], arr ) );\n                        }\n\n                        Base.when.apply( Base, promises ).then(function() {\n                            results.push.apply( results, arr );\n                            deferred.resolve();\n                        }, deferred.reject );\n                    });\n                }\n\n                return deferred.promise();\n            },\n\n            destroy: function() {\n                var elem = this.elem;\n\n                // 还没 init 就调用 destroy\n                if (!elem) {\n                    return;\n                }\n\n                elem.off( 'dragenter', this.dragEnterHandler );\n                elem.off( 'dragover', this.dragOverHandler );\n                elem.off( 'dragleave', this.dragLeaveHandler );\n                elem.off( 'drop', this.dropHandler );\n\n                if ( this.options.disableGlobalDnd ) {\n                    $( document ).off( 'dragover', this.dragOverHandler );\n                    $( document ).off( 'drop', this.dropHandler );\n                }\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePaste\n     */\n    define('runtime/html5/filepaste',[\n        'base',\n        'runtime/html5/runtime',\n        'lib/file'\n    ], function( Base, Html5Runtime, File ) {\n\n        return Html5Runtime.register( 'FilePaste', {\n            init: function() {\n                var opts = this.options,\n                    elem = this.elem = opts.container,\n                    accept = '.*',\n                    arr, i, len, item;\n\n                // accetp的mimeTypes中生成匹配正则。\n                if ( opts.accept ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        item = opts.accept[ i ].mimeTypes;\n                        item && arr.push( item );\n                    }\n\n                    if ( arr.length ) {\n                        accept = arr.join(',');\n                        accept = accept.replace( /,/g, '|' ).replace( /\\*/g, '.*' );\n                    }\n                }\n                this.accept = accept = new RegExp( accept, 'i' );\n                this.hander = Base.bindFn( this._pasteHander, this );\n                elem.on( 'paste', this.hander );\n            },\n\n            _pasteHander: function( e ) {\n                var allowed = [],\n                    ruid = this.getRuid(),\n                    items, item, blob, i, len;\n\n                e = e.originalEvent || e;\n                items = e.clipboardData.items;\n\n                for ( i = 0, len = items.length; i < len; i++ ) {\n                    item = items[ i ];\n\n                    if ( item.kind !== 'file' || !(blob = item.getAsFile()) ) {\n                        continue;\n                    }\n\n                    allowed.push( new File( ruid, blob ) );\n                }\n\n                if ( allowed.length ) {\n                    // 不阻止非文件粘贴（文字粘贴）的事件冒泡\n                    e.preventDefault();\n                    e.stopPropagation();\n                    this.trigger( 'paste', allowed );\n                }\n            },\n\n            destroy: function() {\n                this.elem.off( 'paste', this.hander );\n            }\n        });\n    });\n\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/html5/filepicker',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var $ = Base.$;\n\n        return Html5Runtime.register( 'FilePicker', {\n            init: function() {\n                var container = this.getRuntime().getContainer(),\n                    me = this,\n                    owner = me.owner,\n                    opts = me.options,\n                    label = this.label = $( document.createElement('label') ),\n                    input =  this.input = $( document.createElement('input') ),\n                    arr, i, len, mouseHandler;\n\n                input.attr( 'type', 'file' );\n                input.attr( 'name', opts.name );\n                input.addClass('webuploader-element-invisible');\n\n                label.on( 'click', function() {\n                    input.trigger('click');\n                });\n\n                label.css({\n                    opacity: 0,\n                    width: '100%',\n                    height: '100%',\n                    display: 'block',\n                    cursor: 'pointer',\n                    background: '#ffffff'\n                });\n\n                if ( opts.multiple ) {\n                    input.attr( 'multiple', 'multiple' );\n                }\n\n                // @todo Firefox不支持单独指定后缀\n                if ( opts.accept && opts.accept.length > 0 ) {\n                    arr = [];\n\n                    for ( i = 0, len = opts.accept.length; i < len; i++ ) {\n                        arr.push( opts.accept[ i ].mimeTypes );\n                    }\n\n                    input.attr( 'accept', arr.join(',') );\n                }\n\n                container.append( input );\n                container.append( label );\n\n                mouseHandler = function( e ) {\n                    owner.trigger( e.type );\n                };\n\n                input.on( 'change', function( e ) {\n                    var fn = arguments.callee,\n                        clone;\n\n                    me.files = e.target.files;\n\n                    // reset input\n                    clone = this.cloneNode( true );\n                    clone.value = null;\n                    this.parentNode.replaceChild( clone, this );\n\n                    input.off();\n                    input = $( clone ).on( 'change', fn )\n                            .on( 'mouseenter mouseleave', mouseHandler );\n\n                    owner.trigger('change');\n                });\n\n                label.on( 'mouseenter mouseleave', mouseHandler );\n\n            },\n\n\n            getFiles: function() {\n                return this.files;\n            },\n\n            destroy: function() {\n                this.input.off();\n                this.label.off();\n            }\n        });\n    });\n    /**\n     * @fileOverview Transport\n     * @todo 支持chunked传输，优势：\n     * 可以将大文件分成小块，挨个传输，可以提高大文件成功率，当失败的时候，也只需要重传那小部分，\n     * 而不需要重头再传一次。另外断点续传也需要用chunked方式。\n     */\n    define('runtime/html5/transport',[\n        'base',\n        'runtime/html5/runtime'\n    ], function( Base, Html5Runtime ) {\n\n        var noop = Base.noop,\n            $ = Base.$;\n\n        return Html5Runtime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    formData, binary, fr;\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.getSource();\n                } else {\n                    formData = new FormData();\n                    $.each( owner._formData, function( k, v ) {\n                        formData.append( k, v );\n                    });\n\n                    formData.append( opts.fileVal, blob.getSource(),\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                if ( opts.withCredentials && 'withCredentials' in xhr ) {\n                    xhr.open( opts.method, server, true );\n                    xhr.withCredentials = true;\n                } else {\n                    xhr.open( opts.method, server );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n\n                if ( binary ) {\n                    // 强制设置成 content-type 为文件流。\n                    xhr.overrideMimeType &&\n                            xhr.overrideMimeType('application/octet-stream');\n\n                    // android直接发送blob会导致服务端接收到的是空文件。\n                    // bug详情。\n                    // https://code.google.com/p/android/issues/detail?id=39882\n                    // 所以先用fileReader读取出来再通过arraybuffer的方式发送。\n                    if ( Base.os.android ) {\n                        fr = new FileReader();\n\n                        fr.onload = function() {\n                            xhr.send( this.result );\n                            fr = fr.onload = null;\n                        };\n\n                        fr.readAsArrayBuffer( binary );\n                    } else {\n                        xhr.send( binary );\n                    }\n                } else {\n                    xhr.send( formData );\n                }\n            },\n\n            getResponse: function() {\n                return this._response;\n            },\n\n            getResponseAsJson: function() {\n                return this._parseJson( this._response );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    xhr.abort();\n\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new XMLHttpRequest(),\n                    opts = this.options;\n\n                if ( opts.withCredentials && !('withCredentials' in xhr) &&\n                        typeof XDomainRequest !== 'undefined' ) {\n                    xhr = new XDomainRequest();\n                }\n\n                xhr.upload.onprogress = function( e ) {\n                    var percentage = 0;\n\n                    if ( e.lengthComputable ) {\n                        percentage = e.loaded / e.total;\n                    }\n\n                    return me.trigger( 'progress', percentage );\n                };\n\n                xhr.onreadystatechange = function() {\n\n                    if ( xhr.readyState !== 4 ) {\n                        return;\n                    }\n\n                    xhr.upload.onprogress = noop;\n                    xhr.onreadystatechange = noop;\n                    me._xhr = null;\n                    me._status = xhr.status;\n\n                    if ( xhr.status >= 200 && xhr.status < 300 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger('load');\n                    } else if ( xhr.status >= 500 && xhr.status < 600 ) {\n                        me._response = xhr.responseText;\n                        return me.trigger( 'error', 'server' );\n                    }\n\n\n                    return me.trigger( 'error', me._status ? 'http' : 'abort' );\n                };\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.setRequestHeader( key, val );\n                });\n            },\n\n            _parseJson: function( str ) {\n                var json;\n\n                try {\n                    json = JSON.parse( str );\n                } catch ( ex ) {\n                    json = {};\n                }\n\n                return json;\n            }\n        });\n    });\n    /**\n     * @fileOverview FlashRuntime\n     */\n    define('runtime/flash/runtime',[\n        'base',\n        'runtime/runtime',\n        'runtime/compbase'\n    ], function( Base, Runtime, CompBase ) {\n\n        var $ = Base.$,\n            type = 'flash',\n            components = {};\n\n\n        function getFlashVersion() {\n            var version;\n\n            try {\n                version = navigator.plugins[ 'Shockwave Flash' ];\n                version = version.description;\n            } catch ( ex ) {\n                try {\n                    version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')\n                            .GetVariable('$version');\n                } catch ( ex2 ) {\n                    version = '0.0';\n                }\n            }\n            version = version.match( /\\d+/g );\n            return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 );\n        }\n\n        function FlashRuntime() {\n            var pool = {},\n                clients = {},\n                destroy = this.destroy,\n                me = this,\n                jsreciver = Base.guid('webuploader_');\n\n            Runtime.apply( me, arguments );\n            me.type = type;\n\n\n            // 这个方法的调用者，实际上是RuntimeClient\n            me.exec = function( comp, fn/*, args...*/ ) {\n                var client = this,\n                    uid = client.uid,\n                    args = Base.slice( arguments, 2 ),\n                    instance;\n\n                clients[ uid ] = client;\n\n                if ( components[ comp ] ) {\n                    if ( !pool[ uid ] ) {\n                        pool[ uid ] = new components[ comp ]( client, me );\n                    }\n\n                    instance = pool[ uid ];\n\n                    if ( instance[ fn ] ) {\n                        return instance[ fn ].apply( instance, args );\n                    }\n                }\n\n                return me.flashExec.apply( client, arguments );\n            };\n\n            function handler( evt, obj ) {\n                var type = evt.type || evt,\n                    parts, uid;\n\n                parts = type.split('::');\n                uid = parts[ 0 ];\n                type = parts[ 1 ];\n\n                // console.log.apply( console, arguments );\n\n                if ( type === 'Ready' && uid === me.uid ) {\n                    me.trigger('ready');\n                } else if ( clients[ uid ] ) {\n                    clients[ uid ].trigger( type.toLowerCase(), evt, obj );\n                }\n\n                // Base.log( evt, obj );\n            }\n\n            // flash的接受器。\n            window[ jsreciver ] = function() {\n                var args = arguments;\n\n                // 为了能捕获得到。\n                setTimeout(function() {\n                    handler.apply( null, args );\n                }, 1 );\n            };\n\n            this.jsreciver = jsreciver;\n\n            this.destroy = function() {\n                // @todo 删除池子中的所有实例\n                return destroy && destroy.apply( this, arguments );\n            };\n\n            this.flashExec = function( comp, fn ) {\n                var flash = me.getFlash(),\n                    args = Base.slice( arguments, 2 );\n\n                return flash.exec( this.uid, comp, fn, args );\n            };\n\n            // @todo\n        }\n\n        Base.inherits( Runtime, {\n            constructor: FlashRuntime,\n\n            init: function() {\n                var container = this.getContainer(),\n                    opts = this.options,\n                    html;\n\n                // if not the minimal height, shims are not initialized\n                // in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)\n                container.css({\n                    position: 'absolute',\n                    top: '-8px',\n                    left: '-8px',\n                    width: '9px',\n                    height: '9px',\n                    overflow: 'hidden'\n                });\n\n                // insert flash object\n                html = '<object id=\"' + this.uid + '\" type=\"application/' +\n                        'x-shockwave-flash\" data=\"' +  opts.swf + '\" ';\n\n                if ( Base.browser.ie ) {\n                    html += 'classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" ';\n                }\n\n                html += 'width=\"100%\" height=\"100%\" style=\"outline:0\">'  +\n                    '<param name=\"movie\" value=\"' + opts.swf + '\" />' +\n                    '<param name=\"flashvars\" value=\"uid=' + this.uid +\n                    '&jsreciver=' + this.jsreciver + '\" />' +\n                    '<param name=\"wmode\" value=\"transparent\" />' +\n                    '<param name=\"allowscriptaccess\" value=\"always\" />' +\n                '</object>';\n\n                container.html( html );\n            },\n\n            getFlash: function() {\n                if ( this._flash ) {\n                    return this._flash;\n                }\n\n                this._flash = $( '#' + this.uid ).get( 0 );\n                return this._flash;\n            }\n\n        });\n\n        FlashRuntime.register = function( name, component ) {\n            component = components[ name ] = Base.inherits( CompBase, $.extend({\n\n                // @todo fix this later\n                flashExec: function() {\n                    var owner = this.owner,\n                        runtime = this.getRuntime();\n\n                    return runtime.flashExec.apply( owner, arguments );\n                }\n            }, component ) );\n\n            return component;\n        };\n\n        if ( getFlashVersion() >= 11.4 ) {\n            Runtime.addRuntime( type, FlashRuntime );\n        }\n\n        return FlashRuntime;\n    });\n    /**\n     * @fileOverview FilePicker\n     */\n    define('runtime/flash/filepicker',[\n        'base',\n        'runtime/flash/runtime'\n    ], function( Base, FlashRuntime ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'FilePicker', {\n            init: function( opts ) {\n                var copy = $.extend({}, opts ),\n                    len, i;\n\n                // 修复Flash再没有设置title的情况下无法弹出flash文件选择框的bug.\n                len = copy.accept && copy.accept.length;\n                for (  i = 0; i < len; i++ ) {\n                    if ( !copy.accept[ i ].title ) {\n                        copy.accept[ i ].title = 'Files';\n                    }\n                }\n\n                delete copy.button;\n                delete copy.id;\n                delete copy.container;\n\n                this.flashExec( 'FilePicker', 'init', copy );\n            },\n\n            destroy: function() {\n                this.flashExec( 'FilePicker', 'destroy' );\n            }\n        });\n    });\n    /**\n     * @fileOverview  Transport flash实现\n     */\n    define('runtime/flash/transport',[\n        'base',\n        'runtime/flash/runtime',\n        'runtime/client'\n    ], function( Base, FlashRuntime, RuntimeClient ) {\n        var $ = Base.$;\n\n        return FlashRuntime.register( 'Transport', {\n            init: function() {\n                this._status = 0;\n                this._response = null;\n                this._responseJson = null;\n            },\n\n            send: function() {\n                var owner = this.owner,\n                    opts = this.options,\n                    xhr = this._initAjax(),\n                    blob = owner._blob,\n                    server = opts.server,\n                    binary;\n\n                xhr.connectRuntime( blob.ruid );\n\n                if ( opts.sendAsBinary ) {\n                    server += (/\\?/.test( server ) ? '&' : '?') +\n                            $.param( owner._formData );\n\n                    binary = blob.uid;\n                } else {\n                    $.each( owner._formData, function( k, v ) {\n                        xhr.exec( 'append', k, v );\n                    });\n\n                    xhr.exec( 'appendBlob', opts.fileVal, blob.uid,\n                            opts.filename || owner._formData.name || '' );\n                }\n\n                this._setRequestHeader( xhr, opts.headers );\n                xhr.exec( 'send', {\n                    method: opts.method,\n                    url: server,\n                    forceURLStream: opts.forceURLStream,\n                    mimeType: 'application/octet-stream'\n                }, binary );\n            },\n\n            getStatus: function() {\n                return this._status;\n            },\n\n            getResponse: function() {\n                return this._response || '';\n            },\n\n            getResponseAsJson: function() {\n                return this._responseJson;\n            },\n\n            abort: function() {\n                var xhr = this._xhr;\n\n                if ( xhr ) {\n                    xhr.exec('abort');\n                    xhr.destroy();\n                    this._xhr = xhr = null;\n                }\n            },\n\n            destroy: function() {\n                this.abort();\n            },\n\n            _initAjax: function() {\n                var me = this,\n                    xhr = new RuntimeClient('XMLHttpRequest');\n\n                xhr.on( 'uploadprogress progress', function( e ) {\n                    var percent = e.loaded / e.total;\n                    percent = Math.min( 1, Math.max( 0, percent ) );\n                    return me.trigger( 'progress', percent );\n                });\n\n                xhr.on( 'load', function() {\n                    var status = xhr.exec('getStatus'),\n                        readBody = false,\n                        err = '',\n                        p;\n\n                    xhr.off();\n                    me._xhr = null;\n\n                    if ( status >= 200 && status < 300 ) {\n                        readBody = true;\n                    } else if ( status >= 500 && status < 600 ) {\n                        readBody = true;\n                        err = 'server';\n                    } else {\n                        err = 'http';\n                    }\n\n                    if ( readBody ) {\n                        me._response = xhr.exec('getResponse');\n                        me._response = decodeURIComponent( me._response );\n\n                        // flash 处理可能存在 bug, 没辙只能靠 js 了\n                        // try {\n                        //     me._responseJson = xhr.exec('getResponseAsJson');\n                        // } catch ( error ) {\n\n                        p = window.JSON && window.JSON.parse || function( s ) {\n                            try {\n                                return new Function('return ' + s).call();\n                            } catch ( err ) {\n                                return {};\n                            }\n                        };\n                        me._responseJson  = me._response ? p(me._response) : {};\n\n                        // }\n                    }\n\n                    xhr.destroy();\n                    xhr = null;\n\n                    return err ? me.trigger( 'error', err ) : me.trigger('load');\n                });\n\n                xhr.on( 'error', function() {\n                    xhr.off();\n                    me._xhr = null;\n                    me.trigger( 'error', 'http' );\n                });\n\n                me._xhr = xhr;\n                return xhr;\n            },\n\n            _setRequestHeader: function( xhr, headers ) {\n                $.each( headers, function( key, val ) {\n                    xhr.exec( 'setRequestHeader', key, val );\n                });\n            }\n        });\n    });\n    /**\n     * @fileOverview 没有图像处理的版本。\n     */\n    define('preset/withoutimage',[\n        'base',\n\n        // widgets\n        'widgets/filednd',\n        'widgets/filepaste',\n        'widgets/filepicker',\n        'widgets/queue',\n        'widgets/runtime',\n        'widgets/upload',\n        'widgets/validator',\n\n        // runtimes\n        // html5\n        'runtime/html5/blob',\n        'runtime/html5/dnd',\n        'runtime/html5/filepaste',\n        'runtime/html5/filepicker',\n        'runtime/html5/transport',\n\n        // flash\n        'runtime/flash/filepicker',\n        'runtime/flash/transport'\n    ], function( Base ) {\n        return Base;\n    });\n    define('webuploader',[\n        'preset/withoutimage'\n    ], function( preset ) {\n        return preset;\n    });\n    return require('webuploader');\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/js/read-me.txt",
    "content": "I have created a seperate folder(flot-charts) for Flot Chart items.\nEach and every Flot chart I have used in this template have it's own js file inside flot-charts folder\nin order to get a clear picture of codes."
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/README.md",
    "content": "实验性质功能静态资源目录\n如果不用可以将该目录和WEB-INF.view/lab目录一并删除"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/base/base_leaflet.draw.ext.js",
    "content": "L.Draw.Rectangle.Query = L.Draw.Rectangle\n\t\t.extend({\n\t\t\tstatics : {\n\t\t\t\tTYPE : 'rectangleQuery'\n\t\t\t},\n\n\t\t\toptions : {\n\t\t\t\tshapeOptions : {\n\t\t\t\t\tstroke : true,\n\t\t\t\t\tcolor : '#f06eaa',\n\t\t\t\t\tweight : 4,\n\t\t\t\t\topacity : 0.5,\n\t\t\t\t\tfill : true,\n\t\t\t\t\tfillColor : null, // same as color by default\n\t\t\t\t\tfillOpacity : 0.2,\n\t\t\t\t\tclickable : true\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tinitialize : function(map, options) {\n\t\t\t\tthis._map = map;\n\t\t\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t\t\t// this.TYPE :(\n\t\t\t\tthis.type = L.Draw.Rectangle.Query.TYPE;\n\n\t\t\t\tthis._initialLabelText = L.drawLocal.draw.handlers.rectangle.tooltip.start;\n\n\t\t\t\t// 自定义的\n\t\t\t\tthis._RectangleLayerGroup = new L.FeatureGroup();\n\t\t\t\tthis._map.addLayer(this._RectangleLayerGroup);\n\n\t\t\t\tL.Draw.SimpleShape.prototype.initialize\n\t\t\t\t\t\t.call(this, map, options);\n\t\t\t},\n\t\t\t_onMouseUp : function(e) {\n\n\t\t\t\tvar obj = new Array();\n\t\t\t\tobj[0] = this._shape.getBounds()._northEast;\n\t\t\t\tobj[2] = this._shape.getBounds()._southWest;\n\t\t\t\tobj[1] = L.latLng(this._shape.getBounds()._southWest.lat,\n\t\t\t\t\t\tthis._shape.getBounds()._northEast.lng);\n\t\t\t\tobj[3] = L.latLng(this._shape.getBounds()._northEast.lat,\n\t\t\t\t\t\tthis._shape.getBounds()._southWest.lng);\n\t\t\t\tvar latLngs = obj[0].lat + ',' + obj[0].lng + ';' + obj[1].lat\n\t\t\t\t\t\t+ ',' + obj[1].lng + ';' + obj[2].lat + ','\n\t\t\t\t\t\t+ obj[2].lng + ';' + obj[3].lat + ',' + obj[3].lng;\n\t\t\t\tmapAreaSearchInfo(latLngs, \"rect\", this._RectangleLayerGroup);\n\n\t\t\t\tif (this._shape) {\n\t\t\t\t\tthis._fireCreatedEvent();\n\t\t\t\t}\n\n\t\t\t\tthis.disable();\n\t\t\t\tif (this.options.repeatMode) {\n\t\t\t\t\tthis.enable();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\nL.Draw.Circle.Query = L.Draw.Circle\n\t\t.extend({\n\t\t\tstatics : {\n\t\t\t\tTYPE : 'circleQuery'\n\t\t\t},\n\n\t\t\toptions : {\n\t\t\t\tshapeOptions : {\n\t\t\t\t\tstroke : true,\n\t\t\t\t\tcolor : '#f06eaa',\n\t\t\t\t\tweight : 4,\n\t\t\t\t\topacity : 0.5,\n\t\t\t\t\tfill : true,\n\t\t\t\t\tfillColor : null, // same as color by default\n\t\t\t\t\tfillOpacity : 0.2,\n\t\t\t\t\tclickable : true\n\t\t\t\t},\n\t\t\t\tshowRadius : true,\n\t\t\t\tmetric : true\n\t\t\t// Whether to use the metric meaurement system or imperial\n\t\t\t},\n\n\t\t\tinitialize : function(map, options) {\n\t\t\t\tthis._map = map;\n\t\t\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t\t\t// this.TYPE :(\n\t\t\t\tthis.type = L.Draw.Circle.Query.TYPE;\n\n\t\t\t\tthis._initialLabelText = L.drawLocal.draw.handlers.circle.tooltip.start;\n\t\t\t\t// 自定义的\n\t\t\t\tthis._CircleLayerGroup = new L.FeatureGroup();\n\t\t\t\tthis._map.addLayer(this._CircleLayerGroup);\n\n\t\t\t\tL.Draw.SimpleShape.prototype.initialize\n\t\t\t\t\t\t.call(this, map, options);\n\t\t\t},\n\n\t\t\t_onMouseUp : function(e) {\n\t\t\t\tvar latLngs = this._startLatLng.lat.toString() + ','\n\t\t\t\t\t\t+ this._startLatLng.lng.toString();\n\t\t\t\tvar radius = this._shape.getRadius().toFixed(1);\n\t\t\t\tmapAreaSearchInfo(latLngs + \";\" + radius, \"circle\",\n\t\t\t\t\t\tthis._CircleLayerGroup);\n\t\t\t\tif (this._shape) {\n\t\t\t\t\tthis._fireCreatedEvent();\n\t\t\t\t}\n\n\t\t\t\tthis.disable();\n\t\t\t\tif (this.options.repeatMode) {\n\t\t\t\t\tthis.enable();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\nL.Draw.Polygon.Query = L.Draw.Polyline.extend({\n\n\tstatics : {\n\t\tTYPE : 'polygonQuery'\n\t},\n\n\tPoly : L.Polygon,\n\n\toptions : {\n\t\tshowArea : true,\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\tclickable : true\n\t\t}\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\n\t\tL.Draw.Polyline.prototype.initialize.call(this, map, options);\n\n\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t// this.TYPE :(\n\t\tthis.type = L.Draw.Polygon.Query.TYPE;\n\t},\n\n\t_finishShape : function() {\n\t\tvar latLngsArray = this._poly.getLatLngs();\n\t\tvar latLngs = '';\n\t\tfor ( var i = 0; i < latLngsArray.length; i++) {\n\t\t\tlatLngs += latLngsArray[i].lat.toString() + ','\n\t\t\t\t\t+ latLngsArray[i].lng.toString() + ';';\n\t\t}\n\t\tlatLngs = latLngs.toString().substring(0, (latLngs.length - 1)) + '';\n\t\tmapAreaSearchInfo(latLngs, \"polygon\", this._drawnItems);\n\t\tvar intersects = this._poly.newLatLngIntersects(\n\t\t\t\tthis._poly.getLatLngs()[0], true);\n\n\t\tif ((!this.options.allowIntersection && intersects)\n\t\t\t\t|| !this._shapeIsValid()) {\n\t\t\tthis._showErrorTooltip();\n\t\t\treturn;\n\t\t}\n\n\t\tthis._fireCreatedEvent();\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\n\t}\n});\n\nL.Draw.Reset = L.Draw.SimpleShape.extend({\n\tstatics : {\n\t\tTYPE : 'reset'\n\t},\n\n\toptions : {\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\ttext : 'aaa',\n\t\t\tclickable : true\n\t\t}\n\t// Whether to use the metric meaurement system or imperial\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t// this.TYPE :(\n\t\tthis.type = L.Draw.Reset.TYPE;\n\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map, options);\n\t},\n\taddHooks : function() {\n\t\t// 清空数据\n\t\tif (L.Draw.tempData) {\n\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t// layer : this._drawnItems\n\t\t\tthis._map.removeLayer(L.Draw.tempData.tipMarkerGroup);\n\t\t\tL.Draw.tempData.layer.clearLayers();\n\t\t}\n\t\t// 清空标点数据\n\t\tif (L.Draw.tempData1) {\n\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t// layer : this._drawnItems\n\t\t\tthis._map.removeLayer(L.Draw.tempData1.tipMarkerGroup);\n\t\t\tL.Draw.tempData1.layer.clearLayers();\n\t\t}\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\t},\n\tremoveHooks : function() {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.enableTextSelection();\n\t\t\tthis._tooltip = null;\n\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\tthis._cancelDrawing);\n\t\t}\n\t}\n});\n\nL.Draw.CleanAll = L.Draw.SimpleShape.extend({\n\tstatics : {\n\t\tTYPE : 'cleanAll'\n\t},\n\n\toptions : {\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\ttext : 'aaa',\n\t\t\tclickable : true\n\t\t}\n\t// Whether to use the metric meaurement system or imperial\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t// this.TYPE :(\n\t\tthis.type = L.Draw.CleanAll.TYPE;\n\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map, options);\n\t},\n\taddHooks : function() {\n\t\t// 清空数据\n\t\tif (L.Draw.tempData) {\n\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t// layer : this._drawnItems\n\t\t\tthis._map.removeLayer(L.Draw.tempData.tipMarkerGroup);\n\t\t\tL.Draw.tempData.layer.clearLayers();\n\t\t}\n\t\t// 清空标点数据\n\t\tif (L.Draw.tempData1) {\n\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t// layer : this._drawnItems\n\t\t\tthis._map.removeLayer(L.Draw.tempData1.tipMarkerGroup);\n\t\t\tL.Draw.tempData1.layer.clearLayers();\n\t\t}\n\t\t// 清空非工具条生成的图层\n\t\tif (L.Draw.customData) {\n\t\t\tthis._map.removeLayer(L.Draw.customData);\n\t\t}\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\t},\n\tremoveHooks : function() {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.enableTextSelection();\n\t\t\tthis._tooltip = null;\n\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\tthis._cancelDrawing);\n\t\t}\n\t}\n});\nL.Draw.ZoomIn = L.Draw.SimpleShape.extend({\n\tstatics : {\n\t\tTYPE : 'zoomIn'\n\t},\n\n\toptions : {\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\ttext : 'aaa',\n\t\t\tclickable : true\n\t\t}\n\t// Whether to use the metric meaurement system or imperial\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\t\tthis.type = L.Draw.ZoomIn.TYPE;\n\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map, options);\n\t},\n\n\taddHooks : function() {\n\n\t\tthis.zoom = this._map.getZoom();\n\n\t\tif (this.zoom < 16) {\n\t\t\tthis._map.zoomIn();\n\t\t\t// this._map.setZoom(this.zoom+1);\n\t\t}\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\t},\n\tremoveHooks : function() {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.enableTextSelection();\n\t\t\tthis._tooltip = null;\n\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\tthis._cancelDrawing);\n\t\t}\n\t}\n});\n\nL.Draw.ZoomOut = L.Draw.SimpleShape.extend({\n\tstatics : {\n\t\tTYPE : 'zoomOut'\n\t},\n\n\toptions : {\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\ttext : 'aaa',\n\t\t\tclickable : true\n\t\t}\n\t// Whether to use the metric meaurement system or imperial\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\t\tthis.type = L.Draw.ZoomOut.TYPE;\n\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map, options);\n\t},\n\taddHooks : function() {\n\t\tthis.zoom = this._map.getZoom();\n\n\t\tif (this.zoom > 4) {\n\t\t\tthis._map.zoomOut();\n\t\t\t// this._map.setZoom(this.zoom-1);\n\t\t}\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\t},\n\tremoveHooks : function() {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.enableTextSelection();\n\t\t\tthis._tooltip = null;\n\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\tthis._cancelDrawing);\n\t\t}\n\t}\n});\n\n// 资源流向\n\nfunction orderPolyline() {\n\n\tvar arrow = L.polyline(\n\t\t\t[ [ 39.33429742980725, 106.72119140625 ],\n\t\t\t\t\t[ 39.8928799002948, 116.43310546875 ],\n\t\t\t\t\t[ 41.78769700539063, 123.46435546875 ] ], {}).addTo(map);\n\tcreateLine(arrow);\n\n\tvar arrow1 = L.polyline(\n\t\t\t[ [ 41.78769700539063, 123.46435546875 ],\n\t\t\t\t\t[ 45.60635207711834, 122.82714843749999 ] ], {}).addTo(map);\n\tcreateLine(arrow1);\n\n\tvar arrow2 = L.polyline(\n\t\t\t[ [ 41.78769700539063, 123.46435546875 ],\n\t\t\t\t\t[ 45.775186183521036, 126.57348632812499 ] ], {})\n\t\t\t.addTo(map);\n\tcreateLine(arrow2);\n\n\tvar arrow3 = L.polyline(\n\t\t\t[ [ 41.78769700539063, 123.46435546875 ],\n\t\t\t\t\t[ 43.24520272203356, 128.34228515625 ] ], {}).addTo(map);\n\tcreateLine(arrow3);\n\n\tvar arrow4 = L.polyline(\n\t\t\t[ [ 41.78769700539063, 123.46435546875 ],\n\t\t\t\t\t[ 44.35527821160296, 124.67285156250001 ] ], {}).addTo(map);\n\tcreateLine(arrow4);\n\t// 122.82714843749999 45.60635207711834\n\tvar c1 = L.circle([ 45.60635207711834, 122.82714843749999 ], 20000).addTo(\n\t\t\tmap);\n\tvar c2 = L.circle([ 45.775186183521036, 126.57348632812499 ], 20000).addTo(\n\t\t\tmap);\n\tvar c3 = L.circle([ 43.24520272203356, 128.34228515625 ], 20000).addTo(map);\n\tvar c4 = L.circle([ 44.35527821160296, 124.67285156250001 ], 20000).addTo(\n\t\t\tmap);\n\n\t// 航线图\n\tvar pathPattern = L.polylineDecorator(\n\t\t\t[ [ 26.51, 122.61 ], [ 32.36, 123.40 ], [ 35.21, 120.63 ],\n\t\t\t\t\t[ 37.51, 123.88 ], [ 38.89, 119.18 ] ], {\n\t\t\t\tpatterns : [ {\n\t\t\t\t\toffset : 0,\n\t\t\t\t\trepeat : 10,\n\t\t\t\t\tsymbol : L.Symbol.dash({\n\t\t\t\t\t\tpixelSize : 5,\n\t\t\t\t\t\tpathOptions : {\n\t\t\t\t\t\t\tcolor : '#000',\n\t\t\t\t\t\t\tweight : 1,\n\t\t\t\t\t\t\topacity : 0.2\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}, {\n\t\t\t\t\toffset : '16%',\n\t\t\t\t\trepeat : '33%',\n\t\t\t\t\tsymbol : L.Symbol.marker({\n\t\t\t\t\t\trotate : true,\n\t\t\t\t\t\tmarkerOptions : {\n\t\t\t\t\t\t\ticon : L.icon({\n\t\t\t\t\t\t\t\ticonUrl : '../icon_plane.png',\n\t\t\t\t\t\t\t\ticonAnchor : [ 16, 16 ]\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t} ]\n\t\t\t}).addTo(map);\n\n}\n\nfunction createLine(arrow) {\n\n\tvar arrowHead = L.polylineDecorator(arrow).addTo(map);\n\n\tvar arrowOffset = 0;\n\tvar anim = window.setInterval(function() {\n\t\tarrowHead.setPatterns([ {\n\t\t\toffset : arrowOffset + '%',\n\t\t\trepeat : 0,\n\t\t\tsymbol : L.Symbol.arrowHead({\n\t\t\t\tpixelSize : 13,\n\t\t\t\tpolygon : false,\n\t\t\t\tpathOptions : {\n\t\t\t\t\tstroke : true\n\t\t\t\t}\n\t\t\t})\n\t\t} ]);\n\t\tif (++arrowOffset > 100)\n\t\t\tarrowOffset = 0;\n\t}, 200);\n\n}\n\nfunction addHistogram(provinceMap) {\n\tif (removeHistogram) {\n\t\tthis.histogramLayer = new L.FeatureGroup();\n\t\tvar myIcon = L\n\t\t\t\t.divIcon({\n\t\t\t\t\ticonSize : L.point(1100, 200),\n\t\t\t\t\ticonAnchor : L.point(1150, 205),\n\t\t\t\t\thtml : '<IFRAME NAME=\"content_frame\" width=100% height=100% marginwidth=0 marginheight=0 SRC=\"a.html\" ></IFRAME> '\n\t\t\t\t});\n\t\tvar beiJingMarker = L.marker([ 39.92, 116.41 ], {\n\t\t\ticon : myIcon\n\t\t}).addTo(map);\n\t\tvar myIcon1 = L.divIcon({\n\t\t\ticonSize : L.point(100, 20),\n\t\t\ticonAnchor : L.point(50, 25),\n\t\t\thtml : '山西'\n\t\t});\n\t\tvar shanxiMarker = L.marker([ 37.87, 112.54 ], {\n\t\t\ticon : myIcon1\n\t\t}).addTo(map);\n\t\tvar myIcon2 = L.divIcon({\n\t\t\ticonSize : L.point(100, 20),\n\t\t\ticonAnchor : L.point(50, 25),\n\t\t\thtml : '内蒙古'\n\t\t});\n\t\tvar neimenggugMarker = L.marker([ 40.86, 111.75 ], {\n\t\t\ticon : myIcon2\n\t\t}).addTo(map);\n\t\tvar myIcon3 = L.divIcon({\n\t\t\ticonSize : L.point(100, 20),\n\t\t\ticonAnchor : L.point(50, 25),\n\t\t\thtml : '河北'\n\t\t});\n\t\tvar hebeiMarker = L.marker([ 38.07, 114.50 ], {\n\t\t\ticon : myIcon3\n\t\t}).addTo(map);\n\t\tvar myIcon4 = L.divIcon({\n\t\t\ticonSize : L.point(100, 20),\n\t\t\ticonAnchor : L.point(50, 25),\n\t\t\thtml : '山东'\n\t\t});\n\t\tvar shandongMarker = L.marker([ 36.72, 117.09 ], {\n\t\t\ticon : myIcon4\n\t\t}).addTo(map);\n\t\thistogramLayer.addLayer(beiJingMarker, shanxiMarker, neimenggugMarker,\n\t\t\t\thebeiMarker, shandongMarker);\n\t\tmap.addLayer(histogramLayer);\n\t}\n}\nfunction removeHistogram() {\n\tif (histogramLayer) {\n\t\tmap.removeLayer(this.histogramLayer);\n\t}\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/base/base_map.js",
    "content": "var map;\nvar zTree;\nvar markerArray = new Array();\nvar routeLayer = null;\nfunction initMap(mapServerUrl) {\n\tvar funcLayer = new L.TileLayer.Functional(function (view) {\n\tvar url = \"http://172.16.247.100/gis\"+'/{z}/{y}/{x}.png'\n\t\t.replace('{z}', \"L\" +(parseInt(view.zoom)<10?(\"0\"+view.zoom):view.zoom))\n\t\t.replace('{x}', (function(){\n\t\t\t\t\t\t\tvar x = parseInt(view.tile.column, 10).toString(16)\n\t\t\t\t\t\t\tif(x.length < 8){\n\t\t\t\t\t\t\t\tvar k = x.length;\n\t\t\t\t\t\t\t\tfor(var i = 0; i < 8 - k;i++){\n\t\t\t\t\t\t\t\t\tx = \"0\" + x;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tx = \"C\" + x;\n\t\t\t\t\t\t\t//console.log(x + \"  length :\" + x.length);\n\t\t\t\t\t\t\treturn x.toUpperCase();\n\t\t\t\t\t\t})())\n\t\t.replace('{y}', (function(){\n\t\t\t\t\t\t\tvar y = parseInt(view.tile.row, 10).toString(16)\n\t\t\t\t\t\t\tif(y.length < 8){\n\t\t\t\t\t\t\t\tvar k = y.length;\n\t\t\t\t\t\t\t\tfor(var i = 0; i < 8 - k;i++){\n\t\t\t\t\t\t\t\t\ty = \"0\" + y;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ty = \"R\" + y;\n\t\t\t\t\t\t\treturn y.toUpperCase();\n\t\t\t\t\t\t})())\n\t\t.replace('{s}', view.subdomain);\n\treturn url;\n}, {\n\tsubdomains: '1234',opacity:1\n});\n\t\nmap = L.map('map', {\n    center: [39.918, 116.38],\n    zoom: 5,\n    zoomControl:false,\n    layers: [funcLayer]\t,\n    maxZoom : 16,\n    minZoom:4,\n    maxBounds:[[85.03,-179.82],[-85,179.82]]\n});\n\nvar baseLayers = {\n    \"Google量地图\": funcLayer\n};\t\t\nrouteLayer = L.layerGroup().addTo(map);\nL.control.layers(baseLayers).addTo(map);\nvar drawnItems = new L.FeatureGroup();\nmap.addLayer(drawnItems);\n\nvar drawControl = new L.Control.Draw({\n\tdraw: {\n\t\tposition: 'topleft',\n\t\tpolygon: {\n\t\t\ttitle: '多边形!',\n\t\t\tallowIntersection: false,\n\t\t\tdrawError: {\n\t\t\t\tcolor: '#b00b00',\n\t\t\t\ttimeout: 1000\n\t\t\t},\n\t\t\tshapeOptions: {\n\t\t\t\tcolor: 'blue'\n\t\t\t},\n\t\t\tshowArea: true\n\t\t},\n\t\tpolyline: {\n\t\t\tmetric: false\n\t\t},\n\t\tcircle: {\n\t\t\tshapeOptions: {\n\t\t\t\tcolor: '#662d91'\n\t\t\t}\n\t\t}\n\t}\n});\nmap.addControl(drawControl);\n\nmap.on('draw:created', function (e) {\n\tvar type = e.layerType,\n\t\tlayer = e.layer;\n\n\tdrawnItems.addLayer(layer);\n});\n\nmap.on(\"zoomstart\", function(e){\n});\n\nmap.on(\"zoomend\", function(e){\n\t\tvar zoom = e.target._zoom;\n\t\tvar items = null;\n\t\tif(parseInt(zoom) <=5 ){//全国\n\n\t\t\n\n\t\t} else if(parseInt(zoom) >=5&&parseInt(zoom) <=7){//省级\n\n\t\t}else{//市级\n\t\t}\n\n});\n}\n\n//增加地图点击事件\nfunction addMapClickEvent(){\n\tmap.on(\"click\", function(e){\n\t\tclickMap(e.latlng.lat,e.latlng.lng);\n\t});\n}\n//移除地图点击事件\nfunction remMapClickEvent(){\n\tmap.off(\"click\");\n}\n\n\nfunction dingwei(lat,lng,zoom){\n\tmap.panTo(L.latLng(lat, lng));\n\tmap.setZoom(zoom);\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/base/base_tilesUtils.js",
    "content": "//叠加点数量多 用 叠加点图层方式\nfunction drawPointTile(table,where){\n\t   var url = 'wms/drawTitles?x={x}&y={y}&z={z}&table='+table+\"&where=\"+where;\n\t   var layName = 'pointTitle';\n\t   addTiles(url,layName);\n}\n\n\n//根据tileUrl 返回瓦片图\nvar keyList = new Array();//存储数节点的key值\nvar layerList = new Array();//存储对应key的layer\n\n//titleUrl 请求地址，key 图层名称\nfunction  addTiles(tileUrl, key){\n\tif(key=='404'){\n\t\taddHistogram();\n       return;\n\t}\n\tvar tilesLayer = L.tileLayer(tileUrl, {\n\t\tmaxZoom : 18,\n\t    zIndex:20\n\t});\n\tvar flag = false;\n\tfor(var i=0; i<keyList.length; i++){\n\t\tif(keyList[i] == key){\n\t\t\tlayerList[i] = tilesLayer;\n\t\t\tflag = true;\n\t\t}\n\t}\n\tif(!flag){\n\t\tkeyList.push(key);\n\t\tlayerList.push(tilesLayer);\n\t}\n\tmap.addLayer(tilesLayer);\n\treturn tilesLayer;\n}\n\n//移除叠加的瓦片图层\nfunction removeTiles(key){\n\tif(key=='404'){\n\t\tremoveHistogram();\n       return;\n\t}\n\tfor(var i=0; i<keyList.length; i++){\n\t\tif(keyList[i] == key){\n\t\t\tmap.removeLayer(layerList[i]);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/index.js",
    "content": "var flashMap = {\n    map: null,\n    innerData:{},\n    /**\n     * 标注点点击事件\n     * @param mark\n     */\n    clickMark: function (mark) {\n        console.log(mark);\n        var lat = mark.jsonObj.lat;\n        var lng = mark.jsonObj.lng;\n        alert(\"lat:\"+lat + \",lng:\" + lng );\n    },\n    /**\n     * 鼠标移动到标注点 回调方法\n     * @param mark\n     */\n    mouseOverEvent: function (mark) {\n        var name = mark.jsonObj.name;\n        mark.bindPopup( name).openPopup();\n    },\n    /**\n     * 地图初始化\n     * @param domId\n     */\n    init: function (domId) {\n        var map = L.map(domId, {\n            zoominfoControl: true,\n            zoomControl: false,\n            zoom: 4,\n            maxZoom: 11,\n            minZoom:4,\n            center: [34.346299,106.757186],\n            attributionControl: true\n        });\n        L.tileLayer('http://gisdata.enilu.cn/{z}/{x}/{y}.png', {\n            attribution: 'Map data &copy; GoogleMap,Support by <a href=\"http://www.enilu.cn\">enilu.cn</a>'\n        }).addTo(map);\n        this.map = map;\n    },\n    /**\n     * 添加坐标点\n     * @param data\n     */\n    addMark: function (data) {\n        var marker = L.marker([data.lat, data.lng]).addTo(this.map);\n        //设置自定义属性\n        marker.jsonObj = data;\n        var me = this;\n        marker.on(\"click\", function () {\n            me.clickMark(this);\n        });\n        marker.on(\"mouseover\", function () {\n            me.mouseOverEvent(this);\n        });\n        if (data.name) {\n            marker.bindPopup(data.name);\n        }\n    },\n    /**\n     * 添加多个坐标点\n     * @param positionList\n     */\n    addMarks: function (positionList) {\n        for (var i = 0; i < positionList.length; i++) {\n            this.addMark(positionList[i]);\n        }\n    },\n    /**\n     * 定位\n     * @param lat\n     * @param lng\n     */\n    pointTo:function(lat,lng){\n        this.addMark({lat:31.235958,lng:121.480545,name:'上海'});\n        this.map.panTo(L.latLng(lat, lng));\n\n    },\n    /**\n     * 画圆\n     * @param data\n     */\n    drawCircle:function(data){\n        var me = this;\n        var barLayer = new BarLayer({\n            data : data,\n            map : me.map\n        });\n        barLayer.addLayer();\n        this.innerData.barLayer = barLayer;\n    },\n    /**\n     * 画弧线\n     * @param data\n     */\n    drawArc:function(data){\n        var me = this;\n        var arcLayer = new ArcLayer({\n            data : data,\n            map : me.map\n        });\n        arcLayer.addLayer();\n        this.innerData.arcLayer = arcLayer;\n    }\n}\n\n\n$(document).ready(function () {\n    flashMap.init(\"map\");\n    $('#btnInit').hide();\n    $('#btnAddMark').click(function () {\n        flashMap.addMark({lat: 40.13254611, lng: 116.5056088, name: \"北京\"});\n    })\n    $(\"#btnAddMarks\").click(function () {\n        flashMap.addMarks([\n            {lat: 37.94, lng: 112.64, name: '太原'},\n            {lat: 40.82149932, lng: 111.6842769, name: '呼和浩特市'}]);\n    })\n    $('#btnPointTo').click(function(){\n        flashMap.pointTo(31.235958,121.480545,8);\n    })\n    var  drawCircle = true\n    $('#btnDrawCircle').click(function(){\n        if(drawCircle) {\n            flashMap.drawCircle(cirlData);\n            $(this).text('删除圆圈');\n            drawCircle=false;\n        }else{\n            flashMap.innerData.barLayer.removeLayer();\n            flashMap.innerData.barLayer = null;\n            $(this).text('画圆圈').show();\n            drawCircle = true;\n        }\n\n    });\n    var drawArc = true;\n    $('#btnDrawArc').click(function(){\n        var arcData={\n            style:{color:'red',thickness:4,speed:10},\n            isOut:'1',\n            centerLatLng:{lat:31.1,lng:116.1},\n            latLng:[{lat:41.802542590364354,lng:123.431396484375},\n                {lat:34.252676117101515,lng:108.896484375},\n                {lat:29.611670115197377,lng:106.5234375},\n                {lat:42.81152174509788,lng:113.466796875},\n                {lat:40.27952566881291,lng:86.0009765625}]\n        };\n        if(drawArc){\n            flashMap.drawArc(arcData);\n            $(this).text('删除弧线');\n            drawArc=false;\n        }else{\n            flashMap.innerData.arcLayer.removeLayer();\n            flashMap.innerData.arcLayer = null;\n            $(this).text('画弧线');\n            drawArc=true;\n        }\n\n    })\n\n\n})\n\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/base/base_leaflet.draw.ext.js",
    "content": "L.Draw.Rectangle.Query = L.Draw.Rectangle\n\t\t.extend({\n\t\t\tstatics : {\n\t\t\t\tTYPE : 'rectangleQuery'\n\t\t\t},\n\n\t\t\toptions : {\n\t\t\t\tshapeOptions : {\n\t\t\t\t\tstroke : true,\n\t\t\t\t\tcolor : '#f06eaa',\n\t\t\t\t\tweight : 4,\n\t\t\t\t\topacity : 0.5,\n\t\t\t\t\tfill : true,\n\t\t\t\t\tfillColor : null, // same as color by default\n\t\t\t\t\tfillOpacity : 0.2,\n\t\t\t\t\tclickable : true\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tinitialize : function(map, options) {\n\t\t\t\tthis._map = map;\n\t\t\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t\t\t// this.TYPE :(\n\t\t\t\tthis.type = L.Draw.Rectangle.Query.TYPE;\n\n\t\t\t\tthis._initialLabelText = L.drawLocal.draw.handlers.rectangle.tooltip.start;\n\n\t\t\t\t// 自定义的\n\t\t\t\tthis._RectangleLayerGroup = new L.FeatureGroup();\n\t\t\t\tthis._map.addLayer(this._RectangleLayerGroup);\n\n\t\t\t\tL.Draw.SimpleShape.prototype.initialize\n\t\t\t\t\t\t.call(this, map, options);\n\t\t\t},\n\t\t\t_onMouseUp : function(e) {\n\n\t\t\t\tvar obj = new Array();\n\t\t\t\tobj[0] = this._shape.getBounds()._northEast;\n\t\t\t\tobj[2] = this._shape.getBounds()._southWest;\n\t\t\t\tobj[1] = L.latLng(this._shape.getBounds()._southWest.lat,\n\t\t\t\t\t\tthis._shape.getBounds()._northEast.lng);\n\t\t\t\tobj[3] = L.latLng(this._shape.getBounds()._northEast.lat,\n\t\t\t\t\t\tthis._shape.getBounds()._southWest.lng);\n\t\t\t\tvar latLngs = obj[0].lat + ',' + obj[0].lng + ';' + obj[1].lat\n\t\t\t\t\t\t+ ',' + obj[1].lng + ';' + obj[2].lat + ','\n\t\t\t\t\t\t+ obj[2].lng + ';' + obj[3].lat + ',' + obj[3].lng;\n\t\t\t\tmapAreaSearchInfo(latLngs, \"rect\", this._RectangleLayerGroup);\n\n\t\t\t\tif (this._shape) {\n\t\t\t\t\tthis._fireCreatedEvent();\n\t\t\t\t}\n\n\t\t\t\tthis.disable();\n\t\t\t\tif (this.options.repeatMode) {\n\t\t\t\t\tthis.enable();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\nL.Draw.Circle.Query = L.Draw.Circle\n\t\t.extend({\n\t\t\tstatics : {\n\t\t\t\tTYPE : 'circleQuery'\n\t\t\t},\n\n\t\t\toptions : {\n\t\t\t\tshapeOptions : {\n\t\t\t\t\tstroke : true,\n\t\t\t\t\tcolor : '#f06eaa',\n\t\t\t\t\tweight : 4,\n\t\t\t\t\topacity : 0.5,\n\t\t\t\t\tfill : true,\n\t\t\t\t\tfillColor : null, // same as color by default\n\t\t\t\t\tfillOpacity : 0.2,\n\t\t\t\t\tclickable : true\n\t\t\t\t},\n\t\t\t\tshowRadius : true,\n\t\t\t\tmetric : true\n\t\t\t// Whether to use the metric meaurement system or imperial\n\t\t\t},\n\n\t\t\tinitialize : function(map, options) {\n\t\t\t\tthis._map = map;\n\t\t\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t\t\t// this.TYPE :(\n\t\t\t\tthis.type = L.Draw.Circle.Query.TYPE;\n\n\t\t\t\tthis._initialLabelText = L.drawLocal.draw.handlers.circle.tooltip.start;\n\t\t\t\t// 自定义的\n\t\t\t\tthis._CircleLayerGroup = new L.FeatureGroup();\n\t\t\t\tthis._map.addLayer(this._CircleLayerGroup);\n\n\t\t\t\tL.Draw.SimpleShape.prototype.initialize\n\t\t\t\t\t\t.call(this, map, options);\n\t\t\t},\n\n\t\t\t_onMouseUp : function(e) {\n\t\t\t\tvar latLngs = this._startLatLng.lat.toString() + ','\n\t\t\t\t\t\t+ this._startLatLng.lng.toString();\n\t\t\t\tvar radius = this._shape.getRadius().toFixed(1);\n\t\t\t\tmapAreaSearchInfo(latLngs + \";\" + radius, \"circle\",\n\t\t\t\t\t\tthis._CircleLayerGroup);\n\t\t\t\tif (this._shape) {\n\t\t\t\t\tthis._fireCreatedEvent();\n\t\t\t\t}\n\n\t\t\t\tthis.disable();\n\t\t\t\tif (this.options.repeatMode) {\n\t\t\t\t\tthis.enable();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\nL.Draw.Polygon.Query = L.Draw.Polyline.extend({\n\n\tstatics : {\n\t\tTYPE : 'polygonQuery'\n\t},\n\n\tPoly : L.Polygon,\n\n\toptions : {\n\t\tshowArea : true,\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\tclickable : true\n\t\t}\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\n\t\tL.Draw.Polyline.prototype.initialize.call(this, map, options);\n\n\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t// this.TYPE :(\n\t\tthis.type = L.Draw.Polygon.Query.TYPE;\n\t},\n\n\t_finishShape : function() {\n\t\tvar latLngsArray = this._poly.getLatLngs();\n\t\tvar latLngs = '';\n\t\tfor ( var i = 0; i < latLngsArray.length; i++) {\n\t\t\tlatLngs += latLngsArray[i].lat.toString() + ','\n\t\t\t\t\t+ latLngsArray[i].lng.toString() + ';';\n\t\t}\n\t\tlatLngs = latLngs.toString().substring(0, (latLngs.length - 1)) + '';\n\t\tmapAreaSearchInfo(latLngs, \"polygon\", this._drawnItems);\n\t\tvar intersects = this._poly.newLatLngIntersects(\n\t\t\t\tthis._poly.getLatLngs()[0], true);\n\n\t\tif ((!this.options.allowIntersection && intersects)\n\t\t\t\t|| !this._shapeIsValid()) {\n\t\t\tthis._showErrorTooltip();\n\t\t\treturn;\n\t\t}\n\n\t\tthis._fireCreatedEvent();\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\n\t}\n});\n\nL.Draw.Reset = L.Draw.SimpleShape.extend({\n\tstatics : {\n\t\tTYPE : 'reset'\n\t},\n\n\toptions : {\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\ttext : 'aaa',\n\t\t\tclickable : true\n\t\t}\n\t// Whether to use the metric meaurement system or imperial\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t// this.TYPE :(\n\t\tthis.type = L.Draw.Reset.TYPE;\n\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map, options);\n\t},\n\taddHooks : function() {\n\t\t// 清空数据\n\t\tif (L.Draw.tempData) {\n\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t// layer : this._drawnItems\n\t\t\tthis._map.removeLayer(L.Draw.tempData.tipMarkerGroup);\n\t\t\tL.Draw.tempData.layer.clearLayers();\n\t\t}\n\t\t// 清空标点数据\n\t\tif (L.Draw.tempData1) {\n\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t// layer : this._drawnItems\n\t\t\tthis._map.removeLayer(L.Draw.tempData1.tipMarkerGroup);\n\t\t\tL.Draw.tempData1.layer.clearLayers();\n\t\t}\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\t},\n\tremoveHooks : function() {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.enableTextSelection();\n\t\t\tthis._tooltip = null;\n\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\tthis._cancelDrawing);\n\t\t}\n\t}\n});\n\nL.Draw.CleanAll = L.Draw.SimpleShape.extend({\n\tstatics : {\n\t\tTYPE : 'cleanAll'\n\t},\n\n\toptions : {\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\ttext : 'aaa',\n\t\t\tclickable : true\n\t\t}\n\t// Whether to use the metric meaurement system or imperial\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t// this.TYPE :(\n\t\tthis.type = L.Draw.CleanAll.TYPE;\n\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map, options);\n\t},\n\taddHooks : function() {\n\t\t// 清空数据\n\t\tif (L.Draw.tempData) {\n\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t// layer : this._drawnItems\n\t\t\tthis._map.removeLayer(L.Draw.tempData.tipMarkerGroup);\n\t\t\tL.Draw.tempData.layer.clearLayers();\n\t\t}\n\t\t// 清空标点数据\n\t\tif (L.Draw.tempData1) {\n\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t// layer : this._drawnItems\n\t\t\tthis._map.removeLayer(L.Draw.tempData1.tipMarkerGroup);\n\t\t\tL.Draw.tempData1.layer.clearLayers();\n\t\t}\n\t\t// 清空非工具条生成的图层\n\t\tif (L.Draw.customData) {\n\t\t\tthis._map.removeLayer(L.Draw.customData);\n\t\t}\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\t},\n\tremoveHooks : function() {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.enableTextSelection();\n\t\t\tthis._tooltip = null;\n\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\tthis._cancelDrawing);\n\t\t}\n\t}\n});\nL.Draw.ZoomIn = L.Draw.SimpleShape.extend({\n\tstatics : {\n\t\tTYPE : 'zoomIn'\n\t},\n\n\toptions : {\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\ttext : 'aaa',\n\t\t\tclickable : true\n\t\t}\n\t// Whether to use the metric meaurement system or imperial\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\t\tthis.type = L.Draw.ZoomIn.TYPE;\n\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map, options);\n\t},\n\n\taddHooks : function() {\n\n\t\tthis.zoom = this._map.getZoom();\n\n\t\tif (this.zoom < 16) {\n\t\t\tthis._map.zoomIn();\n\t\t\t// this._map.setZoom(this.zoom+1);\n\t\t}\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\t},\n\tremoveHooks : function() {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.enableTextSelection();\n\t\t\tthis._tooltip = null;\n\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\tthis._cancelDrawing);\n\t\t}\n\t}\n});\n\nL.Draw.ZoomOut = L.Draw.SimpleShape.extend({\n\tstatics : {\n\t\tTYPE : 'zoomOut'\n\t},\n\n\toptions : {\n\t\tshapeOptions : {\n\t\t\tstroke : true,\n\t\t\tcolor : '#f06eaa',\n\t\t\tweight : 4,\n\t\t\topacity : 0.5,\n\t\t\tfill : true,\n\t\t\tfillColor : null, // same as color by default\n\t\t\tfillOpacity : 0.2,\n\t\t\ttext : 'aaa',\n\t\t\tclickable : true\n\t\t}\n\t// Whether to use the metric meaurement system or imperial\n\t},\n\n\tinitialize : function(map, options) {\n\t\tthis._map = map;\n\t\tthis.type = L.Draw.ZoomOut.TYPE;\n\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map, options);\n\t},\n\taddHooks : function() {\n\t\tthis.zoom = this._map.getZoom();\n\n\t\tif (this.zoom > 4) {\n\t\t\tthis._map.zoomOut();\n\t\t\t// this._map.setZoom(this.zoom-1);\n\t\t}\n\t\tthis.disable();\n\t\tif (this.options.repeatMode) {\n\t\t\tthis.enable();\n\t\t}\n\t},\n\tremoveHooks : function() {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.enableTextSelection();\n\t\t\tthis._tooltip = null;\n\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\tthis._cancelDrawing);\n\t\t}\n\t}\n});\n\n// 资源流向\n\nfunction orderPolyline() {\n\n\tvar arrow = L.polyline(\n\t\t\t[ [ 39.33429742980725, 106.72119140625 ],\n\t\t\t\t\t[ 39.8928799002948, 116.43310546875 ],\n\t\t\t\t\t[ 41.78769700539063, 123.46435546875 ] ], {}).addTo(map);\n\tcreateLine(arrow);\n\n\tvar arrow1 = L.polyline(\n\t\t\t[ [ 41.78769700539063, 123.46435546875 ],\n\t\t\t\t\t[ 45.60635207711834, 122.82714843749999 ] ], {}).addTo(map);\n\tcreateLine(arrow1);\n\n\tvar arrow2 = L.polyline(\n\t\t\t[ [ 41.78769700539063, 123.46435546875 ],\n\t\t\t\t\t[ 45.775186183521036, 126.57348632812499 ] ], {})\n\t\t\t.addTo(map);\n\tcreateLine(arrow2);\n\n\tvar arrow3 = L.polyline(\n\t\t\t[ [ 41.78769700539063, 123.46435546875 ],\n\t\t\t\t\t[ 43.24520272203356, 128.34228515625 ] ], {}).addTo(map);\n\tcreateLine(arrow3);\n\n\tvar arrow4 = L.polyline(\n\t\t\t[ [ 41.78769700539063, 123.46435546875 ],\n\t\t\t\t\t[ 44.35527821160296, 124.67285156250001 ] ], {}).addTo(map);\n\tcreateLine(arrow4);\n\t// 122.82714843749999 45.60635207711834\n\tvar c1 = L.circle([ 45.60635207711834, 122.82714843749999 ], 20000).addTo(\n\t\t\tmap);\n\tvar c2 = L.circle([ 45.775186183521036, 126.57348632812499 ], 20000).addTo(\n\t\t\tmap);\n\tvar c3 = L.circle([ 43.24520272203356, 128.34228515625 ], 20000).addTo(map);\n\tvar c4 = L.circle([ 44.35527821160296, 124.67285156250001 ], 20000).addTo(\n\t\t\tmap);\n\n\t// 航线图\n\tvar pathPattern = L.polylineDecorator(\n\t\t\t[ [ 26.51, 122.61 ], [ 32.36, 123.40 ], [ 35.21, 120.63 ],\n\t\t\t\t\t[ 37.51, 123.88 ], [ 38.89, 119.18 ] ], {\n\t\t\t\tpatterns : [ {\n\t\t\t\t\toffset : 0,\n\t\t\t\t\trepeat : 10,\n\t\t\t\t\tsymbol : L.Symbol.dash({\n\t\t\t\t\t\tpixelSize : 5,\n\t\t\t\t\t\tpathOptions : {\n\t\t\t\t\t\t\tcolor : '#000',\n\t\t\t\t\t\t\tweight : 1,\n\t\t\t\t\t\t\topacity : 0.2\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t}, {\n\t\t\t\t\toffset : '16%',\n\t\t\t\t\trepeat : '33%',\n\t\t\t\t\tsymbol : L.Symbol.marker({\n\t\t\t\t\t\trotate : true,\n\t\t\t\t\t\tmarkerOptions : {\n\t\t\t\t\t\t\ticon : L.icon({\n\t\t\t\t\t\t\t\ticonUrl : '../icon_plane.png',\n\t\t\t\t\t\t\t\ticonAnchor : [ 16, 16 ]\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t} ]\n\t\t\t}).addTo(map);\n\n}\n\nfunction createLine(arrow) {\n\n\tvar arrowHead = L.polylineDecorator(arrow).addTo(map);\n\n\tvar arrowOffset = 0;\n\tvar anim = window.setInterval(function() {\n\t\tarrowHead.setPatterns([ {\n\t\t\toffset : arrowOffset + '%',\n\t\t\trepeat : 0,\n\t\t\tsymbol : L.Symbol.arrowHead({\n\t\t\t\tpixelSize : 13,\n\t\t\t\tpolygon : false,\n\t\t\t\tpathOptions : {\n\t\t\t\t\tstroke : true\n\t\t\t\t}\n\t\t\t})\n\t\t} ]);\n\t\tif (++arrowOffset > 100)\n\t\t\tarrowOffset = 0;\n\t}, 200);\n\n}\n\nfunction addHistogram(provinceMap) {\n\tif (removeHistogram) {\n\t\tthis.histogramLayer = new L.FeatureGroup();\n\t\tvar myIcon = L\n\t\t\t\t.divIcon({\n\t\t\t\t\ticonSize : L.point(1100, 200),\n\t\t\t\t\ticonAnchor : L.point(1150, 205),\n\t\t\t\t\thtml : '<IFRAME NAME=\"content_frame\" width=100% height=100% marginwidth=0 marginheight=0 SRC=\"a.html\" ></IFRAME> '\n\t\t\t\t});\n\t\tvar beiJingMarker = L.marker([ 39.92, 116.41 ], {\n\t\t\ticon : myIcon\n\t\t}).addTo(map);\n\t\tvar myIcon1 = L.divIcon({\n\t\t\ticonSize : L.point(100, 20),\n\t\t\ticonAnchor : L.point(50, 25),\n\t\t\thtml : '山西'\n\t\t});\n\t\tvar shanxiMarker = L.marker([ 37.87, 112.54 ], {\n\t\t\ticon : myIcon1\n\t\t}).addTo(map);\n\t\tvar myIcon2 = L.divIcon({\n\t\t\ticonSize : L.point(100, 20),\n\t\t\ticonAnchor : L.point(50, 25),\n\t\t\thtml : '内蒙古'\n\t\t});\n\t\tvar neimenggugMarker = L.marker([ 40.86, 111.75 ], {\n\t\t\ticon : myIcon2\n\t\t}).addTo(map);\n\t\tvar myIcon3 = L.divIcon({\n\t\t\ticonSize : L.point(100, 20),\n\t\t\ticonAnchor : L.point(50, 25),\n\t\t\thtml : '河北'\n\t\t});\n\t\tvar hebeiMarker = L.marker([ 38.07, 114.50 ], {\n\t\t\ticon : myIcon3\n\t\t}).addTo(map);\n\t\tvar myIcon4 = L.divIcon({\n\t\t\ticonSize : L.point(100, 20),\n\t\t\ticonAnchor : L.point(50, 25),\n\t\t\thtml : '山东'\n\t\t});\n\t\tvar shandongMarker = L.marker([ 36.72, 117.09 ], {\n\t\t\ticon : myIcon4\n\t\t}).addTo(map);\n\t\thistogramLayer.addLayer(beiJingMarker, shanxiMarker, neimenggugMarker,\n\t\t\t\thebeiMarker, shandongMarker);\n\t\tmap.addLayer(histogramLayer);\n\t}\n}\nfunction removeHistogram() {\n\tif (histogramLayer) {\n\t\tmap.removeLayer(this.histogramLayer);\n\t}\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/base/base_map.js",
    "content": "var map;\nvar zTree;\nvar markerArray = new Array();\nvar routeLayer = null;\nfunction initMap(mapServerUrl) {\n\tvar funcLayer = new L.TileLayer.Functional(function (view) {\n\tvar url = \"http://gisdata.enilu.cn\"+'/{z}/{y}/{x}.png'\n\t\t.replace('{z}', \"L\" +(parseInt(view.zoom)<10?(\"0\"+view.zoom):view.zoom))\n\t\t.replace('{x}', (function(){\n\t\t\t\t\t\t\tvar x = parseInt(view.tile.column, 10).toString(16)\n\t\t\t\t\t\t\tif(x.length < 8){\n\t\t\t\t\t\t\t\tvar k = x.length;\n\t\t\t\t\t\t\t\tfor(var i = 0; i < 8 - k;i++){\n\t\t\t\t\t\t\t\t\tx = \"0\" + x;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tx = \"C\" + x;\n\t\t\t\t\t\t\t//console.log(x + \"  length :\" + x.length);\n\t\t\t\t\t\t\treturn x.toUpperCase();\n\t\t\t\t\t\t})())\n\t\t.replace('{y}', (function(){\n\t\t\t\t\t\t\tvar y = parseInt(view.tile.row, 10).toString(16)\n\t\t\t\t\t\t\tif(y.length < 8){\n\t\t\t\t\t\t\t\tvar k = y.length;\n\t\t\t\t\t\t\t\tfor(var i = 0; i < 8 - k;i++){\n\t\t\t\t\t\t\t\t\ty = \"0\" + y;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ty = \"R\" + y;\n\t\t\t\t\t\t\treturn y.toUpperCase();\n\t\t\t\t\t\t})())\n\t\t.replace('{s}', view.subdomain);\n\treturn url;\n}, {\n\tsubdomains: '1234',opacity:1\n});\n\t\nmap = L.map('map', {\n    center: [39.918, 116.38],\n    zoom: 5,\n    zoomControl:false,\n    layers: [funcLayer]\t,\n    maxZoom : 16,\n    minZoom:4,\n    maxBounds:[[85.03,-179.82],[-85,179.82]]\n});\n\nvar baseLayers = {\n    \"Google量地图\": funcLayer\n};\t\t\nrouteLayer = L.layerGroup().addTo(map);\nL.control.layers(baseLayers).addTo(map);\nvar drawnItems = new L.FeatureGroup();\nmap.addLayer(drawnItems);\n\nvar drawControl = new L.Control.Draw({\n\tdraw: {\n\t\tposition: 'topleft',\n\t\tpolygon: {\n\t\t\ttitle: '多边形!',\n\t\t\tallowIntersection: false,\n\t\t\tdrawError: {\n\t\t\t\tcolor: '#b00b00',\n\t\t\t\ttimeout: 1000\n\t\t\t},\n\t\t\tshapeOptions: {\n\t\t\t\tcolor: 'blue'\n\t\t\t},\n\t\t\tshowArea: true\n\t\t},\n\t\tpolyline: {\n\t\t\tmetric: false\n\t\t},\n\t\tcircle: {\n\t\t\tshapeOptions: {\n\t\t\t\tcolor: '#662d91'\n\t\t\t}\n\t\t}\n\t}\n});\nmap.addControl(drawControl);\n\nmap.on('draw:created', function (e) {\n\tvar type = e.layerType,\n\t\tlayer = e.layer;\n\n\tdrawnItems.addLayer(layer);\n});\n\nmap.on(\"zoomstart\", function(e){\n});\n\nmap.on(\"zoomend\", function(e){\n\t\tvar zoom = e.target._zoom;\n\t\tvar items = null;\n\t\tif(parseInt(zoom) <=5 ){//全国\n\n\t\t\n\n\t\t} else if(parseInt(zoom) >=5&&parseInt(zoom) <=7){//省级\n\n\t\t}else{//市级\n\t\t}\n\n});\n}\n\n//增加地图点击事件\nfunction addMapClickEvent(){\n\tmap.on(\"click\", function(e){\n\t\tclickMap(e.latlng.lat,e.latlng.lng);\n\t});\n}\n//移除地图点击事件\nfunction remMapClickEvent(){\n\tmap.off(\"click\");\n}\n\n\nfunction dingwei(lat,lng,zoom){\n\tmap.panTo(L.latLng(lat, lng));\n\tmap.setZoom(zoom);\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/base/base_tilesUtils.js",
    "content": "//叠加点数量多 用 叠加点图层方式\nfunction drawPointTile(table,where){\n\t   var url = 'wms/drawTitles?x={x}&y={y}&z={z}&table='+table+\"&where=\"+where;\n\t   var layName = 'pointTitle';\n\t   addTiles(url,layName);\n}\n\n\n//根据tileUrl 返回瓦片图\nvar keyList = new Array();//存储数节点的key值\nvar layerList = new Array();//存储对应key的layer\n\n//titleUrl 请求地址，key 图层名称\nfunction  addTiles(tileUrl, key){\n\tif(key=='404'){\n\t\taddHistogram();\n       return;\n\t}\n\tvar tilesLayer = L.tileLayer(tileUrl, {\n\t\tmaxZoom : 18,\n\t    zIndex:20\n\t});\n\tvar flag = false;\n\tfor(var i=0; i<keyList.length; i++){\n\t\tif(keyList[i] == key){\n\t\t\tlayerList[i] = tilesLayer;\n\t\t\tflag = true;\n\t\t}\n\t}\n\tif(!flag){\n\t\tkeyList.push(key);\n\t\tlayerList.push(tilesLayer);\n\t}\n\tmap.addLayer(tilesLayer);\n\treturn tilesLayer;\n}\n\n//移除叠加的瓦片图层\nfunction removeTiles(key){\n\tif(key=='404'){\n\t\tremoveHistogram();\n       return;\n\t}\n\tfor(var i=0; i<keyList.length; i++){\n\t\tif(keyList[i] == key){\n\t\t\tmap.removeLayer(layerList[i]);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/LMapLib.js",
    "content": "\nvar LMapLib = window.LMapLib = LMapLib || {};\n\n(function() {\n    \n    var POINT_COUNT = 100; // 曲线是由一些小的线段组成的，这个表示这个曲线所有到的折线的个数\n    var CurveLine =\n\n        LMapLib.CurveLine = function(points, opts, pointCount){\n            if(pointCount && pointCount > 0){\n                POINT_COUNT = pointCount;\n            }\n            var curvePoints = getCurvePoints(points);\n            var polyline = new L.Polyline(curvePoints, opts);\n            return polyline;\n        }\n\n        /**\n         * 根据弧线的坐标节点数组\n         */\n        getCurvePoints = function(points) {\n            var curvePoints = [];\n            for (var i = 0; i < points.length - 1; i++) {\n                var p = getCurveByTwoPoints(points[i], points[i + 1]);\n                if (p && p.length > 0) {\n                    curvePoints = curvePoints.concat(p);\n                }\n            }\n            return curvePoints;\n        }\n\n        /**\n         * 根据两点获取曲线坐标点数组\n         * @param Point 起点\n         * @param Point 终点\n         */\n        getCurveByTwoPoints = function(obj1, obj2) {\n            if (!obj1 || !obj2 || !(obj1 instanceof L.LatLng) || !(obj2 instanceof L.LatLng)) {\n                return null;\n            }\n\n            var B1 = function(x) {\n                return 1 - 2 * x + x * x;\n            };\n            var B2 = function(x) {\n                return 2 * x - 2 * x * x;\n            };\n            var B3 = function(x) {\n                return x * x;\n            };\n\n            curveCoordinates = [];\n\n           \n            var isFuture=false;\n            var t, h, h2, lat3, lng3, j, t2;\n            var LnArray = [];\n            var i = 0;\n            var inc = 0;\n\n            if (typeof(obj2) == \"undefined\") {\n                if (typeof(curveCoordinates) != \"undefined\") {\n                    curveCoordinates = [];\n                }\n                return;\n            }\n\n            var lat1 = parseFloat(obj1.lat);\n            var lat2 = parseFloat(obj2.lat);\n            var lng1 = parseFloat(obj1.lng);\n            var lng2 = parseFloat(obj2.lng);\n                \n            // 计算曲线角度的方法\n            if (lng2 > lng1) {\n                if (parseFloat(lng2-lng1) > 180) {\n                    if (lng1 < 0) {\n                        lng1 = parseFloat(180 + 180 + lng1);\n                    }\n                }\n            }\n            \n            if (lng1 > lng2) {\n                if (parseFloat(lng1-lng2) > 180) {\n                    if (lng2 < 0) {\n                        lng2 = parseFloat(180 + 180 + lng2);\n                    }\n                }\n            }\n            j = 0;\n            t2 = 0;\n            if (lat2 == lat1) {\n                t = 0;\n                h = lng1 - lng2;\n            } else if (lng2 == lng1) {\n                t = Math.PI / 2;\n                h = lat1 - lat2;\n            } else {\n                t = Math.atan((lat2 - lat1) / (lng2 - lng1));\n                h = (lat2 - lat1) / Math.sin(t);\n            }\n            if (t2 == 0) {\n                t2 = (t + (Math.PI / 5));\n            }\n            h2 = h / 2;\n            lng3 = h2 * Math.cos(t2) + lng1;\n            lat3 = h2 * Math.sin(t2) + lat1;\n\n            for (i = 0; i < POINT_COUNT + 1; i++) {\n                curveCoordinates.push(L.latLng(\n                    (lat1 * B1(inc) + lat3 * B2(inc) + lat2 * B3(inc)),\n                    (lng1 * B1(inc) + lng3 * B2(inc)) + lng2 * B3(inc)\n                    \n                ));\n                inc = inc + (1 / POINT_COUNT);\n            }\n            return curveCoordinates;\n        }\n\n        /**\n         * 获取弧线的坐标点\n         */\n        function getPath() {\n            return this.points;\n        }\n\n})();\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet/leaflet.css",
    "content": "/* required styles */\n\n.leaflet-map-pane,\n.leaflet-tile,\n.leaflet-marker-icon,\n.leaflet-marker-shadow,\n.leaflet-tile-pane,\n.leaflet-tile-container,\n.leaflet-overlay-pane,\n.leaflet-shadow-pane,\n.leaflet-marker-pane,\n.leaflet-popup-pane,\n.leaflet-overlay-pane svg,\n.leaflet-zoom-box,\n.leaflet-image-layer,\n.leaflet-layer {\n\tposition: absolute;\n\tleft: 0;\n\ttop: 0;\n\t}\n.leaflet-container {\n\toverflow: hidden;\n\t-ms-touch-action: none;\n\t}\n.leaflet-tile,\n.leaflet-marker-icon,\n.leaflet-marker-shadow {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t        user-select: none;\n\t-webkit-user-drag: none;\n\t}\n.leaflet-marker-icon,\n.leaflet-marker-shadow {\n\tdisplay: block;\n\t}\n/* map is broken in FF if you have max-width: 100% on tiles */\n.leaflet-container img {\n\tmax-width: none !important;\n\t}\n/* stupid Android 2 doesn't understand \"max-width: none\" properly */\n.leaflet-container img.leaflet-image-layer {\n\tmax-width: 15000px !important;\n\t}\n.leaflet-tile {\n\tfilter: inherit;\n\tvisibility: hidden;\n\t}\n.leaflet-tile-loaded {\n\tvisibility: inherit;\n\t}\n.leaflet-zoom-box {\n\twidth: 0;\n\theight: 0;\n\t}\n/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */\n.leaflet-overlay-pane svg {\n\t-moz-user-select: none;\n\t}\n\n.leaflet-tile-pane    { z-index: 2; }\n.leaflet-objects-pane { z-index: 3; }\n.leaflet-overlay-pane { z-index: 4; }\n.leaflet-shadow-pane  { z-index: 5; }\n.leaflet-marker-pane  { z-index: 6; }\n.leaflet-popup-pane   { z-index: 7; }\n\n.leaflet-vml-shape {\n\twidth: 1px;\n\theight: 1px;\n\t}\n.lvml {\n\tbehavior: url(#default#VML);\n\tdisplay: inline-block;\n\tposition: absolute;\n\t}\n\n\n/* control positioning */\n\n.leaflet-control {\n\tposition: relative;\n\tz-index: 7;\n\tpointer-events: auto;\n\t}\n.leaflet-top,\n.leaflet-bottom {\n\tposition: absolute;\n\tz-index: 1000;\n\tpointer-events: none;\n\t}\n.leaflet-top {\n\ttop: 0;\n\t}\n.leaflet-right {\n\tright: 0;\n\t}\n.leaflet-bottom {\n\tbottom: 0;\n\t}\n.leaflet-left {\n\tleft: 0;\n\t}\n.leaflet-control {\n\tfloat: left;\n\tclear: both;\n\t}\n.leaflet-right .leaflet-control {\n\tfloat: right;\n\t}\n.leaflet-top .leaflet-control {\n\tmargin-top: 10px;\n\t}\n.leaflet-bottom .leaflet-control {\n\tmargin-bottom: 10px;\n\t}\n.leaflet-left .leaflet-control {\n\tmargin-left: 10px;\n\t}\n.leaflet-right .leaflet-control {\n\tmargin-right: 10px;\n\t}\n\n\n/* zoom and fade animations */\n\n.leaflet-fade-anim .leaflet-tile,\n.leaflet-fade-anim .leaflet-popup {\n\topacity: 0;\n\t-webkit-transition: opacity 0.2s linear;\n\t   -moz-transition: opacity 0.2s linear;\n\t     -o-transition: opacity 0.2s linear;\n\t        transition: opacity 0.2s linear;\n\t}\n.leaflet-fade-anim .leaflet-tile-loaded,\n.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {\n\topacity: 1;\n\t}\n\n.leaflet-zoom-anim .leaflet-zoom-animated {\n\t-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);\n\t   -moz-transition:    -moz-transform 0.25s cubic-bezier(0,0,0.25,1);\n\t     -o-transition:      -o-transform 0.25s cubic-bezier(0,0,0.25,1);\n\t        transition:         transform 0.25s cubic-bezier(0,0,0.25,1);\n\t}\n.leaflet-zoom-anim .leaflet-tile,\n.leaflet-pan-anim .leaflet-tile,\n.leaflet-touching .leaflet-zoom-animated {\n\t-webkit-transition: none;\n\t   -moz-transition: none;\n\t     -o-transition: none;\n\t        transition: none;\n\t}\n\n.leaflet-zoom-anim .leaflet-zoom-hide {\n\tvisibility: hidden;\n\t}\n\n\n/* cursors */\n\n.leaflet-clickable {\n\tcursor: pointer;\n\t}\n.leaflet-container {\n\tcursor: -webkit-grab;\n\tcursor:    -moz-grab;\n\t}\n.leaflet-popup-pane,\n.leaflet-control {\n\tcursor: auto;\n\t}\n.leaflet-dragging .leaflet-container,\n.leaflet-dragging .leaflet-clickable {\n\tcursor: move;\n\tcursor: -webkit-grabbing;\n\tcursor:    -moz-grabbing;\n\t}\n\n\n/* visual tweaks */\n\n.leaflet-container {\n\tbackground: #ddd;\n\toutline: 0;\n\t}\n.leaflet-container a {\n\tcolor: #0078A8;\n\t}\n.leaflet-container a.leaflet-active {\n\toutline: 2px solid orange;\n\t}\n.leaflet-zoom-box {\n\tborder: 2px dotted #38f;\n\tbackground: rgba(255,255,255,0.5);\n\t}\n\n\n/* general typography */\n.leaflet-container {\n\tfont: 12px/1.5 \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n\t}\n\n\n/* general toolbar styles */\n\n.leaflet-bar {\n\tbox-shadow: 0 1px 5px rgba(0,0,0,0.65);\n\tborder-radius: 4px;\n\t}\n.leaflet-bar a,\n.leaflet-bar a:hover {\n\tbackground-color: #fff;\n\tborder-bottom: 1px solid #ccc;\n\twidth: 26px;\n\theight: 26px;\n\tline-height: 26px;\n\tdisplay: block;\n\ttext-align: center;\n\ttext-decoration: none;\n\tcolor: black;\n\t}\n.leaflet-bar a,\n.leaflet-control-layers-toggle {\n\tbackground-position: 50% 50%;\n\tbackground-repeat: no-repeat;\n\tdisplay: block;\n\t}\n.leaflet-bar a:hover {\n\tbackground-color: #f4f4f4;\n\t}\n.leaflet-bar a:first-child {\n\tborder-top-left-radius: 4px;\n\tborder-top-right-radius: 4px;\n\t}\n.leaflet-bar a:last-child {\n\tborder-bottom-left-radius: 4px;\n\tborder-bottom-right-radius: 4px;\n\tborder-bottom: none;\n\t}\n.leaflet-bar a.leaflet-disabled {\n\tcursor: default;\n\tbackground-color: #f4f4f4;\n\tcolor: #bbb;\n\t}\n\n.leaflet-touch .leaflet-bar a {\n\twidth: 30px;\n\theight: 30px;\n\tline-height: 30px;\n\t}\n\n\n/* zoom control */\n\n.leaflet-control-zoom-in,\n.leaflet-control-zoom-out {\n\tfont: bold 18px 'Lucida Console', Monaco, monospace;\n\ttext-indent: 1px;\n\t}\n.leaflet-control-zoom-out {\n\tfont-size: 20px;\n\t}\n\n.leaflet-touch .leaflet-control-zoom-in {\n\tfont-size: 22px;\n\t}\n.leaflet-touch .leaflet-control-zoom-out {\n\tfont-size: 24px;\n\t}\n\n\n/* layers control */\n\n.leaflet-control-layers {\n\tbox-shadow: 0 1px 5px rgba(0,0,0,0.4);\n\tbackground: #fff;\n\tborder-radius: 5px;\n\t}\n.leaflet-control-layers-toggle {\n\tbackground-image: url(images/layers.png);\n\twidth: 36px;\n\theight: 36px;\n\t}\n.leaflet-retina .leaflet-control-layers-toggle {\n\tbackground-image: url(images/layers-2x.png);\n\tbackground-size: 26px 26px;\n\t}\n.leaflet-touch .leaflet-control-layers-toggle {\n\twidth: 44px;\n\theight: 44px;\n\t}\n.leaflet-control-layers .leaflet-control-layers-list,\n.leaflet-control-layers-expanded .leaflet-control-layers-toggle {\n\tdisplay: none;\n\t}\n.leaflet-control-layers-expanded .leaflet-control-layers-list {\n\tdisplay: block;\n\tposition: relative;\n\t}\n.leaflet-control-layers-expanded {\n\tpadding: 6px 10px 6px 6px;\n\tcolor: #333;\n\tbackground: #fff;\n\t}\n.leaflet-control-layers-selector {\n\tmargin-top: 2px;\n\tposition: relative;\n\ttop: 1px;\n\t}\n.leaflet-control-layers label {\n\tdisplay: block;\n\t}\n.leaflet-control-layers-separator {\n\theight: 0;\n\tborder-top: 1px solid #ddd;\n\tmargin: 5px -10px 5px -6px;\n\t}\n\n\n/* attribution and scale controls */\n\n.leaflet-container .leaflet-control-attribution {\n\tbackground: #fff;\n\tbackground: rgba(255, 255, 255, 0.7);\n\tmargin: 0;\n\t}\n.leaflet-control-attribution,\n.leaflet-control-scale-line {\n\tpadding: 0 5px;\n\tcolor: #333;\n\t}\n.leaflet-control-attribution a {\n\ttext-decoration: none;\n\t}\n.leaflet-control-attribution a:hover {\n\ttext-decoration: underline;\n\t}\n.leaflet-container .leaflet-control-attribution,\n.leaflet-container .leaflet-control-scale {\n\tfont-size: 11px;\n\t}\n.leaflet-left .leaflet-control-scale {\n\tmargin-left: 5px;\n\t}\n.leaflet-bottom .leaflet-control-scale {\n\tmargin-bottom: 5px;\n\t}\n.leaflet-control-scale-line {\n\tborder: 2px solid #777;\n\tborder-top: none;\n\tline-height: 1.1;\n\tpadding: 2px 5px 1px;\n\tfont-size: 11px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\t-moz-box-sizing: content-box;\n\t     box-sizing: content-box;\n\n\tbackground: #fff;\n\tbackground: rgba(255, 255, 255, 0.5);\n\t}\n.leaflet-control-scale-line:not(:first-child) {\n\tborder-top: 2px solid #777;\n\tborder-bottom: none;\n\tmargin-top: -2px;\n\t}\n.leaflet-control-scale-line:not(:first-child):not(:last-child) {\n\tborder-bottom: 2px solid #777;\n\t}\n\n.leaflet-touch .leaflet-control-attribution,\n.leaflet-touch .leaflet-control-layers,\n.leaflet-touch .leaflet-bar {\n\tbox-shadow: none;\n\t}\n.leaflet-touch .leaflet-control-layers,\n.leaflet-touch .leaflet-bar {\n\tborder: 2px solid rgba(0,0,0,0.2);\n\tbackground-clip: padding-box;\n\t}\n\n\n/* popup */\n\n.leaflet-popup {\n\tposition: absolute;\n\ttext-align: center;\n\t}\n.leaflet-popup-content-wrapper {\n\tpadding: 1px;\n\ttext-align: left;\n\tborder-radius: 12px;\n\t}\n.leaflet-popup-content {\n\tmargin: 13px 19px;\n\tline-height: 1.4;\n\t}\n.leaflet-popup-content p {\n\tmargin: 18px 0;\n\t}\n.leaflet-popup-tip-container {\n\tmargin: 0 auto;\n\twidth: 40px;\n\theight: 20px;\n\tposition: relative;\n\toverflow: hidden;\n\t}\n.leaflet-popup-tip {\n\twidth: 17px;\n\theight: 17px;\n\tpadding: 1px;\n\n\tmargin: -10px auto 0;\n\n\t-webkit-transform: rotate(45deg);\n\t   -moz-transform: rotate(45deg);\n\t    -ms-transform: rotate(45deg);\n\t     -o-transform: rotate(45deg);\n\t        transform: rotate(45deg);\n\t}\n.leaflet-popup-content-wrapper,\n.leaflet-popup-tip {\n\tbackground: white;\n\n\tbox-shadow: 0 3px 14px rgba(0,0,0,0.4);\n\t}\n.leaflet-container a.leaflet-popup-close-button {\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tpadding: 4px 4px 0 0;\n\ttext-align: center;\n\twidth: 18px;\n\theight: 14px;\n\tfont: 16px/14px Tahoma, Verdana, sans-serif;\n\tcolor: #c3c3c3;\n\ttext-decoration: none;\n\tfont-weight: bold;\n\tbackground: transparent;\n\t}\n.leaflet-container a.leaflet-popup-close-button:hover {\n\tcolor: #999;\n\t}\n.leaflet-popup-scrolled {\n\toverflow: auto;\n\tborder-bottom: 1px solid #ddd;\n\tborder-top: 1px solid #ddd;\n\t}\n\n.leaflet-oldie .leaflet-popup-content-wrapper {\n\tzoom: 1;\n\t}\n.leaflet-oldie .leaflet-popup-tip {\n\twidth: 24px;\n\tmargin: 0 auto;\n\n\t-ms-filter: \"progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)\";\n\tfilter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);\n\t}\n.leaflet-oldie .leaflet-popup-tip-container {\n\tmargin-top: -1px;\n\t}\n\n.leaflet-oldie .leaflet-control-zoom,\n.leaflet-oldie .leaflet-control-layers,\n.leaflet-oldie .leaflet-popup-content-wrapper,\n.leaflet-oldie .leaflet-popup-tip {\n\tborder: 1px solid #999;\n\t}\n\n\n/* div icon */\n\n.leaflet-div-icon {\n\tbackground: #fff;\n\tborder: 1px solid #666;\n\t}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet/leaflet.functionaltilelayer.js",
    "content": "L.TileLayer.Functional = L.TileLayer.extend({\n\n  _tileFunction: null,\n\n  initialize: function (tileFunction, options) {\n    this._tileFunction = tileFunction;\n    L.Util.setOptions(this, options);\n  },\n\n  getTileUrl: function (tilePoint) {\n    // Note: bbox code untested; pulled from TileLayer.WMS\n    var map = this._map,\n        crs = map.options.crs,\n        tileSize = this.options.tileSize,\n        zoom = this._map.getZoom(),\n        nwPoint = tilePoint.multiplyBy(tileSize),\n        sePoint = nwPoint.add(new L.Point(tileSize, tileSize)),\n        nw = crs.project(map.unproject(nwPoint, zoom)),\n        se = crs.project(map.unproject(sePoint, zoom)),\n        bbox = [nw.x, se.y, se.x, nw.y].join(','),\n        view = {\n          bbox: bbox,\n          width: tileSize,\n          height: tileSize,\n          zoom: zoom,\n          tile: {\n            row: tilePoint.y,\n            column: tilePoint.x\n          },\n          subdomain: this._getSubdomain(tilePoint)\n        };\n\n    return this._tileFunction(view);\n  },\n\n  _loadTile: function (tile, tilePoint) {\n    var tileUrl = this.getTileUrl(tilePoint);\n\n    tile._layer = this;\n    tile.onload = this._tileOnLoad;\n    tile.onerror = this._tileOnError;\n\n    if (typeof tileUrl === \"string\") {\n      tile.src = tileUrl;\n    } else if (tileUrl) {\n      // assume jQuery.Deferred\n      tileUrl.done(function (tileUrl) {\n        tile.src = tileUrl;\n      });\n    }\n  }\n});\n\nL.tileLayer.functional = function (tileFunction, options) {\n  return new L.TileLayer.Functional(tileFunction, options);\n};"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet/leaflet.js",
    "content": "/*\n Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com\n (c) 2010-2013, Vladimir Agafonkin\n (c) 2010-2011, CloudMade\n*/\n!function(t,e,i){var n=t.L,o={};o.version=\"0.7-dev\",\"object\"==typeof module&&\"object\"==typeof module.exports?module.exports=o:\"function\"==typeof define&&define.amd&&define(o),o.noConflict=function(){return t.L=n,this},t.L=o,o.Util={extend:function(t){var e,i,n,o,s=Array.prototype.slice.call(arguments,1);for(i=0,n=s.length;n>i;i++){o=s[i]||{};for(e in o)o.hasOwnProperty(e)&&(t[e]=o[e])}return t},bind:function(t,e){var i=arguments.length>2?Array.prototype.slice.call(arguments,2):null;return function(){return t.apply(e,i||arguments)}},stamp:function(){var t=0,e=\"_leaflet_id\";return function(i){return i[e]=i[e]||++t,i[e]}}(),invokeEach:function(t,e,i){var n,o;if(\"object\"==typeof t){o=Array.prototype.slice.call(arguments,3);for(n in t)e.apply(i,[n,t[n]].concat(o));return!0}return!1},limitExecByInterval:function(t,e,i){var n,o;return function s(){var a=arguments;return n?(o=!0,void 0):(n=!0,setTimeout(function(){n=!1,o&&(s.apply(i,a),o=!1)},e),t.apply(i,a),void 0)}},falseFn:function(){return!1},formatNum:function(t,e){var i=Math.pow(10,e||5);return Math.round(t*i)/i},trim:function(t){return t.trim?t.trim():t.replace(/^\\s+|\\s+$/g,\"\")},splitWords:function(t){return o.Util.trim(t).split(/\\s+/)},setOptions:function(t,e){return t.options=o.extend({},t.options,e),t.options},getParamString:function(t,e,i){var n=[];for(var o in t)n.push(encodeURIComponent(i?o.toUpperCase():o)+\"=\"+encodeURIComponent(t[o]));return(e&&-1!==e.indexOf(\"?\")?\"&\":\"?\")+n.join(\"&\")},template:function(t,e){return t.replace(/\\{ *([\\w_]+) *\\}/g,function(t,n){var o=e[n];if(o===i)throw new Error(\"No value provided for variable \"+t);return\"function\"==typeof o&&(o=o(e)),o})},isArray:function(t){return\"[object Array]\"===Object.prototype.toString.call(t)},emptyImageUrl:\"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=\"},function(){function e(e){var i,n,o=[\"webkit\",\"moz\",\"o\",\"ms\"];for(i=0;i<o.length&&!n;i++)n=t[o[i]+e];return n}function i(e){var i=+new Date,o=Math.max(0,16-(i-n));return n=i+o,t.setTimeout(e,o)}var n=0,s=t.requestAnimationFrame||e(\"RequestAnimationFrame\")||i,a=t.cancelAnimationFrame||e(\"CancelAnimationFrame\")||e(\"CancelRequestAnimationFrame\")||function(e){t.clearTimeout(e)};o.Util.requestAnimFrame=function(e,n,a,r){return e=o.bind(e,n),a&&s===i?(e(),void 0):s.call(t,e,r)},o.Util.cancelAnimFrame=function(e){e&&a.call(t,e)}}(),o.extend=o.Util.extend,o.bind=o.Util.bind,o.stamp=o.Util.stamp,o.setOptions=o.Util.setOptions,o.Class=function(){},o.Class.extend=function(t){var e=function(){this.initialize&&this.initialize.apply(this,arguments),this._initHooks&&this.callInitHooks()},i=function(){};i.prototype=this.prototype;var n=new i;n.constructor=e,e.prototype=n;for(var s in this)this.hasOwnProperty(s)&&\"prototype\"!==s&&(e[s]=this[s]);t.statics&&(o.extend(e,t.statics),delete t.statics),t.includes&&(o.Util.extend.apply(null,[n].concat(t.includes)),delete t.includes),t.options&&n.options&&(t.options=o.extend({},n.options,t.options)),o.extend(n,t),n._initHooks=[];var a=this;return e.__super__=a.prototype,n.callInitHooks=function(){if(!this._initHooksCalled){a.prototype.callInitHooks&&a.prototype.callInitHooks.call(this),this._initHooksCalled=!0;for(var t=0,e=n._initHooks.length;e>t;t++)n._initHooks[t].call(this)}},e},o.Class.include=function(t){o.extend(this.prototype,t)},o.Class.mergeOptions=function(t){o.extend(this.prototype.options,t)},o.Class.addInitHook=function(t){var e=Array.prototype.slice.call(arguments,1),i=\"function\"==typeof t?t:function(){this[t].apply(this,e)};this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(i)};var s=\"_leaflet_events\";o.Mixin={},o.Mixin.Events={addEventListener:function(t,e,i){if(o.Util.invokeEach(t,this.addEventListener,this,e,i))return this;var n,a,r,h,l,u,c,d=this[s]=this[s]||{},p=i&&o.stamp(i);for(t=o.Util.splitWords(t),n=0,a=t.length;a>n;n++)r={action:e,context:i||this},h=t[n],i?(l=h+\"_idx\",u=l+\"_len\",c=d[l]=d[l]||{},c[p]||(c[p]=[],d[u]=(d[u]||0)+1),c[p].push(r)):(d[h]=d[h]||[],d[h].push(r));return this},hasEventListeners:function(t){var e=this[s];return!!e&&(t in e&&e[t].length>0||t+\"_idx\"in e&&e[t+\"_idx_len\"]>0)},removeEventListener:function(t,e,i){if(!this[s])return this;if(!t)return this.clearAllEventListeners();if(o.Util.invokeEach(t,this.removeEventListener,this,e,i))return this;var n,a,r,h,l,u,c,d,p,_=this[s],m=i&&o.stamp(i);for(t=o.Util.splitWords(t),n=0,a=t.length;a>n;n++)if(r=t[n],u=r+\"_idx\",c=u+\"_len\",d=_[u],e){if(h=i&&d?d[m]:_[r]){for(l=h.length-1;l>=0;l--)h[l].action!==e||i&&h[l].context!==i||(p=h.splice(l,1),p[0].action=o.Util.falseFn);i&&d&&0===h.length&&(delete d[m],_[c]--)}}else delete _[r],delete _[u];return this},clearAllEventListeners:function(){return delete this[s],this},fireEvent:function(t,e){if(!this.hasEventListeners(t))return this;var i,n,a,r,h,l=o.Util.extend({},e,{type:t,target:this}),u=this[s];if(u[t])for(i=u[t].slice(),n=0,a=i.length;a>n;n++)i[n].action.call(i[n].context||this,l);r=u[t+\"_idx\"];for(h in r)if(i=r[h].slice())for(n=0,a=i.length;a>n;n++)i[n].action.call(i[n].context||this,l);return this},addOneTimeEventListener:function(t,e,i){if(o.Util.invokeEach(t,this.addOneTimeEventListener,this,e,i))return this;var n=o.bind(function(){this.removeEventListener(t,e,i).removeEventListener(t,n,i)},this);return this.addEventListener(t,e,i).addEventListener(t,n,i)}},o.Mixin.Events.on=o.Mixin.Events.addEventListener,o.Mixin.Events.off=o.Mixin.Events.removeEventListener,o.Mixin.Events.once=o.Mixin.Events.addOneTimeEventListener,o.Mixin.Events.fire=o.Mixin.Events.fireEvent,function(){var n=!!t.ActiveXObject,s=n&&!t.XMLHttpRequest,a=n&&!e.querySelector,r=n&&!e.addEventListener,h=navigator.userAgent.toLowerCase(),l=-1!==h.indexOf(\"webkit\"),u=-1!==h.indexOf(\"chrome\"),c=-1!==h.indexOf(\"phantom\"),d=-1!==h.indexOf(\"android\"),p=-1!==h.search(\"android [23]\"),_=typeof orientation!=i+\"\",m=t.navigator&&t.navigator.msPointerEnabled&&t.navigator.msMaxTouchPoints,f=\"devicePixelRatio\"in t&&t.devicePixelRatio>1||\"matchMedia\"in t&&t.matchMedia(\"(min-resolution:144dpi)\")&&t.matchMedia(\"(min-resolution:144dpi)\").matches,g=e.documentElement,v=n&&\"transition\"in g.style,y=\"WebKitCSSMatrix\"in t&&\"m11\"in new t.WebKitCSSMatrix,L=\"MozPerspective\"in g.style,P=\"OTransition\"in g.style,x=!t.L_DISABLE_3D&&(v||y||L||P)&&!c,w=!t.L_NO_TOUCH&&!c&&function(){var t=\"ontouchstart\";if(m||t in g)return!0;var i=e.createElement(\"div\"),n=!1;return i.setAttribute?(i.setAttribute(t,\"return;\"),\"function\"==typeof i[t]&&(n=!0),i.removeAttribute(t),i=null,n):!1}();o.Browser={ie:n,ie6:s,ie7:a,ielt9:r,webkit:l,android:d,android23:p,chrome:u,ie3d:v,webkit3d:y,gecko3d:L,opera3d:P,any3d:x,mobile:_,mobileWebkit:_&&l,mobileWebkit3d:_&&y,mobileOpera:_&&t.opera,touch:w,msTouch:m,retina:f}}(),o.Point=function(t,e,i){this.x=i?Math.round(t):t,this.y=i?Math.round(e):e},o.Point.prototype={clone:function(){return new o.Point(this.x,this.y)},add:function(t){return this.clone()._add(o.point(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(o.point(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},distanceTo:function(t){t=o.point(t);var e=t.x-this.x,i=t.y-this.y;return Math.sqrt(e*e+i*i)},equals:function(t){return t=o.point(t),t.x===this.x&&t.y===this.y},contains:function(t){return t=o.point(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return\"Point(\"+o.Util.formatNum(this.x)+\", \"+o.Util.formatNum(this.y)+\")\"}},o.point=function(t,e,n){return t instanceof o.Point?t:o.Util.isArray(t)?new o.Point(t[0],t[1]):t===i||null===t?t:new o.Point(t,e,n)},o.Bounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;o>n;n++)this.extend(i[n])},o.Bounds.prototype={extend:function(t){return t=o.point(t),this.min||this.max?(this.min.x=Math.min(t.x,this.min.x),this.max.x=Math.max(t.x,this.max.x),this.min.y=Math.min(t.y,this.min.y),this.max.y=Math.max(t.y,this.max.y)):(this.min=t.clone(),this.max=t.clone()),this},getCenter:function(t){return new o.Point((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t)},getBottomLeft:function(){return new o.Point(this.min.x,this.max.y)},getTopRight:function(){return new o.Point(this.max.x,this.min.y)},getSize:function(){return this.max.subtract(this.min)},contains:function(t){var e,i;return t=\"number\"==typeof t[0]||t instanceof o.Point?o.point(t):o.bounds(t),t instanceof o.Bounds?(e=t.min,i=t.max):e=i=t,e.x>=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,a=s.x>=e.x&&n.x<=i.x,r=s.y>=e.y&&n.y<=i.y;return a&&r},isValid:function(){return!(!this.min||!this.max)}},o.bounds=function(t,e){return!t||t instanceof o.Bounds?t:new o.Bounds(t,e)},o.Transformation=function(t,e,i,n){this._a=t,this._b=e,this._c=i,this._d=n},o.Transformation.prototype={transform:function(t,e){return this._transform(t.clone(),e)},_transform:function(t,e){return e=e||1,t.x=e*(this._a*t.x+this._b),t.y=e*(this._c*t.y+this._d),t},untransform:function(t,e){return e=e||1,new o.Point((t.x/e-this._b)/this._a,(t.y/e-this._d)/this._c)}},o.DomUtil={get:function(t){return\"string\"==typeof t?e.getElementById(t):t},getStyle:function(t,i){var n=t.style[i];if(!n&&t.currentStyle&&(n=t.currentStyle[i]),(!n||\"auto\"===n)&&e.defaultView){var o=e.defaultView.getComputedStyle(t,null);n=o?o[i]:null}return\"auto\"===n?null:n},getViewportOffset:function(t){var i,n=0,s=0,a=t,r=e.body,h=e.documentElement,l=o.Browser.ie7;do{if(n+=a.offsetTop||0,s+=a.offsetLeft||0,n+=parseInt(o.DomUtil.getStyle(a,\"borderTopWidth\"),10)||0,s+=parseInt(o.DomUtil.getStyle(a,\"borderLeftWidth\"),10)||0,i=o.DomUtil.getStyle(a,\"position\"),a.offsetParent===r&&\"absolute\"===i)break;if(\"fixed\"===i){n+=r.scrollTop||h.scrollTop||0,s+=r.scrollLeft||h.scrollLeft||0;break}if(\"relative\"===i&&!a.offsetLeft){var u=o.DomUtil.getStyle(a,\"width\"),c=o.DomUtil.getStyle(a,\"max-width\"),d=a.getBoundingClientRect();(\"none\"!==u||\"none\"!==c)&&(s+=d.left+a.clientLeft),n+=d.top+(r.scrollTop||h.scrollTop||0);break}a=a.offsetParent}while(a);a=t;do{if(a===r)break;n-=a.scrollTop||0,s-=a.scrollLeft||0,o.DomUtil.documentIsLtr()||!o.Browser.webkit&&!l||(s+=a.scrollWidth-a.clientWidth,l&&\"hidden\"!==o.DomUtil.getStyle(a,\"overflow-y\")&&\"hidden\"!==o.DomUtil.getStyle(a,\"overflow\")&&(s+=17)),a=a.parentNode}while(a);return new o.Point(s,n)},documentIsLtr:function(){return o.DomUtil._docIsLtrCached||(o.DomUtil._docIsLtrCached=!0,o.DomUtil._docIsLtr=\"ltr\"===o.DomUtil.getStyle(e.body,\"direction\")),o.DomUtil._docIsLtr},create:function(t,i,n){var o=e.createElement(t);return o.className=i,n&&n.appendChild(o),o},hasClass:function(t,e){return t.className.length>0&&new RegExp(\"(^|\\\\s)\"+e+\"(\\\\s|$)\").test(t.className)},addClass:function(t,e){o.DomUtil.hasClass(t,e)||(t.className+=(t.className?\" \":\"\")+e)},removeClass:function(t,e){t.className=o.Util.trim((\" \"+t.className+\" \").replace(\" \"+e+\" \",\" \"))},setOpacity:function(t,e){if(\"opacity\"in t.style)t.style.opacity=e;else if(\"filter\"in t.style){var i=!1,n=\"DXImageTransform.Microsoft.Alpha\";try{i=t.filters.item(n)}catch(o){if(1===e)return}e=Math.round(100*e),i?(i.Enabled=100!==e,i.Opacity=e):t.style.filter+=\" progid:\"+n+\"(opacity=\"+e+\")\"}},testProp:function(t){for(var i=e.documentElement.style,n=0;n<t.length;n++)if(t[n]in i)return t[n];return!1},getTranslateString:function(t){var e=o.Browser.webkit3d,i=\"translate\"+(e?\"3d\":\"\")+\"(\",n=(e?\",0\":\"\")+\")\";return i+t.x+\"px,\"+t.y+\"px\"+n},getScaleString:function(t,e){var i=o.DomUtil.getTranslateString(e.add(e.multiplyBy(-1*t))),n=\" scale(\"+t+\") \";return i+n},setPosition:function(t,e,i){t._leaflet_pos=e,!i&&o.Browser.any3d?(t.style[o.DomUtil.TRANSFORM]=o.DomUtil.getTranslateString(e),o.Browser.mobileWebkit3d&&(t.style.WebkitBackfaceVisibility=\"hidden\")):(t.style.left=e.x+\"px\",t.style.top=e.y+\"px\")},getPosition:function(t){return t._leaflet_pos}},o.DomUtil.TRANSFORM=o.DomUtil.testProp([\"transform\",\"WebkitTransform\",\"OTransform\",\"MozTransform\",\"msTransform\"]),o.DomUtil.TRANSITION=o.DomUtil.testProp([\"webkitTransition\",\"transition\",\"OTransition\",\"MozTransition\",\"msTransition\"]),o.DomUtil.TRANSITION_END=\"webkitTransition\"===o.DomUtil.TRANSITION||\"OTransition\"===o.DomUtil.TRANSITION?o.DomUtil.TRANSITION+\"End\":\"transitionend\",function(){var i=o.DomUtil.testProp([\"userSelect\",\"WebkitUserSelect\",\"OUserSelect\",\"MozUserSelect\",\"msUserSelect\"]);o.extend(o.DomUtil,{disableTextSelection:function(){if(o.DomEvent.on(t,\"selectstart\",o.DomEvent.preventDefault),i){var n=e.documentElement.style;this._userSelect=n[i],n[i]=\"none\"}},enableTextSelection:function(){o.DomEvent.off(t,\"selectstart\",o.DomEvent.preventDefault),i&&(e.documentElement.style[i]=this._userSelect,delete this._userSelect)},disableImageDrag:function(){o.DomEvent.on(t,\"dragstart\",o.DomEvent.preventDefault)},enableImageDrag:function(){o.DomEvent.off(t,\"dragstart\",o.DomEvent.preventDefault)}})}(),o.LatLng=function(t,e){var i=parseFloat(t),n=parseFloat(e);if(isNaN(i)||isNaN(n))throw new Error(\"Invalid LatLng object: (\"+t+\", \"+e+\")\");this.lat=i,this.lng=n},o.extend(o.LatLng,{DEG_TO_RAD:Math.PI/180,RAD_TO_DEG:180/Math.PI,MAX_MARGIN:1e-9}),o.LatLng.prototype={equals:function(t){if(!t)return!1;t=o.latLng(t);var e=Math.max(Math.abs(this.lat-t.lat),Math.abs(this.lng-t.lng));return e<=o.LatLng.MAX_MARGIN},toString:function(t){return\"LatLng(\"+o.Util.formatNum(this.lat,t)+\", \"+o.Util.formatNum(this.lng,t)+\")\"},distanceTo:function(t){t=o.latLng(t);var e=6378137,i=o.LatLng.DEG_TO_RAD,n=(t.lat-this.lat)*i,s=(t.lng-this.lng)*i,a=this.lat*i,r=t.lat*i,h=Math.sin(n/2),l=Math.sin(s/2),u=h*h+l*l*Math.cos(a)*Math.cos(r);return 2*e*Math.atan2(Math.sqrt(u),Math.sqrt(1-u))},wrap:function(t,e){var i=this.lng;return t=t||-180,e=e||180,i=(i+e)%(e-t)+(t>i||i===e?e:t),new o.LatLng(this.lat,i)}},o.latLng=function(t,e){return t instanceof o.LatLng?t:o.Util.isArray(t)?new o.LatLng(t[0],t[1]):t===i||null===t?t:\"object\"==typeof t&&\"lat\"in t?new o.LatLng(t.lat,\"lng\"in t?t.lng:t.lon):new o.LatLng(t,e)},o.LatLngBounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;o>n;n++)this.extend(i[n])},o.LatLngBounds.prototype={extend:function(t){return t?(t=\"number\"==typeof t[0]||\"string\"==typeof t[0]||t instanceof o.LatLng?o.latLng(t):o.latLngBounds(t),t instanceof o.LatLng?this._southWest||this._northEast?(this._southWest.lat=Math.min(t.lat,this._southWest.lat),this._southWest.lng=Math.min(t.lng,this._southWest.lng),this._northEast.lat=Math.max(t.lat,this._northEast.lat),this._northEast.lng=Math.max(t.lng,this._northEast.lng)):(this._southWest=new o.LatLng(t.lat,t.lng),this._northEast=new o.LatLng(t.lat,t.lng)):t instanceof o.LatLngBounds&&(this.extend(t._southWest),this.extend(t._northEast)),this):this},pad:function(t){var e=this._southWest,i=this._northEast,n=Math.abs(e.lat-i.lat)*t,s=Math.abs(e.lng-i.lng)*t;return new o.LatLngBounds(new o.LatLng(e.lat-n,e.lng-s),new o.LatLng(i.lat+n,i.lng+s))},getCenter:function(){return new o.LatLng((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new o.LatLng(this.getNorth(),this.getWest())},getSouthEast:function(){return new o.LatLng(this.getSouth(),this.getEast())},getWest:function(){return this._southWest.lng},getSouth:function(){return this._southWest.lat},getEast:function(){return this._northEast.lng},getNorth:function(){return this._northEast.lat},contains:function(t){t=\"number\"==typeof t[0]||t instanceof o.LatLng?o.latLng(t):o.latLngBounds(t);var e,i,n=this._southWest,s=this._northEast;return t instanceof o.LatLngBounds?(e=t.getSouthWest(),i=t.getNorthEast()):e=i=t,e.lat>=n.lat&&i.lat<=s.lat&&e.lng>=n.lng&&i.lng<=s.lng},intersects:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),a=s.lat>=e.lat&&n.lat<=i.lat,r=s.lng>=e.lng&&n.lng<=i.lng;return a&&r},toBBoxString:function(){return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(\",\")},equals:function(t){return t?(t=o.latLngBounds(t),this._southWest.equals(t.getSouthWest())&&this._northEast.equals(t.getNorthEast())):!1},isValid:function(){return!(!this._southWest||!this._northEast)}},o.latLngBounds=function(t,e){return!t||t instanceof o.LatLngBounds?t:new o.LatLngBounds(t,e)},o.Projection={},o.Projection.SphericalMercator={MAX_LATITUDE:85.0511287798,project:function(t){var e=o.LatLng.DEG_TO_RAD,i=this.MAX_LATITUDE,n=Math.max(Math.min(i,t.lat),-i),s=t.lng*e,a=n*e;return a=Math.log(Math.tan(Math.PI/4+a/2)),new o.Point(s,a)},unproject:function(t){var e=o.LatLng.RAD_TO_DEG,i=t.x*e,n=(2*Math.atan(Math.exp(t.y))-Math.PI/2)*e;return new o.LatLng(n,i)}},o.Projection.LonLat={project:function(t){return new o.Point(t.lng,t.lat)},unproject:function(t){return new o.LatLng(t.y,t.x)}},o.CRS={latLngToPoint:function(t,e){var i=this.projection.project(t),n=this.scale(e);return this.transformation._transform(i,n)},pointToLatLng:function(t,e){var i=this.scale(e),n=this.transformation.untransform(t,i);return this.projection.unproject(n)},project:function(t){return this.projection.project(t)},scale:function(t){return 256*Math.pow(2,t)}},o.CRS.Simple=o.extend({},o.CRS,{projection:o.Projection.LonLat,transformation:new o.Transformation(1,0,-1,0),scale:function(t){return Math.pow(2,t)}}),o.CRS.EPSG3857=o.extend({},o.CRS,{code:\"EPSG:3857\",projection:o.Projection.SphericalMercator,transformation:new o.Transformation(.5/Math.PI,.5,-.5/Math.PI,.5),project:function(t){var e=this.projection.project(t),i=6378137;return e.multiplyBy(i)}}),o.CRS.EPSG900913=o.extend({},o.CRS.EPSG3857,{code:\"EPSG:900913\"}),o.CRS.EPSG4326=o.extend({},o.CRS,{code:\"EPSG:4326\",projection:o.Projection.LonLat,transformation:new o.Transformation(1/360,.5,-1/360,.5)}),o.Map=o.Class.extend({includes:o.Mixin.Events,options:{crs:o.CRS.EPSG3857,fadeAnimation:o.DomUtil.TRANSITION&&!o.Browser.android23,trackResize:!0,markerZoomAnimation:o.DomUtil.TRANSITION&&o.Browser.any3d},initialize:function(t,e){e=o.setOptions(this,e),this._initContainer(t),this._initLayout(),this._initEvents(),e.maxBounds&&this.setMaxBounds(e.maxBounds),e.center&&e.zoom!==i&&this.setView(o.latLng(e.center),e.zoom,{reset:!0}),this._handlers=[],this._layers={},this._zoomBoundLayers={},this._tileLayersNum=0,this.callInitHooks(),this._addLayers(e.layers)},setView:function(t,e){return this._resetView(o.latLng(t),this._limitZoom(e)),this},setZoom:function(t,e){return this.setView(this.getCenter(),t,{zoom:e})},zoomIn:function(t,e){return this.setZoom(this._zoom+(t||1),e)},zoomOut:function(t,e){return this.setZoom(this._zoom-(t||1),e)},setZoomAround:function(t,e,i){var n=this.getZoomScale(e),s=this.getSize().divideBy(2),a=t instanceof o.Point?t:this.latLngToContainerPoint(t),r=a.subtract(s).multiplyBy(1-1/n),h=this.containerPointToLatLng(s.add(r));return this.setView(h,e,{zoom:i})},fitBounds:function(t,e){e=e||{},t=t.getBounds?t.getBounds():o.latLngBounds(t);var i=o.point(e.paddingTopLeft||e.padding||[0,0]),n=o.point(e.paddingBottomRight||e.padding||[0,0]),s=this.getBoundsZoom(t,!1,i.add(n)),a=n.subtract(i).divideBy(2),r=this.project(t.getSouthWest(),s),h=this.project(t.getNorthEast(),s),l=this.unproject(r.add(h).divideBy(2).add(a),s);return this.setView(l,s,e)},fitWorld:function(t){return this.fitBounds([[-90,-180],[90,180]],t)},panTo:function(t,e){return this.setView(t,this._zoom,{pan:e})},panBy:function(t){return this.fire(\"movestart\"),this._rawPanBy(o.point(t)),this.fire(\"move\"),this.fire(\"moveend\")},setMaxBounds:function(t,e){if(t=o.latLngBounds(t),this.options.maxBounds=t,!t)return this._boundsMinZoom=null,this.off(\"moveend\",this._panInsideMaxBounds,this),this;var i=this.getBoundsZoom(t,!0);return this._boundsMinZoom=i,this._loaded&&(this._zoom<i?this.setView(t.getCenter(),i,e):this.panInsideBounds(t)),this.on(\"moveend\",this._panInsideMaxBounds,this),this},panInsideBounds:function(t){t=o.latLngBounds(t);var e=this.getPixelBounds(),i=e.getBottomLeft(),n=e.getTopRight(),s=this.project(t.getSouthWest()),a=this.project(t.getNorthEast()),r=0,h=0;return n.y<a.y&&(h=Math.ceil(a.y-n.y)),n.x>a.x&&(r=Math.floor(a.x-n.x)),i.y>s.y&&(h=Math.floor(s.y-i.y)),i.x<s.x&&(r=Math.ceil(s.x-i.x)),r||h?this.panBy([r,h]):this},addLayer:function(t){var e=o.stamp(t);return this._layers[e]?this:(this._layers[e]=t,!t.options||isNaN(t.options.maxZoom)&&isNaN(t.options.minZoom)||(this._zoomBoundLayers[e]=t,this._updateZoomLevels()),this.options.zoomAnimation&&o.TileLayer&&t instanceof o.TileLayer&&(this._tileLayersNum++,this._tileLayersToLoad++,t.on(\"load\",this._onTileLayerLoad,this)),this._loaded&&this._layerAdd(t),this)},removeLayer:function(t){var e=o.stamp(t);if(this._layers[e])return this._loaded&&t.onRemove(this),delete this._layers[e],this._loaded&&this.fire(\"layerremove\",{layer:t}),this._zoomBoundLayers[e]&&(delete this._zoomBoundLayers[e],this._updateZoomLevels()),this.options.zoomAnimation&&o.TileLayer&&t instanceof o.TileLayer&&(this._tileLayersNum--,this._tileLayersToLoad--,t.off(\"load\",this._onTileLayerLoad,this)),this},hasLayer:function(t){return t?o.stamp(t)in this._layers:!1},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},invalidateSize:function(t){t=o.extend({animate:!1,pan:!0},t===!0?{animate:!0}:t);var e=this.getSize();if(this._sizeChanged=!0,this.options.maxBounds&&this.setMaxBounds(this.options.maxBounds),!this._loaded)return this;var i=this.getSize(),n=e.subtract(i).divideBy(2).round();return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire(\"move\"),clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(o.bind(this.fire,this,\"moveend\"),200)),this.fire(\"resize\",{oldSize:e,newSize:i})):this},addHandler:function(t,e){if(e){var i=this[t]=new e(this);return this._handlers.push(i),this.options[t]&&i.enable(),this}},remove:function(){return this._loaded&&this.fire(\"unload\"),this._initEvents(\"off\"),delete this._container._leaflet,this._clearPanes(),this._clearControlPos&&this._clearControlPos(),this._clearHandlers(),this},getCenter:function(){return this._checkIfLoaded(),this._moved()?this.layerPointToLatLng(this._getCenterLayerPoint()):this._initialCenter},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds(),e=this.unproject(t.getBottomLeft()),i=this.unproject(t.getTopRight());return new o.LatLngBounds(e,i)},getMinZoom:function(){var t=this._layersMinZoom===i?0:this._layersMinZoom,e=this._boundsMinZoom===i?0:this._boundsMinZoom;return this.options.minZoom===i?Math.max(t,e):this.options.minZoom},getMaxZoom:function(){return this.options.maxZoom===i?this._layersMaxZoom===i?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=o.latLngBounds(t);var n,s=this.getMinZoom()-(e?1:0),a=this.getMaxZoom(),r=this.getSize(),h=t.getNorthWest(),l=t.getSouthEast(),u=!0;i=o.point(i||[0,0]);do s++,n=this.project(l,s).subtract(this.project(h,s)).add(i),u=e?n.x<r.x||n.y<r.y:r.contains(n);while(u&&a>=s);return u&&e?null:e?s:s-1},getSize:function(){return(!this._size||this._sizeChanged)&&(this._size=new o.Point(this._container.clientWidth,this._container.clientHeight),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(){var t=this._getTopLeftPoint();return new o.Bounds(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._initialTopLeftPoint},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t){var e=this.options.crs;return e.scale(t)/e.scale(this._zoom)},getScaleZoom:function(t){return this._zoom+Math.log(t)/Math.LN2},project:function(t,e){return e=e===i?this._zoom:e,this.options.crs.latLngToPoint(o.latLng(t),e)},unproject:function(t,e){return e=e===i?this._zoom:e,this.options.crs.pointToLatLng(o.point(t),e)},layerPointToLatLng:function(t){var e=o.point(t).add(this.getPixelOrigin());return this.unproject(e)},latLngToLayerPoint:function(t){var e=this.project(o.latLng(t))._round();return e._subtract(this.getPixelOrigin())},containerPointToLayerPoint:function(t){return o.point(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return o.point(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var e=this.containerPointToLayerPoint(o.point(t));return this.layerPointToLatLng(e)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(o.latLng(t)))},mouseEventToContainerPoint:function(t){return o.DomEvent.getMousePosition(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var e=this._container=o.DomUtil.get(t);if(!e)throw new Error(\"Map container not found.\");if(e._leaflet)throw new Error(\"Map container is already initialized.\");e._leaflet=!0},_initLayout:function(){var t=this._container;o.DomUtil.addClass(t,\"leaflet-container\"+(o.Browser.touch?\" leaflet-touch\":\"\")+(o.Browser.retina?\" leaflet-retina\":\"\")+(this.options.fadeAnimation?\" leaflet-fade-anim\":\"\"));var e=o.DomUtil.getStyle(t,\"position\");\"absolute\"!==e&&\"relative\"!==e&&\"fixed\"!==e&&(t.style.position=\"relative\"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._mapPane=t.mapPane=this._createPane(\"leaflet-map-pane\",this._container),this._tilePane=t.tilePane=this._createPane(\"leaflet-tile-pane\",this._mapPane),t.objectsPane=this._createPane(\"leaflet-objects-pane\",this._mapPane),t.shadowPane=this._createPane(\"leaflet-shadow-pane\"),t.overlayPane=this._createPane(\"leaflet-overlay-pane\"),t.markerPane=this._createPane(\"leaflet-marker-pane\"),t.popupPane=this._createPane(\"leaflet-popup-pane\");var e=\" leaflet-zoom-hide\";this.options.markerZoomAnimation||(o.DomUtil.addClass(t.markerPane,e),o.DomUtil.addClass(t.shadowPane,e),o.DomUtil.addClass(t.popupPane,e))},_createPane:function(t,e){return o.DomUtil.create(\"div\",t,e||this._panes.objectsPane)},_clearPanes:function(){this._container.removeChild(this._mapPane)},_addLayers:function(t){t=t?o.Util.isArray(t)?t:[t]:[];for(var e=0,i=t.length;i>e;e++)this.addLayer(t[e])},_resetView:function(t,e,i,n){var s=this._zoom!==e;n||(this.fire(\"movestart\"),s&&this.fire(\"zoomstart\")),this._zoom=e,this._initialCenter=t,this._initialTopLeftPoint=this._getNewTopLeftPoint(t),i?this._initialTopLeftPoint._add(this._getMapPanePos()):o.DomUtil.setPosition(this._mapPane,new o.Point(0,0)),this._tileLayersToLoad=this._tileLayersNum;var a=!this._loaded;this._loaded=!0,a&&(this.fire(\"load\"),this.eachLayer(this._layerAdd,this)),this.fire(\"viewreset\",{hard:!i}),this.fire(\"move\"),(s||n)&&this.fire(\"zoomend\"),this.fire(\"moveend\",{hard:!i})},_rawPanBy:function(t){o.DomUtil.setPosition(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_updateZoomLevels:function(){var t,e=1/0,n=-1/0,o=this._getZoomSpan();for(t in this._zoomBoundLayers){var s=this._zoomBoundLayers[t];isNaN(s.options.minZoom)||(e=Math.min(e,s.options.minZoom)),isNaN(s.options.maxZoom)||(n=Math.max(n,s.options.maxZoom))}t===i?this._layersMaxZoom=this._layersMinZoom=i:(this._layersMaxZoom=n,this._layersMinZoom=e),o!==this._getZoomSpan()&&this.fire(\"zoomlevelschange\")},_panInsideMaxBounds:function(){this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error(\"Set map center and zoom first.\")},_initEvents:function(e){if(o.DomEvent){e=e||\"on\",o.DomEvent[e](this._container,\"click\",this._onMouseClick,this);var i,n,s=[\"dblclick\",\"mousedown\",\"mouseup\",\"mouseenter\",\"mouseleave\",\"mousemove\",\"contextmenu\"];for(i=0,n=s.length;n>i;i++)o.DomEvent[e](this._container,s[i],this._fireMouseEvent,this);this.options.trackResize&&o.DomEvent[e](t,\"resize\",this._onResize,this)}},_onResize:function(){o.Util.cancelAnimFrame(this._resizeRequest),this._resizeRequest=o.Util.requestAnimFrame(this.invalidateSize,this,!1,this._container)},_onMouseClick:function(t){!this._loaded||!t._simulated&&this.dragging&&this.dragging.moved()||o.DomEvent._skipped(t)||(this.fire(\"preclick\"),this._fireMouseEvent(t))},_fireMouseEvent:function(t){if(this._loaded&&!o.DomEvent._skipped(t)){var e=t.type;if(e=\"mouseenter\"===e?\"mouseover\":\"mouseleave\"===e?\"mouseout\":e,this.hasEventListeners(e)){\"contextmenu\"===e&&o.DomEvent.preventDefault(t);var i=this.mouseEventToContainerPoint(t),n=this.containerPointToLayerPoint(i),s=this.layerPointToLatLng(n);this.fire(e,{latlng:s,layerPoint:n,containerPoint:i,originalEvent:t})}}},_onTileLayerLoad:function(){this._tileLayersToLoad--,this._tileLayersNum&&!this._tileLayersToLoad&&this.fire(\"tilelayersload\")},_clearHandlers:function(){for(var t=0,e=this._handlers.length;e>t;t++)this._handlers[t].disable()},whenReady:function(t,e){return this._loaded?t.call(e||this,this):this.on(\"load\",t,e),this},_layerAdd:function(t){t.onAdd(this),this.fire(\"layeradd\",{layer:t})},_getMapPanePos:function(){return o.DomUtil.getPosition(this._mapPane)},_moved:function(){var t=this._getMapPanePos();return t&&!t.equals([0,0])},_getTopLeftPoint:function(){return this.getPixelOrigin().subtract(this._getMapPanePos())},_getNewTopLeftPoint:function(t,e){var i=this.getSize()._divideBy(2);return this.project(t,e)._subtract(i)._round()},_latLngToNewLayerPoint:function(t,e,i){var n=this._getNewTopLeftPoint(i,e).add(this._getMapPanePos());return this.project(t,e)._subtract(n)},_getCenterLayerPoint:function(){return this.containerPointToLayerPoint(this.getSize()._divideBy(2))},_getCenterOffset:function(t){return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint())},_limitZoom:function(t){var e=this.getMinZoom(),i=this.getMaxZoom();return Math.max(e,Math.min(i,t))}}),o.map=function(t,e){return new o.Map(t,e)},o.Projection.Mercator={MAX_LATITUDE:85.0840591556,R_MINOR:6356752.314245179,R_MAJOR:6378137,project:function(t){var e=o.LatLng.DEG_TO_RAD,i=this.MAX_LATITUDE,n=Math.max(Math.min(i,t.lat),-i),s=this.R_MAJOR,a=this.R_MINOR,r=t.lng*e*s,h=n*e,l=a/s,u=Math.sqrt(1-l*l),c=u*Math.sin(h);c=Math.pow((1-c)/(1+c),.5*u);var d=Math.tan(.5*(.5*Math.PI-h))/c;return h=-s*Math.log(d),new o.Point(r,h)},unproject:function(t){for(var e,i=o.LatLng.RAD_TO_DEG,n=this.R_MAJOR,s=this.R_MINOR,a=t.x*i/n,r=s/n,h=Math.sqrt(1-r*r),l=Math.exp(-t.y/n),u=Math.PI/2-2*Math.atan(l),c=15,d=1e-7,p=c,_=.1;Math.abs(_)>d&&--p>0;)e=h*Math.sin(u),_=Math.PI/2-2*Math.atan(l*Math.pow((1-e)/(1+e),.5*h))-u,u+=_;return new o.LatLng(u*i,a)}},o.CRS.EPSG3395=o.extend({},o.CRS,{code:\"EPSG:3395\",projection:o.Projection.Mercator,transformation:function(){var t=o.Projection.Mercator,e=t.R_MAJOR,i=t.R_MINOR;return new o.Transformation(.5/(Math.PI*e),.5,-.5/(Math.PI*i),.5)}()}),o.TileLayer=o.Class.extend({includes:o.Mixin.Events,options:{minZoom:0,maxZoom:18,tileSize:256,subdomains:\"abc\",errorTileUrl:\"\",attribution:\"\",zoomOffset:0,opacity:1,unloadInvisibleTiles:o.Browser.mobile,updateWhenIdle:o.Browser.mobile},initialize:function(t,e){e=o.setOptions(this,e),e.detectRetina&&o.Browser.retina&&e.maxZoom>0&&(e.tileSize=Math.floor(e.tileSize/2),e.zoomOffset++,e.minZoom>0&&e.minZoom--,this.options.maxZoom--),e.bounds&&(e.bounds=o.latLngBounds(e.bounds)),this._url=t;var i=this.options.subdomains;\"string\"==typeof i&&(this.options.subdomains=i.split(\"\"))},onAdd:function(t){this._map=t,this._animated=t._zoomAnimated,this._initContainer(),t.on({viewreset:this._reset,moveend:this._update},this),this._animated&&t.on({zoomanim:this._animateZoom,zoomend:this._endZoomAnim},this),this.options.updateWhenIdle||(this._limitedUpdate=o.Util.limitExecByInterval(this._update,150,this),t.on(\"move\",this._limitedUpdate,this)),this._reset(),this._update()\n},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){this._container.parentNode.removeChild(this._container),t.off({viewreset:this._reset,moveend:this._update},this),this._animated&&t.off({zoomanim:this._animateZoom,zoomend:this._endZoomAnim},this),this.options.updateWhenIdle||t.off(\"move\",this._limitedUpdate,this),this._container=null,this._map=null},bringToFront:function(){var t=this._map._panes.tilePane;return this._container&&(t.appendChild(this._container),this._setAutoZIndex(t,Math.max)),this},bringToBack:function(){var t=this._map._panes.tilePane;return this._container&&(t.insertBefore(this._container,t.firstChild),this._setAutoZIndex(t,Math.min)),this},getAttribution:function(){return this.options.attribution},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},setUrl:function(t,e){return this._url=t,e||this.redraw(),this},redraw:function(){return this._map&&(this._reset({hard:!0}),this._update()),this},_updateZIndex:function(){this._container&&this.options.zIndex!==i&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t,e){var i,n,o,s=t.children,a=-e(1/0,-1/0);for(n=0,o=s.length;o>n;n++)s[n]!==this._container&&(i=parseInt(s[n].style.zIndex,10),isNaN(i)||(a=e(a,i)));this.options.zIndex=this._container.style.zIndex=(isFinite(a)?a:0)+e(1,-1)},_updateOpacity:function(){var t,e=this._tiles;if(o.Browser.ielt9)for(t in e)o.DomUtil.setOpacity(e[t],this.options.opacity);else o.DomUtil.setOpacity(this._container,this.options.opacity)},_initContainer:function(){var t=this._map._panes.tilePane;if(!this._container){if(this._container=o.DomUtil.create(\"div\",\"leaflet-layer\"),this._updateZIndex(),this._animated){var e=\"leaflet-tile-container leaflet-zoom-animated\";this._bgBuffer=o.DomUtil.create(\"div\",e,this._container),this._tileContainer=o.DomUtil.create(\"div\",e,this._container)}else this._tileContainer=this._container;t.appendChild(this._container),this.options.opacity<1&&this._updateOpacity()}},_reset:function(t){for(var e in this._tiles)this.fire(\"tileunload\",{tile:this._tiles[e]});this._tiles={},this._tilesToLoad=0,this.options.reuseTiles&&(this._unusedTiles=[]),this._tileContainer.innerHTML=\"\",this._animated&&t&&t.hard&&this._clearBgBuffer(),this._initContainer()},_getTileSize:function(){var t=this._map,e=t.getZoom(),i=this.options.maxNativeZoom,n=this.options.tileSize;return i&&e>i&&(n=Math.round(t.getZoomScale(e)/t.getZoomScale(i)*n)),n},_update:function(){if(this._map){var t=this._map,e=t.getPixelBounds(),i=t.getZoom(),n=this._getTileSize();if(!(i>this.options.maxZoom||i<this.options.minZoom)){var s=o.bounds(e.min.divideBy(n)._floor(),e.max.divideBy(n)._floor());this._addTilesFromCenterOut(s),(this.options.unloadInvisibleTiles||this.options.reuseTiles)&&this._removeOtherTiles(s)}}},_addTilesFromCenterOut:function(t){var i,n,s,a=[],r=t.getCenter();for(i=t.min.y;i<=t.max.y;i++)for(n=t.min.x;n<=t.max.x;n++)s=new o.Point(n,i),this._tileShouldBeLoaded(s)&&a.push(s);var h=a.length;if(0!==h){a.sort(function(t,e){return t.distanceTo(r)-e.distanceTo(r)});var l=e.createDocumentFragment();for(this._tilesToLoad||this.fire(\"loading\"),this._tilesToLoad+=h,n=0;h>n;n++)this._addTile(a[n],l);this._tileContainer.appendChild(l)}},_tileShouldBeLoaded:function(t){if(t.x+\":\"+t.y in this._tiles)return!1;var e=this.options;if(!e.continuousWorld){var i=this._getWrapTileNum();if(e.noWrap&&(t.x<0||t.x>=i)||t.y<0||t.y>=i)return!1}if(e.bounds){var n=e.tileSize,o=t.multiplyBy(n),s=o.add([n,n]),a=this._map.unproject(o),r=this._map.unproject(s);if(e.continuousWorld||e.noWrap||(a=a.wrap(),r=r.wrap()),!e.bounds.intersects([a,r]))return!1}return!0},_removeOtherTiles:function(t){var e,i,n,o;for(o in this._tiles)e=o.split(\":\"),i=parseInt(e[0],10),n=parseInt(e[1],10),(i<t.min.x||i>t.max.x||n<t.min.y||n>t.max.y)&&this._removeTile(o)},_removeTile:function(t){var e=this._tiles[t];this.fire(\"tileunload\",{tile:e,url:e.src}),this.options.reuseTiles?(o.DomUtil.removeClass(e,\"leaflet-tile-loaded\"),this._unusedTiles.push(e)):e.parentNode===this._tileContainer&&this._tileContainer.removeChild(e),o.Browser.android||(e.onload=null,e.src=o.Util.emptyImageUrl),delete this._tiles[t]},_addTile:function(t,e){var i=this._getTilePos(t),n=this._getTile();o.DomUtil.setPosition(n,i,o.Browser.chrome||o.Browser.android23),this._tiles[t.x+\":\"+t.y]=n,this._loadTile(n,t),n.parentNode!==this._tileContainer&&e.appendChild(n)},_getZoomForUrl:function(){var t=this.options,e=this._map.getZoom();return t.zoomReverse&&(e=t.maxZoom-e),e+=t.zoomOffset,t.maxNativeZoom?Math.min(e,t.maxNativeZoom):e},_getTilePos:function(t){var e=this._map.getPixelOrigin(),i=this._getTileSize();return t.multiplyBy(i).subtract(e)},getTileUrl:function(t){return o.Util.template(this._url,o.extend({s:this._getSubdomain(t),z:t.z,x:t.x,y:t.y},this.options))},_getWrapTileNum:function(){return Math.pow(2,this._getZoomForUrl())},_adjustTilePoint:function(t){var e=this._getWrapTileNum();this.options.continuousWorld||this.options.noWrap||(t.x=(t.x%e+e)%e),this.options.tms&&(t.y=e-t.y-1),t.z=this._getZoomForUrl()},_getSubdomain:function(t){var e=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[e]},_getTile:function(){if(this.options.reuseTiles&&this._unusedTiles.length>0){var t=this._unusedTiles.pop();return this._resetTile(t),t}return this._createTile()},_resetTile:function(){},_createTile:function(){var t=o.DomUtil.create(\"img\",\"leaflet-tile\");return t.style.width=t.style.height=this._getTileSize()+\"px\",t.galleryimg=\"no\",t.onselectstart=t.onmousemove=o.Util.falseFn,o.Browser.ielt9&&this.options.opacity!==i&&o.DomUtil.setOpacity(t,this.options.opacity),t},_loadTile:function(t,e){t._layer=this,t.onload=this._tileOnLoad,t.onerror=this._tileOnError,this._adjustTilePoint(e),t.src=this.getTileUrl(e)},_tileLoaded:function(){this._tilesToLoad--,this._tilesToLoad||(this.fire(\"load\"),this._animated&&(clearTimeout(this._clearBgBufferTimer),this._clearBgBufferTimer=setTimeout(o.bind(this._clearBgBuffer,this),500)))},_tileOnLoad:function(){var t=this._layer;this.src!==o.Util.emptyImageUrl&&(o.DomUtil.addClass(this,\"leaflet-tile-loaded\"),t.fire(\"tileload\",{tile:this,url:this.src})),t._tileLoaded()},_tileOnError:function(){var t=this._layer;t.fire(\"tileerror\",{tile:this,url:this.src});var e=t.options.errorTileUrl;e&&(this.src=e),t._tileLoaded()}}),o.tileLayer=function(t,e){return new o.TileLayer(t,e)},o.TileLayer.WMS=o.TileLayer.extend({defaultWmsParams:{service:\"WMS\",request:\"GetMap\",version:\"1.1.1\",layers:\"\",styles:\"\",format:\"image/jpeg\",transparent:!1},initialize:function(t,e){this._url=t;var i=o.extend({},this.defaultWmsParams),n=e.tileSize||this.options.tileSize;i.width=i.height=e.detectRetina&&o.Browser.retina?2*n:n;for(var s in e)this.options.hasOwnProperty(s)||\"crs\"===s||(i[s]=e[s]);this.wmsParams=i,o.setOptions(this,e)},onAdd:function(t){this._crs=this.options.crs||t.options.crs;var e=parseFloat(this.wmsParams.version)>=1.3?\"crs\":\"srs\";this.wmsParams[e]=this._crs.code,o.TileLayer.prototype.onAdd.call(this,t)},getTileUrl:function(t){var e=this._map,i=this.options.tileSize,n=t.multiplyBy(i),s=n.add([i,i]),a=this._crs.project(e.unproject(n,t.z)),r=this._crs.project(e.unproject(s,t.z)),h=[a.x,r.y,r.x,a.y].join(\",\"),l=o.Util.template(this._url,{s:this._getSubdomain(t)});return l+o.Util.getParamString(this.wmsParams,l,!0)+\"&BBOX=\"+h},setParams:function(t,e){return o.extend(this.wmsParams,t),e||this.redraw(),this}}),o.tileLayer.wms=function(t,e){return new o.TileLayer.WMS(t,e)},o.TileLayer.Canvas=o.TileLayer.extend({options:{async:!1},initialize:function(t){o.setOptions(this,t)},redraw:function(){this._map&&(this._reset({hard:!0}),this._update());for(var t in this._tiles)this._redrawTile(this._tiles[t]);return this},_redrawTile:function(t){this.drawTile(t,t._tilePoint,this._map._zoom)},_createTile:function(){var t=o.DomUtil.create(\"canvas\",\"leaflet-tile\");return t.width=t.height=this.options.tileSize,t.onselectstart=t.onmousemove=o.Util.falseFn,t},_loadTile:function(t,e){t._layer=this,t._tilePoint=e,this._redrawTile(t),this.options.async||this.tileDrawn(t)},drawTile:function(){},tileDrawn:function(t){this._tileOnLoad.call(t)}}),o.tileLayer.canvas=function(t){return new o.TileLayer.Canvas(t)},o.ImageOverlay=o.Class.extend({includes:o.Mixin.Events,options:{opacity:1},initialize:function(t,e,i){this._url=t,this._bounds=o.latLngBounds(e),o.setOptions(this,i)},onAdd:function(t){this._map=t,this._image||this._initImage(),t._panes.overlayPane.appendChild(this._image),t.on(\"viewreset\",this._reset,this),t.options.zoomAnimation&&o.Browser.any3d&&t.on(\"zoomanim\",this._animateZoom,this),this._reset()},onRemove:function(t){t.getPanes().overlayPane.removeChild(this._image),t.off(\"viewreset\",this._reset,this),t.options.zoomAnimation&&t.off(\"zoomanim\",this._animateZoom,this)},addTo:function(t){return t.addLayer(this),this},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},bringToFront:function(){return this._image&&this._map._panes.overlayPane.appendChild(this._image),this},bringToBack:function(){var t=this._map._panes.overlayPane;return this._image&&t.insertBefore(this._image,t.firstChild),this},_initImage:function(){this._image=o.DomUtil.create(\"img\",\"leaflet-image-layer\"),this._map.options.zoomAnimation&&o.Browser.any3d?o.DomUtil.addClass(this._image,\"leaflet-zoom-animated\"):o.DomUtil.addClass(this._image,\"leaflet-zoom-hide\"),this._updateOpacity(),o.extend(this._image,{galleryimg:\"no\",onselectstart:o.Util.falseFn,onmousemove:o.Util.falseFn,onload:o.bind(this._onImageLoad,this),src:this._url})},_animateZoom:function(t){var e=this._map,i=this._image,n=e.getZoomScale(t.zoom),s=this._bounds.getNorthWest(),a=this._bounds.getSouthEast(),r=e._latLngToNewLayerPoint(s,t.zoom,t.center),h=e._latLngToNewLayerPoint(a,t.zoom,t.center)._subtract(r),l=r._add(h._multiplyBy(.5*(1-1/n)));i.style[o.DomUtil.TRANSFORM]=o.DomUtil.getTranslateString(l)+\" scale(\"+n+\") \"},_reset:function(){var t=this._image,e=this._map.latLngToLayerPoint(this._bounds.getNorthWest()),i=this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(e);o.DomUtil.setPosition(t,e),t.style.width=i.x+\"px\",t.style.height=i.y+\"px\"},_onImageLoad:function(){this.fire(\"load\")},_updateOpacity:function(){o.DomUtil.setOpacity(this._image,this.options.opacity)}}),o.imageOverlay=function(t,e,i){return new o.ImageOverlay(t,e,i)},o.Icon=o.Class.extend({options:{className:\"\"},initialize:function(t){o.setOptions(this,t)},createIcon:function(t){return this._createIcon(\"icon\",t)},createShadow:function(t){return this._createIcon(\"shadow\",t)},_createIcon:function(t,e){var i=this._getIconUrl(t);if(!i){if(\"icon\"===t)throw new Error(\"iconUrl not set in Icon options (see the docs).\");return null}var n;return n=e&&\"IMG\"===e.tagName?this._createImg(i,e):this._createImg(i),this._setIconStyles(n,t),n},_setIconStyles:function(t,e){var i,n=this.options,s=o.point(n[e+\"Size\"]);i=\"shadow\"===e?o.point(n.shadowAnchor||n.iconAnchor):o.point(n.iconAnchor),!i&&s&&(i=s.divideBy(2,!0)),t.className=\"leaflet-marker-\"+e+\" \"+n.className,i&&(t.style.marginLeft=-i.x+\"px\",t.style.marginTop=-i.y+\"px\"),s&&(t.style.width=s.x+\"px\",t.style.height=s.y+\"px\")},_createImg:function(t,i){return o.Browser.ie6?(i||(i=e.createElement(\"div\")),i.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\"'+t+'\")'):(i||(i=e.createElement(\"img\")),i.src=t),i},_getIconUrl:function(t){return o.Browser.retina&&this.options[t+\"RetinaUrl\"]?this.options[t+\"RetinaUrl\"]:this.options[t+\"Url\"]}}),o.icon=function(t){return new o.Icon(t)},o.Icon.Default=o.Icon.extend({options:{iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],shadowSize:[41,41]},_getIconUrl:function(t){var e=t+\"Url\";if(this.options[e])return this.options[e];o.Browser.retina&&\"icon\"===t&&(t+=\"-2x\");var i=o.Icon.Default.imagePath;if(!i)throw new Error(\"Couldn't autodetect L.Icon.Default.imagePath, set it manually.\");return i+\"/marker-\"+t+\".png\"}}),o.Icon.Default.imagePath=function(){var t,i,n,o,s,a=e.getElementsByTagName(\"script\"),r=/[\\/^]leaflet[\\-\\._]?([\\w\\-\\._]*)\\.js\\??/;for(t=0,i=a.length;i>t;t++)if(n=a[t].src,o=n.match(r))return s=n.split(r)[0],(s?s+\"/\":\"\")+\"images\"}(),o.Marker=o.Class.extend({includes:o.Mixin.Events,options:{icon:new o.Icon.Default,title:\"\",clickable:!0,draggable:!1,keyboard:!0,zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250},initialize:function(t,e){o.setOptions(this,e),this._latlng=o.latLng(t)},onAdd:function(t){this._map=t,t.on(\"viewreset\",this.update,this),this._initIcon(),this.update(),t.options.zoomAnimation&&t.options.markerZoomAnimation&&t.on(\"zoomanim\",this._animateZoom,this)},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){this.dragging&&this.dragging.disable(),this._removeIcon(),this._removeShadow(),this.fire(\"remove\"),t.off({viewreset:this.update,zoomanim:this._animateZoom},this),this._map=null},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=o.latLng(t),this.update(),this.fire(\"move\",{latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update(),this},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup),this},update:function(){if(this._icon){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,e=this._map,i=e.options.zoomAnimation&&e.options.markerZoomAnimation,n=i?\"leaflet-zoom-animated\":\"leaflet-zoom-hide\",s=t.icon.createIcon(this._icon),a=!1;s!==this._icon&&(this._icon&&this._removeIcon(),a=!0,t.title&&(s.title=t.title)),o.DomUtil.addClass(s,n),t.keyboard&&(s.tabIndex=\"0\"),this._icon=s,this._initInteraction(),t.riseOnHover&&o.DomEvent.on(s,\"mouseover\",this._bringToFront,this).on(s,\"mouseout\",this._resetZIndex,this);var r=t.icon.createShadow(this._shadow),h=!1;r!==this._shadow&&(this._removeShadow(),h=!0),r&&o.DomUtil.addClass(r,n),this._shadow=r,t.opacity<1&&this._updateOpacity();var l=this._map._panes;a&&l.markerPane.appendChild(this._icon),r&&h&&l.shadowPane.appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&o.DomEvent.off(this._icon,\"mouseover\",this._bringToFront).off(this._icon,\"mouseout\",this._resetZIndex),this._map._panes.markerPane.removeChild(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&this._map._panes.shadowPane.removeChild(this._shadow),this._shadow=null},_setPos:function(t){o.DomUtil.setPosition(this._icon,t),this._shadow&&o.DomUtil.setPosition(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPos(e)},_initInteraction:function(){if(this.options.clickable){var t=this._icon,e=[\"dblclick\",\"mousedown\",\"mouseover\",\"mouseout\",\"contextmenu\"];o.DomUtil.addClass(t,\"leaflet-clickable\"),o.DomEvent.on(t,\"click\",this._onMouseClick,this),o.DomEvent.on(t,\"keypress\",this._onKeyPress,this);for(var i=0;i<e.length;i++)o.DomEvent.on(t,e[i],this._fireMouseEvent,this);o.Handler.MarkerDrag&&(this.dragging=new o.Handler.MarkerDrag(this),this.options.draggable&&this.dragging.enable())}},_onMouseClick:function(t){var e=this.dragging&&this.dragging.moved();(this.hasEventListeners(t.type)||e)&&o.DomEvent.stopPropagation(t),e||(this.dragging&&this.dragging._enabled||!this._map.dragging||!this._map.dragging.moved())&&this.fire(t.type,{originalEvent:t,latlng:this._latlng})},_onKeyPress:function(t){13===t.keyCode&&this.fire(\"click\",{originalEvent:t,latlng:this._latlng})},_fireMouseEvent:function(t){this.fire(t.type,{originalEvent:t,latlng:this._latlng}),\"contextmenu\"===t.type&&this.hasEventListeners(t.type)&&o.DomEvent.preventDefault(t),\"mousedown\"!==t.type?o.DomEvent.stopPropagation(t):o.DomEvent.preventDefault(t)},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){o.DomUtil.setOpacity(this._icon,this.options.opacity),this._shadow&&o.DomUtil.setOpacity(this._shadow,this.options.opacity)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)}}),o.marker=function(t,e){return new o.Marker(t,e)},o.DivIcon=o.Icon.extend({options:{iconSize:[12,12],className:\"leaflet-div-icon\",html:!1},createIcon:function(t){var i=t&&\"DIV\"===t.tagName?t:e.createElement(\"div\"),n=this.options;return i.innerHTML=n.html!==!1?n.html:\"\",n.bgPos&&(i.style.backgroundPosition=-n.bgPos.x+\"px \"+-n.bgPos.y+\"px\"),this._setIconStyles(i,\"icon\"),i},createShadow:function(){return null}}),o.divIcon=function(t){return new o.DivIcon(t)},o.Map.mergeOptions({closePopupOnClick:!0}),o.Popup=o.Class.extend({includes:o.Mixin.Events,options:{minWidth:50,maxWidth:300,maxHeight:null,autoPan:!0,closeButton:!0,offset:[0,7],autoPanPadding:[5,5],keepInView:!1,className:\"\",zoomAnimation:!0},initialize:function(t,e){o.setOptions(this,t),this._source=e,this._animated=o.Browser.any3d&&this.options.zoomAnimation,this._isOpen=!1},onAdd:function(t){this._map=t,this._container||this._initLayout(),this._updateContent();var e=t.options.fadeAnimation;e&&o.DomUtil.setOpacity(this._container,0),t._panes.popupPane.appendChild(this._container),t.on(this._getEvents(),this),this._update(),e&&o.DomUtil.setOpacity(this._container,1),this.fire(\"open\"),t.fire(\"popupopen\",{popup:this}),this._source&&this._source.fire(\"popupopen\",{popup:this})},addTo:function(t){return t.addLayer(this),this},openOn:function(t){return t.openPopup(this),this},onRemove:function(t){t._panes.popupPane.removeChild(this._container),o.Util.falseFn(this._container.offsetWidth),t.off(this._getEvents(),this),t.options.fadeAnimation&&o.DomUtil.setOpacity(this._container,0),this._map=null,this.fire(\"close\"),t.fire(\"popupclose\",{popup:this}),this._source&&this._source.fire(\"popupclose\",{popup:this})},setLatLng:function(t){return this._latlng=o.latLng(t),this._update(),this},setContent:function(t){return this._content=t,this._update(),this},_getEvents:function(){var t={viewreset:this._updatePosition};return this._animated&&(t.zoomanim=this._zoomAnimation),(\"closeOnClick\"in this.options?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t,e=\"leaflet-popup\",i=e+\" \"+this.options.className+\" leaflet-zoom-\"+(this._animated?\"animated\":\"hide\"),n=this._container=o.DomUtil.create(\"div\",i);this.options.closeButton&&(t=this._closeButton=o.DomUtil.create(\"a\",e+\"-close-button\",n),t.href=\"#close\",t.innerHTML=\"&#215;\",o.DomEvent.disableClickPropagation(t),o.DomEvent.on(t,\"click\",this._onCloseButtonClick,this));var s=this._wrapper=o.DomUtil.create(\"div\",e+\"-content-wrapper\",n);o.DomEvent.disableClickPropagation(s),this._contentNode=o.DomUtil.create(\"div\",e+\"-content\",s),o.DomEvent.on(this._contentNode,\"mousewheel\",o.DomEvent.stopPropagation),o.DomEvent.on(this._contentNode,\"MozMousePixelScroll\",o.DomEvent.stopPropagation),o.DomEvent.on(s,\"contextmenu\",o.DomEvent.stopPropagation),this._tipContainer=o.DomUtil.create(\"div\",e+\"-tip-container\",n),this._tip=o.DomUtil.create(\"div\",e+\"-tip\",this._tipContainer)},_update:function(){this._map&&(this._container.style.visibility=\"hidden\",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility=\"\",this._adjustPan())},_updateContent:function(){if(this._content){if(\"string\"==typeof this._content)this._contentNode.innerHTML=this._content;else{for(;this._contentNode.hasChildNodes();)this._contentNode.removeChild(this._contentNode.firstChild);this._contentNode.appendChild(this._content)}this.fire(\"contentupdate\")}},_updateLayout:function(){var t=this._contentNode,e=t.style;e.width=\"\",e.whiteSpace=\"nowrap\";var i=t.offsetWidth;i=Math.min(i,this.options.maxWidth),i=Math.max(i,this.options.minWidth),e.width=i+1+\"px\",e.whiteSpace=\"\",e.height=\"\";var n=t.offsetHeight,s=this.options.maxHeight,a=\"leaflet-popup-scrolled\";s&&n>s?(e.height=s+\"px\",o.DomUtil.addClass(t,a)):o.DomUtil.removeClass(t,a),this._containerWidth=this._container.offsetWidth},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),e=this._animated,i=o.point(this.options.offset);e&&o.DomUtil.setPosition(this._container,t),this._containerBottom=-i.y-(e?0:t.y),this._containerLeft=-Math.round(this._containerWidth/2)+i.x+(e?0:t.x),this._container.style.bottom=this._containerBottom+\"px\",this._container.style.left=this._containerLeft+\"px\"}},_zoomAnimation:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);o.DomUtil.setPosition(this._container,e)},_adjustPan:function(){if(this.options.autoPan){var t=this._map,e=this._container.offsetHeight,i=this._containerWidth,n=new o.Point(this._containerLeft,-e-this._containerBottom);this._animated&&n._add(o.DomUtil.getPosition(this._container));var s=t.layerPointToContainerPoint(n),a=o.point(this.options.autoPanPadding),r=t.getSize(),h=0,l=0;s.x+i>r.x&&(h=s.x+i-r.x+a.x),s.x-h<0&&(h=s.x-a.x),s.y+e>r.y&&(l=s.y+e-r.y+a.y),s.y-l<0&&(l=s.y-a.y),(h||l)&&t.fire(\"autopanstart\").panBy([h,l])}},_onCloseButtonClick:function(t){this._close(),o.DomEvent.stop(t)}}),o.popup=function(t,e){return new o.Popup(t,e)},o.Map.include({openPopup:function(t,e,i){if(this.closePopup(),!(t instanceof o.Popup)){var n=t;t=new o.Popup(i).setLatLng(e).setContent(n)}return t._isOpen=!0,this._popup=t,this.addLayer(t)},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&(this.removeLayer(t),t._isOpen=!1),this}}),o.Marker.include({openPopup:function(){return this._popup&&this._map&&!this._map.hasLayer(this._popup)&&(this._popup.setLatLng(this._latlng),this._map.openPopup(this._popup)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(){return this._popup&&(this._popup._isOpen?this.closePopup():this.openPopup()),this},bindPopup:function(t,e){var i=o.point(this.options.icon.options.popupAnchor||[0,0]);return i=i.add(o.Popup.prototype.options.offset),e&&e.offset&&(i=i.add(e.offset)),e=o.extend({offset:i},e),this._popup||this.on(\"click\",this.togglePopup,this).on(\"remove\",this.closePopup,this).on(\"move\",this._movePopup,this),t instanceof o.Popup?(o.setOptions(t,e),this._popup=t):this._popup=new o.Popup(e,this).setContent(t),this},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off(\"click\",this.togglePopup).off(\"remove\",this.closePopup).off(\"move\",this._movePopup)),this},_movePopup:function(t){this._popup.setLatLng(t.latlng)}}),o.LayerGroup=o.Class.extend({initialize:function(t){this._layers={};var e,i;if(t)for(e=0,i=t.length;i>e;e++)this.addLayer(t[e])},addLayer:function(t){var e=this.getLayerId(t);return this._layers[e]=t,this._map&&this._map.addLayer(t),this},removeLayer:function(t){var e=t in this._layers?t:this.getLayerId(t);return this._map&&this._layers[e]&&this._map.removeLayer(this._layers[e]),delete this._layers[e],this},hasLayer:function(t){return t?t in this._layers||this.getLayerId(t)in this._layers:!1},clearLayers:function(){return this.eachLayer(this.removeLayer,this),this},invoke:function(t){var e,i,n=Array.prototype.slice.call(arguments,1);for(e in this._layers)i=this._layers[e],i[t]&&i[t].apply(i,n);return this},onAdd:function(t){this._map=t,this.eachLayer(t.addLayer,t)},onRemove:function(t){this.eachLayer(t.removeLayer,t),this._map=null},addTo:function(t){return t.addLayer(this),this},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},getLayer:function(t){return this._layers[t]},getLayers:function(){var t=[];for(var e in this._layers)t.push(this._layers[e]);return t},setZIndex:function(t){return this.invoke(\"setZIndex\",t)},getLayerId:function(t){return o.stamp(t)}}),o.layerGroup=function(t){return new o.LayerGroup(t)},o.FeatureGroup=o.LayerGroup.extend({includes:o.Mixin.Events,statics:{EVENTS:\"click dblclick mouseover mouseout mousemove contextmenu popupopen popupclose\"},addLayer:function(t){return this.hasLayer(t)?this:(t.on(o.FeatureGroup.EVENTS,this._propagateEvent,this),o.LayerGroup.prototype.addLayer.call(this,t),this._popupContent&&t.bindPopup&&t.bindPopup(this._popupContent,this._popupOptions),this.fire(\"layeradd\",{layer:t}))},removeLayer:function(t){return this.hasLayer(t)?(t in this._layers&&(t=this._layers[t]),t.off(o.FeatureGroup.EVENTS,this._propagateEvent,this),o.LayerGroup.prototype.removeLayer.call(this,t),this._popupContent&&this.invoke(\"unbindPopup\"),this.fire(\"layerremove\",{layer:t})):this},bindPopup:function(t,e){return this._popupContent=t,this._popupOptions=e,this.invoke(\"bindPopup\",t,e)},setStyle:function(t){return this.invoke(\"setStyle\",t)},bringToFront:function(){return this.invoke(\"bringToFront\")},bringToBack:function(){return this.invoke(\"bringToBack\")},getBounds:function(){var t=new o.LatLngBounds;return this.eachLayer(function(e){t.extend(e instanceof o.Marker?e.getLatLng():e.getBounds())}),t},_propagateEvent:function(t){t.layer||(t.layer=t.target),t.target=this,this.fire(t.type,t)}}),o.featureGroup=function(t){return new o.FeatureGroup(t)},o.Path=o.Class.extend({includes:[o.Mixin.Events],statics:{CLIP_PADDING:function(){var e=o.Browser.mobile?1280:2e3,i=(e/Math.max(t.outerWidth,t.outerHeight)-1)/2;return Math.max(0,Math.min(.5,i))}()},options:{stroke:!0,color:\"#0033ff\",dashArray:null,lineCap:null,lineJoin:null,weight:5,opacity:.5,fill:!1,fillColor:null,fillOpacity:.2,clickable:!0},initialize:function(t){o.setOptions(this,t)},onAdd:function(t){this._map=t,this._container||(this._initElements(),this._initEvents()),this.projectLatlngs(),this._updatePath(),this._container&&this._map._pathRoot.appendChild(this._container),this.fire(\"add\"),t.on({viewreset:this.projectLatlngs,moveend:this._updatePath},this)},addTo:function(t){return t.addLayer(this),this},onRemove:function(t){t._pathRoot.removeChild(this._container),this.fire(\"remove\"),this._map=null,o.Browser.vml&&(this._container=null,this._stroke=null,this._fill=null),t.off({viewreset:this.projectLatlngs,moveend:this._updatePath},this)},projectLatlngs:function(){},setStyle:function(t){return o.setOptions(this,t),this._container&&this._updateStyle(),this},redraw:function(){return this._map&&(this.projectLatlngs(),this._updatePath()),this}}),o.Map.include({_updatePathViewport:function(){var t=o.Path.CLIP_PADDING,e=this.getSize(),i=o.DomUtil.getPosition(this._mapPane),n=i.multiplyBy(-1)._subtract(e.multiplyBy(t)._round()),s=n.add(e.multiplyBy(1+2*t)._round());this._pathViewport=new o.Bounds(n,s)}}),o.Path.SVG_NS=\"http://www.w3.org/2000/svg\",o.Browser.svg=!(!e.createElementNS||!e.createElementNS(o.Path.SVG_NS,\"svg\").createSVGRect),o.Path=o.Path.extend({statics:{SVG:o.Browser.svg},bringToFront:function(){var t=this._map._pathRoot,e=this._container;return e&&t.lastChild!==e&&t.appendChild(e),this},bringToBack:function(){var t=this._map._pathRoot,e=this._container,i=t.firstChild;return e&&i!==e&&t.insertBefore(e,i),this},getPathString:function(){},_createElement:function(t){return e.createElementNS(o.Path.SVG_NS,t)},_initElements:function(){this._map._initPathRoot(),this._initPath(),this._initStyle()},_initPath:function(){this._container=this._createElement(\"g\"),this._path=this._createElement(\"path\"),this._container.appendChild(this._path)},_initStyle:function(){this.options.stroke&&(this._path.setAttribute(\"stroke-linejoin\",\"round\"),this._path.setAttribute(\"stroke-linecap\",\"round\")),this.options.fill&&this._path.setAttribute(\"fill-rule\",\"evenodd\"),this.options.pointerEvents&&this._path.setAttribute(\"pointer-events\",this.options.pointerEvents),this.options.clickable||this.options.pointerEvents||this._path.setAttribute(\"pointer-events\",\"none\"),this._updateStyle()},_updateStyle:function(){this.options.stroke?(this._path.setAttribute(\"stroke\",this.options.color),this._path.setAttribute(\"stroke-opacity\",this.options.opacity),this._path.setAttribute(\"stroke-width\",this.options.weight),this.options.dashArray?this._path.setAttribute(\"stroke-dasharray\",this.options.dashArray):this._path.removeAttribute(\"stroke-dasharray\"),this.options.lineCap&&this._path.setAttribute(\"stroke-linecap\",this.options.lineCap),this.options.lineJoin&&this._path.setAttribute(\"stroke-linejoin\",this.options.lineJoin)):this._path.setAttribute(\"stroke\",\"none\"),this.options.fill?(this._path.setAttribute(\"fill\",this.options.fillColor||this.options.color),this._path.setAttribute(\"fill-opacity\",this.options.fillOpacity)):this._path.setAttribute(\"fill\",\"none\")},_updatePath:function(){var t=this.getPathString();t||(t=\"M0 0\"),this._path.setAttribute(\"d\",t)},_initEvents:function(){if(this.options.clickable){(o.Browser.svg||!o.Browser.vml)&&this._path.setAttribute(\"class\",\"leaflet-clickable\"),o.DomEvent.on(this._container,\"click\",this._onMouseClick,this);for(var t=[\"dblclick\",\"mousedown\",\"mouseover\",\"mouseout\",\"mousemove\",\"contextmenu\"],e=0;e<t.length;e++)o.DomEvent.on(this._container,t[e],this._fireMouseEvent,this)}},_onMouseClick:function(t){this._map.dragging&&this._map.dragging.moved()||this._fireMouseEvent(t)},_fireMouseEvent:function(t){if(this.hasEventListeners(t.type)){var e=this._map,i=e.mouseEventToContainerPoint(t),n=e.containerPointToLayerPoint(i),s=e.layerPointToLatLng(n);this.fire(t.type,{latlng:s,layerPoint:n,containerPoint:i,originalEvent:t}),\"contextmenu\"===t.type&&o.DomEvent.preventDefault(t),\"mousemove\"!==t.type&&o.DomEvent.stopPropagation(t)}}}),o.Map.include({_initPathRoot:function(){this._pathRoot||(this._pathRoot=o.Path.prototype._createElement(\"svg\"),this._panes.overlayPane.appendChild(this._pathRoot),this.options.zoomAnimation&&o.Browser.any3d?(this._pathRoot.setAttribute(\"class\",\" leaflet-zoom-animated\"),this.on({zoomanim:this._animatePathZoom,zoomend:this._endPathZoom})):this._pathRoot.setAttribute(\"class\",\" leaflet-zoom-hide\"),this.on(\"moveend\",this._updateSvgViewport),this._updateSvgViewport())},_animatePathZoom:function(t){var e=this.getZoomScale(t.zoom),i=this._getCenterOffset(t.center)._multiplyBy(-e)._add(this._pathViewport.min);this._pathRoot.style[o.DomUtil.TRANSFORM]=o.DomUtil.getTranslateString(i)+\" scale(\"+e+\") \",this._pathZooming=!0},_endPathZoom:function(){this._pathZooming=!1},_updateSvgViewport:function(){if(!this._pathZooming){this._updatePathViewport();var t=this._pathViewport,e=t.min,i=t.max,n=i.x-e.x,s=i.y-e.y,a=this._pathRoot,r=this._panes.overlayPane;o.Browser.mobileWebkit&&r.removeChild(a),o.DomUtil.setPosition(a,e),a.setAttribute(\"width\",n),a.setAttribute(\"height\",s),a.setAttribute(\"viewBox\",[e.x,e.y,n,s].join(\" \")),o.Browser.mobileWebkit&&r.appendChild(a)}}}),o.Path.include({bindPopup:function(t,e){return t instanceof o.Popup?this._popup=t:((!this._popup||e)&&(this._popup=new o.Popup(e,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on(\"click\",this._openPopup,this).on(\"remove\",this.closePopup,this),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this._popup=null,this.off(\"click\",this._openPopup).off(\"remove\",this.closePopup),this._popupHandlersAdded=!1),this},openPopup:function(t){return this._popup&&(t=t||this._latlng||this._latlngs[Math.floor(this._latlngs.length/2)],this._openPopup({latlng:t})),this},closePopup:function(){return this._popup&&this._popup._close(),this},_openPopup:function(t){this._popup.setLatLng(t.latlng),this._map.openPopup(this._popup)}}),o.Browser.vml=!o.Browser.svg&&function(){try{var t=e.createElement(\"div\");t.innerHTML='<v:shape adj=\"1\"/>';var i=t.firstChild;return i.style.behavior=\"url(#default#VML)\",i&&\"object\"==typeof i.adj}catch(n){return!1}}(),o.Path=o.Browser.svg||!o.Browser.vml?o.Path:o.Path.extend({statics:{VML:!0,CLIP_PADDING:.02},_createElement:function(){try{return e.namespaces.add(\"lvml\",\"urn:schemas-microsoft-com:vml\"),function(t){return e.createElement(\"<lvml:\"+t+' class=\"lvml\">')\n}}catch(t){return function(t){return e.createElement(\"<\"+t+' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"lvml\">')}}}(),_initPath:function(){var t=this._container=this._createElement(\"shape\");o.DomUtil.addClass(t,\"leaflet-vml-shape\"),this.options.clickable&&o.DomUtil.addClass(t,\"leaflet-clickable\"),t.coordsize=\"1 1\",this._path=this._createElement(\"path\"),t.appendChild(this._path),this._map._pathRoot.appendChild(t)},_initStyle:function(){this._updateStyle()},_updateStyle:function(){var t=this._stroke,e=this._fill,i=this.options,n=this._container;n.stroked=i.stroke,n.filled=i.fill,i.stroke?(t||(t=this._stroke=this._createElement(\"stroke\"),t.endcap=\"round\",n.appendChild(t)),t.weight=i.weight+\"px\",t.color=i.color,t.opacity=i.opacity,t.dashStyle=i.dashArray?i.dashArray instanceof Array?i.dashArray.join(\" \"):i.dashArray.replace(/( *, *)/g,\" \"):\"\",i.lineCap&&(t.endcap=i.lineCap.replace(\"butt\",\"flat\")),i.lineJoin&&(t.joinstyle=i.lineJoin)):t&&(n.removeChild(t),this._stroke=null),i.fill?(e||(e=this._fill=this._createElement(\"fill\"),n.appendChild(e)),e.color=i.fillColor||i.color,e.opacity=i.fillOpacity):e&&(n.removeChild(e),this._fill=null)},_updatePath:function(){var t=this._container.style;t.display=\"none\",this._path.v=this.getPathString()+\" \",t.display=\"\"}}),o.Map.include(o.Browser.svg||!o.Browser.vml?{}:{_initPathRoot:function(){if(!this._pathRoot){var t=this._pathRoot=e.createElement(\"div\");t.className=\"leaflet-vml-container\",this._panes.overlayPane.appendChild(t),this.on(\"moveend\",this._updatePathViewport),this._updatePathViewport()}}}),o.Browser.canvas=function(){return!!e.createElement(\"canvas\").getContext}(),o.Path=o.Path.SVG&&!t.L_PREFER_CANVAS||!o.Browser.canvas?o.Path:o.Path.extend({statics:{CANVAS:!0,SVG:!1},redraw:function(){return this._map&&(this.projectLatlngs(),this._requestUpdate()),this},setStyle:function(t){return o.setOptions(this,t),this._map&&(this._updateStyle(),this._requestUpdate()),this},onRemove:function(t){t.off(\"viewreset\",this.projectLatlngs,this).off(\"moveend\",this._updatePath,this),this.options.clickable&&(this._map.off(\"click\",this._onClick,this),this._map.off(\"mousemove\",this._onMouseMove,this)),this._requestUpdate(),this._map=null},_requestUpdate:function(){this._map&&!o.Path._updateRequest&&(o.Path._updateRequest=o.Util.requestAnimFrame(this._fireMapMoveEnd,this._map))},_fireMapMoveEnd:function(){o.Path._updateRequest=null,this.fire(\"moveend\")},_initElements:function(){this._map._initPathRoot(),this._ctx=this._map._canvasCtx},_updateStyle:function(){var t=this.options;t.stroke&&(this._ctx.lineWidth=t.weight,this._ctx.strokeStyle=t.color),t.fill&&(this._ctx.fillStyle=t.fillColor||t.color)},_drawPath:function(){var t,e,i,n,s,a;for(this._ctx.beginPath(),t=0,i=this._parts.length;i>t;t++){for(e=0,n=this._parts[t].length;n>e;e++)s=this._parts[t][e],a=(0===e?\"move\":\"line\")+\"To\",this._ctx[a](s.x,s.y);this instanceof o.Polygon&&this._ctx.closePath()}},_checkIfEmpty:function(){return!this._parts.length},_updatePath:function(){if(!this._checkIfEmpty()){var t=this._ctx,e=this.options;this._drawPath(),t.save(),this._updateStyle(),e.fill&&(t.globalAlpha=e.fillOpacity,t.fill()),e.stroke&&(t.globalAlpha=e.opacity,t.stroke()),t.restore()}},_initEvents:function(){this.options.clickable&&(this._map.on(\"mousemove\",this._onMouseMove,this),this._map.on(\"click\",this._onClick,this))},_onClick:function(t){this._containsPoint(t.layerPoint)&&this.fire(\"click\",t)},_onMouseMove:function(t){this._map&&!this._map._animatingZoom&&(this._containsPoint(t.layerPoint)?(this._ctx.canvas.style.cursor=\"pointer\",this._mouseInside=!0,this.fire(\"mouseover\",t)):this._mouseInside&&(this._ctx.canvas.style.cursor=\"\",this._mouseInside=!1,this.fire(\"mouseout\",t)))}}),o.Map.include(o.Path.SVG&&!t.L_PREFER_CANVAS||!o.Browser.canvas?{}:{_initPathRoot:function(){var t,i=this._pathRoot;i||(i=this._pathRoot=e.createElement(\"canvas\"),i.style.position=\"absolute\",t=this._canvasCtx=i.getContext(\"2d\"),t.lineCap=\"round\",t.lineJoin=\"round\",this._panes.overlayPane.appendChild(i),this.options.zoomAnimation&&(this._pathRoot.className=\"leaflet-zoom-animated\",this.on(\"zoomanim\",this._animatePathZoom),this.on(\"zoomend\",this._endPathZoom)),this.on(\"moveend\",this._updateCanvasViewport),this._updateCanvasViewport())},_updateCanvasViewport:function(){if(!this._pathZooming){this._updatePathViewport();var t=this._pathViewport,e=t.min,i=t.max.subtract(e),n=this._pathRoot;o.DomUtil.setPosition(n,e),n.width=i.x,n.height=i.y,n.getContext(\"2d\").translate(-e.x,-e.y)}}}),o.LineUtil={simplify:function(t,e){if(!e||!t.length)return t.slice();var i=e*e;return t=this._reducePoints(t,i),t=this._simplifyDP(t,i)},pointToSegmentDistance:function(t,e,i){return Math.sqrt(this._sqClosestPointOnSegment(t,e,i,!0))},closestPointOnSegment:function(t,e,i){return this._sqClosestPointOnSegment(t,e,i)},_simplifyDP:function(t,e){var n=t.length,o=typeof Uint8Array!=i+\"\"?Uint8Array:Array,s=new o(n);s[0]=s[n-1]=1,this._simplifyDPStep(t,s,e,0,n-1);var a,r=[];for(a=0;n>a;a++)s[a]&&r.push(t[a]);return r},_simplifyDPStep:function(t,e,i,n,o){var s,a,r,h=0;for(a=n+1;o-1>=a;a++)r=this._sqClosestPointOnSegment(t[a],t[n],t[o],!0),r>h&&(s=a,h=r);h>i&&(e[s]=1,this._simplifyDPStep(t,e,i,n,s),this._simplifyDPStep(t,e,i,s,o))},_reducePoints:function(t,e){for(var i=[t[0]],n=1,o=0,s=t.length;s>n;n++)this._sqDist(t[n],t[o])>e&&(i.push(t[n]),o=n);return s-1>o&&i.push(t[s-1]),i},clipSegment:function(t,e,i,n){var o,s,a,r=n?this._lastCode:this._getBitCode(t,i),h=this._getBitCode(e,i);for(this._lastCode=h;;){if(!(r|h))return[t,e];if(r&h)return!1;o=r||h,s=this._getEdgeIntersection(t,e,o,i),a=this._getBitCode(s,i),o===r?(t=s,r=a):(e=s,h=a)}},_getEdgeIntersection:function(t,e,i,n){var s=e.x-t.x,a=e.y-t.y,r=n.min,h=n.max;return 8&i?new o.Point(t.x+s*(h.y-t.y)/a,h.y):4&i?new o.Point(t.x+s*(r.y-t.y)/a,r.y):2&i?new o.Point(h.x,t.y+a*(h.x-t.x)/s):1&i?new o.Point(r.x,t.y+a*(r.x-t.x)/s):void 0},_getBitCode:function(t,e){var i=0;return t.x<e.min.x?i|=1:t.x>e.max.x&&(i|=2),t.y<e.min.y?i|=4:t.y>e.max.y&&(i|=8),i},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n},_sqClosestPointOnSegment:function(t,e,i,n){var s,a=e.x,r=e.y,h=i.x-a,l=i.y-r,u=h*h+l*l;return u>0&&(s=((t.x-a)*h+(t.y-r)*l)/u,s>1?(a=i.x,r=i.y):s>0&&(a+=h*s,r+=l*s)),h=t.x-a,l=t.y-r,n?h*h+l*l:new o.Point(a,r)}},o.Polyline=o.Path.extend({initialize:function(t,e){o.Path.prototype.initialize.call(this,e),this._latlngs=this._convertLatLngs(t)},options:{smoothFactor:1,noClip:!1},projectLatlngs:function(){this._originalPoints=[];for(var t=0,e=this._latlngs.length;e>t;t++)this._originalPoints[t]=this._map.latLngToLayerPoint(this._latlngs[t])},getPathString:function(){for(var t=0,e=this._parts.length,i=\"\";e>t;t++)i+=this._getPathPartStr(this._parts[t]);return i},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._latlngs=this._convertLatLngs(t),this.redraw()},addLatLng:function(t){return this._latlngs.push(o.latLng(t)),this.redraw()},spliceLatLngs:function(){var t=[].splice.apply(this._latlngs,arguments);return this._convertLatLngs(this._latlngs,!0),this.redraw(),t},closestLayerPoint:function(t){for(var e,i,n=1/0,s=this._parts,a=null,r=0,h=s.length;h>r;r++)for(var l=s[r],u=1,c=l.length;c>u;u++){e=l[u-1],i=l[u];var d=o.LineUtil._sqClosestPointOnSegment(t,e,i,!0);n>d&&(n=d,a=o.LineUtil._sqClosestPointOnSegment(t,e,i))}return a&&(a.distance=Math.sqrt(n)),a},getBounds:function(){return new o.LatLngBounds(this.getLatLngs())},_convertLatLngs:function(t,e){var i,n,s=e?t:[];for(i=0,n=t.length;n>i;i++){if(o.Util.isArray(t[i])&&\"number\"!=typeof t[i][0])return;s[i]=o.latLng(t[i])}return s},_initEvents:function(){o.Path.prototype._initEvents.call(this)},_getPathPartStr:function(t){for(var e,i=o.Path.VML,n=0,s=t.length,a=\"\";s>n;n++)e=t[n],i&&e._round(),a+=(n?\"L\":\"M\")+e.x+\" \"+e.y;return a},_clipPoints:function(){var t,e,i,n=this._originalPoints,s=n.length;if(this.options.noClip)return this._parts=[n],void 0;this._parts=[];var a=this._parts,r=this._map._pathViewport,h=o.LineUtil;for(t=0,e=0;s-1>t;t++)i=h.clipSegment(n[t],n[t+1],r,t),i&&(a[e]=a[e]||[],a[e].push(i[0]),(i[1]!==n[t+1]||t===s-2)&&(a[e].push(i[1]),e++))},_simplifyPoints:function(){for(var t=this._parts,e=o.LineUtil,i=0,n=t.length;n>i;i++)t[i]=e.simplify(t[i],this.options.smoothFactor)},_updatePath:function(){this._map&&(this._clipPoints(),this._simplifyPoints(),o.Path.prototype._updatePath.call(this))}}),o.polyline=function(t,e){return new o.Polyline(t,e)},o.PolyUtil={},o.PolyUtil.clipPolygon=function(t,e){var i,n,s,a,r,h,l,u,c,d=[1,4,2,8],p=o.LineUtil;for(n=0,l=t.length;l>n;n++)t[n]._code=p._getBitCode(t[n],e);for(a=0;4>a;a++){for(u=d[a],i=[],n=0,l=t.length,s=l-1;l>n;s=n++)r=t[n],h=t[s],r._code&u?h._code&u||(c=p._getEdgeIntersection(h,r,u,e),c._code=p._getBitCode(c,e),i.push(c)):(h._code&u&&(c=p._getEdgeIntersection(h,r,u,e),c._code=p._getBitCode(c,e),i.push(c)),i.push(r));t=i}return t},o.Polygon=o.Polyline.extend({options:{fill:!0},initialize:function(t,e){var i,n,s;if(o.Polyline.prototype.initialize.call(this,t,e),t&&o.Util.isArray(t[0])&&\"number\"!=typeof t[0][0])for(this._latlngs=this._convertLatLngs(t[0]),this._holes=t.slice(1),i=0,n=this._holes.length;n>i;i++)s=this._holes[i]=this._convertLatLngs(this._holes[i]),s[0].equals(s[s.length-1])&&s.pop();t=this._latlngs,t.length>=2&&t[0].equals(t[t.length-1])&&t.pop()},projectLatlngs:function(){if(o.Polyline.prototype.projectLatlngs.call(this),this._holePoints=[],this._holes){var t,e,i,n;for(t=0,i=this._holes.length;i>t;t++)for(this._holePoints[t]=[],e=0,n=this._holes[t].length;n>e;e++)this._holePoints[t][e]=this._map.latLngToLayerPoint(this._holes[t][e])}},_clipPoints:function(){var t=this._originalPoints,e=[];if(this._parts=[t].concat(this._holePoints),!this.options.noClip){for(var i=0,n=this._parts.length;n>i;i++){var s=o.PolyUtil.clipPolygon(this._parts[i],this._map._pathViewport);s.length&&e.push(s)}this._parts=e}},_getPathPartStr:function(t){var e=o.Polyline.prototype._getPathPartStr.call(this,t);return e+(o.Browser.svg?\"z\":\"x\")}}),o.polygon=function(t,e){return new o.Polygon(t,e)},function(){function t(t){return o.FeatureGroup.extend({initialize:function(t,e){this._layers={},this._options=e,this.setLatLngs(t)},setLatLngs:function(e){var i=0,n=e.length;for(this.eachLayer(function(t){n>i?t.setLatLngs(e[i++]):this.removeLayer(t)},this);n>i;)this.addLayer(new t(e[i++],this._options));return this},getLatLngs:function(){var t=[];return this.eachLayer(function(e){t.push(e.getLatLngs())}),t}})}o.MultiPolyline=t(o.Polyline),o.MultiPolygon=t(o.Polygon),o.multiPolyline=function(t,e){return new o.MultiPolyline(t,e)},o.multiPolygon=function(t,e){return new o.MultiPolygon(t,e)}}(),o.Rectangle=o.Polygon.extend({initialize:function(t,e){o.Polygon.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return t=o.latLngBounds(t),[t.getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}}),o.rectangle=function(t,e){return new o.Rectangle(t,e)},o.Circle=o.Path.extend({initialize:function(t,e,i){o.Path.prototype.initialize.call(this,i),this._latlng=o.latLng(t),this._mRadius=e},options:{fill:!0},setLatLng:function(t){return this._latlng=o.latLng(t),this.redraw()},setRadius:function(t){return this._mRadius=t,this.redraw()},projectLatlngs:function(){var t=this._getLngRadius(),e=this._latlng,i=this._map.latLngToLayerPoint([e.lat,e.lng-t]);this._point=this._map.latLngToLayerPoint(e),this._radius=Math.max(this._point.x-i.x,1)},getBounds:function(){var t=this._getLngRadius(),e=360*(this._mRadius/40075017),i=this._latlng;return new o.LatLngBounds([i.lat-e,i.lng-t],[i.lat+e,i.lng+t])},getLatLng:function(){return this._latlng},getPathString:function(){var t=this._point,e=this._radius;return this._checkIfEmpty()?\"\":o.Browser.svg?\"M\"+t.x+\",\"+(t.y-e)+\"A\"+e+\",\"+e+\",0,1,1,\"+(t.x-.1)+\",\"+(t.y-e)+\" z\":(t._round(),e=Math.round(e),\"AL \"+t.x+\",\"+t.y+\" \"+e+\",\"+e+\" 0,\"+23592600)},getRadius:function(){return this._mRadius},_getLatRadius:function(){return 360*(this._mRadius/40075017)},_getLngRadius:function(){return this._getLatRadius()/Math.cos(o.LatLng.DEG_TO_RAD*this._latlng.lat)},_checkIfEmpty:function(){if(!this._map)return!1;var t=this._map._pathViewport,e=this._radius,i=this._point;return i.x-e>t.max.x||i.y-e>t.max.y||i.x+e<t.min.x||i.y+e<t.min.y}}),o.circle=function(t,e,i){return new o.Circle(t,e,i)},o.CircleMarker=o.Circle.extend({options:{radius:10,weight:2},initialize:function(t,e){o.Circle.prototype.initialize.call(this,t,null,e),this._radius=this.options.radius},projectLatlngs:function(){this._point=this._map.latLngToLayerPoint(this._latlng)},_updateStyle:function(){o.Circle.prototype._updateStyle.call(this),this.setRadius(this.options.radius)},setLatLng:function(t){o.Circle.prototype.setLatLng.call(this,t),this._popup&&this._popup._isOpen&&this._popup.setLatLng(t)},setRadius:function(t){return this.options.radius=this._radius=t,this.redraw()}}),o.circleMarker=function(t,e){return new o.CircleMarker(t,e)},o.Polyline.include(o.Path.CANVAS?{_containsPoint:function(t,e){var i,n,s,a,r,h,l,u=this.options.weight/2;for(o.Browser.touch&&(u+=10),i=0,a=this._parts.length;a>i;i++)for(l=this._parts[i],n=0,r=l.length,s=r-1;r>n;s=n++)if((e||0!==n)&&(h=o.LineUtil.pointToSegmentDistance(t,l[s],l[n]),u>=h))return!0;return!1}}:{}),o.Polygon.include(o.Path.CANVAS?{_containsPoint:function(t){var e,i,n,s,a,r,h,l,u=!1;if(o.Polyline.prototype._containsPoint.call(this,t,!0))return!0;for(s=0,h=this._parts.length;h>s;s++)for(e=this._parts[s],a=0,l=e.length,r=l-1;l>a;r=a++)i=e[a],n=e[r],i.y>t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(u=!u);return u}}:{}),o.Circle.include(o.Path.CANVAS?{_drawPath:function(){var t=this._point;this._ctx.beginPath(),this._ctx.arc(t.x,t.y,this._radius,0,2*Math.PI,!1)},_containsPoint:function(t){var e=this._point,i=this.options.stroke?this.options.weight/2:0;return t.distanceTo(e)<=this._radius+i}}:{}),o.CircleMarker.include(o.Path.CANVAS?{_updateStyle:function(){o.Path.prototype._updateStyle.call(this)}}:{}),o.GeoJSON=o.FeatureGroup.extend({initialize:function(t,e){o.setOptions(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,s=o.Util.isArray(t)?t:t.features;if(s){for(e=0,i=s.length;i>e;e++)n=s[e],(n.geometries||n.geometry||n.features||n.coordinates)&&this.addData(s[e]);return this}var a=this.options;if(!a.filter||a.filter(t)){var r=o.GeoJSON.geometryToLayer(t,a.pointToLayer,a.coordsToLatLng);return r.feature=o.GeoJSON.asFeature(t),r.defaultOptions=r.options,this.resetStyle(r),a.onEachFeature&&a.onEachFeature(t,r),this.addLayer(r)}},resetStyle:function(t){var e=this.options.style;e&&(o.Util.extend(t.options,t.defaultOptions),this._setLayerStyle(t,e))},setStyle:function(t){this.eachLayer(function(e){this._setLayerStyle(e,t)},this)},_setLayerStyle:function(t,e){\"function\"==typeof e&&(e=e(t.feature)),t.setStyle&&t.setStyle(e)}}),o.extend(o.GeoJSON,{geometryToLayer:function(t,e,i){var n,s,a,r,h,l=\"Feature\"===t.type?t.geometry:t,u=l.coordinates,c=[];switch(i=i||this.coordsToLatLng,l.type){case\"Point\":return n=i(u),e?e(t,n):new o.Marker(n);case\"MultiPoint\":for(a=0,r=u.length;r>a;a++)n=i(u[a]),h=e?e(t,n):new o.Marker(n),c.push(h);return new o.FeatureGroup(c);case\"LineString\":return s=this.coordsToLatLngs(u,0,i),new o.Polyline(s);case\"Polygon\":if(2===u.length&&!u[1].length)throw new Error(\"Invalid GeoJSON object.\");return s=this.coordsToLatLngs(u,1,i),new o.Polygon(s);case\"MultiLineString\":return s=this.coordsToLatLngs(u,1,i),new o.MultiPolyline(s);case\"MultiPolygon\":return s=this.coordsToLatLngs(u,2,i),new o.MultiPolygon(s);case\"GeometryCollection\":for(a=0,r=l.geometries.length;r>a;a++)h=this.geometryToLayer({geometry:l.geometries[a],type:\"Feature\",properties:t.properties},e,i),c.push(h);return new o.FeatureGroup(c);default:throw new Error(\"Invalid GeoJSON object.\")}},coordsToLatLng:function(t){return new o.LatLng(t[1],t[0])},coordsToLatLngs:function(t,e,i){var n,o,s,a=[];for(o=0,s=t.length;s>o;o++)n=e?this.coordsToLatLngs(t[o],e-1,i):(i||this.coordsToLatLng)(t[o]),a.push(n);return a},latLngToCoords:function(t){return[t.lng,t.lat]},latLngsToCoords:function(t){for(var e=[],i=0,n=t.length;n>i;i++)e.push(o.GeoJSON.latLngToCoords(t[i]));return e},getFeature:function(t,e){return t.feature?o.extend({},t.feature,{geometry:e}):o.GeoJSON.asFeature(e)},asFeature:function(t){return\"Feature\"===t.type?t:{type:\"Feature\",properties:{},geometry:t}}});var a={toGeoJSON:function(){return o.GeoJSON.getFeature(this,{type:\"Point\",coordinates:o.GeoJSON.latLngToCoords(this.getLatLng())})}};o.Marker.include(a),o.Circle.include(a),o.CircleMarker.include(a),o.Polyline.include({toGeoJSON:function(){return o.GeoJSON.getFeature(this,{type:\"LineString\",coordinates:o.GeoJSON.latLngsToCoords(this.getLatLngs())})}}),o.Polygon.include({toGeoJSON:function(){var t,e,i,n=[o.GeoJSON.latLngsToCoords(this.getLatLngs())];if(n[0].push(n[0][0]),this._holes)for(t=0,e=this._holes.length;e>t;t++)i=o.GeoJSON.latLngsToCoords(this._holes[t]),i.push(i[0]),n.push(i);return o.GeoJSON.getFeature(this,{type:\"Polygon\",coordinates:n})}}),function(){function t(t,e){t.include({toGeoJSON:function(){var t=[];return this.eachLayer(function(e){t.push(e.toGeoJSON().geometry.coordinates)}),o.GeoJSON.getFeature(this,{type:e,coordinates:t})}})}t(o.MultiPolyline,\"MultiLineString\"),t(o.MultiPolygon,\"MultiPolygon\")}(),o.LayerGroup.include({toGeoJSON:function(){var t=[];return this.eachLayer(function(e){e.toGeoJSON&&t.push(o.GeoJSON.asFeature(e.toGeoJSON()))}),{type:\"FeatureCollection\",features:t}}}),o.geoJson=function(t,e){return new o.GeoJSON(t,e)},o.DomEvent={addListener:function(t,e,i,n){var s,a,r,h=o.stamp(i),l=\"_leaflet_\"+e+h;return t[l]?this:(s=function(e){return i.call(n||t,e||o.DomEvent._getEvent())},o.Browser.msTouch&&0===e.indexOf(\"touch\")?this.addMsTouchListener(t,e,s,h):(o.Browser.touch&&\"dblclick\"===e&&this.addDoubleTapListener&&this.addDoubleTapListener(t,s,h),\"addEventListener\"in t?\"mousewheel\"===e?(t.addEventListener(\"DOMMouseScroll\",s,!1),t.addEventListener(e,s,!1)):\"mouseenter\"===e||\"mouseleave\"===e?(a=s,r=\"mouseenter\"===e?\"mouseover\":\"mouseout\",s=function(e){return o.DomEvent._checkMouse(t,e)?a(e):void 0},t.addEventListener(r,s,!1)):\"click\"===e&&o.Browser.android?(a=s,s=function(t){return o.DomEvent._filterClick(t,a)},t.addEventListener(e,s,!1)):t.addEventListener(e,s,!1):\"attachEvent\"in t&&t.attachEvent(\"on\"+e,s),t[l]=s,this))},removeListener:function(t,e,i){var n=o.stamp(i),s=\"_leaflet_\"+e+n,a=t[s];return a?(o.Browser.msTouch&&0===e.indexOf(\"touch\")?this.removeMsTouchListener(t,e,n):o.Browser.touch&&\"dblclick\"===e&&this.removeDoubleTapListener?this.removeDoubleTapListener(t,n):\"removeEventListener\"in t?\"mousewheel\"===e?(t.removeEventListener(\"DOMMouseScroll\",a,!1),t.removeEventListener(e,a,!1)):\"mouseenter\"===e||\"mouseleave\"===e?t.removeEventListener(\"mouseenter\"===e?\"mouseover\":\"mouseout\",a,!1):t.removeEventListener(e,a,!1):\"detachEvent\"in t&&t.detachEvent(\"on\"+e,a),t[s]=null,this):this},stopPropagation:function(t){return t.stopPropagation?t.stopPropagation():t.cancelBubble=!0,this},disableClickPropagation:function(t){for(var e=o.DomEvent.stopPropagation,i=o.Draggable.START.length-1;i>=0;i--)o.DomEvent.addListener(t,o.Draggable.START[i],e);return o.DomEvent.addListener(t,\"click\",o.DomEvent._fakeStop).addListener(t,\"dblclick\",e)},preventDefault:function(t){return t.preventDefault?t.preventDefault():t.returnValue=!1,this},stop:function(t){return o.DomEvent.preventDefault(t).stopPropagation(t)},getMousePosition:function(t,i){var n=o.Browser.ie7,s=e.body,a=e.documentElement,r=t.pageX?t.pageX-s.scrollLeft-a.scrollLeft:t.clientX,h=t.pageY?t.pageY-s.scrollTop-a.scrollTop:t.clientY,l=new o.Point(r,h);if(!i)return l;var u=i.getBoundingClientRect(),c=u.left-i.clientLeft,d=u.top-i.clientTop;return o.DomUtil.documentIsLtr()||!o.Browser.webkit&&!n||(c+=i.scrollWidth-i.clientWidth,n&&\"hidden\"!==o.DomUtil.getStyle(i,\"overflow-y\")&&\"hidden\"!==o.DomUtil.getStyle(i,\"overflow\")&&(c+=17)),l._subtract(new o.Point(c,d))},getWheelDelta:function(t){var e=0;return t.wheelDelta&&(e=t.wheelDelta/120),t.detail&&(e=-t.detail/3),e},_skipEvents:{},_fakeStop:function(t){o.DomEvent._skipEvents[t.type]=!0},_skipped:function(t){var e=this._skipEvents[t.type];return this._skipEvents[t.type]=!1,e},_checkMouse:function(t,e){var i=e.relatedTarget;if(!i)return!0;try{for(;i&&i!==t;)i=i.parentNode}catch(n){return!1}return i!==t},_getEvent:function(){var e=t.event;if(!e)for(var i=arguments.callee.caller;i&&(e=i.arguments[0],!e||t.Event!==e.constructor);)i=i.caller;return e},_filterClick:function(t,e){var i=t.timeStamp||t.originalEvent.timeStamp,n=o.DomEvent._lastClick&&i-o.DomEvent._lastClick;return n&&n>100&&1e3>n||t.target._simulatedClick&&!t._simulated?(o.DomEvent.stop(t),void 0):(o.DomEvent._lastClick=i,e(t))}},o.DomEvent.on=o.DomEvent.addListener,o.DomEvent.off=o.DomEvent.removeListener,o.Draggable=o.Class.extend({includes:o.Mixin.Events,statics:{START:o.Browser.touch?[\"touchstart\",\"mousedown\"]:[\"mousedown\"],END:{mousedown:\"mouseup\",touchstart:\"touchend\",MSPointerDown:\"touchend\"},MOVE:{mousedown:\"mousemove\",touchstart:\"touchmove\",MSPointerDown:\"touchmove\"}},initialize:function(t,e){this._element=t,this._dragStartTarget=e||t},enable:function(){if(!this._enabled){for(var t=o.Draggable.START.length-1;t>=0;t--)o.DomEvent.on(this._dragStartTarget,o.Draggable.START[t],this._onDown,this);this._enabled=!0}},disable:function(){if(this._enabled){for(var t=o.Draggable.START.length-1;t>=0;t--)o.DomEvent.off(this._dragStartTarget,o.Draggable.START[t],this._onDown,this);this._enabled=!1,this._moved=!1}},_onDown:function(t){if(!t.shiftKey&&(1===t.which||1===t.button||t.touches)&&(o.DomEvent.stopPropagation(t),!o.Draggable._disabled)){o.DomUtil.disableImageDrag(),o.DomUtil.disableTextSelection();var i=t.touches?t.touches[0]:t,n=i.target;o.Browser.touch&&\"a\"===n.tagName.toLowerCase()&&o.DomUtil.addClass(n,\"leaflet-active\"),this._moved=!1,this._moving||(this._startPoint=new o.Point(i.clientX,i.clientY),this._startPos=this._newPos=o.DomUtil.getPosition(this._element),o.DomEvent.on(e,o.Draggable.MOVE[t.type],this._onMove,this).on(e,o.Draggable.END[t.type],this._onUp,this))}},_onMove:function(t){if(!(t.touches&&t.touches.length>1)){var i=t.touches&&1===t.touches.length?t.touches[0]:t,n=new o.Point(i.clientX,i.clientY),s=n.subtract(this._startPoint);(s.x||s.y)&&(o.DomEvent.preventDefault(t),this._moved||(this.fire(\"dragstart\"),this._moved=!0,this._startPos=o.DomUtil.getPosition(this._element).subtract(s),o.Browser.touch||o.DomUtil.addClass(e.body,\"leaflet-dragging\")),this._newPos=this._startPos.add(s),this._moving=!0,o.Util.cancelAnimFrame(this._animRequest),this._animRequest=o.Util.requestAnimFrame(this._updatePosition,this,!0,this._dragStartTarget))}},_updatePosition:function(){this.fire(\"predrag\"),o.DomUtil.setPosition(this._element,this._newPos),this.fire(\"drag\")},_onUp:function(){o.Browser.touch||o.DomUtil.removeClass(e.body,\"leaflet-dragging\");for(var t in o.Draggable.MOVE)o.DomEvent.off(e,o.Draggable.MOVE[t],this._onMove).off(e,o.Draggable.END[t],this._onUp);o.DomUtil.enableImageDrag(),o.DomUtil.enableTextSelection(),this._moved&&(o.Util.cancelAnimFrame(this._animRequest),this.fire(\"dragend\")),this._moving=!1}}),o.Handler=o.Class.extend({initialize:function(t){this._map=t},enable:function(){this._enabled||(this._enabled=!0,this.addHooks())},disable:function(){this._enabled&&(this._enabled=!1,this.removeHooks())},enabled:function(){return!!this._enabled}}),o.Map.mergeOptions({dragging:!0,inertia:!o.Browser.android23,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,inertiaThreshold:o.Browser.touch?32:18,easeLinearity:.25,worldCopyJump:!1}),o.Map.Drag=o.Handler.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new o.Draggable(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),t.options.worldCopyJump&&(this._draggable.on(\"predrag\",this._onPreDrag,this),t.on(\"viewreset\",this._onViewReset,this),this._onViewReset())}this._draggable.enable()},removeHooks:function(){this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(){var t=this._map;t._panAnim&&t._panAnim.stop(),t.fire(\"movestart\").fire(\"dragstart\"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(){if(this._map.options.inertia){var t=this._lastTime=+new Date,e=this._lastPos=this._draggable._newPos;this._positions.push(e),this._times.push(t),t-this._times[0]>200&&(this._positions.shift(),this._times.shift())}this._map.fire(\"move\").fire(\"drag\")},_onViewReset:function(){var t=this._map.getSize()._divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.project([0,180]).x},_onPreDrag:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,s=(n+e+i)%t-e-i,a=Math.abs(o+i)<Math.abs(s+i)?o:s;this._draggable._newPos.x=a},_onDragEnd:function(){var t=this._map,e=t.options,i=+new Date-this._lastTime,n=!e.inertia||i>e.inertiaThreshold||!this._positions[0];if(t.fire(\"dragend\"),n)t.fire(\"moveend\");else{var s=this._lastPos.subtract(this._positions[0]),a=(this._lastTime+i-this._times[0])/1e3,r=e.easeLinearity,h=s.multiplyBy(r/a),l=h.distanceTo([0,0]),u=Math.min(e.inertiaMaxSpeed,l),c=h.multiplyBy(u/l),d=u/(e.inertiaDeceleration*r),p=c.multiplyBy(-d/2).round();p.x&&p.y?o.Util.requestAnimFrame(function(){t.panBy(p,{duration:d,easeLinearity:r,noMoveStart:!0})}):t.fire(\"moveend\")}}}),o.Map.addInitHook(\"addHandler\",\"dragging\",o.Map.Drag),o.Map.mergeOptions({doubleClickZoom:!0}),o.Map.DoubleClickZoom=o.Handler.extend({addHooks:function(){this._map.on(\"dblclick\",this._onDoubleClick)},removeHooks:function(){this._map.off(\"dblclick\",this._onDoubleClick)},_onDoubleClick:function(t){this.setZoomAround(t.containerPoint,this._zoom+1)}}),o.Map.addInitHook(\"addHandler\",\"doubleClickZoom\",o.Map.DoubleClickZoom),o.Map.mergeOptions({scrollWheelZoom:!0}),o.Map.ScrollWheelZoom=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,\"mousewheel\",this._onWheelScroll,this),o.DomEvent.on(this._map._container,\"MozMousePixelScroll\",o.DomEvent.preventDefault),this._delta=0},removeHooks:function(){o.DomEvent.off(this._map._container,\"mousewheel\",this._onWheelScroll),o.DomEvent.off(this._map._container,\"MozMousePixelScroll\",o.DomEvent.preventDefault)},_onWheelScroll:function(t){var e=o.DomEvent.getWheelDelta(t);this._delta+=e,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date);var i=Math.max(40-(+new Date-this._startTime),0);clearTimeout(this._timer),this._timer=setTimeout(o.bind(this._performZoom,this),i),o.DomEvent.preventDefault(t),o.DomEvent.stopPropagation(t)},_performZoom:function(){var t=this._map,e=this._delta,i=t.getZoom();e=e>0?Math.ceil(e):Math.floor(e),e=Math.max(Math.min(e,4),-4),e=t._limitZoom(i+e)-i,this._delta=0,this._startTime=null,e&&t.setZoomAround(this._lastMousePos,i+e)}}),o.Map.addInitHook(\"addHandler\",\"scrollWheelZoom\",o.Map.ScrollWheelZoom),o.extend(o.DomEvent,{_touchstart:o.Browser.msTouch?\"MSPointerDown\":\"touchstart\",_touchend:o.Browser.msTouch?\"MSPointerUp\":\"touchend\",addDoubleTapListener:function(t,i,n){function s(t){var e;if(o.Browser.msTouch?(_.push(t.pointerId),e=_.length):e=t.touches.length,!(e>1)){var i=Date.now(),n=i-(r||i);h=t.touches?t.touches[0]:t,l=n>0&&u>=n,r=i}}function a(t){if(o.Browser.msTouch){var e=_.indexOf(t.pointerId);if(-1===e)return;_.splice(e,1)}if(l){if(o.Browser.msTouch){var n,s={};for(var a in h)n=h[a],s[a]=\"function\"==typeof n?n.bind(h):n;h=s}h.type=\"dblclick\",i(h),r=null}}var r,h,l=!1,u=250,c=\"_leaflet_\",d=this._touchstart,p=this._touchend,_=[];t[c+d+n]=s,t[c+p+n]=a;var m=o.Browser.msTouch?e.documentElement:t;return t.addEventListener(d,s,!1),m.addEventListener(p,a,!1),o.Browser.msTouch&&m.addEventListener(\"MSPointerCancel\",a,!1),this},removeDoubleTapListener:function(t,i){var n=\"_leaflet_\";return t.removeEventListener(this._touchstart,t[n+this._touchstart+i],!1),(o.Browser.msTouch?e.documentElement:t).removeEventListener(this._touchend,t[n+this._touchend+i],!1),o.Browser.msTouch&&e.documentElement.removeEventListener(\"MSPointerCancel\",t[n+this._touchend+i],!1),this}}),o.extend(o.DomEvent,{_msTouches:[],_msDocumentListener:!1,addMsTouchListener:function(t,e,i,n){switch(e){case\"touchstart\":return this.addMsTouchListenerStart(t,e,i,n);case\"touchend\":return this.addMsTouchListenerEnd(t,e,i,n);case\"touchmove\":return this.addMsTouchListenerMove(t,e,i,n);default:throw\"Unknown touch event type\"}},addMsTouchListenerStart:function(t,i,n,o){var s=\"_leaflet_\",a=this._msTouches,r=function(t){for(var e=!1,i=0;i<a.length;i++)if(a[i].pointerId===t.pointerId){e=!0;break}e||a.push(t),t.touches=a.slice(),t.changedTouches=[t],n(t)};if(t[s+\"touchstart\"+o]=r,t.addEventListener(\"MSPointerDown\",r,!1),!this._msDocumentListener){var h=function(t){for(var e=0;e<a.length;e++)if(a[e].pointerId===t.pointerId){a.splice(e,1);break}};e.documentElement.addEventListener(\"MSPointerUp\",h,!1),e.documentElement.addEventListener(\"MSPointerCancel\",h,!1),this._msDocumentListener=!0}return this},addMsTouchListenerMove:function(t,e,i,n){function o(t){if(t.pointerType!==t.MSPOINTER_TYPE_MOUSE||0!==t.buttons){for(var e=0;e<a.length;e++)if(a[e].pointerId===t.pointerId){a[e]=t;break}t.touches=a.slice(),t.changedTouches=[t],i(t)}}var s=\"_leaflet_\",a=this._msTouches;return t[s+\"touchmove\"+n]=o,t.addEventListener(\"MSPointerMove\",o,!1),this},addMsTouchListenerEnd:function(t,e,i,n){var o=\"_leaflet_\",s=this._msTouches,a=function(t){for(var e=0;e<s.length;e++)if(s[e].pointerId===t.pointerId){s.splice(e,1);break}t.touches=s.slice(),t.changedTouches=[t],i(t)};return t[o+\"touchend\"+n]=a,t.addEventListener(\"MSPointerUp\",a,!1),t.addEventListener(\"MSPointerCancel\",a,!1),this},removeMsTouchListener:function(t,e,i){var n=\"_leaflet_\",o=t[n+e+i];switch(e){case\"touchstart\":t.removeEventListener(\"MSPointerDown\",o,!1);break;case\"touchmove\":t.removeEventListener(\"MSPointerMove\",o,!1);break;case\"touchend\":t.removeEventListener(\"MSPointerUp\",o,!1),t.removeEventListener(\"MSPointerCancel\",o,!1)}return this}}),o.Map.mergeOptions({touchZoom:o.Browser.touch&&!o.Browser.android23}),o.Map.TouchZoom=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,\"touchstart\",this._onTouchStart,this)},removeHooks:function(){o.DomEvent.off(this._map._container,\"touchstart\",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var n=i.mouseEventToLayerPoint(t.touches[0]),s=i.mouseEventToLayerPoint(t.touches[1]),a=i._getCenterLayerPoint();this._startCenter=n.add(s)._divideBy(2),this._startDist=n.distanceTo(s),this._moved=!1,this._zooming=!0,this._centerOffset=a.subtract(this._startCenter),i._panAnim&&i._panAnim.stop(),o.DomEvent.on(e,\"touchmove\",this._onTouchMove,this).on(e,\"touchend\",this._onTouchEnd,this),o.DomEvent.preventDefault(t)}},_onTouchMove:function(t){var e=this._map;if(t.touches&&2===t.touches.length&&this._zooming){var i=e.mouseEventToLayerPoint(t.touches[0]),n=e.mouseEventToLayerPoint(t.touches[1]);this._scale=i.distanceTo(n)/this._startDist,this._delta=i._add(n)._divideBy(2)._subtract(this._startCenter),1!==this._scale&&(this._moved||(o.DomUtil.addClass(e._mapPane,\"leaflet-touching\"),e.fire(\"movestart\").fire(\"zoomstart\"),this._moved=!0),o.Util.cancelAnimFrame(this._animRequest),this._animRequest=o.Util.requestAnimFrame(this._updateOnMove,this,!0,this._map._container),o.DomEvent.preventDefault(t))}},_updateOnMove:function(){var t=this._map,e=this._getScaleOrigin(),i=t.layerPointToLatLng(e),n=t.getScaleZoom(this._scale);t._animateZoom(i,n,this._startCenter,this._scale,this._delta)},_onTouchEnd:function(){if(!this._moved||!this._zooming)return this._zooming=!1,void 0;var t=this._map;this._zooming=!1,o.DomUtil.removeClass(t._mapPane,\"leaflet-touching\"),o.Util.cancelAnimFrame(this._animRequest),o.DomEvent.off(e,\"touchmove\",this._onTouchMove).off(e,\"touchend\",this._onTouchEnd);\nvar i=this._getScaleOrigin(),n=t.layerPointToLatLng(i),s=t.getZoom(),a=t.getScaleZoom(this._scale)-s,r=a>0?Math.ceil(a):Math.floor(a),h=t._limitZoom(s+r),l=t.getZoomScale(h)/this._scale;t._animateZoom(n,h,i,l)},_getScaleOrigin:function(){var t=this._centerOffset.subtract(this._delta).divideBy(this._scale);return this._startCenter.add(t)}}),o.Map.addInitHook(\"addHandler\",\"touchZoom\",o.Map.TouchZoom),o.Map.mergeOptions({tap:!0,tapTolerance:15}),o.Map.Tap=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,\"touchstart\",this._onDown,this)},removeHooks:function(){o.DomEvent.off(this._map._container,\"touchstart\",this._onDown,this)},_onDown:function(t){if(t.touches){if(o.DomEvent.preventDefault(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,clearTimeout(this._holdTimeout),void 0;var i=t.touches[0],n=i.target;this._startPos=this._newPos=new o.Point(i.clientX,i.clientY),\"a\"===n.tagName.toLowerCase()&&o.DomUtil.addClass(n,\"leaflet-active\"),this._holdTimeout=setTimeout(o.bind(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent(\"contextmenu\",i))},this),1e3),o.DomEvent.on(e,\"touchmove\",this._onMove,this).on(e,\"touchend\",this._onUp,this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),o.DomEvent.off(e,\"touchmove\",this._onMove,this).off(e,\"touchend\",this._onUp,this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],n=i.target;\"a\"===n.tagName.toLowerCase()&&o.DomUtil.removeClass(n,\"leaflet-active\"),this._isTapValid()&&this._simulateEvent(\"click\",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var e=t.touches[0];this._newPos=new o.Point(e.clientX,e.clientY)},_simulateEvent:function(i,n){var o=e.createEvent(\"MouseEvents\");o._simulated=!0,n.target._simulatedClick=!0,o.initMouseEvent(i,!0,!0,t,1,n.screenX,n.screenY,n.clientX,n.clientY,!1,!1,!1,!1,0,null),n.target.dispatchEvent(o)}}),o.Browser.touch&&!o.Browser.msTouch&&o.Map.addInitHook(\"addHandler\",\"tap\",o.Map.Tap),o.Map.mergeOptions({boxZoom:!0}),o.Map.BoxZoom=o.Handler.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane},addHooks:function(){o.DomEvent.on(this._container,\"mousedown\",this._onMouseDown,this)},removeHooks:function(){o.DomEvent.off(this._container,\"mousedown\",this._onMouseDown)},_onMouseDown:function(t){return!t.shiftKey||1!==t.which&&1!==t.button?!1:(o.DomUtil.disableTextSelection(),o.DomUtil.disableImageDrag(),this._startLayerPoint=this._map.mouseEventToLayerPoint(t),this._box=o.DomUtil.create(\"div\",\"leaflet-zoom-box\",this._pane),o.DomUtil.setPosition(this._box,this._startLayerPoint),this._container.style.cursor=\"crosshair\",o.DomEvent.on(e,\"mousemove\",this._onMouseMove,this).on(e,\"mouseup\",this._onMouseUp,this).on(e,\"keydown\",this._onKeyDown,this),this._map.fire(\"boxzoomstart\"),void 0)},_onMouseMove:function(t){var e=this._startLayerPoint,i=this._box,n=this._map.mouseEventToLayerPoint(t),s=n.subtract(e),a=new o.Point(Math.min(n.x,e.x),Math.min(n.y,e.y));o.DomUtil.setPosition(i,a),i.style.width=Math.max(0,Math.abs(s.x)-4)+\"px\",i.style.height=Math.max(0,Math.abs(s.y)-4)+\"px\"},_finish:function(){this._pane.removeChild(this._box),this._container.style.cursor=\"\",o.DomUtil.enableTextSelection(),o.DomUtil.enableImageDrag(),o.DomEvent.off(e,\"mousemove\",this._onMouseMove).off(e,\"mouseup\",this._onMouseUp).off(e,\"keydown\",this._onKeyDown)},_onMouseUp:function(t){this._finish();var e=this._map,i=e.mouseEventToLayerPoint(t);if(!this._startLayerPoint.equals(i)){var n=new o.LatLngBounds(e.layerPointToLatLng(this._startLayerPoint),e.layerPointToLatLng(i));e.fitBounds(n),e.fire(\"boxzoomend\",{boxZoomBounds:n})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}}),o.Map.addInitHook(\"addHandler\",\"boxZoom\",o.Map.BoxZoom),o.Map.mergeOptions({keyboard:!0,keyboardPanOffset:80,keyboardZoomOffset:1}),o.Map.Keyboard=o.Handler.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61],zoomOut:[189,109,173]},initialize:function(t){this._map=t,this._setPanOffset(t.options.keyboardPanOffset),this._setZoomOffset(t.options.keyboardZoomOffset)},addHooks:function(){var t=this._map._container;-1===t.tabIndex&&(t.tabIndex=\"0\"),o.DomEvent.on(t,\"focus\",this._onFocus,this).on(t,\"blur\",this._onBlur,this).on(t,\"mousedown\",this._onMouseDown,this),this._map.on(\"focus\",this._addHooks,this).on(\"blur\",this._removeHooks,this)},removeHooks:function(){this._removeHooks();var t=this._map._container;o.DomEvent.off(t,\"focus\",this._onFocus,this).off(t,\"blur\",this._onBlur,this).off(t,\"mousedown\",this._onMouseDown,this),this._map.off(\"focus\",this._addHooks,this).off(\"blur\",this._removeHooks,this)},_onMouseDown:function(){if(!this._focused){var i=e.body,n=e.documentElement,o=i.scrollTop||n.scrollTop,s=i.scrollLeft||n.scrollLeft;this._map._container.focus(),t.scrollTo(s,o)}},_onFocus:function(){this._focused=!0,this._map.fire(\"focus\")},_onBlur:function(){this._focused=!1,this._map.fire(\"blur\")},_setPanOffset:function(t){var e,i,n=this._panKeys={},o=this.keyCodes;for(e=0,i=o.left.length;i>e;e++)n[o.left[e]]=[-1*t,0];for(e=0,i=o.right.length;i>e;e++)n[o.right[e]]=[t,0];for(e=0,i=o.down.length;i>e;e++)n[o.down[e]]=[0,t];for(e=0,i=o.up.length;i>e;e++)n[o.up[e]]=[0,-1*t]},_setZoomOffset:function(t){var e,i,n=this._zoomKeys={},o=this.keyCodes;for(e=0,i=o.zoomIn.length;i>e;e++)n[o.zoomIn[e]]=t;for(e=0,i=o.zoomOut.length;i>e;e++)n[o.zoomOut[e]]=-t},_addHooks:function(){o.DomEvent.on(e,\"keydown\",this._onKeyDown,this)},_removeHooks:function(){o.DomEvent.off(e,\"keydown\",this._onKeyDown,this)},_onKeyDown:function(t){var e=t.keyCode,i=this._map;if(e in this._panKeys){if(i._panAnim&&i._panAnim._inProgress)return;i.panBy(this._panKeys[e]),i.options.maxBounds&&i.panInsideBounds(i.options.maxBounds)}else{if(!(e in this._zoomKeys))return;i.setZoom(i.getZoom()+this._zoomKeys[e])}o.DomEvent.stop(t)}}),o.Map.addInitHook(\"addHandler\",\"keyboard\",o.Map.Keyboard),o.Handler.MarkerDrag=o.Handler.extend({initialize:function(t){this._marker=t},addHooks:function(){var t=this._marker._icon;this._draggable||(this._draggable=new o.Draggable(t,t)),this._draggable.on(\"dragstart\",this._onDragStart,this).on(\"drag\",this._onDrag,this).on(\"dragend\",this._onDragEnd,this),this._draggable.enable(),o.DomUtil.addClass(this._marker._icon,\"leaflet-marker-draggable\")},removeHooks:function(){this._draggable.off(\"dragstart\",this._onDragStart,this).off(\"drag\",this._onDrag,this).off(\"dragend\",this._onDragEnd,this),this._draggable.disable(),o.DomUtil.removeClass(this._marker._icon,\"leaflet-marker-draggable\")},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(){this._marker.closePopup().fire(\"movestart\").fire(\"dragstart\"),o.DomUtil.addClass(this._marker._icon,\"leaflet-marker-dragging\")},_onDrag:function(){var t=this._marker,e=t._shadow,i=o.DomUtil.getPosition(t._icon),n=t._map.layerPointToLatLng(i);e&&o.DomUtil.setPosition(e,i),t._latlng=n,t.fire(\"move\",{latlng:n}).fire(\"drag\")},_onDragEnd:function(){this._marker.fire(\"moveend\").fire(\"dragend\"),o.DomUtil.removeClass(this._marker._icon,\"leaflet-marker-dragging\")}}),o.Control=o.Class.extend({options:{position:\"topright\"},initialize:function(t){o.setOptions(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),n=t._controlCorners[i];return o.DomUtil.addClass(e,\"leaflet-control\"),-1!==i.indexOf(\"bottom\")?n.insertBefore(e,n.firstChild):n.appendChild(e),this},removeFrom:function(t){var e=this.getPosition(),i=t._controlCorners[e];return i.removeChild(this._container),this._map=null,this.onRemove&&this.onRemove(t),this}}),o.control=function(t){return new o.Control(t)},o.Map.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.removeFrom(this),this},_initControlPos:function(){function t(t,s){var a=i+t+\" \"+i+s;e[t+s]=o.DomUtil.create(\"div\",a,n)}var e=this._controlCorners={},i=\"leaflet-\",n=this._controlContainer=o.DomUtil.create(\"div\",i+\"control-container\",this._container);t(\"top\",\"left\"),t(\"top\",\"right\"),t(\"bottom\",\"left\"),t(\"bottom\",\"right\")},_clearControlPos:function(){this._container.removeChild(this._controlContainer)}}),o.Control.Zoom=o.Control.extend({options:{position:\"topleft\"},onAdd:function(t){var e=\"leaflet-control-zoom\",i=o.DomUtil.create(\"div\",e+\" leaflet-bar\");return this._map=t,this._zoomInButton=this._createButton(\"+\",\"Zoom in\",e+\"-in\",i,this._zoomIn,this),this._zoomOutButton=this._createButton(\"-\",\"Zoom out\",e+\"-out\",i,this._zoomOut,this),t.on(\"zoomend zoomlevelschange\",this._updateDisabled,this),i},onRemove:function(t){t.off(\"zoomend zoomlevelschange\",this._updateDisabled,this)},_zoomIn:function(t){this._map.zoomIn(t.shiftKey?3:1)},_zoomOut:function(t){this._map.zoomOut(t.shiftKey?3:1)},_createButton:function(t,e,i,n,s,a){var r=o.DomUtil.create(\"a\",i,n);r.innerHTML=t,r.href=\"#\",r.title=e;var h=o.DomEvent.stopPropagation;return o.DomEvent.on(r,\"click\",h).on(r,\"mousedown\",h).on(r,\"dblclick\",h).on(r,\"click\",o.DomEvent.preventDefault).on(r,\"click\",s,a),r},_updateDisabled:function(){var t=this._map,e=\"leaflet-disabled\";o.DomUtil.removeClass(this._zoomInButton,e),o.DomUtil.removeClass(this._zoomOutButton,e),t._zoom===t.getMinZoom()&&o.DomUtil.addClass(this._zoomOutButton,e),t._zoom===t.getMaxZoom()&&o.DomUtil.addClass(this._zoomInButton,e)}}),o.Map.mergeOptions({zoomControl:!0}),o.Map.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new o.Control.Zoom,this.addControl(this.zoomControl))}),o.control.zoom=function(t){return new o.Control.Zoom(t)},o.Control.Attribution=o.Control.extend({options:{position:\"bottomright\",prefix:'<a href=\"http://leafletjs.com\" title=\"A JS library for interactive maps\">Leaflet</a>'},initialize:function(t){o.setOptions(this,t),this._attributions={}},onAdd:function(t){return this._container=o.DomUtil.create(\"div\",\"leaflet-control-attribution\"),o.DomEvent.disableClickPropagation(this._container),t.on(\"layeradd\",this._onLayerAdd,this).on(\"layerremove\",this._onLayerRemove,this),this._update(),this._container},onRemove:function(t){t.off(\"layeradd\",this._onLayerAdd).off(\"layerremove\",this._onLayerRemove)},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):void 0},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):void 0},_update:function(){if(this._map){var t=[];for(var e in this._attributions)this._attributions[e]&&t.push(e);var i=[];this.options.prefix&&i.push(this.options.prefix),t.length&&i.push(t.join(\", \")),this._container.innerHTML=i.join(\" | \")}},_onLayerAdd:function(t){t.layer.getAttribution&&this.addAttribution(t.layer.getAttribution())},_onLayerRemove:function(t){t.layer.getAttribution&&this.removeAttribution(t.layer.getAttribution())}}),o.Map.mergeOptions({attributionControl:!0}),o.Map.addInitHook(function(){this.options.attributionControl&&(this.attributionControl=(new o.Control.Attribution).addTo(this))}),o.control.attribution=function(t){return new o.Control.Attribution(t)},o.Control.Scale=o.Control.extend({options:{position:\"bottomleft\",maxWidth:100,metric:!0,imperial:!0,updateWhenIdle:!1},onAdd:function(t){this._map=t;var e=\"leaflet-control-scale\",i=o.DomUtil.create(\"div\",e),n=this.options;return this._addScales(n,e,i),t.on(n.updateWhenIdle?\"moveend\":\"move\",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?\"moveend\":\"move\",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=o.DomUtil.create(\"div\",e+\"-line\",i)),t.imperial&&(this._iScale=o.DomUtil.create(\"div\",e+\"-line\",i))},_update:function(){var t=this._map.getBounds(),e=t.getCenter().lat,i=6378137*Math.PI*Math.cos(e*Math.PI/180),n=i*(t.getNorthEast().lng-t.getSouthWest().lng)/180,o=this._map.getSize(),s=this.options,a=0;o.x>0&&(a=n*(s.maxWidth/o.x)),this._updateScales(s,a)},_updateScales:function(t,e){t.metric&&e&&this._updateMetric(e),t.imperial&&e&&this._updateImperial(e)},_updateMetric:function(t){var e=this._getRoundNum(t);this._mScale.style.width=this._getScaleWidth(e/t)+\"px\",this._mScale.innerHTML=1e3>e?e+\" m\":e/1e3+\" km\"},_updateImperial:function(t){var e,i,n,o=3.2808399*t,s=this._iScale;o>5280?(e=o/5280,i=this._getRoundNum(e),s.style.width=this._getScaleWidth(i/e)+\"px\",s.innerHTML=i+\" mi\"):(n=this._getRoundNum(o),s.style.width=this._getScaleWidth(n/o)+\"px\",s.innerHTML=n+\" ft\")},_getScaleWidth:function(t){return Math.round(this.options.maxWidth*t)-10},_getRoundNum:function(t){var e=Math.pow(10,(Math.floor(t)+\"\").length-1),i=t/e;return i=i>=10?10:i>=5?5:i>=3?3:i>=2?2:1,e*i}}),o.control.scale=function(t){return new o.Control.Scale(t)},o.Control.Layers=o.Control.extend({options:{collapsed:!0,position:\"topright\",autoZIndex:!0},initialize:function(t,e,i){o.setOptions(this,i),this._layers={},this._lastZIndex=0,this._handlingClick=!1;for(var n in t)this._addLayer(t[n],n);for(n in e)this._addLayer(e[n],n,!0)},onAdd:function(t){return this._initLayout(),this._update(),t.on(\"layeradd\",this._onLayerChange,this).on(\"layerremove\",this._onLayerChange,this),this._container},onRemove:function(t){t.off(\"layeradd\",this._onLayerChange).off(\"layerremove\",this._onLayerChange)},addBaseLayer:function(t,e){return this._addLayer(t,e),this._update(),this},addOverlay:function(t,e){return this._addLayer(t,e,!0),this._update(),this},removeLayer:function(t){var e=o.stamp(t);return delete this._layers[e],this._update(),this},_initLayout:function(){var t=\"leaflet-control-layers\",e=this._container=o.DomUtil.create(\"div\",t);e.setAttribute(\"aria-haspopup\",!0),o.Browser.touch?o.DomEvent.on(e,\"click\",o.DomEvent.stopPropagation):(o.DomEvent.disableClickPropagation(e),o.DomEvent.on(e,\"mousewheel\",o.DomEvent.stopPropagation));var i=this._form=o.DomUtil.create(\"form\",t+\"-list\");if(this.options.collapsed){o.Browser.android||o.DomEvent.on(e,\"mouseover\",this._expand,this).on(e,\"mouseout\",this._collapse,this);var n=this._layersLink=o.DomUtil.create(\"a\",t+\"-toggle\",e);n.href=\"#\",n.title=\"Layers\",o.Browser.touch?o.DomEvent.on(n,\"click\",o.DomEvent.stop).on(n,\"click\",this._expand,this):o.DomEvent.on(n,\"focus\",this._expand,this),this._map.on(\"click\",this._collapse,this)}else this._expand();this._baseLayersList=o.DomUtil.create(\"div\",t+\"-base\",i),this._separator=o.DomUtil.create(\"div\",t+\"-separator\",i),this._overlaysList=o.DomUtil.create(\"div\",t+\"-overlays\",i),e.appendChild(i)},_addLayer:function(t,e,i){var n=o.stamp(t);this._layers[n]={layer:t,name:e,overlay:i},this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex))},_update:function(){if(this._container){this._baseLayersList.innerHTML=\"\",this._overlaysList.innerHTML=\"\";var t,e,i=!1,n=!1;for(t in this._layers)e=this._layers[t],this._addItem(e),n=n||e.overlay,i=i||!e.overlay;this._separator.style.display=n&&i?\"\":\"none\"}},_onLayerChange:function(t){var e=this._layers[o.stamp(t.layer)];if(e){this._handlingClick||this._update();var i=e.overlay?\"layeradd\"===t.type?\"overlayadd\":\"overlayremove\":\"layeradd\"===t.type?\"baselayerchange\":null;i&&this._map.fire(i,e)}},_createRadioElement:function(t,i){var n='<input type=\"radio\" class=\"leaflet-control-layers-selector\" name=\"'+t+'\"';i&&(n+=' checked=\"checked\"'),n+=\"/>\";var o=e.createElement(\"div\");return o.innerHTML=n,o.firstChild},_addItem:function(t){var i,n=e.createElement(\"label\"),s=this._map.hasLayer(t.layer);t.overlay?(i=e.createElement(\"input\"),i.type=\"checkbox\",i.className=\"leaflet-control-layers-selector\",i.defaultChecked=s):i=this._createRadioElement(\"leaflet-base-layers\",s),i.layerId=o.stamp(t.layer),o.DomEvent.on(i,\"click\",this._onInputClick,this);var a=e.createElement(\"span\");a.innerHTML=\" \"+t.name,n.appendChild(i),n.appendChild(a);var r=t.overlay?this._overlaysList:this._baseLayersList;return r.appendChild(n),n},_onInputClick:function(){var t,e,i,n=this._form.getElementsByTagName(\"input\"),o=n.length;for(this._handlingClick=!0,t=0;o>t;t++)e=n[t],i=this._layers[e.layerId],e.checked&&!this._map.hasLayer(i.layer)?this._map.addLayer(i.layer):!e.checked&&this._map.hasLayer(i.layer)&&this._map.removeLayer(i.layer);this._handlingClick=!1},_expand:function(){o.DomUtil.addClass(this._container,\"leaflet-control-layers-expanded\")},_collapse:function(){this._container.className=this._container.className.replace(\" leaflet-control-layers-expanded\",\"\")}}),o.control.layers=function(t,e,i){return new o.Control.Layers(t,e,i)},o.PosAnimation=o.Class.extend({includes:o.Mixin.Events,run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._newPos=e,this.fire(\"start\"),t.style[o.DomUtil.TRANSITION]=\"all \"+(i||.25)+\"s cubic-bezier(0,0,\"+(n||.5)+\",1)\",o.DomEvent.on(t,o.DomUtil.TRANSITION_END,this._onTransitionEnd,this),o.DomUtil.setPosition(t,e),o.Util.falseFn(t.offsetWidth),this._stepTimer=setInterval(o.bind(this._onStep,this),50)},stop:function(){this._inProgress&&(o.DomUtil.setPosition(this._el,this._getPos()),this._onTransitionEnd(),o.Util.falseFn(this._el.offsetWidth))},_onStep:function(){var t=this._getPos();return t?(this._el._leaflet_pos=t,this.fire(\"step\"),void 0):(this._onTransitionEnd(),void 0)},_transformRe:/([-+]?(?:\\d*\\.)?\\d+)\\D*, ([-+]?(?:\\d*\\.)?\\d+)\\D*\\)/,_getPos:function(){var e,i,n,s=this._el,a=t.getComputedStyle(s);if(o.Browser.any3d){if(n=a[o.DomUtil.TRANSFORM].match(this._transformRe),!n)return;e=parseFloat(n[1]),i=parseFloat(n[2])}else e=parseFloat(a.left),i=parseFloat(a.top);return new o.Point(e,i,!0)},_onTransitionEnd:function(){o.DomEvent.off(this._el,o.DomUtil.TRANSITION_END,this._onTransitionEnd,this),this._inProgress&&(this._inProgress=!1,this._el.style[o.DomUtil.TRANSITION]=\"\",this._el._leaflet_pos=this._newPos,clearInterval(this._stepTimer),this.fire(\"step\").fire(\"end\"))}}),o.Map.include({setView:function(t,e,n){if(e=this._limitZoom(e),t=o.latLng(t),n=n||{},this._panAnim&&this._panAnim.stop(),this._loaded&&!n.reset&&n!==!0){n.animate!==i&&(n.zoom=o.extend({animate:n.animate},n.zoom),n.pan=o.extend({animate:n.animate},n.pan));var s=this._zoom!==e?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,e,n.zoom):this._tryAnimatedPan(t,n.pan);if(s)return clearTimeout(this._sizeTimer),this}return this._resetView(t,e),this},panBy:function(t,e){if(t=o.point(t).round(),e=e||{},!t.x&&!t.y)return this;if(this._panAnim||(this._panAnim=new o.PosAnimation,this._panAnim.on({step:this._onPanTransitionStep,end:this._onPanTransitionEnd},this)),e.noMoveStart||this.fire(\"movestart\"),e.animate!==!1){o.DomUtil.addClass(this._mapPane,\"leaflet-pan-anim\");var i=this._getMapPanePos().subtract(t);this._panAnim.run(this._mapPane,i,e.duration||.25,e.easeLinearity)}else this._rawPanBy(t),this.fire(\"move\").fire(\"moveend\");return this},_onPanTransitionStep:function(){this.fire(\"move\")},_onPanTransitionEnd:function(){o.DomUtil.removeClass(this._mapPane,\"leaflet-pan-anim\"),this.fire(\"moveend\")},_tryAnimatedPan:function(t,e){var i=this._getCenterOffset(t)._floor();return(e&&e.animate)===!0||this.getSize().contains(i)?(this.panBy(i,e),!0):!1}}),o.PosAnimation=o.DomUtil.TRANSITION?o.PosAnimation:o.PosAnimation.extend({run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=i||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=o.DomUtil.getPosition(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire(\"start\"),this._animate()},stop:function(){this._inProgress&&(this._step(),this._complete())},_animate:function(){this._animId=o.Util.requestAnimFrame(this._animate,this),this._step()},_step:function(){var t=+new Date-this._startTime,e=1e3*this._duration;e>t?this._runFrame(this._easeOut(t/e)):(this._runFrame(1),this._complete())},_runFrame:function(t){var e=this._startPos.add(this._offset.multiplyBy(t));o.DomUtil.setPosition(this._el,e),this.fire(\"step\")},_complete:function(){o.Util.cancelAnimFrame(this._animId),this._inProgress=!1,this.fire(\"end\")},_easeOut:function(t){return 1-Math.pow(1-t,this._easeOutPower)}}),o.Map.mergeOptions({zoomAnimation:!0,zoomAnimationThreshold:4}),o.DomUtil.TRANSITION&&o.Map.addInitHook(function(){this._zoomAnimated=this.options.zoomAnimation&&o.DomUtil.TRANSITION&&o.Browser.any3d&&!o.Browser.android23&&!o.Browser.mobileOpera,this._zoomAnimated&&o.DomEvent.on(this._mapPane,o.DomUtil.TRANSITION_END,this._catchTransitionEnd,this)}),o.Map.include(o.DomUtil.TRANSITION?{_catchTransitionEnd:function(){this._animatingZoom&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName(\"leaflet-zoom-animated\").length},_tryAnimatedZoom:function(t,e,i){if(this._animatingZoom)return!0;if(i=i||{},!this._zoomAnimated||i.animate===!1||this._nothingToAnimate()||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),o=this._getCenterOffset(t)._divideBy(1-1/n),s=this._getCenterLayerPoint()._add(o);return i.animate===!0||this.getSize().contains(o)?(this.fire(\"movestart\").fire(\"zoomstart\"),this._animateZoom(t,e,s,n,null,!0),!0):!1},_animateZoom:function(t,e,i,n,s,a){this._animatingZoom=!0,o.DomUtil.addClass(this._mapPane,\"leaflet-zoom-anim\"),this._animateToCenter=t,this._animateToZoom=e,o.Draggable&&(o.Draggable._disabled=!0),this.fire(\"zoomanim\",{center:t,zoom:e,origin:i,scale:n,delta:s,backwards:a})},_onZoomTransitionEnd:function(){this._animatingZoom=!1,o.DomUtil.removeClass(this._mapPane,\"leaflet-zoom-anim\"),this._resetView(this._animateToCenter,this._animateToZoom,!0,!0),o.Draggable&&(o.Draggable._disabled=!1)}}:{}),o.TileLayer.include({_animateZoom:function(t){this._animating||(this._animating=!0,this._prepareBgBuffer());var e=this._bgBuffer,i=o.DomUtil.TRANSFORM,n=t.delta?o.DomUtil.getTranslateString(t.delta):e.style[i],s=o.DomUtil.getScaleString(t.scale,t.origin);e.style[i]=t.backwards?s+\" \"+n:n+\" \"+s},_endZoomAnim:function(){var t=this._tileContainer,e=this._bgBuffer;t.style.visibility=\"\",t.parentNode.appendChild(t),o.Util.falseFn(e.offsetWidth),this._animating=!1},_clearBgBuffer:function(){var t=this._map;!t||t._animatingZoom||t.touchZoom._zooming||(this._bgBuffer.innerHTML=\"\",this._bgBuffer.style[o.DomUtil.TRANSFORM]=\"\")},_prepareBgBuffer:function(){var t=this._tileContainer,e=this._bgBuffer,i=this._getLoadedTilesPercentage(e),n=this._getLoadedTilesPercentage(t);return e&&i>.5&&.5>n?(t.style.visibility=\"hidden\",this._stopLoadingImages(t),void 0):(e.style.visibility=\"hidden\",e.style[o.DomUtil.TRANSFORM]=\"\",this._tileContainer=e,e=this._bgBuffer=t,this._stopLoadingImages(e),clearTimeout(this._clearBgBufferTimer),void 0)},_getLoadedTilesPercentage:function(t){var e,i,n=t.getElementsByTagName(\"img\"),o=0;for(e=0,i=n.length;i>e;e++)n[e].complete&&o++;return o/i},_stopLoadingImages:function(t){var e,i,n,s=Array.prototype.slice.call(t.getElementsByTagName(\"img\"));for(e=0,i=s.length;i>e;e++)n=s[e],n.complete||(n.onload=o.Util.falseFn,n.onerror=o.Util.falseFn,n.src=o.Util.emptyImageUrl,n.parentNode.removeChild(n))}}),o.Map.include({_defaultLocateOptions:{watch:!1,setView:!1,maxZoom:1/0,timeout:1e4,maximumAge:0,enableHighAccuracy:!1},locate:function(t){if(t=this._locateOptions=o.extend(this._defaultLocateOptions,t),!navigator.geolocation)return this._handleGeolocationError({code:0,message:\"Geolocation not supported.\"}),this;var e=o.bind(this._handleGeolocationResponse,this),i=o.bind(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e=t.code,i=t.message||(1===e?\"permission denied\":2===e?\"position unavailable\":\"timeout\");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire(\"locationerror\",{code:e,message:\"Geolocation error: \"+i+\".\"})},_handleGeolocationResponse:function(t){var e=t.coords.latitude,i=t.coords.longitude,n=new o.LatLng(e,i),s=180*t.coords.accuracy/40075017,a=s/Math.cos(o.LatLng.DEG_TO_RAD*e),r=o.latLngBounds([e-s,i-a],[e+s,i+a]),h=this._locateOptions;if(h.setView){var l=Math.min(this.getBoundsZoom(r),h.maxZoom);this.setView(n,l)}var u={latlng:n,bounds:r};for(var c in t.coords)\"number\"==typeof t.coords[c]&&(u[c]=t.coords[c]);this.fire(\"locationfound\",u)}})}(window,document);"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet/leaflet.markercluster.js",
    "content": "/*\n Leaflet.markercluster, Provides Beautiful Animated Marker Clustering functionality for Leaflet, a JS library for interactive maps.\n https://github.com/Leaflet/Leaflet.markercluster\n (c) 2012-2013, Dave Leaver, smartrak\n*/\n!function(t,e){L.MarkerClusterGroup=L.FeatureGroup.extend({options:{maxClusterRadius:80,iconCreateFunction:null,spiderfyOnMaxZoom:!0,showCoverageOnHover:!0,zoomToBoundsOnClick:!0,singleMarkerMode:!1,disableClusteringAtZoom:null,removeOutsideVisibleBounds:!0,animateAddingMarkers:!1,spiderfyDistanceMultiplier:1,polygonOptions:{}},initialize:function(t){L.Util.setOptions(this,t),this.options.iconCreateFunction||(this.options.iconCreateFunction=this._defaultIconCreateFunction),this._featureGroup=L.featureGroup(),this._featureGroup.on(L.FeatureGroup.EVENTS,this._propagateEvent,this),this._nonPointGroup=L.featureGroup(),this._nonPointGroup.on(L.FeatureGroup.EVENTS,this._propagateEvent,this),this._inZoomAnimation=0,this._needsClustering=[],this._needsRemoving=[],this._currentShownBounds=null},addLayer:function(t){if(t instanceof L.LayerGroup){var e=[];for(var i in t._layers)e.push(t._layers[i]);return this.addLayers(e)}if(!t.getLatLng)return this._nonPointGroup.addLayer(t),this;if(!this._map)return this._needsClustering.push(t),this;if(this.hasLayer(t))return this;this._unspiderfy&&this._unspiderfy(),this._addLayer(t,this._maxZoom);var n=t,s=this._map.getZoom();if(t.__parent)for(;n.__parent._zoom>=s;)n=n.__parent;return this._currentShownBounds.contains(n.getLatLng())&&(this.options.animateAddingMarkers?this._animationAddLayer(t,n):this._animationAddLayerNonAnimated(t,n)),this},removeLayer:function(t){if(t instanceof L.LayerGroup){var e=[];for(var i in t._layers)e.push(t._layers[i]);return this.removeLayers(e)}return t.getLatLng?this._map?t.__parent?(this._unspiderfy&&(this._unspiderfy(),this._unspiderfyLayer(t)),this._removeLayer(t,!0),this._featureGroup.hasLayer(t)&&(this._featureGroup.removeLayer(t),t.setOpacity&&t.setOpacity(1)),this):this:(!this._arraySplice(this._needsClustering,t)&&this.hasLayer(t)&&this._needsRemoving.push(t),this):(this._nonPointGroup.removeLayer(t),this)},addLayers:function(t){var e,i,n,s=this._map,r=this._featureGroup,o=this._nonPointGroup;for(e=0,i=t.length;i>e;e++)if(n=t[e],n.getLatLng){if(!this.hasLayer(n))if(s){if(this._addLayer(n,this._maxZoom),n.__parent&&2===n.__parent.getChildCount()){var a=n.__parent.getAllChildMarkers(),h=a[0]===n?a[1]:a[0];r.removeLayer(h)}}else this._needsClustering.push(n)}else o.addLayer(n);return s&&(r.eachLayer(function(t){t instanceof L.MarkerCluster&&t._iconNeedsUpdate&&t._updateIcon()}),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds)),this},removeLayers:function(t){var e,i,n,s=this._featureGroup,r=this._nonPointGroup;if(!this._map){for(e=0,i=t.length;i>e;e++)n=t[e],this._arraySplice(this._needsClustering,n),r.removeLayer(n);return this}for(e=0,i=t.length;i>e;e++)n=t[e],n.__parent?(this._removeLayer(n,!0,!0),s.hasLayer(n)&&(s.removeLayer(n),n.setOpacity&&n.setOpacity(1))):r.removeLayer(n);return this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds),s.eachLayer(function(t){t instanceof L.MarkerCluster&&t._updateIcon()}),this},clearLayers:function(){return this._map||(this._needsClustering=[],delete this._gridClusters,delete this._gridUnclustered),this._noanimationUnspiderfy&&this._noanimationUnspiderfy(),this._featureGroup.clearLayers(),this._nonPointGroup.clearLayers(),this.eachLayer(function(t){delete t.__parent}),this._map&&this._generateInitialClusters(),this},getBounds:function(){var t=new L.LatLngBounds;if(this._topClusterLevel)t.extend(this._topClusterLevel._bounds);else for(var e=this._needsClustering.length-1;e>=0;e--)t.extend(this._needsClustering[e].getLatLng());var i=this._nonPointGroup.getBounds();return i.isValid()&&t.extend(i),t},eachLayer:function(t,e){var i,n=this._needsClustering.slice();for(this._topClusterLevel&&this._topClusterLevel.getAllChildMarkers(n),i=n.length-1;i>=0;i--)t.call(e,n[i]);this._nonPointGroup.eachLayer(t,e)},hasLayer:function(t){if(!t)return!1;var e,i=this._needsClustering;for(e=i.length-1;e>=0;e--)if(i[e]===t)return!0;for(i=this._needsRemoving,e=i.length-1;e>=0;e--)if(i[e]===t)return!1;return!(!t.__parent||t.__parent._group!==this)||this._nonPointGroup.hasLayer(t)},zoomToShowLayer:function(t,e){var i=function(){if((t._icon||t.__parent._icon)&&!this._inZoomAnimation)if(this._map.off(\"moveend\",i,this),this.off(\"animationend\",i,this),t._icon)e();else if(t.__parent._icon){var n=function(){this.off(\"spiderfied\",n,this),e()};this.on(\"spiderfied\",n,this),t.__parent.spiderfy()}};t._icon?e():t.__parent._zoom<this._map.getZoom()?(this._map.on(\"moveend\",i,this),t._icon||this._map.panTo(t.getLatLng())):(this._map.on(\"moveend\",i,this),this.on(\"animationend\",i,this),this._map.setView(t.getLatLng(),t.__parent._zoom+1),t.__parent.zoomToBounds())},onAdd:function(t){this._map=t;var e,i,n;if(!isFinite(this._map.getMaxZoom()))throw\"Map has no maxZoom specified\";for(this._featureGroup.onAdd(t),this._nonPointGroup.onAdd(t),this._gridClusters||this._generateInitialClusters(),e=0,i=this._needsRemoving.length;i>e;e++)n=this._needsRemoving[e],this._removeLayer(n,!0);for(this._needsRemoving=[],e=0,i=this._needsClustering.length;i>e;e++)n=this._needsClustering[e],n.getLatLng?n.__parent||this._addLayer(n,this._maxZoom):this._featureGroup.addLayer(n);this._needsClustering=[],this._map.on(\"zoomend\",this._zoomEnd,this),this._map.on(\"moveend\",this._moveEnd,this),this._spiderfierOnAdd&&this._spiderfierOnAdd(),this._bindEvents(),this._zoom=this._map.getZoom(),this._currentShownBounds=this._getExpandedVisibleBounds(),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,this._currentShownBounds)},onRemove:function(t){t.off(\"zoomend\",this._zoomEnd,this),t.off(\"moveend\",this._moveEnd,this),this._unbindEvents(),this._map._mapPane.className=this._map._mapPane.className.replace(\" leaflet-cluster-anim\",\"\"),this._spiderfierOnRemove&&this._spiderfierOnRemove(),this._featureGroup.onRemove(t),this._nonPointGroup.onRemove(t),this._featureGroup.clearLayers(),this._map=null},getVisibleParent:function(t){for(var e=t;null!==e&&!e._icon;)e=e.__parent;return e},_arraySplice:function(t,e){for(var i=t.length-1;i>=0;i--)if(t[i]===e)return t.splice(i,1),!0},_removeLayer:function(t,e,i){var n=this._gridClusters,s=this._gridUnclustered,r=this._featureGroup,o=this._map;if(e)for(var a=this._maxZoom;a>=0&&s[a].removeObject(t,o.project(t.getLatLng(),a));a--);var h,_=t.__parent,u=_._markers;for(this._arraySplice(u,t);_&&(_._childCount--,!(_._zoom<0));)e&&_._childCount<=1?(h=_._markers[0]===t?_._markers[1]:_._markers[0],n[_._zoom].removeObject(_,o.project(_._cLatLng,_._zoom)),s[_._zoom].addObject(h,o.project(h.getLatLng(),_._zoom)),this._arraySplice(_.__parent._childClusters,_),_.__parent._markers.push(h),h.__parent=_.__parent,_._icon&&(r.removeLayer(_),i||r.addLayer(h))):(_._recalculateBounds(),i&&_._icon||_._updateIcon()),_=_.__parent;delete t.__parent},_propagateEvent:function(t){t.layer instanceof L.MarkerCluster&&(t.type=\"cluster\"+t.type),this.fire(t.type,t)},_defaultIconCreateFunction:function(t){var e=t.getChildCount(),i=\" marker-cluster-\";return i+=10>e?\"small\":100>e?\"medium\":\"large\",new L.DivIcon({html:\"<div><span>\"+e+\"</span></div>\",className:\"marker-cluster\"+i,iconSize:new L.Point(40,40)})},_bindEvents:function(){var t=this._map,e=this.options.spiderfyOnMaxZoom,i=this.options.showCoverageOnHover,n=this.options.zoomToBoundsOnClick;(e||n)&&this.on(\"clusterclick\",this._zoomOrSpiderfy,this),i&&(this.on(\"clustermouseover\",this._showCoverage,this),this.on(\"clustermouseout\",this._hideCoverage,this),t.on(\"zoomend\",this._hideCoverage,this),t.on(\"layerremove\",this._hideCoverageOnRemove,this))},_zoomOrSpiderfy:function(t){var e=this._map;e.getMaxZoom()===e.getZoom()?this.options.spiderfyOnMaxZoom&&t.layer.spiderfy():this.options.zoomToBoundsOnClick&&t.layer.zoomToBounds()},_showCoverage:function(t){var e=this._map;this._inZoomAnimation||(this._shownPolygon&&e.removeLayer(this._shownPolygon),t.layer.getChildCount()>2&&t.layer!==this._spiderfied&&(this._shownPolygon=new L.Polygon(t.layer.getConvexHull(),this.options.polygonOptions),e.addLayer(this._shownPolygon)))},_hideCoverage:function(){this._shownPolygon&&(this._map.removeLayer(this._shownPolygon),this._shownPolygon=null)},_hideCoverageOnRemove:function(t){t.layer===this&&this._hideCoverage()},_unbindEvents:function(){var t=this.options.spiderfyOnMaxZoom,e=this.options.showCoverageOnHover,i=this.options.zoomToBoundsOnClick,n=this._map;(t||i)&&this.off(\"clusterclick\",this._zoomOrSpiderfy,this),e&&(this.off(\"clustermouseover\",this._showCoverage,this),this.off(\"clustermouseout\",this._hideCoverage,this),n.off(\"zoomend\",this._hideCoverage,this),n.off(\"layerremove\",this._hideCoverageOnRemove,this))},_zoomEnd:function(){this._map&&(this._mergeSplitClusters(),this._zoom=this._map._zoom,this._currentShownBounds=this._getExpandedVisibleBounds())},_moveEnd:function(){if(!this._inZoomAnimation){var t=this._getExpandedVisibleBounds();this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,this._zoom,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,this._zoom,t),this._currentShownBounds=t}},_generateInitialClusters:function(){var t=this._map.getMaxZoom(),e=this.options.maxClusterRadius;this.options.disableClusteringAtZoom&&(t=this.options.disableClusteringAtZoom-1),this._maxZoom=t,this._gridClusters={},this._gridUnclustered={};for(var i=t;i>=0;i--)this._gridClusters[i]=new L.DistanceGrid(e),this._gridUnclustered[i]=new L.DistanceGrid(e);this._topClusterLevel=new L.MarkerCluster(this,-1)},_addLayer:function(t,e){var i,n,s=this._gridClusters,r=this._gridUnclustered;for(this.options.singleMarkerMode&&(t.options.icon=this.options.iconCreateFunction({getChildCount:function(){return 1},getAllChildMarkers:function(){return[t]}}));e>=0;e--){i=this._map.project(t.getLatLng(),e);var o=s[e].getNearObject(i);if(o)return o._addChild(t),t.__parent=o,void 0;if(o=r[e].getNearObject(i)){var a=o.__parent;a&&this._removeLayer(o,!1);var h=new L.MarkerCluster(this,e,o,t);s[e].addObject(h,this._map.project(h._cLatLng,e)),o.__parent=h,t.__parent=h;var _=h;for(n=e-1;n>a._zoom;n--)_=new L.MarkerCluster(this,n,_),s[n].addObject(_,this._map.project(o.getLatLng(),n));for(a._addChild(_),n=e;n>=0&&r[n].removeObject(o,this._map.project(o.getLatLng(),n));n--);return}r[e].addObject(t,i)}this._topClusterLevel._addChild(t),t.__parent=this._topClusterLevel},_mergeSplitClusters:function(){this._zoom<this._map._zoom?(this._animationStart(),this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,this._zoom,this._getExpandedVisibleBounds()),this._animationZoomIn(this._zoom,this._map._zoom)):this._zoom>this._map._zoom?(this._animationStart(),this._animationZoomOut(this._zoom,this._map._zoom)):this._moveEnd()},_getExpandedVisibleBounds:function(){if(!this.options.removeOutsideVisibleBounds)return this.getBounds();var t=this._map,e=t.getBounds(),i=e._southWest,n=e._northEast,s=L.Browser.mobile?0:Math.abs(i.lat-n.lat),r=L.Browser.mobile?0:Math.abs(i.lng-n.lng);return new L.LatLngBounds(new L.LatLng(i.lat-s,i.lng-r,!0),new L.LatLng(n.lat+s,n.lng+r,!0))},_animationAddLayerNonAnimated:function(t,e){if(e===t)this._featureGroup.addLayer(t);else if(2===e._childCount){e._addToMap();var i=e.getAllChildMarkers();this._featureGroup.removeLayer(i[0]),this._featureGroup.removeLayer(i[1])}else e._updateIcon()}}),L.MarkerClusterGroup.include(L.DomUtil.TRANSITION?{_animationStart:function(){this._map._mapPane.className+=\" leaflet-cluster-anim\",this._inZoomAnimation++},_animationEnd:function(){this._map&&(this._map._mapPane.className=this._map._mapPane.className.replace(\" leaflet-cluster-anim\",\"\")),this._inZoomAnimation--,this.fire(\"animationend\")},_animationZoomIn:function(t,e){var i,n=this,s=this._getExpandedVisibleBounds(),r=this._featureGroup;this._topClusterLevel._recursively(s,t,0,function(n){var o,a=n._latlng,h=n._markers;for(s.contains(a)||(a=null),n._isSingleParent()&&t+1===e?(r.removeLayer(n),n._recursivelyAddChildrenToMap(null,e,s)):(n.setOpacity(0),n._recursivelyAddChildrenToMap(a,e,s)),i=h.length-1;i>=0;i--)o=h[i],s.contains(o._latlng)||r.removeLayer(o)}),this._forceLayout(),n._topClusterLevel._recursivelyBecomeVisible(s,e),r.eachLayer(function(t){t instanceof L.MarkerCluster||!t._icon||t.setOpacity(1)}),n._topClusterLevel._recursively(s,t,e,function(t){t._recursivelyRestoreChildPositions(e)}),setTimeout(function(){n._topClusterLevel._recursively(s,t,0,function(t){r.removeLayer(t),t.setOpacity(1)}),n._animationEnd()},200)},_animationZoomOut:function(t,e){this._animationZoomOutSingle(this._topClusterLevel,t-1,e),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds()),this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t,this._getExpandedVisibleBounds())},_animationZoomOutSingle:function(t,e,i){var n=this._getExpandedVisibleBounds();t._recursivelyAnimateChildrenInAndAddSelfToMap(n,e+1,i);var s=this;this._forceLayout(),t._recursivelyBecomeVisible(n,i),setTimeout(function(){if(1===t._childCount){var r=t._markers[0];r.setLatLng(r.getLatLng()),r.setOpacity(1)}else t._recursively(n,i,0,function(t){t._recursivelyRemoveChildrenFromMap(n,e+1)});s._animationEnd()},200)},_animationAddLayer:function(t,e){var i=this,n=this._featureGroup;n.addLayer(t),e!==t&&(e._childCount>2?(e._updateIcon(),this._forceLayout(),this._animationStart(),t._setPos(this._map.latLngToLayerPoint(e.getLatLng())),t.setOpacity(0),setTimeout(function(){n.removeLayer(t),t.setOpacity(1),i._animationEnd()},200)):(this._forceLayout(),i._animationStart(),i._animationZoomOutSingle(e,this._map.getMaxZoom(),this._map.getZoom())))},_forceLayout:function(){L.Util.falseFn(e.body.offsetWidth)}}:{_animationStart:function(){},_animationZoomIn:function(t,e){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds())},_animationZoomOut:function(t,e){this._topClusterLevel._recursivelyRemoveChildrenFromMap(this._currentShownBounds,t),this._topClusterLevel._recursivelyAddChildrenToMap(null,e,this._getExpandedVisibleBounds())},_animationAddLayer:function(t,e){this._animationAddLayerNonAnimated(t,e)}}),L.markerClusterGroup=function(t){return new L.MarkerClusterGroup(t)},L.MarkerCluster=L.Marker.extend({initialize:function(t,e,i,n){L.Marker.prototype.initialize.call(this,i?i._cLatLng||i.getLatLng():new L.LatLng(0,0),{icon:this}),this._group=t,this._zoom=e,this._markers=[],this._childClusters=[],this._childCount=0,this._iconNeedsUpdate=!0,this._bounds=new L.LatLngBounds,i&&this._addChild(i),n&&this._addChild(n)},getAllChildMarkers:function(t){t=t||[];for(var e=this._childClusters.length-1;e>=0;e--)this._childClusters[e].getAllChildMarkers(t);for(var i=this._markers.length-1;i>=0;i--)t.push(this._markers[i]);return t},getChildCount:function(){return this._childCount},zoomToBounds:function(){this._group._map.fitBounds(this._bounds)},getBounds:function(){var t=new L.LatLngBounds;return t.extend(this._bounds),t},_updateIcon:function(){this._iconNeedsUpdate=!0,this._icon&&this.setIcon(this)},createIcon:function(){return this._iconNeedsUpdate&&(this._iconObj=this._group.options.iconCreateFunction(this),this._iconNeedsUpdate=!1),this._iconObj.createIcon()},createShadow:function(){return this._iconObj.createShadow()},_addChild:function(t,e){this._iconNeedsUpdate=!0,this._expandBounds(t),t instanceof L.MarkerCluster?(e||(this._childClusters.push(t),t.__parent=this),this._childCount+=t._childCount):(e||this._markers.push(t),this._childCount++),this.__parent&&this.__parent._addChild(t,!0)},_expandBounds:function(t){var e,i=t._wLatLng||t._latlng;t instanceof L.MarkerCluster?(this._bounds.extend(t._bounds),e=t._childCount):(this._bounds.extend(i),e=1),this._cLatLng||(this._cLatLng=t._cLatLng||i);var n=this._childCount+e;this._wLatLng?(this._wLatLng.lat=(i.lat*e+this._wLatLng.lat*this._childCount)/n,this._wLatLng.lng=(i.lng*e+this._wLatLng.lng*this._childCount)/n):this._latlng=this._wLatLng=new L.LatLng(i.lat,i.lng)},_addToMap:function(t){t&&(this._backupLatlng=this._latlng,this.setLatLng(t)),this._group._featureGroup.addLayer(this)},_recursivelyAnimateChildrenIn:function(t,e,i){this._recursively(t,0,i-1,function(t){var i,n,s=t._markers;for(i=s.length-1;i>=0;i--)n=s[i],n._icon&&(n._setPos(e),n.setOpacity(0))},function(t){var i,n,s=t._childClusters;for(i=s.length-1;i>=0;i--)n=s[i],n._icon&&(n._setPos(e),n.setOpacity(0))})},_recursivelyAnimateChildrenInAndAddSelfToMap:function(t,e,i){this._recursively(t,i,0,function(n){n._recursivelyAnimateChildrenIn(t,n._group._map.latLngToLayerPoint(n.getLatLng()).round(),e),n._isSingleParent()&&e-1===i?(n.setOpacity(1),n._recursivelyRemoveChildrenFromMap(t,e)):n.setOpacity(0),n._addToMap()})},_recursivelyBecomeVisible:function(t,e){this._recursively(t,0,e,null,function(t){t.setOpacity(1)})},_recursivelyAddChildrenToMap:function(t,e,i){this._recursively(i,-1,e,function(n){if(e!==n._zoom)for(var s=n._markers.length-1;s>=0;s--){var r=n._markers[s];i.contains(r._latlng)&&(t&&(r._backupLatlng=r.getLatLng(),r.setLatLng(t),r.setOpacity&&r.setOpacity(0)),n._group._featureGroup.addLayer(r))}},function(e){e._addToMap(t)})},_recursivelyRestoreChildPositions:function(t){for(var e=this._markers.length-1;e>=0;e--){var i=this._markers[e];i._backupLatlng&&(i.setLatLng(i._backupLatlng),delete i._backupLatlng)}if(t-1===this._zoom)for(var n=this._childClusters.length-1;n>=0;n--)this._childClusters[n]._restorePosition();else for(var s=this._childClusters.length-1;s>=0;s--)this._childClusters[s]._recursivelyRestoreChildPositions(t)},_restorePosition:function(){this._backupLatlng&&(this.setLatLng(this._backupLatlng),delete this._backupLatlng)},_recursivelyRemoveChildrenFromMap:function(t,e,i){var n,s;this._recursively(t,-1,e-1,function(t){for(s=t._markers.length-1;s>=0;s--)n=t._markers[s],i&&i.contains(n._latlng)||(t._group._featureGroup.removeLayer(n),n.setOpacity&&n.setOpacity(1))},function(t){for(s=t._childClusters.length-1;s>=0;s--)n=t._childClusters[s],i&&i.contains(n._latlng)||(t._group._featureGroup.removeLayer(n),n.setOpacity&&n.setOpacity(1))})},_recursively:function(t,e,i,n,s){var r,o,a=this._childClusters,h=this._zoom;if(e>h)for(r=a.length-1;r>=0;r--)o=a[r],t.intersects(o._bounds)&&o._recursively(t,e,i,n,s);else if(n&&n(this),s&&this._zoom===i&&s(this),i>h)for(r=a.length-1;r>=0;r--)o=a[r],t.intersects(o._bounds)&&o._recursively(t,e,i,n,s)},_recalculateBounds:function(){var t,e=this._markers,i=this._childClusters;for(this._bounds=new L.LatLngBounds,delete this._wLatLng,t=e.length-1;t>=0;t--)this._expandBounds(e[t]);for(t=i.length-1;t>=0;t--)this._expandBounds(i[t])},_isSingleParent:function(){return this._childClusters.length>0&&this._childClusters[0]._childCount===this._childCount}}),L.DistanceGrid=function(t){this._cellSize=t,this._sqCellSize=t*t,this._grid={},this._objectPoint={}},L.DistanceGrid.prototype={addObject:function(t,e){var i=this._getCoord(e.x),n=this._getCoord(e.y),s=this._grid,r=s[n]=s[n]||{},o=r[i]=r[i]||[],a=L.Util.stamp(t);this._objectPoint[a]=e,o.push(t)},updateObject:function(t,e){this.removeObject(t),this.addObject(t,e)},removeObject:function(t,e){var i,n,s=this._getCoord(e.x),r=this._getCoord(e.y),o=this._grid,a=o[r]=o[r]||{},h=a[s]=a[s]||[];for(delete this._objectPoint[L.Util.stamp(t)],i=0,n=h.length;n>i;i++)if(h[i]===t)return h.splice(i,1),1===n&&delete a[s],!0},eachObject:function(t,e){var i,n,s,r,o,a,h,_=this._grid;for(i in _){o=_[i];for(n in o)for(a=o[n],s=0,r=a.length;r>s;s++)h=t.call(e,a[s]),h&&(s--,r--)}},getNearObject:function(t){var e,i,n,s,r,o,a,h,_=this._getCoord(t.x),u=this._getCoord(t.y),l=this._objectPoint,d=this._sqCellSize,p=null;for(e=u-1;u+1>=e;e++)if(s=this._grid[e])for(i=_-1;_+1>=i;i++)if(r=s[i])for(n=0,o=r.length;o>n;n++)a=r[n],h=this._sqDist(l[L.Util.stamp(a)],t),d>h&&(d=h,p=a);return p},_getCoord:function(t){return Math.floor(t/this._cellSize)},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n}},function(){L.QuickHull={getDistant:function(t,e){var i=e[1].lat-e[0].lat,n=e[0].lng-e[1].lng;return n*(t.lat-e[0].lat)+i*(t.lng-e[0].lng)},findMostDistantPointFromBaseLine:function(t,e){var i,n,s,r=0,o=null,a=[];for(i=e.length-1;i>=0;i--)n=e[i],s=this.getDistant(n,t),s>0&&(a.push(n),s>r&&(r=s,o=n));return{maxPoint:o,newPoints:a}},buildConvexHull:function(t,e){var i=[],n=this.findMostDistantPointFromBaseLine(t,e);return n.maxPoint?(i=i.concat(this.buildConvexHull([t[0],n.maxPoint],n.newPoints)),i=i.concat(this.buildConvexHull([n.maxPoint,t[1]],n.newPoints))):[t]},getConvexHull:function(t){var e,i=!1,n=!1,s=null,r=null;for(e=t.length-1;e>=0;e--){var o=t[e];(i===!1||o.lat>i)&&(s=o,i=o.lat),(n===!1||o.lat<n)&&(r=o,n=o.lat)}var a=[].concat(this.buildConvexHull([r,s],t),this.buildConvexHull([s,r],t));return a}}}(),L.MarkerCluster.include({getConvexHull:function(){var t,e,i,n=this.getAllChildMarkers(),s=[],r=[];for(i=n.length-1;i>=0;i--)e=n[i].getLatLng(),s.push(e);for(t=L.QuickHull.getConvexHull(s),i=t.length-1;i>=0;i--)r.push(t[i][0]);return r}}),L.MarkerCluster.include({_2PI:2*Math.PI,_circleFootSeparation:25,_circleStartAngle:Math.PI/6,_spiralFootSeparation:28,_spiralLengthStart:11,_spiralLengthFactor:5,_circleSpiralSwitchover:9,spiderfy:function(){if(this._group._spiderfied!==this&&!this._group._inZoomAnimation){var t,e=this.getAllChildMarkers(),i=this._group,n=i._map,s=n.latLngToLayerPoint(this._latlng);this._group._unspiderfy(),this._group._spiderfied=this,e.length>=this._circleSpiralSwitchover?t=this._generatePointsSpiral(e.length,s):(s.y+=10,t=this._generatePointsCircle(e.length,s)),this._animationSpiderfy(e,t)}},unspiderfy:function(t){this._group._inZoomAnimation||(this._animationUnspiderfy(t),this._group._spiderfied=null)},_generatePointsCircle:function(t,e){var i,n,s=this._group.options.spiderfyDistanceMultiplier*this._circleFootSeparation*(2+t),r=s/this._2PI,o=this._2PI/t,a=[];for(a.length=t,i=t-1;i>=0;i--)n=this._circleStartAngle+i*o,a[i]=new L.Point(e.x+r*Math.cos(n),e.y+r*Math.sin(n))._round();return a},_generatePointsSpiral:function(t,e){var i,n=this._group.options.spiderfyDistanceMultiplier*this._spiralLengthStart,s=this._group.options.spiderfyDistanceMultiplier*this._spiralFootSeparation,r=this._group.options.spiderfyDistanceMultiplier*this._spiralLengthFactor,o=0,a=[];for(a.length=t,i=t-1;i>=0;i--)o+=s/n+5e-4*i,a[i]=new L.Point(e.x+n*Math.cos(o),e.y+n*Math.sin(o))._round(),n+=this._2PI*r/o;return a},_noanimationUnspiderfy:function(){var t,e,i=this._group,n=i._map,s=i._featureGroup,r=this.getAllChildMarkers();for(this.setOpacity(1),e=r.length-1;e>=0;e--)t=r[e],s.removeLayer(t),t._preSpiderfyLatlng&&(t.setLatLng(t._preSpiderfyLatlng),delete t._preSpiderfyLatlng),t.setZIndexOffset&&t.setZIndexOffset(0),t._spiderLeg&&(n.removeLayer(t._spiderLeg),delete t._spiderLeg)}}),L.MarkerCluster.include(L.DomUtil.TRANSITION?{SVG_ANIMATION:function(){return e.createElementNS(\"http://www.w3.org/2000/svg\",\"animate\").toString().indexOf(\"SVGAnimate\")>-1}(),_animationSpiderfy:function(t,i){var n,s,r,o,a=this,h=this._group,_=h._map,u=h._featureGroup,l=_.latLngToLayerPoint(this._latlng);for(n=t.length-1;n>=0;n--)s=t[n],s.setOpacity?(s.setZIndexOffset(1e6),s.setOpacity(0),u.addLayer(s),s._setPos(l)):u.addLayer(s);h._forceLayout(),h._animationStart();var d=L.Path.SVG?0:.3,p=L.Path.SVG_NS;for(n=t.length-1;n>=0;n--)if(o=_.layerPointToLatLng(i[n]),s=t[n],s._preSpiderfyLatlng=s._latlng,s.setLatLng(o),s.setOpacity&&s.setOpacity(1),r=new L.Polyline([a._latlng,o],{weight:1.5,color:\"#222\",opacity:d}),_.addLayer(r),s._spiderLeg=r,L.Path.SVG&&this.SVG_ANIMATION){var c=r._path.getTotalLength();r._path.setAttribute(\"stroke-dasharray\",c+\",\"+c);var m=e.createElementNS(p,\"animate\");m.setAttribute(\"attributeName\",\"stroke-dashoffset\"),m.setAttribute(\"begin\",\"indefinite\"),m.setAttribute(\"from\",c),m.setAttribute(\"to\",0),m.setAttribute(\"dur\",.25),r._path.appendChild(m),m.beginElement(),m=e.createElementNS(p,\"animate\"),m.setAttribute(\"attributeName\",\"stroke-opacity\"),m.setAttribute(\"attributeName\",\"stroke-opacity\"),m.setAttribute(\"begin\",\"indefinite\"),m.setAttribute(\"from\",0),m.setAttribute(\"to\",.5),m.setAttribute(\"dur\",.25),r._path.appendChild(m),m.beginElement()}if(a.setOpacity(.3),L.Path.SVG)for(this._group._forceLayout(),n=t.length-1;n>=0;n--)s=t[n]._spiderLeg,s.options.opacity=.5,s._path.setAttribute(\"stroke-opacity\",.5);setTimeout(function(){h._animationEnd(),h.fire(\"spiderfied\")},200)},_animationUnspiderfy:function(t){var e,i,n,s=this._group,r=s._map,o=s._featureGroup,a=t?r._latLngToNewLayerPoint(this._latlng,t.zoom,t.center):r.latLngToLayerPoint(this._latlng),h=this.getAllChildMarkers(),_=L.Path.SVG&&this.SVG_ANIMATION;for(s._animationStart(),this.setOpacity(1),i=h.length-1;i>=0;i--)e=h[i],e._preSpiderfyLatlng&&(e.setLatLng(e._preSpiderfyLatlng),delete e._preSpiderfyLatlng,e.setOpacity?(e._setPos(a),e.setOpacity(0)):o.removeLayer(e),_&&(n=e._spiderLeg._path.childNodes[0],n.setAttribute(\"to\",n.getAttribute(\"from\")),n.setAttribute(\"from\",0),n.beginElement(),n=e._spiderLeg._path.childNodes[1],n.setAttribute(\"from\",.5),n.setAttribute(\"to\",0),n.setAttribute(\"stroke-opacity\",0),n.beginElement(),e._spiderLeg._path.setAttribute(\"stroke-opacity\",0)));setTimeout(function(){var t=0;for(i=h.length-1;i>=0;i--)e=h[i],e._spiderLeg&&t++;for(i=h.length-1;i>=0;i--)e=h[i],e._spiderLeg&&(e.setOpacity&&(e.setOpacity(1),e.setZIndexOffset(0)),t>1&&o.removeLayer(e),r.removeLayer(e._spiderLeg),delete e._spiderLeg);s._animationEnd()},200)}}:{_animationSpiderfy:function(t,e){var i,n,s,r,o=this._group,a=o._map,h=o._featureGroup;for(i=t.length-1;i>=0;i--)r=a.layerPointToLatLng(e[i]),n=t[i],n._preSpiderfyLatlng=n._latlng,n.setLatLng(r),n.setZIndexOffset&&n.setZIndexOffset(1e6),h.addLayer(n),s=new L.Polyline([this._latlng,r],{weight:1.5,color:\"#222\"}),a.addLayer(s),n._spiderLeg=s;this.setOpacity(.3),o.fire(\"spiderfied\")},_animationUnspiderfy:function(){this._noanimationUnspiderfy()}}),L.MarkerClusterGroup.include({_spiderfied:null,_spiderfierOnAdd:function(){this._map.on(\"click\",this._unspiderfyWrapper,this),this._map.options.zoomAnimation?this._map.on(\"zoomstart\",this._unspiderfyZoomStart,this):this._map.on(\"zoomend\",this._unspiderfyWrapper,this),L.Path.SVG&&!L.Browser.touch&&this._map._initPathRoot()},_spiderfierOnRemove:function(){this._map.off(\"click\",this._unspiderfyWrapper,this),this._map.off(\"zoomstart\",this._unspiderfyZoomStart,this),this._map.off(\"zoomanim\",this._unspiderfyZoomAnim,this),this._unspiderfy()},_unspiderfyZoomStart:function(){this._map&&this._map.on(\"zoomanim\",this._unspiderfyZoomAnim,this)},_unspiderfyZoomAnim:function(t){L.DomUtil.hasClass(this._map._mapPane,\"leaflet-touching\")||(this._map.off(\"zoomanim\",this._unspiderfyZoomAnim,this),this._unspiderfy(t))},_unspiderfyWrapper:function(){this._unspiderfy()},_unspiderfy:function(t){this._spiderfied&&this._spiderfied.unspiderfy(t)},_noanimationUnspiderfy:function(){this._spiderfied&&this._spiderfied._noanimationUnspiderfy()},_unspiderfyLayer:function(t){t._spiderLeg&&(this._featureGroup.removeLayer(t),t.setOpacity(1),t.setZIndexOffset(0),this._map.removeLayer(t._spiderLeg),delete t._spiderLeg)}})}(window,document);"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/LICENSE",
    "content": "MIT License\n\nCopyright (c) 2013 Benjamin Becquet\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/README.md",
    "content": "# Leaflet PolylineDecorator\n\nA Leaflet plug-in to define and draw patterns on existing Polylines or along coordinate paths.\n\n## Features\n\n* Dashed or dotted lines, arrow heads, markers following line\n* Works on Polygons too! (easy, as Polygon extends Polyline)\n* Multiple patterns can be applied to the same line\n* New behaviors can be obtained by defining new symbols\n\n## Usage\n\n```javascript\n    var polyline = L.polyline([...]).addTo(map);\n    var decorator = L.polylineDecorator(polyline, {\n        patterns: [\n            // define a pattern of 10px-wide dashes, repeated every 20px on the line \n            {offset: 0, repeat: '20px', symbol: new L.Symbol.Dash({pixelSize: 10})}\n        ]\n    }).addTo(map);\n```\n\nThe `polyline` parameter can be a single array of `L.LatLng` or, with Leaflet's simplified syntax, an array of 2-cells arrays of coordinates. \nIt is useful if you don't want to actually display a polyline, but just a pattern following coordinates, like a dotted line.\n\n## Screenshot\n\n![screenshot](https://raw.github.com/bbecquet/Leaflet.PolylineDecorator/master/screenshot.png \"Screenshot showing different applications of the library\")\n\n## Performance note\n\nPlease note that this library is in an early stage, and many operations could still be optimized.\nMoreover, as it requires a lot of (re-)computations, and each pattern symbol is an actual `L.ILayer` object, it can have an impact on the responsiveness of your map, especially if used on many objects.\nIn cases where it's applicable (dash patterns), you should probably use instead the `dashArray` property of `L.Path`, as it's natively drawn by the browser.\n\n## TODO\n\n* Documentation\n* Optimize rendering and mem footprint\n* Other symbol types\n* Animations(?)\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/example/example.html",
    "content": "﻿<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" />\n    \n    <title>Leaflet Polyline Decorator example</title>\n\n    <link rel=\"stylesheet\" href=\"http://cdn.leafletjs.com/leaflet-0.7/leaflet.css\" />\n    <style>\n      * { margin: 0; padding: 0; }\n      html, body { height: 100%; }\n      #map { width:100%; height:100%; }\n    </style>\n    \n    <script src=\"http://cdn.leafletjs.com/leaflet-0.7/leaflet.js\"></script>\n    <script src=\"../src/L.LineUtil.PolylineDecorator.js\"></script>\n    <script src=\"../src/L.RotatedMarker.js\"></script>\n    <script src=\"../src/L.Symbol.js\"></script>\n    <script src=\"../src/L.PolylineDecorator.js\"></script>\n    \n    <script src=\"example.js\"></script>\n  </head>\n\n  <body onload=\"init();\">\n    <div id=\"map\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/example/example.js",
    "content": "﻿\nfunction init() {\n    var map = new L.Map('map', {\n        center: [52.0, -11.0],\n        zoom: 5,\n        layers: [\n            new L.TileLayer('http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png', {\n                attribution: 'Tiles Courtesy of <a href=\"http://www.mapquest.com/\">MapQuest</a> &mdash; Map data &copy; <a href=\"http://openstreetmap.org\">OpenStreetMap</a> contributors',\n                maxZoom: 18,\n                subdomains: '1234'\n            })\n        ]\n    });\n    \n    // --- Arrow, with animation to demonstrate the use of setPatterns ---\n    var arrow = L.polyline([[57, -19], [60, -12]], {}).addTo(map);\n    var arrowHead = L.polylineDecorator(arrow).addTo(map);\n    \n    var arrowOffset = 0;\n    var anim = window.setInterval(function() {\n        arrowHead.setPatterns([\n            {offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 15, polygon: false, pathOptions: {stroke: true}})}\n        ])\n        if(++arrowOffset > 100)\n            arrowOffset = 0;\n    }, 100);\n\n    // --- Polygon ---\n    var polygon = L.polygon([[54, -6], [55, -7], [56, -2], [55, 1], [53, 0], [54, -6]], {color: \"#ff7800\", weight: 1}).addTo(map);\n    var pd = L.polylineDecorator(polygon, {\n        patterns: [\n            {offset: 0, repeat: 10, symbol: L.Symbol.dash({pixelSize: 0})}\n        ]\n    }).addTo(map);\n\n    // --- Multi-pattern without Polyline ---    \n    var pathPattern = L.polylineDecorator(\n        [ [ 49.543519, -12.469833 ], [ 49.808981, -12.895285 ], [ 50.056511, -13.555761 ], [ 50.217431, -14.758789 ], [ 50.476537, -15.226512 ], [ 50.377111, -15.706069 ], [ 50.200275, -16.000263 ], [ 49.860606, -15.414253 ], [ 49.672607, -15.710152 ], [ 49.863344, -16.451037 ], [ 49.774564, -16.875042 ], [ 49.498612, -17.106036 ], [ 49.435619, -17.953064 ], [ 49.041792, -19.118781 ], [ 48.548541, -20.496888 ], [ 47.930749, -22.391501 ], [ 47.547723, -23.781959 ], [ 47.095761, -24.941630 ], [ 46.282478, -25.178463 ], [ 45.409508, -25.601434 ], [ 44.833574, -25.346101 ], [ 44.039720, -24.988345 ] ],\n        {\n            patterns: [\n                { offset: 12, repeat: 25, symbol: L.Symbol.dash({pixelSize: 10, pathOptions: {color: '#f00', weight: 2}}) },\n                { offset: 0, repeat: 25, symbol: L.Symbol.dash({pixelSize: 0}) }\n            ]\n        }\n    ).addTo(map);\n\n    // --- Markers proportionnaly located ---   \n    var markerLine = L.polyline([[58.44773, -28.65234], [52.9354, -23.33496], [53.01478, -14.32617], [58.1707, -10.37109], [59.68993, -0.65918]], {}).addTo(map);\n    var markerPatterns = L.polylineDecorator(markerLine, {\n        patterns: [\n            { offset: '5%', repeat: '10%', symbol: L.Symbol.marker()}\n        ]\n    }).addTo(map);\n    \n    // --- Example with a rotated marker --- \n    var pathPattern = L.polylineDecorator(\n        [ [ 42.9, -15 ], [ 44.18, -11.4 ], [ 45.77, -8.0 ], [ 47.61, -6.4 ], [ 49.41, -6.1 ], [ 51.01, -7.2 ] ],\n        {\n            patterns: [\n                { offset: 0, repeat: 10, symbol: L.Symbol.dash({pixelSize: 5, pathOptions: {color: '#000', weight: 1, opacity: 0.2}}) },\n                { offset: '16%', repeat: '33%', symbol: L.Symbol.marker({rotate: true, markerOptions: {\n                    icon: L.icon({\n                        iconUrl: 'icon_plane.png',\n                        iconAnchor: [16, 16] \n                    })\n                }})}\n            ]\n        }\n    ).addTo(map);\n\n    // --- Example with an array of Polylines ---\n    var multiCoords1 = [\n        [[47.5468, -0.7910], [48.8068, -0.1318], [49.1242, 1.6699], [49.4966, 3.2958], [51.4266, 2.8564], [51.7542, 2.1093]], \n        [[48.0193, -2.8125], [46.3165, -2.8564], [44.9336, -1.0107], [44.5278, 1.5820], [44.8714, 3.7353], [45.8287, 5.1855], [48.1953, 5.1416]], \n        [[45.9205, 0.4394], [46.7699, 0.9228], [47.6061, 2.5488], [47.7540, 3.3837]]\n    ];\n    var plArray = [];\n    for(var i=0; i<multiCoords1.length; i++) {\n        plArray.push(L.polyline(multiCoords1[i]).addTo(map));\n    }\n    L.polylineDecorator(multiCoords1, {\n        patterns: [\n            {offset: 25, repeat: 50, symbol: L.Symbol.arrowHead({pixelSize: 15, pathOptions: {fillOpacity: 1, weight: 0}})}\n        ]\n    }).addTo(map);\n\n    // --- Example with a MultiPolygon ---\n    var multiCoords2 = [\n        [[55.4788, 4.1748], [53.7487, 4.5263], [52.4560, 7.3388], [56.3165, 7.8662]],\n        [[53.9302, 9.2724] , [52.8027, 9.8876], [52.1604, 12.0849], [53.5141, 14.5019], [54.9523, 14.3261], [55.5037, 10.5908]]\n    ];\n    var multiPl = L.multiPolygon(multiCoords2, {weight: 0, fillOpacity: 0}).addTo(map);\n    L.polylineDecorator(multiPl, {\n        patterns: [\n            {offset: 0, repeat: 10, symbol: L.Symbol.dash({pixelSize: 0, pathOptions: {color: '#080'}})}\n        ]\n    }).addTo(map);\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/leaflet.polylineDecorator.js",
    "content": "\nL.LineUtil.PolylineDecorator = {\n    computeAngle: function(a, b) {\n        return (Math.atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI) + 90;\n    },\n\n    getPointPathPixelLength: function(pts) {\n        var nbPts = pts.length;\n        if(nbPts < 2) {\n            return 0;\n        }\n        var dist = 0,\n            prevPt = pts[0],\n            pt;\n        for(var i=1; i<nbPts; i++) {\n            dist += prevPt.distanceTo(pt = pts[i]);\n            prevPt = pt;\n        } \n        return dist;\n    },\n\n    getPixelLength: function(pl, map) {\n        var ll = (pl instanceof L.Polyline) ? pl.getLatLngs() : pl,\n            nbPts = ll.length;\n        if(nbPts < 2) {\n            return 0;\n        }\n        var dist = 0,\n            prevPt = map.latLngToLayerPoint(ll[0]), pt; \n        for(var i=1; i<nbPts; i++) {\n            dist += prevPt.distanceTo(pt = map.latLngToLayerPoint(ll[i]));\n            prevPt = pt;\n        } \n        return dist;\n    },\n\n    /**\n    * path: array of L.LatLng\n    * offsetRatio: the ratio of the total pixel length where the pattern will start\n    * repeatRatio: the ratio of the total pixel length between two points of the pattern \n    * map: the map, to access the current projection state\n    */\n    projectPatternOnPath: function (path, offsetRatio, repeatRatio, map) {\n        var pathAsPoints = [], i;\n        for(i=0, l=path.length; i<l; i++) {\n            pathAsPoints[i] = map.latLngToLayerPoint(path[i]);\n        }\n        // project the pattern as pixel points\n        var pattern = this.projectPatternOnPointPath(pathAsPoints, offsetRatio, repeatRatio);\n        // and convert it to latlngs;\n        for(i=0, l=pattern.length; i<l; i++) {\n            pattern[i].latLng = map.layerPointToLatLng(pattern[i].pt);\n        }        \n        return pattern;\n    },\n    \n    projectPatternOnPointPath: function (pts, offsetRatio, repeatRatio) {\n        var positions = [];\n        // 1. compute the absolute interval length in pixels\n        var repeatIntervalLength = this.getPointPathPixelLength(pts) * repeatRatio;\n        // 2. find the starting point by using the offsetRatio\n        var previous = this.interpolateOnPointPath(pts, offsetRatio);\n        positions.push(previous);\n        if(repeatRatio > 0) {\n            // 3. consider only the rest of the path, starting at the previous point\n            var remainingPath = pts;\n            remainingPath = remainingPath.slice(previous.predecessor);\n            remainingPath[0] = previous.pt;\n            var remainingLength = this.getPointPathPixelLength(remainingPath);\n            // 4. project as a ratio of the remaining length,\n            // and repeat while there is room for another point of the pattern\n            while(repeatIntervalLength <= remainingLength) {\n                previous = this.interpolateOnPointPath(remainingPath, repeatIntervalLength/remainingLength);\n                positions.push(previous);\n                remainingPath = remainingPath.slice(previous.predecessor);\n                remainingPath[0] = previous.pt;\n                remainingLength = this.getPointPathPixelLength(remainingPath);\n            }\n        }\n        return positions;\n    },\n\n    /**\n    * pts: array of L.Point\n    * ratio: the ratio of the total length where the point should be computed\n    * Returns null if ll has less than 2 LatLng, or an object with the following properties:\n    *    latLng: the LatLng of the interpolated point\n    *    predecessor: the index of the previous vertex on the path\n    *    heading: the heading of the path at this point, in degrees\n    */\n    interpolateOnPointPath: function (pts, ratio) {\n        var nbVertices = pts.length;\n\n        if (nbVertices < 2) {\n            return null;\n        }\n        // easy limit cases: ratio negative/zero => first vertex\n        if (ratio <= 0) {\n            return {\n                pt: pts[0],\n                predecessor: 0,\n                heading: this.computeAngle(pts[0], pts[1])\n            };\n        }\n        // ratio >=1 => last vertex\n        if (ratio >= 1) {\n            return {\n                pt: pts[nbVertices - 1],\n                predecessor: nbVertices - 1,\n                heading: this.computeAngle(pts[nbVertices - 2], pts[nbVertices - 1])\n            };\n        }\n        // 1-segment-only path => direct linear interpolation\n        if (nbVertices == 2) {\n            return {\n                pt: this.interpolateBetweenPoints(pts[0], pts[1], ratio),\n                predecessor: 0,\n                heading: this.computeAngle(pts[0], pts[1])\n            };\n        }\n            \n        var pathLength = this.getPointPathPixelLength(pts);\n        var a = pts[0], b = a,\n            ratioA = 0, ratioB = 0,\n            distB = 0;\n        // follow the path segments until we find the one\n        // on which the point must lie => [ab] \n        var i = 1;\n        for (; i < nbVertices && ratioB < ratio; i++) {\n            a = b;\n            ratioA = ratioB;\n            b = pts[i];\n            distB += a.distanceTo(b);\n            ratioB = distB / pathLength;\n        }\n\n        // compute the ratio relative to the segment [ab]\n        var segmentRatio = (ratio - ratioA) / (ratioB - ratioA);\n\n        return {\n            pt: this.interpolateBetweenPoints(a, b, segmentRatio),\n            predecessor: i-2,\n            heading: this.computeAngle(a, b)\n        };\n    },\n    \n    /**\n    * Finds the point which lies on the segment defined by points A and B,\n    * at the given ratio of the distance from A to B, by linear interpolation. \n    */\n    interpolateBetweenPoints: function (ptA, ptB, ratio) {\n        if(ptB.x != ptA.x) {\n            return new L.Point(\n                (ptA.x * (1 - ratio)) + (ratio * ptB.x),\n                (ptA.y * (1 - ratio)) + (ratio * ptB.y)\n            );\n        }\n        // special case where points lie on the same vertical axis\n        return new L.Point(ptA.x, ptA.y + (ptB.y - ptA.y) * ratio);\n    }\n};\nL.RotatedMarker = L.Marker.extend({\n    options: {\n        angle: 0\n    },\n    _setPos: function (pos) {\n        L.Marker.prototype._setPos.call(this, pos);\n        \n        if (L.DomUtil.TRANSFORM) {\n            // use the CSS transform rule if available\n            this._icon.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)';\n        } else if(L.Browser.ie) {\n            // fallback for IE6, IE7, IE8\n            var rad = this.options.angle * L.LatLng.DEG_TO_RAD,\n                costheta = Math.cos(rad),\n                sintheta = Math.sin(rad);\n            this._icon.style.filter += ' progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\\'auto expand\\', M11=' + \n                costheta + ', M12=' + (-sintheta) + ', M21=' + sintheta + ', M22=' + costheta + ')';                \n        }\n    }\n});\n\nL.rotatedMarker = function (pos, options) {\n    return new L.RotatedMarker(pos, options);\n};﻿/**\n* Defines several classes of symbol factories,\n* to be used with L.PolylineDecorator\n*/\n\nL.Symbol = L.Symbol || {};\n\n/**\n* A simple dash symbol, drawn as a Polyline.\n* Can also be used for dots, if 'pixelSize' option is given the 0 value.\n*/\nL.Symbol.Dash = L.Class.extend({\n    isZoomDependant: true,\n    \n    options: {\n        pixelSize: 10,\n        pathOptions: { }\n    },\n    \n    initialize: function (options) {\n        L.Util.setOptions(this, options);\n        this.options.pathOptions.clickable = false;\n    },\n\n    buildSymbol: function(dirPoint, latLngs, map, index, total) {\n        var opts = this.options;\n        \n        // for a dot, nothing more to compute\n        if(opts.pixelSize <= 1) {\n            return new L.Polyline([dirPoint.latLng, dirPoint.latLng], opts.pathOptions);\n        }\n        \n        var midPoint = map.project(dirPoint.latLng);\n        var angle = (-(dirPoint.heading - 90)) * L.LatLng.DEG_TO_RAD;\n        var a = new L.Point(\n                midPoint.x + opts.pixelSize * Math.cos(angle + Math.PI) / 2,\n                midPoint.y + opts.pixelSize * Math.sin(angle) / 2\n            );\n        // compute second point by central symmetry to avoid unecessary cos/sin\n        var b = midPoint.add(midPoint.subtract(a));\n        return new L.Polyline([map.unproject(a), map.unproject(b)], opts.pathOptions);\n    }\n});\n\nL.Symbol.dash = function (options) {\n    return new L.Symbol.Dash(options);\n};\n\nL.Symbol.ArrowHead = L.Class.extend({\n    isZoomDependant: true,\n    \n    options: {\n        polygon: true,\n        pixelSize: 10,\n        headAngle: 60,\n        pathOptions: {\n            stroke: false,\n            weight: 2\n        }\n    },\n    \n    initialize: function (options) {\n        L.Util.setOptions(this, options);\n        this.options.pathOptions.clickable = false;\n    },\n\n    buildSymbol: function(dirPoint, latLngs, map, index, total) {\n        var opts = this.options;\n        var path;\n        if(opts.polygon) {\n            path = new L.Polygon(this._buildArrowPath(dirPoint, map), opts.pathOptions);\n        } else {\n            path = new L.Polyline(this._buildArrowPath(dirPoint, map), opts.pathOptions);\n        }\n        return path;\n    },\n    \n    _buildArrowPath: function (dirPoint, map) {\n        var tipPoint = map.project(dirPoint.latLng);\n        var direction = (-(dirPoint.heading - 90)) * L.LatLng.DEG_TO_RAD;\n        var radianArrowAngle = this.options.headAngle / 2 * L.LatLng.DEG_TO_RAD; \n        \n        var headAngle1 = direction + radianArrowAngle,\n            headAngle2 = direction - radianArrowAngle;\n        var arrowHead1 = new L.Point(\n                tipPoint.x - this.options.pixelSize * Math.cos(headAngle1),\n                tipPoint.y + this.options.pixelSize * Math.sin(headAngle1)),\n            arrowHead2 = new L.Point(\n                tipPoint.x - this.options.pixelSize * Math.cos(headAngle2),\n                tipPoint.y + this.options.pixelSize * Math.sin(headAngle2));\n\n        return [\n            map.unproject(arrowHead1),\n            dirPoint.latLng,\n            map.unproject(arrowHead2)\n        ];\n    }\n});\n\nL.Symbol.arrowHead = function (options) {\n    return new L.Symbol.ArrowHead(options);\n};\n\nL.Symbol.Marker = L.Class.extend({\n    isZoomDependant: false,\n\n    options: {\n        markerOptions: { },\n        rotate: false\n    },\n    \n    initialize: function (options) {\n        L.Util.setOptions(this, options);\n        this.options.markerOptions.clickable = false;\n        this.options.markerOptions.draggable = false;\n        this.isZoomDependant = (L.Browser.ie && this.options.rotate);\n    },\n\n    buildSymbol: function(directionPoint, latLngs, map, index, total) {\n        if(!this.options.rotate) {\n            return new L.Marker(directionPoint.latLng, this.options.markerOptions);\n        }\n        else {\n            this.options.markerOptions.angle = directionPoint.heading;\n            return new L.RotatedMarker(directionPoint.latLng, this.options.markerOptions);\n        }\n    }\n});\n\nL.Symbol.marker = function (options) {\n    return new L.Symbol.Marker(options);\n};\n\n\n\nL.PolylineDecorator = L.LayerGroup.extend({\n    options: {\n        patterns: []\n    },\n\n    initialize: function(paths, options) {\n        L.LayerGroup.prototype.initialize.call(this);\n        L.Util.setOptions(this, options);\n        this._map = null;\n        this._initPaths(paths);\n        this._initPatterns();\n    },\n\n    /**\n    * Deals with all the different cases. p can be one of these types:\n    * array of LatLng, array of 2-number arrays, Polyline, Polygon,\n    * array of one of the previous, MultiPolyline, MultiPolygon. \n    */\n    _initPaths: function(p) {\n        this._paths = [];\n        var isPolygon = false;\n        if(p instanceof L.MultiPolyline || (isPolygon = (p instanceof L.MultiPolygon))) {\n            var lines = p.getLatLngs();\n            for(var i=0; i<lines.length; i++) {\n                this._initPath(lines[i], isPolygon);\n            }   \n        } else if(p instanceof L.Polyline) {\n            this._initPath(p.getLatLngs(), (p instanceof L.Polygon));\n        } else if(L.Util.isArray(p) && p.length > 0) {\n            if(p[0] instanceof L.Polyline) {\n                for(var i=0; i<p.length; i++) {\n                    this._initPath(p[i].getLatLngs(), (p[i] instanceof L.Polygon));\n                }\n            } else {\n                this._initPath(p);\n            }\n        }\n    },\n\n    _isCoordArray: function(ll) {\n        return(L.Util.isArray(ll) && ll.length > 0 && (\n            ll[0] instanceof L.LatLng || \n            (L.Util.isArray(ll[0]) && ll[0].length == 2 && typeof ll[0][0] === 'number')\n        ));\n    },\n\n    _initPath: function(path, isPolygon) {\n        var latLngs;\n        // It may still be an array of array of coordinates\n        // (ex: polygon with rings)\n        if(this._isCoordArray(path)) {\n            latLngs = [path];\n        } else {\n            latLngs = path;\n        }\n        for(var i=0; i<latLngs.length; i++) {\n            // As of Leaflet >= v0.6, last polygon vertex (=first) isn't repeated.\n            // Our algorithm needs it, so we add it back explicitly.\n            if(isPolygon) {\n                latLngs[i].push(latLngs[i][0]);\n            }\n            this._paths.push(latLngs[i]);\n        }\n    },   \n\n    _initPatterns: function() {\n        this._isZoomDependant = false;\n        this._patterns = [];\n        var pattern;\n        // parse pattern definitions and precompute some values\n        for(var i=0;i<this.options.patterns.length;i++) {\n            pattern = this._parsePatternDef(this.options.patterns[i]);\n            this._patterns.push(pattern);\n            // determines if we have to recompute the pattern on each zoom change\n            this._isZoomDependant = this._isZoomDependant ||\n                pattern.isOffsetInPixels ||\n                pattern.isRepeatInPixels ||\n                pattern.symbolFactory.isZoomDependant;\n        }\n    },\n\n    /**\n    * Changes the patterns used by this decorator \n    * and redraws the new one.\n    */\n    setPatterns: function(patterns) {\n        this.options.patterns = patterns;\n        this._initPatterns();\n        this._softRedraw();\n    },\n\n    /**\n    * Changes the patterns used by this decorator \n    * and redraws the new one.\n    */\n    setPaths: function(paths) {\n        this._initPaths(paths);\n        this.redraw();\n    },\n\n    /**\n    * Parse the pattern definition\n    */\n    _parsePatternDef: function(patternDef, latLngs) {\n        var pattern = {\n            cache: [],\n            symbolFactory: patternDef.symbol,\n            isOffsetInPixels: false,\n            isRepeatInPixels: false\n        };\n        \n        // Parse offset and repeat values, managing the two cases:\n        // absolute (in pixels) or relative (in percentage of the polyline length)\n        if(typeof patternDef.offset === 'string' && patternDef.offset.indexOf('%') != -1) {\n            pattern.offset = parseFloat(patternDef.offset) / 100;\n        } else {\n            pattern.offset = parseFloat(patternDef.offset);\n            pattern.isOffsetInPixels = (pattern.offset > 0);\n        }\n        \n        \n        if(typeof patternDef.repeat === 'string' && patternDef.repeat.indexOf('%') != -1) {\n            pattern.repeat = parseFloat(patternDef.repeat) / 100;\n        } else {\n            pattern.repeat = parseFloat(patternDef.repeat);\n            pattern.isRepeatInPixels = (pattern.repeat > 0);\n        }\n        \n        // TODO: 0 => not pixel dependant => 0%\n        \n        return(pattern);\n    },\n\n    onAdd: function (map) {\n        this._map = map;\n        this._draw();\n        // listen to zoom changes to redraw pixel-spaced patterns\n        if(this._isZoomDependant) {\n            this._map.on('zoomend', this._softRedraw, this);\n        }\n    },\n\n    onRemove: function (map) {\n        // remove optional map zoom listener\n        this._map.off('zoomend', this._softRedraw, this);\n        this._map = null;\n        L.LayerGroup.prototype.onRemove.call(this, map);\n    },\n\n    /**\n    * Returns an array of ILayers object\n    */\n    _buildSymbols: function(latLngs, symbolFactory, directionPoints) {\n        var symbols = [];\n        for(var i=0, l=directionPoints.length; i<l; i++) {\n            symbols.push(symbolFactory.buildSymbol(directionPoints[i], latLngs, this._map, i, l));\n        }\n        return symbols;\n    },\n\n    _getCache: function(pattern, zoom, pathIndex) {\n        var zoomCache = pattern.cache[zoom];\n        if(typeof zoomCache === 'undefined') {\n            pattern.cache[zoom] = [];\n            return null;\n        }\n        return zoomCache[pathIndex];\n    },\n\n    /**\n    * Select pairs of LatLng and heading angle,\n    * that define positions and directions of the symbols\n    * on the path \n    */\n    _getDirectionPoints: function(pathIndex, pattern) {\n        var zoom = this._map.getZoom();\n        var dirPoints = this._getCache(pattern, zoom, pathIndex);\n        if(dirPoints) {\n            return dirPoints;\n        }\n\n        var offset, repeat, pathPixelLength = null, latLngs = this._paths[pathIndex];\n        if(pattern.isOffsetInPixels) {\n            pathPixelLength =  L.LineUtil.PolylineDecorator.getPixelLength(latLngs, this._map);\n            offset = pattern.offset/pathPixelLength;\n        } else {\n            offset = pattern.offset;\n        }\n        if(pattern.isRepeatInPixels) {\n            pathPixelLength = (pathPixelLength !== null) ? pathPixelLength : L.LineUtil.PolylineDecorator.getPixelLength(latLngs, this._map);\n            repeat = pattern.repeat/pathPixelLength; \n        } else {\n            repeat = pattern.repeat;\n        }\n        dirPoints = L.LineUtil.PolylineDecorator.projectPatternOnPath(latLngs, offset, repeat, this._map);\n        // save in cache to avoid recomputing this\n        pattern.cache[zoom][pathIndex] = dirPoints;\n        \n        return dirPoints;\n    },\n\n    /**\n    * Public redraw, invalidating the cache.\n    */\n    redraw: function() {\n        this._redraw(true);\n    },\n    \n    /**\n    * \"Soft\" redraw, called internally for example on zoom changes,\n    * keeping the cache. \n    */\n    _softRedraw: function() {\n        this._redraw(false);\n    },\n    \n    _redraw: function(clearCache) {\n        if(this._map === null)\n            return;\n        this.clearLayers();\n        if(clearCache) {\n            for(var i=0; i<this._patterns.length; i++) {\n                this._patterns[i].cache = [];\n            }\n        }\n        this._draw();\n    },\n    \n    /**\n    * Draw a single pattern\n    */\n    _drawPattern: function(pattern) {\n        var directionPoints, symbols;\n        for(var i=0; i < this._paths.length; i++) {\n            directionPoints = this._getDirectionPoints(i, pattern);\n            symbols = this._buildSymbols(this._paths[i], pattern.symbolFactory, directionPoints);\n            for(var j=0; j < symbols.length; j++) {\n                this.addLayer(symbols[j]);\n            }\n        }\n    },\n\n    /**\n    * Draw all patterns\n    */\n    _draw: function () {\n        for(var i=0; i<this._patterns.length; i++) {\n            this._drawPattern(this._patterns[i]);\n        }\n    }\n});\n/*\n * Allows compact syntax to be used\n */\nL.polylineDecorator = function (paths, options) {\n    return new L.PolylineDecorator(paths, options);\n};\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/src/L.LineUtil.PolylineDecorator.js",
    "content": "\nL.LineUtil.PolylineDecorator = {\n    computeAngle: function(a, b) {\n        return (Math.atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI) + 90;\n    },\n\n    getPointPathPixelLength: function(pts) {\n        var nbPts = pts.length;\n        if(nbPts < 2) {\n            return 0;\n        }\n        var dist = 0,\n            prevPt = pts[0],\n            pt;\n        for(var i=1; i<nbPts; i++) {\n            dist += prevPt.distanceTo(pt = pts[i]);\n            prevPt = pt;\n        } \n        return dist;\n    },\n\n    getPixelLength: function(pl, map) {\n        var ll = (pl instanceof L.Polyline) ? pl.getLatLngs() : pl,\n            nbPts = ll.length;\n        if(nbPts < 2) {\n            return 0;\n        }\n        var dist = 0,\n            prevPt = map.latLngToLayerPoint(ll[0]), pt; \n        for(var i=1; i<nbPts; i++) {\n            dist += prevPt.distanceTo(pt = map.latLngToLayerPoint(ll[i]));\n            prevPt = pt;\n        } \n        return dist;\n    },\n\n    /**\n    * path: array of L.LatLng\n    * offsetRatio: the ratio of the total pixel length where the pattern will start\n    * repeatRatio: the ratio of the total pixel length between two points of the pattern \n    * map: the map, to access the current projection state\n    */\n    projectPatternOnPath: function (path, offsetRatio, repeatRatio, map) {\n        var pathAsPoints = [], i;\n        for(i=0, l=path.length; i<l; i++) {\n            pathAsPoints[i] = map.latLngToLayerPoint(path[i]);\n        }\n        // project the pattern as pixel points\n        var pattern = this.projectPatternOnPointPath(pathAsPoints, offsetRatio, repeatRatio);\n        // and convert it to latlngs;\n        for(i=0, l=pattern.length; i<l; i++) {\n            pattern[i].latLng = map.layerPointToLatLng(pattern[i].pt);\n        }        \n        return pattern;\n    },\n    \n    projectPatternOnPointPath: function (pts, offsetRatio, repeatRatio) {\n        var positions = [];\n        // 1. compute the absolute interval length in pixels\n        var repeatIntervalLength = this.getPointPathPixelLength(pts) * repeatRatio;\n        // 2. find the starting point by using the offsetRatio\n        var previous = this.interpolateOnPointPath(pts, offsetRatio);\n        positions.push(previous);\n        if(repeatRatio > 0) {\n            // 3. consider only the rest of the path, starting at the previous point\n            var remainingPath = pts;\n            remainingPath = remainingPath.slice(previous.predecessor);\n            remainingPath[0] = previous.pt;\n            var remainingLength = this.getPointPathPixelLength(remainingPath);\n            // 4. project as a ratio of the remaining length,\n            // and repeat while there is room for another point of the pattern\n            while(repeatIntervalLength <= remainingLength) {\n                previous = this.interpolateOnPointPath(remainingPath, repeatIntervalLength/remainingLength);\n                positions.push(previous);\n                remainingPath = remainingPath.slice(previous.predecessor);\n                remainingPath[0] = previous.pt;\n                remainingLength = this.getPointPathPixelLength(remainingPath);\n            }\n        }\n        return positions;\n    },\n\n    /**\n    * pts: array of L.Point\n    * ratio: the ratio of the total length where the point should be computed\n    * Returns null if ll has less than 2 LatLng, or an object with the following properties:\n    *    latLng: the LatLng of the interpolated point\n    *    predecessor: the index of the previous vertex on the path\n    *    heading: the heading of the path at this point, in degrees\n    */\n    interpolateOnPointPath: function (pts, ratio) {\n        var nbVertices = pts.length;\n\n        if (nbVertices < 2) {\n            return null;\n        }\n        // easy limit cases: ratio negative/zero => first vertex\n        if (ratio <= 0) {\n            return {\n                pt: pts[0],\n                predecessor: 0,\n                heading: this.computeAngle(pts[0], pts[1])\n            };\n        }\n        // ratio >=1 => last vertex\n        if (ratio >= 1) {\n            return {\n                pt: pts[nbVertices - 1],\n                predecessor: nbVertices - 1,\n                heading: this.computeAngle(pts[nbVertices - 2], pts[nbVertices - 1])\n            };\n        }\n        // 1-segment-only path => direct linear interpolation\n        if (nbVertices == 2) {\n            return {\n                pt: this.interpolateBetweenPoints(pts[0], pts[1], ratio),\n                predecessor: 0,\n                heading: this.computeAngle(pts[0], pts[1])\n            };\n        }\n            \n        var pathLength = this.getPointPathPixelLength(pts);\n        var a = pts[0], b = a,\n            ratioA = 0, ratioB = 0,\n            distB = 0;\n        // follow the path segments until we find the one\n        // on which the point must lie => [ab] \n        var i = 1;\n        for (; i < nbVertices && ratioB < ratio; i++) {\n            a = b;\n            ratioA = ratioB;\n            b = pts[i];\n            distB += a.distanceTo(b);\n            ratioB = distB / pathLength;\n        }\n\n        // compute the ratio relative to the segment [ab]\n        var segmentRatio = (ratio - ratioA) / (ratioB - ratioA);\n\n        return {\n            pt: this.interpolateBetweenPoints(a, b, segmentRatio),\n            predecessor: i-2,\n            heading: this.computeAngle(a, b)\n        };\n    },\n    \n    /**\n    * Finds the point which lies on the segment defined by points A and B,\n    * at the given ratio of the distance from A to B, by linear interpolation. \n    */\n    interpolateBetweenPoints: function (ptA, ptB, ratio) {\n        if(ptB.x != ptA.x) {\n            return new L.Point(\n                (ptA.x * (1 - ratio)) + (ratio * ptB.x),\n                (ptA.y * (1 - ratio)) + (ratio * ptB.y)\n            );\n        }\n        // special case where points lie on the same vertical axis\n        return new L.Point(ptA.x, ptA.y + (ptB.y - ptA.y) * ratio);\n    }\n};\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/src/L.PolylineDecorator.js",
    "content": "\nL.PolylineDecorator = L.LayerGroup.extend({\n    options: {\n        patterns: []\n    },\n\n    initialize: function(paths, options) {\n        L.LayerGroup.prototype.initialize.call(this);\n        L.Util.setOptions(this, options);\n        this._map = null;\n        this._initPaths(paths);\n        this._initPatterns();\n    },\n\n    /**\n    * Deals with all the different cases. p can be one of these types:\n    * array of LatLng, array of 2-number arrays, Polyline, Polygon,\n    * array of one of the previous, MultiPolyline, MultiPolygon. \n    */\n    _initPaths: function(p) {\n        this._paths = [];\n        var isPolygon = false;\n        if(p instanceof L.MultiPolyline || (isPolygon = (p instanceof L.MultiPolygon))) {\n            var lines = p.getLatLngs();\n            for(var i=0; i<lines.length; i++) {\n                this._initPath(lines[i], isPolygon);\n            }   \n        } else if(p instanceof L.Polyline) {\n            this._initPath(p.getLatLngs(), (p instanceof L.Polygon));\n        } else if(L.Util.isArray(p) && p.length > 0) {\n            if(p[0] instanceof L.Polyline) {\n                for(var i=0; i<p.length; i++) {\n                    this._initPath(p[i].getLatLngs(), (p[i] instanceof L.Polygon));\n                }\n            } else {\n                this._initPath(p);\n            }\n        }\n    },\n\n    _isCoordArray: function(ll) {\n        return(L.Util.isArray(ll) && ll.length > 0 && (\n            ll[0] instanceof L.LatLng || \n            (L.Util.isArray(ll[0]) && ll[0].length == 2 && typeof ll[0][0] === 'number')\n        ));\n    },\n\n    _initPath: function(path, isPolygon) {\n        var latLngs;\n        // It may still be an array of array of coordinates\n        // (ex: polygon with rings)\n        if(this._isCoordArray(path)) {\n            latLngs = [path];\n        } else {\n            latLngs = path;\n        }\n        for(var i=0; i<latLngs.length; i++) {\n            // As of Leaflet >= v0.6, last polygon vertex (=first) isn't repeated.\n            // Our algorithm needs it, so we add it back explicitly.\n            if(isPolygon) {\n                latLngs[i].push(latLngs[i][0]);\n            }\n            this._paths.push(latLngs[i]);\n        }\n    },   \n\n    _initPatterns: function() {\n        this._isZoomDependant = false;\n        this._patterns = [];\n        var pattern;\n        // parse pattern definitions and precompute some values\n        for(var i=0;i<this.options.patterns.length;i++) {\n            pattern = this._parsePatternDef(this.options.patterns[i]);\n            this._patterns.push(pattern);\n            // determines if we have to recompute the pattern on each zoom change\n            this._isZoomDependant = this._isZoomDependant ||\n                pattern.isOffsetInPixels ||\n                pattern.isRepeatInPixels ||\n                pattern.symbolFactory.isZoomDependant;\n        }\n    },\n\n    /**\n    * Changes the patterns used by this decorator \n    * and redraws the new one.\n    */\n    setPatterns: function(patterns) {\n        this.options.patterns = patterns;\n        this._initPatterns();\n        this._softRedraw();\n    },\n\n    /**\n    * Changes the patterns used by this decorator \n    * and redraws the new one.\n    */\n    setPaths: function(paths) {\n        this._initPaths(paths);\n        this.redraw();\n    },\n\n    /**\n    * Parse the pattern definition\n    */\n    _parsePatternDef: function(patternDef, latLngs) {\n        var pattern = {\n            cache: [],\n            symbolFactory: patternDef.symbol,\n            isOffsetInPixels: false,\n            isRepeatInPixels: false\n        };\n        \n        // Parse offset and repeat values, managing the two cases:\n        // absolute (in pixels) or relative (in percentage of the polyline length)\n        if(typeof patternDef.offset === 'string' && patternDef.offset.indexOf('%') != -1) {\n            pattern.offset = parseFloat(patternDef.offset) / 100;\n        } else {\n            pattern.offset = parseFloat(patternDef.offset);\n            pattern.isOffsetInPixels = (pattern.offset > 0);\n        }\n        \n        \n        if(typeof patternDef.repeat === 'string' && patternDef.repeat.indexOf('%') != -1) {\n            pattern.repeat = parseFloat(patternDef.repeat) / 100;\n        } else {\n            pattern.repeat = parseFloat(patternDef.repeat);\n            pattern.isRepeatInPixels = (pattern.repeat > 0);\n        }\n        \n        // TODO: 0 => not pixel dependant => 0%\n        \n        return(pattern);\n    },\n\n    onAdd: function (map) {\n        this._map = map;\n        this._draw();\n        // listen to zoom changes to redraw pixel-spaced patterns\n        if(this._isZoomDependant) {\n            this._map.on('zoomend', this._softRedraw, this);\n        }\n    },\n\n    onRemove: function (map) {\n        // remove optional map zoom listener\n        this._map.off('zoomend', this._softRedraw, this);\n        this._map = null;\n        L.LayerGroup.prototype.onRemove.call(this, map);\n    },\n\n    /**\n    * Returns an array of ILayers object\n    */\n    _buildSymbols: function(latLngs, symbolFactory, directionPoints) {\n        var symbols = [];\n        for(var i=0, l=directionPoints.length; i<l; i++) {\n            symbols.push(symbolFactory.buildSymbol(directionPoints[i], latLngs, this._map, i, l));\n        }\n        return symbols;\n    },\n\n    _getCache: function(pattern, zoom, pathIndex) {\n        var zoomCache = pattern.cache[zoom];\n        if(typeof zoomCache === 'undefined') {\n            pattern.cache[zoom] = [];\n            return null;\n        }\n        return zoomCache[pathIndex];\n    },\n\n    /**\n    * Select pairs of LatLng and heading angle,\n    * that define positions and directions of the symbols\n    * on the path \n    */\n    _getDirectionPoints: function(pathIndex, pattern) {\n        var zoom = this._map.getZoom();\n        var dirPoints = this._getCache(pattern, zoom, pathIndex);\n        if(dirPoints) {\n            return dirPoints;\n        }\n\n        var offset, repeat, pathPixelLength = null, latLngs = this._paths[pathIndex];\n        if(pattern.isOffsetInPixels) {\n            pathPixelLength =  L.LineUtil.PolylineDecorator.getPixelLength(latLngs, this._map);\n            offset = pattern.offset/pathPixelLength;\n        } else {\n            offset = pattern.offset;\n        }\n        if(pattern.isRepeatInPixels) {\n            pathPixelLength = (pathPixelLength !== null) ? pathPixelLength : L.LineUtil.PolylineDecorator.getPixelLength(latLngs, this._map);\n            repeat = pattern.repeat/pathPixelLength; \n        } else {\n            repeat = pattern.repeat;\n        }\n        dirPoints = L.LineUtil.PolylineDecorator.projectPatternOnPath(latLngs, offset, repeat, this._map);\n        // save in cache to avoid recomputing this\n        pattern.cache[zoom][pathIndex] = dirPoints;\n        \n        return dirPoints;\n    },\n\n    /**\n    * Public redraw, invalidating the cache.\n    */\n    redraw: function() {\n        this._redraw(true);\n    },\n    \n    /**\n    * \"Soft\" redraw, called internally for example on zoom changes,\n    * keeping the cache. \n    */\n    _softRedraw: function() {\n        this._redraw(false);\n    },\n    \n    _redraw: function(clearCache) {\n        if(this._map === null)\n            return;\n        this.clearLayers();\n        if(clearCache) {\n            for(var i=0; i<this._patterns.length; i++) {\n                this._patterns[i].cache = [];\n            }\n        }\n        this._draw();\n    },\n    \n    /**\n    * Draw a single pattern\n    */\n    _drawPattern: function(pattern) {\n        var directionPoints, symbols;\n        for(var i=0; i < this._paths.length; i++) {\n            directionPoints = this._getDirectionPoints(i, pattern);\n            symbols = this._buildSymbols(this._paths[i], pattern.symbolFactory, directionPoints);\n            for(var j=0; j < symbols.length; j++) {\n                this.addLayer(symbols[j]);\n            }\n        }\n    },\n\n    /**\n    * Draw all patterns\n    */\n    _draw: function () {\n        for(var i=0; i<this._patterns.length; i++) {\n            this._drawPattern(this._patterns[i]);\n        }\n    }\n});\n/*\n * Allows compact syntax to be used\n */\nL.polylineDecorator = function (paths, options) {\n    return new L.PolylineDecorator(paths, options);\n};\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/src/L.RotatedMarker.js",
    "content": "L.RotatedMarker = L.Marker.extend({\n    options: {\n        angle: 0\n    },\n    _setPos: function (pos) {\n        L.Marker.prototype._setPos.call(this, pos);\n        \n        if (L.DomUtil.TRANSFORM) {\n            // use the CSS transform rule if available\n            this._icon.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)';\n        } else if(L.Browser.ie) {\n            // fallback for IE6, IE7, IE8\n            var rad = this.options.angle * L.LatLng.DEG_TO_RAD,\n                costheta = Math.cos(rad),\n                sintheta = Math.sin(rad);\n            this._icon.style.filter += ' progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\\'auto expand\\', M11=' + \n                costheta + ', M12=' + (-sintheta) + ', M21=' + sintheta + ', M22=' + costheta + ')';                \n        }\n    }\n});\n\nL.rotatedMarker = function (pos, options) {\n    return new L.RotatedMarker(pos, options);\n};"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.PolylineDecorator-master/src/L.Symbol.js",
    "content": "﻿/**\n* Defines several classes of symbol factories,\n* to be used with L.PolylineDecorator\n*/\n\nL.Symbol = L.Symbol || {};\n\n/**\n* A simple dash symbol, drawn as a Polyline.\n* Can also be used for dots, if 'pixelSize' option is given the 0 value.\n*/\nL.Symbol.Dash = L.Class.extend({\n    isZoomDependant: true,\n    \n    options: {\n        pixelSize: 10,\n        pathOptions: { }\n    },\n    \n    initialize: function (options) {\n        L.Util.setOptions(this, options);\n        this.options.pathOptions.clickable = false;\n    },\n\n    buildSymbol: function(dirPoint, latLngs, map, index, total) {\n        var opts = this.options;\n        \n        // for a dot, nothing more to compute\n        if(opts.pixelSize <= 1) {\n            return new L.Polyline([dirPoint.latLng, dirPoint.latLng], opts.pathOptions);\n        }\n        \n        var midPoint = map.project(dirPoint.latLng);\n        var angle = (-(dirPoint.heading - 90)) * L.LatLng.DEG_TO_RAD;\n        var a = new L.Point(\n                midPoint.x + opts.pixelSize * Math.cos(angle + Math.PI) / 2,\n                midPoint.y + opts.pixelSize * Math.sin(angle) / 2\n            );\n        // compute second point by central symmetry to avoid unecessary cos/sin\n        var b = midPoint.add(midPoint.subtract(a));\n        return new L.Polyline([map.unproject(a), map.unproject(b)], opts.pathOptions);\n    }\n});\n\nL.Symbol.dash = function (options) {\n    return new L.Symbol.Dash(options);\n};\n\nL.Symbol.ArrowHead = L.Class.extend({\n    isZoomDependant: true,\n    \n    options: {\n        polygon: true,\n        pixelSize: 10,\n        headAngle: 60,\n        pathOptions: {\n            stroke: false,\n            weight: 2\n        }\n    },\n    \n    initialize: function (options) {\n        L.Util.setOptions(this, options);\n        this.options.pathOptions.clickable = false;\n    },\n\n    buildSymbol: function(dirPoint, latLngs, map, index, total) {\n        var opts = this.options;\n        var path;\n        if(opts.polygon) {\n            path = new L.Polygon(this._buildArrowPath(dirPoint, map), opts.pathOptions);\n        } else {\n            path = new L.Polyline(this._buildArrowPath(dirPoint, map), opts.pathOptions);\n        }\n        return path;\n    },\n    \n    _buildArrowPath: function (dirPoint, map) {\n        var tipPoint = map.project(dirPoint.latLng);\n        var direction = (-(dirPoint.heading - 90)) * L.LatLng.DEG_TO_RAD;\n        var radianArrowAngle = this.options.headAngle / 2 * L.LatLng.DEG_TO_RAD; \n        \n        var headAngle1 = direction + radianArrowAngle,\n            headAngle2 = direction - radianArrowAngle;\n        var arrowHead1 = new L.Point(\n                tipPoint.x - this.options.pixelSize * Math.cos(headAngle1),\n                tipPoint.y + this.options.pixelSize * Math.sin(headAngle1)),\n            arrowHead2 = new L.Point(\n                tipPoint.x - this.options.pixelSize * Math.cos(headAngle2),\n                tipPoint.y + this.options.pixelSize * Math.sin(headAngle2));\n\n        return [\n            map.unproject(arrowHead1),\n            dirPoint.latLng,\n            map.unproject(arrowHead2)\n        ];\n    }\n});\n\nL.Symbol.arrowHead = function (options) {\n    return new L.Symbol.ArrowHead(options);\n};\n\nL.Symbol.Marker = L.Class.extend({\n    isZoomDependant: false,\n\n    options: {\n        markerOptions: { },\n        rotate: false\n    },\n    \n    initialize: function (options) {\n        L.Util.setOptions(this, options);\n        this.options.markerOptions.clickable = false;\n        this.options.markerOptions.draggable = false;\n        this.isZoomDependant = (L.Browser.ie && this.options.rotate);\n    },\n\n    buildSymbol: function(directionPoint, latLngs, map, index, total) {\n        if(!this.options.rotate) {\n            return new L.Marker(directionPoint.latLng, this.options.markerOptions);\n        }\n        else {\n            this.options.markerOptions.angle = directionPoint.heading;\n            return new L.RotatedMarker(directionPoint.latLng, this.options.markerOptions);\n        }\n    }\n});\n\nL.Symbol.marker = function (options) {\n    return new L.Symbol.Marker(options);\n};\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.draw/leaflet.draw-src.js",
    "content": "/*\n\tLeaflet.draw, a plugin that adds drawing and editing tools to Leaflet powered maps.\n\t(c) 2012-2013, Jacob Toye, Smartrak\n\n\thttps://github.com/Leaflet/Leaflet.draw\n\thttp://leafletjs.com\n\thttps://github.com/jacobtoye\n */\n(function(window, document, undefined) {\n\t/*\n\t * Leaflet.draw assumes that you have already included the Leaflet library.\n\t */\n\n\tL.drawVersion = '0.2.3-dev';\n\n\tL.drawLocal = {\n\t\tdraw : {\n\t\t\ttoolbar : {\n\t\t\t\tactions : {\n\t\t\t\t\ttitle : '取消绘画',\n\t\t\t\t\ttext : '取消'\n\t\t\t\t},\n\t\t\t\tbuttons : {\n\t\t\t\t\tzoomIn : '放大',\n\t\t\t\t\tzoomOut : '缩小',\n\t\t\t\t\tpolyline : '画线',\n\t\t\t\t\tpolygon : '画多边形',\n\t\t\t\t\trectangle : '画正方形',\n\t\t\t\t\tcircle : '画圆',\n\t\t\t\t\tmarker : '标点',\n\t\t\t\t\trectangleQuery : '画正方形查询',\n\t\t\t\t\tcircleQuery : '画圆查询',\n\t\t\t\t\tpolygonQuery : '画多边形查询',\n\t\t\t\t\treset : '重置',\n\t\t\t\t\tcleanAll : '清空地图'\n\t\t\t\t}\n\t\t\t},\n\t\t\thandlers : {\n\t\t\t\tcircle : {\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\tstart : '点击并拖拽开始画圆'\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tmarker : {\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\tstart : '点击开始标点'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tpolygon : {\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\tstart : '点击开始画多边形',\n\t\t\t\t\t\tcont : '继续点击画多边形',\n\t\t\t\t\t\tend : '点击第一个点结束画多边形'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tpolyline : {\n\t\t\t\t\terror : '<strong>错误:</strong> 形状边缘不能交叉!',\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\tstart : '点击开始画线',\n\t\t\t\t\t\tcont : '继续点击画线',\n\t\t\t\t\t\tend : '点击最后一个点结束画线'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\trectangle : {\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\tstart : '点击画矩形'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\treset : {\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\tstart : '重置'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsimpleshape : {\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\tend : '松开鼠标结束绘制'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\tedit : {\n\t\t\ttoolbar : {\n\t\t\t\tactions : {\n\t\t\t\t\tsave : {\n\t\t\t\t\t\ttitle : '保存修改.',\n\t\t\t\t\t\ttext : '保存'\n\t\t\t\t\t},\n\t\t\t\t\tcancel : {\n\t\t\t\t\t\ttitle : '取消编辑，丢弃所有的变化。',\n\t\t\t\t\t\ttext : '取消'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tbuttons : {\n\t\t\t\t\tedit : '编辑图层',\n\t\t\t\t\teditDisabled : '没有图层可编辑',\n\t\t\t\t\tremove : '删除图层',\n\t\t\t\t\tremoveDisabled : '没有图层删除'\n\t\t\t\t}\n\t\t\t},\n\t\t\thandlers : {\n\t\t\t\tedit : {\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\ttext : '拖动把手,或标记编辑功能。',\n\t\t\t\t\t\tsubtext : '单击取消撤销更改。'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tremove : {\n\t\t\t\t\ttooltip : {\n\t\t\t\t\t\ttext : '点击取消'\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\tL.Draw = {};\n\n\tL.Draw.Feature = L.Handler.extend({\n\t\tincludes : L.Mixin.Events,\n\n\t\tinitialize : function(map, options) {\n\t\t\tthis._map = map;\n\n\t\t\tthis._container = map._container;\n\t\t\tthis._overlayPane = map._panes.overlayPane;\n\t\t\tthis._popupPane = map._panes.popupPane;\n\n\t\t\t// Merge default shapeOptions options with custom shapeOptions\n\t\t\tif (options && options.shapeOptions) {\n\t\t\t\toptions.shapeOptions = L.Util.extend({},\n\t\t\t\t\t\tthis.options.shapeOptions, options.shapeOptions);\n\t\t\t}\n\t\t\tL.setOptions(this, options);\n\t\t},\n\n\t\tenable : function() {\n\t\t\tif (this._enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tL.Handler.prototype.enable.call(this);\n\n\t\t\tthis.fire('enabled', {\n\t\t\t\thandler : this.type\n\t\t\t});\n\n\t\t\tthis._map.fire('draw:drawstart', {\n\t\t\t\tlayerType : this.type\n\t\t\t});\n\t\t},\n\n\t\tdisable : function() {\n\t\t\tif (!this._enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tL.Handler.prototype.disable.call(this);\n\n\t\t\tthis.fire('disabled', {\n\t\t\t\thandler : this.type\n\t\t\t});\n\n\t\t\tthis._map.fire('draw:drawstop', {\n\t\t\t\tlayerType : this.type\n\t\t\t});\n\t\t},\n\n\t\taddHooks : function() {\n\t\t\tvar map = this._map;\n\n\t\t\tif (map) {\n\t\t\t\tL.DomUtil.disableTextSelection();\n\n\t\t\t\tmap.getContainer().focus();\n\n\t\t\t\tthis._tooltip = new L.Tooltip(this._map);\n\n\t\t\t\tL.DomEvent.addListener(this._container, 'keyup',\n\t\t\t\t\t\tthis._cancelDrawing, this);\n\t\t\t}\n\t\t},\n\n\t\tremoveHooks : function() {\n\t\t\tif (this._map) {\n\t\t\t\tL.DomUtil.enableTextSelection();\n\n\t\t\t\tthis._tooltip.dispose();\n\t\t\t\tthis._tooltip = null;\n\t\t\t\tL.DomEvent.removeListener(this._container, 'keyup',\n\t\t\t\t\t\tthis._cancelDrawing);\n\t\t\t}\n\t\t},\n\n\t\tsetOptions : function(options) {\n\t\t\tL.setOptions(this, options);\n\t\t},\n\n\t\t_fireCreatedEvent : function(layer) {\n\n\t\t\tthis._map.fire('draw:created', {\n\t\t\t\tlayer : layer,\n\t\t\t\tlayerType : this.type\n\t\t\t});\n\t\t},\n\n\t\t// Cancel drawing when the escape key is pressed\n\t\t_cancelDrawing : function(e) {\n\t\t\tif (e.keyCode === 27) {\n\t\t\t\tthis.disable();\n\t\t\t}\n\t\t}\n\t});\n\n\tL.Draw.Polyline = L.Draw.Feature\n\t\t\t.extend({\n\t\t\t\tstatics : {\n\t\t\t\t\tTYPE : 'polyline'\n\t\t\t\t},\n\t\t\t\tPoly : L.Polyline,\n\n\t\t\t\toptions : {\n\t\t\t\t\tallowIntersection : true,\n\t\t\t\t\trepeatMode : false,\n\t\t\t\t\tdrawError : {\n\t\t\t\t\t\tcolor : '#b00b00',\n\t\t\t\t\t\ttimeout : 2500\n\t\t\t\t\t},\n\t\t\t\t\ticon : new L.DivIcon({\n\t\t\t\t\t\ticonSize : new L.Point(8, 8),\n\t\t\t\t\t\tclassName : 'leaflet-div-icon leaflet-editing-icon'\n\t\t\t\t\t}),\n\t\t\t\t\tguidelineDistance : 20,\n\t\t\t\t\tshapeOptions : {\n\t\t\t\t\t\tstroke : true,\n\t\t\t\t\t\tcolor : '#f06eaa',\n\t\t\t\t\t\tweight : 4,\n\t\t\t\t\t\topacity : 0.5,\n\t\t\t\t\t\tfill : false,\n\t\t\t\t\t\tclickable : true\n\t\t\t\t\t},\n\t\t\t\t\tmetric : true, // Whether to use the metric meaurement\n\t\t\t\t\t// system or imperial\n\t\t\t\t\tshowLength : true, // Whether to display distance in the\n\t\t\t\t\t// tooltip\n\t\t\t\t\tzIndexOffset : 2000\n\t\t\t\t// This should be > than the highest z-index any map layers\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(map, options) {\n\t\t\t\t\tthis._map = map;\n\t\t\t\t\t// Need to set this here to ensure the correct message is\n\t\t\t\t\t// used.\n\t\t\t\t\tthis.options.drawError.message = L.drawLocal.draw.handlers.polyline.error;\n\n\t\t\t\t\t// Merge default drawError options with custom options\n\t\t\t\t\tif (options && options.drawError) {\n\t\t\t\t\t\toptions.drawError = L.Util.extend({},\n\t\t\t\t\t\t\t\tthis.options.drawError, options.drawError);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Save the type so super can fire, need to do this as\n\t\t\t\t\t// cannot do this.TYPE :(\n\t\t\t\t\tthis.type = L.Draw.Polyline.TYPE;\n\n\t\t\t\t\t// 自定义的\n\t\t\t\t\tthis._drawnItems = new L.FeatureGroup();\n\t\t\t\t\tthis._map.addLayer(this._drawnItems);\n\n\t\t\t\t\tL.Draw.Feature.prototype.initialize\n\t\t\t\t\t\t\t.call(this, map, options);\n\t\t\t\t},\n\n\t\t\t\taddHooks : function() {\n\n\t\t\t\t\t// 清空数据\n\t\t\t\t\tif (L.Draw.tempData) {\n\t\t\t\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\t\t\t// layer : this._drawnItems\n\t\t\t\t\t\tthis._map.removeLayer(L.Draw.tempData.tipMarkerGroup);\n\t\t\t\t\t\tL.Draw.tempData.layer.clearLayers();\n\t\t\t\t\t}\n\t\t\t\t\t// 清空标点数据\n\t\t\t\t\tif (L.Draw.tempData1) {\n\t\t\t\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\t\t\t// layer : this._drawnItems\n\t\t\t\t\t\tthis._map.removeLayer(L.Draw.tempData1.tipMarkerGroup);\n\t\t\t\t\t\tL.Draw.tempData1.layer.clearLayers();\n\t\t\t\t\t}\n\n\t\t\t\t\tL.Draw.Feature.prototype.addHooks.call(this);\n\t\t\t\t\tif (this._map) {\n\t\t\t\t\t\tthis._markers = [];\n\n\t\t\t\t\t\t// 初始化绘制完成状态为false;\n\t\t\t\t\t\tthis._drawStatus = false;\n\n\t\t\t\t\t\t// 扩展的属性\n\t\t\t\t\t\tthis._tipMarkerGroup = new L.LayerGroup();\n\t\t\t\t\t\tthis._map.addLayer(this._tipMarkerGroup);\n\n\t\t\t\t\t\tthis._tipIdPrefix = 'tip_' + (new Date()).getTime();\n\t\t\t\t\t\t// ///\n\n\t\t\t\t\t\tthis._markerGroup = new L.LayerGroup();\n\t\t\t\t\t\tthis._map.addLayer(this._markerGroup);\n\n\t\t\t\t\t\tthis._poly = new L.Polyline([],\n\t\t\t\t\t\t\t\tthis.options.shapeOptions);\n\n\t\t\t\t\t\tthis._tooltip.updateContent(this._getTooltipText());\n\n\t\t\t\t\t\t// Make a transparent marker that will used to catch\n\t\t\t\t\t\t// click events. These click\n\t\t\t\t\t\t// events will create the vertices. We need to do this\n\t\t\t\t\t\t// so we can ensure that\n\t\t\t\t\t\t// we can create vertices over other map layers\n\t\t\t\t\t\t// (markers, vector layers). We\n\t\t\t\t\t\t// also do not want to trigger any click handlers of\n\t\t\t\t\t\t// objects we are clicking on\n\t\t\t\t\t\t// while drawing.\n\t\t\t\t\t\tif (!this._mouseMarker) {\n\t\t\t\t\t\t\tthis._mouseMarker = L\n\t\t\t\t\t\t\t\t\t.marker(\n\t\t\t\t\t\t\t\t\t\t\tthis._map.getCenter(),\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\ticon : L\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.divIcon({\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tclassName : 'leaflet-mouse-marker',\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ticonAnchor : [ 20,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t20 ],\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ticonSize : [ 40, 40 ]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t\t\t\topacity : 0,\n\t\t\t\t\t\t\t\t\t\t\t\tzIndexOffset : this.options.zIndexOffset\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis._mouseMarker.on('click', this._onClick, this)\n\t\t\t\t\t\t\t\t.addTo(this._map);\n\n\t\t\t\t\t\tthis._map.on('mousemove', this._onMouseMove, this).on(\n\t\t\t\t\t\t\t\t'zoomend', this._onZoomEnd, this);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremoveHooks : function() {\n\t\t\t\t\tL.Draw.Feature.prototype.removeHooks.call(this);\n\n\t\t\t\t\tthis._clearHideErrorTimeout();\n\n\t\t\t\t\tthis._cleanUpShape();\n\n\t\t\t\t\t// remove markers from map\n\t\t\t\t\tthis._map.removeLayer(this._markerGroup);\n\t\t\t\t\tdelete this._markerGroup;\n\t\t\t\t\tdelete this._markers;\n\n\t\t\t\t\tthis._map.removeLayer(this._poly);\n\t\t\t\t\tdelete this._poly;\n\n\t\t\t\t\tthis._mouseMarker.off('click', this._onClick, this);\n\t\t\t\t\tthis._map.removeLayer(this._mouseMarker);\n\t\t\t\t\tdelete this._mouseMarker;\n\n\t\t\t\t\t// clean up DOM\n\t\t\t\t\tthis._clearGuides();\n\n\t\t\t\t\tthis._map.off('mousemove', this._onMouseMove, this).off(\n\t\t\t\t\t\t\t'zoomend', this._onZoomEnd, this);\n\t\t\t\t},\n\n\t\t\t\t_finishShape : function() {\n\t\t\t\t\tvar intersects = this._poly.newLatLngIntersects(this._poly\n\t\t\t\t\t\t\t.getLatLngs()[0], true);\n\n\t\t\t\t\tif ((!this.options.allowIntersection && intersects)\n\t\t\t\t\t\t\t|| !this._shapeIsValid()) {\n\t\t\t\t\t\tthis._showErrorTooltip();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._fireCreatedEvent();\n\t\t\t\t\tthis.disable();\n\t\t\t\t\tif (this.options.repeatMode) {\n\t\t\t\t\t\tthis.enable();\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\t// Called to verify the shape is valid when the user tries to\n\t\t\t\t// finish it\n\t\t\t\t// Return false if the shape is not valid\n\t\t\t\t_shapeIsValid : function() {\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\n\t\t\t\t_onZoomEnd : function() {\n\t\t\t\t\tthis._updateGuide();\n\t\t\t\t},\n\n\t\t\t\t_onMouseMove : function(e) {\n\t\t\t\t\tvar newPos = e.layerPoint, latlng = e.latlng;\n\n\t\t\t\t\t// Save latlng\n\t\t\t\t\t// should this be moved to _updateGuide() ?\n\t\t\t\t\tthis._currentLatLng = latlng;\n\n\t\t\t\t\tthis._updateTooltip(latlng);\n\n\t\t\t\t\t// Update the guide line\n\t\t\t\t\tthis._updateGuide(newPos);\n\n\t\t\t\t\t// Update the mouse marker position\n\t\t\t\t\tthis._mouseMarker.setLatLng(latlng);\n\n\t\t\t\t\tL.DomEvent.preventDefault(e.originalEvent);\n\t\t\t\t},\n\n\t\t\t\t_onClick : function(e) {\n\n\t\t\t\t\tvar latlng = e.target.getLatLng(), markerCount = this._markers.length;\n\n\t\t\t\t\tif (markerCount > 0 && !this.options.allowIntersection\n\t\t\t\t\t\t\t&& this._poly.newLatLngIntersects(latlng)) {\n\t\t\t\t\t\tthis._showErrorTooltip();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else if (this._errorShown) {\n\t\t\t\t\t\tthis._hideErrorTooltip();\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._markers.push(this._createMarker(latlng));\n\n\t\t\t\t\tthis._poly.addLatLng(latlng);\n\n\t\t\t\t\tif (this._poly.getLatLngs().length === 2) {\n\t\t\t\t\t\tthis._map.addLayer(this._poly);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._updateFinishHandler();\n\n\t\t\t\t\tthis._vertexAdded(latlng);\n\n\t\t\t\t\tthis._clearGuides();\n\n\t\t\t\t\tthis._updateTooltip();\n\n\t\t\t\t\t// 测距添加Tip\n\t\t\t\t\tif (this.type == 'polyline') {\n\t\t\t\t\t\tvar tip = this._getTooltipText().subtext;\n\t\t\t\t\t\tif (this._markers.length == 1) {\n\t\t\t\t\t\t\ttip = '起点';\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar myIcon = L\n\t\t\t\t\t\t\t\t.divIcon({\n\t\t\t\t\t\t\t\t\ticonSize : L.point(90, 20),\n\t\t\t\t\t\t\t\t\ticonAnchor : L.point(50, 25),\n\t\t\t\t\t\t\t\t\t html : '<div style=\"width:100%;height:100%;text-align: center;background-color:#9BD1FA\" id=\"'\n\t\t\t\t\t\t\t\t\t + this._tipIdPrefix\n\t\t\t\t\t\t\t\t\t + ''\n\t\t\t\t\t\t\t\t\t + this._markers.length\n\t\t\t\t\t\t\t\t\t + '\">'\n\t\t\t\t\t\t\t\t\t + tip\n\t\t\t\t\t\t\t\t\t + '</div>'\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\tvar tipMarker = L.marker(latlng, {\n\t\t\t\t\t\t\ticon : myIcon\n\t\t\t\t\t\t}).addTo(this._map);\n\t\t\t\t\t\tthis._tipMarkerGroup.addLayer(tipMarker);\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\t_updateFinishHandler : function() {\n\t\t\t\t\tvar markerCount = this._markers.length;\n\t\t\t\t\t// The last marker should have a click handler to close the\n\t\t\t\t\t// polyline\n\t\t\t\t\tif (markerCount > 1) {\n\t\t\t\t\t\tthis._markers[markerCount - 1].on('click',\n\t\t\t\t\t\t\t\tthis._finishShape, this);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Remove the old marker click handler (as only the last\n\t\t\t\t\t// point should close the polyline)\n\t\t\t\t\tif (markerCount > 2) {\n\t\t\t\t\t\tthis._markers[markerCount - 2].off('click',\n\t\t\t\t\t\t\t\tthis._finishShape, this);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_createMarker : function(latlng) {\n\t\t\t\t\tvar marker = new L.Marker(latlng, {\n\t\t\t\t\t\ticon : this.options.icon,\n\t\t\t\t\t\tzIndexOffset : this.options.zIndexOffset * 2\n\t\t\t\t\t});\n\n\t\t\t\t\tthis._markerGroup.addLayer(marker);\n\n\t\t\t\t\treturn marker;\n\t\t\t\t},\n\n\t\t\t\t_updateGuide : function(newPos) {\n\t\t\t\t\tvar markerCount = this._markers.length;\n\n\t\t\t\t\tif (markerCount > 0) {\n\t\t\t\t\t\tnewPos = newPos\n\t\t\t\t\t\t\t\t|| this._map\n\t\t\t\t\t\t\t\t\t\t.latLngToLayerPoint(this._currentLatLng);\n\n\t\t\t\t\t\t// draw the guide line\n\t\t\t\t\t\tthis._clearGuides();\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t\t._drawGuide(\n\t\t\t\t\t\t\t\t\t\tthis._map\n\t\t\t\t\t\t\t\t\t\t\t\t.latLngToLayerPoint(this._markers[markerCount - 1]\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t.getLatLng()), newPos);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_updateTooltip : function(latLng) {\n\t\t\t\t\tvar text = this._getTooltipText();\n\n\t\t\t\t\tif (latLng) {\n\t\t\t\t\t\tthis._tooltip.updatePosition(latLng);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!this._errorShown) {\n\t\t\t\t\t\tthis._tooltip.updateContent(text);\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\t_drawGuide : function(pointA, pointB) {\n\t\t\t\t\tvar length = Math.floor(Math.sqrt(Math.pow(\n\t\t\t\t\t\t\t(pointB.x - pointA.x), 2)\n\t\t\t\t\t\t\t+ Math.pow((pointB.y - pointA.y), 2))), i, fraction, dashPoint, dash;\n\n\t\t\t\t\t// create the guides container if we haven't yet\n\t\t\t\t\tif (!this._guidesContainer) {\n\t\t\t\t\t\tthis._guidesContainer = L.DomUtil.create('div',\n\t\t\t\t\t\t\t\t'leaflet-draw-guides', this._overlayPane);\n\t\t\t\t\t}\n\n\t\t\t\t\t// draw a dash every GuildeLineDistance\n\t\t\t\t\tfor (i = this.options.guidelineDistance; i < length; i += this.options.guidelineDistance) {\n\t\t\t\t\t\t// work out fraction along line we are\n\t\t\t\t\t\tfraction = i / length;\n\n\t\t\t\t\t\t// calculate new x,y point\n\t\t\t\t\t\tdashPoint = {\n\t\t\t\t\t\t\tx : Math.floor((pointA.x * (1 - fraction))\n\t\t\t\t\t\t\t\t\t+ (fraction * pointB.x)),\n\t\t\t\t\t\t\ty : Math.floor((pointA.y * (1 - fraction))\n\t\t\t\t\t\t\t\t\t+ (fraction * pointB.y))\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// add guide dash to guide container\n\t\t\t\t\t\tdash = L.DomUtil.create('div',\n\t\t\t\t\t\t\t\t'leaflet-draw-guide-dash',\n\t\t\t\t\t\t\t\tthis._guidesContainer);\n\t\t\t\t\t\tdash.style.backgroundColor = !this._errorShown ? this.options.shapeOptions.color\n\t\t\t\t\t\t\t\t: this.options.drawError.color;\n\n\t\t\t\t\t\tL.DomUtil.setPosition(dash, dashPoint);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_updateGuideColor : function(color) {\n\t\t\t\t\tif (this._guidesContainer) {\n\t\t\t\t\t\tfor ( var i = 0, l = this._guidesContainer.childNodes.length; i < l; i++) {\n\t\t\t\t\t\t\tthis._guidesContainer.childNodes[i].style.backgroundColor = color;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t// removes all child elements (guide dashes) from the guides\n\t\t\t\t// container\n\t\t\t\t_clearGuides : function() {\n\t\t\t\t\tif (this._guidesContainer) {\n\t\t\t\t\t\twhile (this._guidesContainer.firstChild) {\n\t\t\t\t\t\t\tthis._guidesContainer\n\t\t\t\t\t\t\t\t\t.removeChild(this._guidesContainer.firstChild);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_getTooltipText : function() {\n\t\t\t\t\tvar showLength = this.options.showLength, labelText, distance, distanceStr;\n\n\t\t\t\t\tif (this._markers.length === 0) {\n\t\t\t\t\t\tlabelText = {\n\t\t\t\t\t\t\ttext : L.drawLocal.draw.handlers.polyline.tooltip.start\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdistanceStr = showLength ? this._getMeasurementString()\n\t\t\t\t\t\t\t\t: '';\n\n\t\t\t\t\t\tif (this._markers.length === 1) {\n\t\t\t\t\t\t\tlabelText = {\n\t\t\t\t\t\t\t\ttext : L.drawLocal.draw.handlers.polyline.tooltip.cont,\n\t\t\t\t\t\t\t\tsubtext : distanceStr\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlabelText = {\n\t\t\t\t\t\t\t\ttext : L.drawLocal.draw.handlers.polyline.tooltip.end,\n\t\t\t\t\t\t\t\tsubtext : distanceStr\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn labelText;\n\t\t\t\t},\n\n\t\t\t\t_getMeasurementString : function() {\n\t\t\t\t\tvar currentLatLng = this._currentLatLng, previousLatLng = this._markers[this._markers.length - 1]\n\t\t\t\t\t\t\t.getLatLng(), distance;\n\n\t\t\t\t\t// calculate the distance from the last fixed point to the\n\t\t\t\t\t// mouse position\n\t\t\t\t\tdistance = this._measurementRunningTotal\n\t\t\t\t\t\t\t+ currentLatLng.distanceTo(previousLatLng);\n\n\t\t\t\t\treturn L.GeometryUtil.readableDistance(distance,\n\t\t\t\t\t\t\tthis.options.metric);\n\t\t\t\t},\n\n\t\t\t\t_showErrorTooltip : function() {\n\t\t\t\t\tthis._errorShown = true;\n\n\t\t\t\t\t// Update tooltip\n\t\t\t\t\tthis._tooltip.showAsError().updateContent({\n\t\t\t\t\t\ttext : this.options.drawError.message\n\t\t\t\t\t});\n\n\t\t\t\t\t// Update shape\n\t\t\t\t\tthis._updateGuideColor(this.options.drawError.color);\n\t\t\t\t\tthis._poly.setStyle({\n\t\t\t\t\t\tcolor : this.options.drawError.color\n\t\t\t\t\t});\n\n\t\t\t\t\t// Hide the error after 2 seconds\n\t\t\t\t\tthis._clearHideErrorTimeout();\n\t\t\t\t\tthis._hideErrorTimeout = setTimeout(L.Util.bind(\n\t\t\t\t\t\t\tthis._hideErrorTooltip, this),\n\t\t\t\t\t\t\tthis.options.drawError.timeout);\n\t\t\t\t},\n\n\t\t\t\t_hideErrorTooltip : function() {\n\t\t\t\t\tthis._errorShown = false;\n\n\t\t\t\t\tthis._clearHideErrorTimeout();\n\n\t\t\t\t\t// Revert tooltip\n\t\t\t\t\tthis._tooltip.removeError().updateContent(\n\t\t\t\t\t\t\tthis._getTooltipText());\n\n\t\t\t\t\t// Revert shape\n\t\t\t\t\tthis._updateGuideColor(this.options.shapeOptions.color);\n\t\t\t\t\tthis._poly.setStyle({\n\t\t\t\t\t\tcolor : this.options.shapeOptions.color\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\t_clearHideErrorTimeout : function() {\n\t\t\t\t\tif (this._hideErrorTimeout) {\n\t\t\t\t\t\tclearTimeout(this._hideErrorTimeout);\n\t\t\t\t\t\tthis._hideErrorTimeout = null;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_vertexAdded : function(latlng) {\n\t\t\t\t\tif (this._markers.length === 1) {\n\t\t\t\t\t\tthis._measurementRunningTotal = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._measurementRunningTotal += latlng\n\t\t\t\t\t\t\t\t.distanceTo(this._markers[this._markers.length - 2]\n\t\t\t\t\t\t\t\t\t\t.getLatLng());\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_cleanUpShape : function() {\n\t\t\t\t\tif (this._markers.length > 1) {\n\t\t\t\t\t\tthis._markers[this._markers.length - 1].off('click',\n\t\t\t\t\t\t\t\tthis._finishShape, this);\n\t\t\t\t\t\t// 如果不是正常绘制完成的话，删除已经添加的tipMarker\n\t\t\t\t\t\tif (!this._drawStatus) {\n\t\t\t\t\t\t\tthis._map.removeLayer(this._tipMarkerGroup);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\t_fireCreatedEvent : function() {\n\t\t\t\t\tthis._drawStatus = true;\n\n\t\t\t\t\tvar poly = new this.Poly(this._poly.getLatLngs(),\n\t\t\t\t\t\t\tthis.options.shapeOptions);\n\t\t\t\t\tL.Draw.Feature.prototype._fireCreatedEvent.call(this, poly);\n\n\t\t\t\t\tthis._drawnItems.addLayer(poly);\n\t\t\t\t\tL.Draw.tempData = {\n\t\t\t\t\t\ttipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\t\t\tlayer : this._drawnItems\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t});\n\n\tL.Draw.Polygon = L.Draw.Polyline.extend({\n\t\tstatics : {\n\t\t\tTYPE : 'polygon'\n\t\t},\n\n\t\tPoly : L.Polygon,\n\n\t\toptions : {\n\t\t\tshowArea : true,\n\t\t\tshapeOptions : {\n\t\t\t\tstroke : true,\n\t\t\t\tcolor : '#f06eaa',\n\t\t\t\tweight : 4,\n\t\t\t\topacity : 0.5,\n\t\t\t\tfill : true,\n\t\t\t\tfillColor : null, // same as color by default\n\t\t\t\tfillOpacity : 0.2,\n\t\t\t\tclickable : true\n\t\t\t}\n\t\t},\n\n\t\tinitialize : function(map, options) {\n\t\t\tthis._map = map;\n\n\t\t\tL.Draw.Polyline.prototype.initialize.call(this, map, options);\n\n\t\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t\t// this.TYPE :(\n\t\t\tthis.type = L.Draw.Polygon.TYPE;\n\t\t},\n\n\t\t_updateFinishHandler : function() {\n\t\t\tvar markerCount = this._markers.length;\n\n\t\t\t// The first marker should have a click handler to close the polygon\n\t\t\tif (markerCount === 1) {\n\t\t\t\tthis._markers[0].on('click', this._finishShape, this);\n\t\t\t}\n\n\t\t\t// Add and update the double click handler\n\t\t\tif (markerCount > 2) {\n\t\t\t\tthis._markers[markerCount - 1].on('dblclick',\n\t\t\t\t\t\tthis._finishShape, this);\n\t\t\t\t// Only need to remove handler if has been added before\n\t\t\t\tif (markerCount > 3) {\n\t\t\t\t\tthis._markers[markerCount - 2].off('dblclick',\n\t\t\t\t\t\t\tthis._finishShape, this);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t_getTooltipText : function() {\n\t\t\tvar text, subtext;\n\n\t\t\tif (this._markers.length === 0) {\n\t\t\t\ttext = L.drawLocal.draw.handlers.polygon.tooltip.start;\n\t\t\t} else if (this._markers.length < 3) {\n\t\t\t\ttext = L.drawLocal.draw.handlers.polygon.tooltip.cont;\n\t\t\t} else {\n\t\t\t\ttext = L.drawLocal.draw.handlers.polygon.tooltip.end;\n\t\t\t\tsubtext = this._getMeasurementString();\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttext : text,\n\t\t\t\tsubtext : subtext\n\t\t\t};\n\t\t},\n\n\t\t_getMeasurementString : function() {\n\t\t\tvar area = this._area;\n\n\t\t\tif (!area) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn L.GeometryUtil.readableArea(area, this.options.metric);\n\t\t},\n\n\t\t_shapeIsValid : function() {\n\t\t\treturn this._markers.length >= 3;\n\t\t},\n\n\t\t_vertexAdded : function() {\n\t\t\t// Check to see if we should show the area\n\t\t\tif (this.options.allowIntersection || !this.options.showArea) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar latLngs = this._poly.getLatLngs();\n\n\t\t\tthis._area = L.GeometryUtil.geodesicArea(latLngs);\n\n\t\t},\n\t\t_finishShape : function() {\n\n\t\t\tvar myUnit;\n\t\t\tvar latLngsArray = this._poly.getLatLngs();\n\t\t\tvar area = this._area / 1000000;\n\t\t\tif (area >= 10000) {\n\t\t\t\tarea = area / 10000;\n\t\t\t\tmyUnit = '万平方千米';\n\t\t\t} else {\n\t\t\t\tmyUnit = '平方千米';\n\t\t\t}\n\t\t\tvar myIcon = L.divIcon({\n\t\t\t\ticonSize : L.point(130, 40),\n\t\t\t\ticonAnchor : L.point(50, 25),\n\t\t\t\thtml : '<div id=\"CircleId\" style=\"width:100%;height:100%;text-align: center;background-color:#9BD1FA\" >' + '面积：' + area.toFixed(2)\n\t\t\t\t\t\t+ myUnit + '</div>'\n\t\t\t});\n\t\t\tvar tipPloygon = L.marker(latLngsArray[latLngsArray.length - 1], {\n\t\t\t\ticon : myIcon\n\t\t\t}).addTo(this._map);\n\t\t\tthis._tipMarkerGroup.addLayer(tipPloygon);\n\t\t\tvar intersects = this._poly.newLatLngIntersects(this._poly\n\t\t\t\t\t.getLatLngs()[0], true);\n\t\t\tif ((!this.options.allowIntersection && intersects)\n\t\t\t\t\t|| !this._shapeIsValid()) {\n\t\t\t\tthis._showErrorTooltip();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._fireCreatedEvent();\n\t\t\tthis.disable();\n\t\t\tif (this.options.repeatMode) {\n\t\t\t\tthis.enable();\n\t\t\t}\n\n\t\t},\n\t\t// 点击取消清除多边形\n\t\t_cleanUpShape : function() {\n\n\t\t\t// 如果不是正常绘制完成的话，删除已经添加的tipMarker\n\t\t\tif (!this._drawStatus) {\n\t\t\t\tif (this._tipMarkerGroup) {\n\t\t\t\t\tthis._map.removeLayer(this._tipMarkerGroup);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar markerCount = this._markers.length;\n\t\t\tif (markerCount > 0) {\n\t\t\t\tthis._markers[0].off('click', this._finishShape, this);\n\n\t\t\t\tif (markerCount > 2) {\n\t\t\t\t\tthis._markers[markerCount - 1].off('dblclick',\n\t\t\t\t\t\t\tthis._finishShape, this);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\tL.SimpleShape = {};\n\n\tL.Draw.SimpleShape = L.Draw.Feature\n\t\t\t.extend({\n\t\t\t\toptions : {\n\t\t\t\t\trepeatMode : false\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(map, options) {\n\t\t\t\t\tthis._endLabelText = L.drawLocal.draw.handlers.simpleshape.tooltip.end;\n\n\t\t\t\t\tL.Draw.Feature.prototype.initialize\n\t\t\t\t\t\t\t.call(this, map, options);\n\t\t\t\t},\n\n\t\t\t\taddHooks : function() {\n\n\t\t\t\t\t// 清空数据\n\t\t\t\t\tif (L.Draw.tempData) {\n\t\t\t\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\t\t\t// layer : this._drawnItems\n\t\t\t\t\t\tthis._map.removeLayer(L.Draw.tempData.tipMarkerGroup);\n\t\t\t\t\t\tL.Draw.tempData.layer.clearLayers();\n\t\t\t\t\t}\n\n\t\t\t\t\t// 清空标点数据\n\t\t\t\t\tif (L.Draw.tempData1) {\n\t\t\t\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\t\t\t// layer : this._drawnItems\n\t\t\t\t\t\tthis._map.removeLayer(L.Draw.tempData1.tipMarkerGroup);\n\t\t\t\t\t\tL.Draw.tempData1.layer.clearLayers();\n\t\t\t\t\t}\n\n\t\t\t\t\tL.Draw.Feature.prototype.addHooks.call(this);\n\t\t\t\t\tif (this._map) {\n\n\t\t\t\t\t\t// 初始化绘制完成状态为false;\n\t\t\t\t\t\tthis._drawStatus = false;\n\n\t\t\t\t\t\t// 扩展的属性\n\t\t\t\t\t\tthis._tipMarkerGroup = new L.LayerGroup();\n\t\t\t\t\t\tthis._map.addLayer(this._tipMarkerGroup);\n\t\t\t\t\t\t// 如果不是正常绘制完成的话，删除已经添加的tipMarker\n\t\t\t\t\t\tif (!this._drawStatus) {\n\t\t\t\t\t\t\tthis._map.removeLayer(this._tipMarkerGroup);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis._map.dragging.disable();\n\t\t\t\t\t\t// TODO refactor: move cursor to styles\n\t\t\t\t\t\tthis._container.style.cursor = 'crosshair';\n\n\t\t\t\t\t\tthis._tooltip.updateContent({\n\t\t\t\t\t\t\ttext : this._initialLabelText\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis._map.on('mousedown', this._onMouseDown, this).on(\n\t\t\t\t\t\t\t\t'mousemove', this._onMouseMove, this);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremoveHooks : function() {\n\t\t\t\t\tL.Draw.Feature.prototype.removeHooks.call(this);\n\t\t\t\t\tif (this._map) {\n\t\t\t\t\t\tthis._map.dragging.enable();\n\t\t\t\t\t\t// TODO refactor: move cursor to styles\n\t\t\t\t\t\tthis._container.style.cursor = '';\n\n\t\t\t\t\t\tthis._map.off('mousedown', this._onMouseDown, this)\n\t\t\t\t\t\t\t\t.off('mousemove', this._onMouseMove, this);\n\n\t\t\t\t\t\tL.DomEvent.off(document, 'mouseup', this._onMouseUp);\n\n\t\t\t\t\t\t// If the box element doesn't exist they must not have\n\t\t\t\t\t\t// moved the mouse, so don't need to destroy/return\n\t\t\t\t\t\tif (this._shape) {\n\t\t\t\t\t\t\tthis._map.removeLayer(this._shape);\n\t\t\t\t\t\t\tdelete this._shape;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._isDrawing = false;\n\t\t\t\t},\n\n\t\t\t\t_onMouseDown : function(e) {\n\t\t\t\t\tthis._isDrawing = true;\n\t\t\t\t\tthis._startLatLng = e.latlng;\n\n\t\t\t\t\tL.DomEvent.on(document, 'mouseup', this._onMouseUp, this)\n\t\t\t\t\t\t\t.preventDefault(e.originalEvent);\n\t\t\t\t},\n\n\t\t\t\t_onMouseMove : function(e) {\n\t\t\t\t\tvar latlng = e.latlng;\n\n\t\t\t\t\tthis._tooltip.updatePosition(latlng);\n\t\t\t\t\tif (this._isDrawing) {\n\t\t\t\t\t\tthis._tooltip.updateContent({\n\t\t\t\t\t\t\ttext : this._endLabelText\n\t\t\t\t\t\t});\n\t\t\t\t\t\tthis._drawShape(latlng);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_onMouseUp : function() {\n\t\t\t\t\tif (this._shape) {\n\t\t\t\t\t\tthis._fireCreatedEvent();\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.disable();\n\t\t\t\t\tif (this.options.repeatMode) {\n\t\t\t\t\t\tthis.enable();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\tL.Draw.Rectangle = L.Draw.SimpleShape\n\t\t\t.extend({\n\t\t\t\tstatics : {\n\t\t\t\t\tTYPE : 'rectangle'\n\t\t\t\t},\n\n\t\t\t\toptions : {\n\t\t\t\t\tshapeOptions : {\n\t\t\t\t\t\tstroke : true,\n\t\t\t\t\t\tcolor : '#f06eaa',\n\t\t\t\t\t\tweight : 4,\n\t\t\t\t\t\topacity : 0.5,\n\t\t\t\t\t\tfill : true,\n\t\t\t\t\t\tfillColor : null, // same as color by default\n\t\t\t\t\t\tfillOpacity : 0.2,\n\t\t\t\t\t\tclickable : true\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(map, options) {\n\t\t\t\t\tthis._map = map;\n\t\t\t\t\t// Save the type so super can fire, need to do this as\n\t\t\t\t\t// cannot do this.TYPE :(\n\t\t\t\t\tthis.type = L.Draw.Rectangle.TYPE;\n\n\t\t\t\t\tthis._initialLabelText = L.drawLocal.draw.handlers.rectangle.tooltip.start;\n\n\t\t\t\t\t// 自定义的\n\t\t\t\t\tthis._RectangleLayerGroup = new L.FeatureGroup();\n\t\t\t\t\tthis._map.addLayer(this._RectangleLayerGroup);\n\n\t\t\t\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map,\n\t\t\t\t\t\t\toptions);\n\t\t\t\t},\n\n\t\t\t\t_drawShape : function(latlng) {\n\n\t\t\t\t\tif (!this._shape) {\n\n\t\t\t\t\t\tthis._shape = new L.Rectangle(new L.LatLngBounds(\n\t\t\t\t\t\t\t\tthis._startLatLng, latlng),\n\t\t\t\t\t\t\t\tthis.options.shapeOptions);\n\t\t\t\t\t\tthis._map.addLayer(this._shape);\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthis._shape.setBounds(new L.LatLngBounds(\n\t\t\t\t\t\t\t\tthis._startLatLng, latlng));\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_fireCreatedEvent : function() {\n\n\t\t\t\t\tthis._drawStatus = true;\n\n\t\t\t\t\tvar rectangle = new L.Rectangle(this._shape.getBounds(),\n\t\t\t\t\t\t\tthis.options.shapeOptions);\n\t\t\t\t\tL.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,\n\t\t\t\t\t\t\trectangle);\n\n\t\t\t\t\tthis._RectangleLayerGroup.addLayer(rectangle);\n\t\t\t\t\tL.Draw.tempData = {\n\t\t\t\t\t\ttipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\t\t\tlayer : this._RectangleLayerGroup\n\t\t\t\t\t}\n\n\t\t\t\t},\n\t\t\t\t_onMouseUp : function() {\n\n\t\t\t\t\tvar myUnit;\n\t\t\t\t\tvar obj = new Array();\n\t\t\t\t\tobj[0] = this._shape.getBounds()._northEast;\n\t\t\t\t\tobj[2] = this._shape.getBounds()._southWest;\n\t\t\t\t\tobj[1] = L.latLng(this._shape.getBounds()._southWest.lat,\n\t\t\t\t\t\t\tthis._shape.getBounds()._northEast.lng);\n\t\t\t\t\tobj[3] = L.latLng(this._shape.getBounds()._northEast.lat,\n\t\t\t\t\t\t\tthis._shape.getBounds()._southWest.lng);\n\t\t\t\t\tvar area = (L.GeometryUtil.geodesicArea(obj) / 1000000)\n\t\t\t\t\t\t\t.toFixed(2);\n\t\t\t\t\tif (area >= 10000) {\n\t\t\t\t\t\tarea = (area / 10000).toFixed(2);\n\t\t\t\t\t\tmyUnit = '万平方千米';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmyUnit = '平方千米';\n\t\t\t\t\t}\n\t\t\t\t\tvar myIcon = L.divIcon({\n\t\t\t\t\t\ticonSize : L.point(130, 40),\n\t\t\t\t\t\ticonAnchor : L.point(65, 20),\n\t\t\t\t\t\thtml : '<div id=\"rectangleId\" style=\"width:100%;height:100%;text-align: center;background-color:#9BD1FA\">面积：' + area + myUnit\n\t\t\t\t\t\t\t\t+ '&nbsp;</div>'\n\t\t\t\t\t});\n\t\t\t\t\tvar tipRectangle = L.marker(this._shape.getBounds().getCenter(), {\n\t\t\t\t\t\ticon : myIcon\n\t\t\t\t\t}).addTo(this._map);\n\t\t\t\t\tthis._RectangleLayerGroup.addLayer(tipRectangle);\n\t\t\t\t\tif (this._shape) {\n\t\t\t\t\t\tthis._fireCreatedEvent();\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.disable();\n\t\t\t\t\tif (this.options.repeatMode) {\n\t\t\t\t\t\tthis.enable();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\tL.Draw.Circle = L.Draw.SimpleShape\n\t\t\t.extend({\n\t\t\t\tstatics : {\n\t\t\t\t\tTYPE : 'circle'\n\t\t\t\t},\n\n\t\t\t\toptions : {\n\t\t\t\t\tshapeOptions : {\n\t\t\t\t\t\tstroke : true,\n\t\t\t\t\t\tcolor : '#f06eaa',\n\t\t\t\t\t\tweight : 4,\n\t\t\t\t\t\topacity : 0.5,\n\t\t\t\t\t\tfill : true,\n\t\t\t\t\t\tfillColor : null, // same as color by default\n\t\t\t\t\t\tfillOpacity : 0.2,\n\t\t\t\t\t\tclickable : true\n\t\t\t\t\t},\n\t\t\t\t\tshowRadius : true,\n\t\t\t\t\tmetric : true\n\t\t\t\t// Whether to use the metric meaurement system or imperial\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(map, options) {\n\t\t\t\t\tthis._map = map;\n\t\t\t\t\t// Save the type so super can fire, need to do this as\n\t\t\t\t\t// cannot do this.TYPE :(\n\t\t\t\t\tthis.type = L.Draw.Circle.TYPE;\n\n\t\t\t\t\tthis._initialLabelText = L.drawLocal.draw.handlers.circle.tooltip.start;\n\t\t\t\t\t// 自定义的\n\t\t\t\t\tthis._CircleLayerGroup = new L.FeatureGroup();\n\t\t\t\t\tthis._map.addLayer(this._CircleLayerGroup);\n\n\t\t\t\t\tL.Draw.SimpleShape.prototype.initialize.call(this, map,\n\t\t\t\t\t\t\toptions);\n\t\t\t\t},\n\n\t\t\t\t_drawShape : function(latlng) {\n\t\t\t\t\tif (!this._shape) {\n\t\t\t\t\t\tthis._shape = new L.Circle(this._startLatLng,\n\t\t\t\t\t\t\t\tthis._startLatLng.distanceTo(latlng),\n\t\t\t\t\t\t\t\tthis.options.shapeOptions);\n\t\t\t\t\t\tthis._map.addLayer(this._shape);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._shape.setRadius(this._startLatLng\n\t\t\t\t\t\t\t\t.distanceTo(latlng));\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_fireCreatedEvent : function() {\n\n\t\t\t\t\tthis._drawStatus = true;\n\t\t\t\t\tvar circle = new L.Circle(this._startLatLng, this._shape\n\t\t\t\t\t\t\t.getRadius(), this.options.shapeOptions);\n\t\t\t\t\tL.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,\n\t\t\t\t\t\t\tcircle);\n\t\t\t\t\tthis._CircleLayerGroup.addLayer(circle);\n\t\t\t\t\tL.Draw.tempData = {\n\t\t\t\t\t\ttipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\t\t\tlayer : this._CircleLayerGroup\n\t\t\t\t\t}\n\n\t\t\t\t},\n\n\t\t\t\t_onMouseMove : function(e) {\n\t\t\t\t\tvar latlng = e.latlng, metric = this.options.metric, showRadius = this.options.showRadius, useMetric = this.options.metric, radius;\n\t\t\t\t\tthis._tooltip.updatePosition(latlng);\n\t\t\t\t\tif (this._isDrawing) {\n\t\t\t\t\t\tthis._drawShape(latlng);\n\n\t\t\t\t\t\t// Get the new radius (rounded to 1 dp)\n\t\t\t\t\t\tradius = this._shape.getRadius().toFixed(1);\n\n\t\t\t\t\t\tthis._tooltip.updateContent({\n\t\t\t\t\t\t\ttext : this._endLabelText,\n\t\t\t\t\t\t\tsubtext : showRadius ? '半径: '\n\t\t\t\t\t\t\t\t\t+ L.GeometryUtil.readableDistance(radius,\n\t\t\t\t\t\t\t\t\t\t\tuseMetric) : ''\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t_onMouseUp : function() {\n\n\t\t\t\t\tvar metric = this.options.metric, showRadius = this.options.showRadius, useMetric = this.options.metric, radius, myUnit;\n\t\t\t\t\t// alert(this.getlatLng);\n\t\t\t\t\tradius = this._shape.getRadius().toFixed(1);\n\t\t\t\t\tvar r = 0;// 半径\n\t\t\t\t\tvar unit = \"\";// 单位\n\t\t\t\t\t// if(showRadius){\n\t\t\t\t\tbjStr = L.GeometryUtil.readableDistance(radius, useMetric);\n\t\t\t\t\tif (radius > 1000) {\n\t\t\t\t\t\tr = (radius / 1000).toFixed(2);\n\t\t\t\t\t\tunit = \"km\";\n\t\t\t\t\t} else {\n\t\t\t\t\t\tr = Math.ceil(radius);\n\t\t\t\t\t\tunit = \"m\";\n\t\t\t\t\t}\n\t\t\t\t\tvar area = (3.1415926 * r * r).toFixed(2);// 面积\n\t\t\t\t\tif (unit == 'km') {\n\t\t\t\t\t\tif (area >= 10000) {\n\t\t\t\t\t\t\tarea = (area / 10000).toFixed(2);\n\t\t\t\t\t\t\tmyUnit = '万平方千米';\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmyUnit = '平方千米';\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmyUnit = '平方米';\n\n\t\t\t\t\t}\n\t\t\t\t\tvar myIcon = L.divIcon({\n\t\t\t\t\t\ticonSize : L.point(160, 40),\n\t\t\t\t\t\ticonAnchor : L.point(50, 25),\n\t\t\t\t\t\thtml : '<div id=\"CircleId\" style=\"width:100%;height:100%;text-align: center;background-color:#9BD1FA\"  >' + '半径：' + bjStr\n\t\t\t\t\t\t\t\t+ '</br>面积：' + area + myUnit + '</div>'\n\t\t\t\t\t});\n\n\t\t\t\t\tif (radius != 0) {\n\t\t\t\t\t\tvar tipCircle = L.marker(this._shape.getLatLng(), {\n\t\t\t\t\t\t\ticon : myIcon\n\t\t\t\t\t\t}).addTo(this._map);\n\t\t\t\t\t\tthis._CircleLayerGroup.addLayer(tipCircle);\n\t\t\t\t\t}\n\n\t\t\t\t\t// }\n\n\t\t\t\t\tif (this._shape) {\n\t\t\t\t\t\tthis._fireCreatedEvent();\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.disable();\n\t\t\t\t\tif (this.options.repeatMode) {\n\t\t\t\t\t\tthis.enable();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\tL.Draw.Marker = L.Draw.Feature.extend({\n\t\tstatics : {\n\t\t\tTYPE : 'marker'\n\t\t},\n\n\t\toptions : {\n\t\t\ticon : new L.Icon.Default(),\n\t\t\trepeatMode : false,\n\t\t\tzIndexOffset : 2000\n\t\t// This should be > than the highest z-index any markers\n\t\t},\n\n\t\tinitialize : function(map, options) {\n\t\t\tthis._map = map;\n\t\t\t// Save the type so super can fire, need to do this as cannot do\n\t\t\t// this.TYPE :(\n\t\t\tthis.type = L.Draw.Marker.TYPE;\n\t\t\t// 自定义的\n\t\t\tthis._drawnItems = new L.FeatureGroup();\n\t\t\tthis._map.addLayer(this._drawnItems);\n\n\t\t\tL.Draw.Feature.prototype.initialize.call(this, map, options);\n\t\t},\n\n\t\taddHooks : function() {\n\n\t\t\t// 清空数据\n\t\t\tif (L.Draw.tempData) {\n\t\t\t\t// tipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\t// layer : this._drawnItems\n\t\t\t\tthis._map.removeLayer(L.Draw.tempData.tipMarkerGroup);\n\t\t\t\tL.Draw.tempData.layer.clearLayers();\n\t\t\t}\n\n\t\t\tL.Draw.Feature.prototype.addHooks.call(this);\n\n\t\t\tif (this._map) {\n\n\t\t\t\t// 初始化绘制完成状态为false;\n\t\t\t\tthis._drawStatus = false;\n\n\t\t\t\t// 扩展的属性\n\t\t\t\tthis._tipMarkerGroup = new L.LayerGroup();\n\t\t\t\tthis._map.addLayer(this._tipMarkerGroup);\n\t\t\t\t// 如果不是正常绘制完成的话，删除已经添加的tipMarker\n\t\t\t\tif (!this._drawStatus) {\n\t\t\t\t\tthis._map.removeLayer(this._tipMarkerGroup);\n\t\t\t\t}\n\n\t\t\t\tthis._tooltip.updateContent({\n\t\t\t\t\ttext : L.drawLocal.draw.handlers.marker.tooltip.start\n\t\t\t\t});\n\n\t\t\t\t// Same mouseMarker as in Draw.Polyline\n\t\t\t\tif (!this._mouseMarker) {\n\t\t\t\t\tthis._mouseMarker = L.marker(this._map.getCenter(), {\n\t\t\t\t\t\ticon : L.divIcon({\n\t\t\t\t\t\t\tclassName : 'leaflet-mouse-marker',\n\t\t\t\t\t\t\ticonAnchor : [ 20, 20 ],\n\t\t\t\t\t\t\ticonSize : [ 40, 40 ]\n\t\t\t\t\t\t}),\n\t\t\t\t\t\topacity : 0,\n\t\t\t\t\t\tzIndexOffset : this.options.zIndexOffset\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis._mouseMarker.on('click', this._onClick, this).addTo(\n\t\t\t\t\t\tthis._map);\n\n\t\t\t\tthis._map.on('mousemove', this._onMouseMove, this);\n\t\t\t}\n\t\t},\n\n\t\tremoveHooks : function() {\n\t\t\tL.Draw.Feature.prototype.removeHooks.call(this);\n\n\t\t\tif (this._map) {\n\t\t\t\tif (this._marker) {\n\t\t\t\t\tthis._marker.off('click', this._onClick, this);\n\t\t\t\t\tthis._map.off('click', this._onClick, this).removeLayer(\n\t\t\t\t\t\t\tthis._marker);\n\t\t\t\t\tdelete this._marker;\n\t\t\t\t}\n\n\t\t\t\tthis._mouseMarker.off('click', this._onClick, this);\n\t\t\t\tthis._map.removeLayer(this._mouseMarker);\n\t\t\t\tdelete this._mouseMarker;\n\n\t\t\t\tthis._map.off('mousemove', this._onMouseMove, this);\n\t\t\t}\n\t\t},\n\n\t\t_onMouseMove : function(e) {\n\t\t\tvar latlng = e.latlng;\n\n\t\t\tthis._tooltip.updatePosition(latlng);\n\t\t\tthis._mouseMarker.setLatLng(latlng);\n\n\t\t\tif (!this._marker) {\n\t\t\t\tthis._marker = new L.Marker(latlng, {\n\t\t\t\t\ticon : this.options.icon,\n\t\t\t\t\tzIndexOffset : this.options.zIndexOffset\n\t\t\t\t});\n\t\t\t\t// Bind to both marker and map to make sure we get the click\n\t\t\t\t// event.\n\t\t\t\tthis._marker.on('click', this._onClick, this);\n\t\t\t\tthis._map.on('click', this._onClick, this).addLayer(\n\t\t\t\t\t\tthis._marker);\n\t\t\t} else {\n\t\t\t\tlatlng = this._mouseMarker.getLatLng();\n\t\t\t\tthis._marker.setLatLng(latlng);\n\t\t\t}\n\t\t},\n\n\t\t_onClick : function() {\n\t\t\tthis._fireCreatedEvent();\n\t\t\tthis.disable();\n\t\t\tif (this.options.repeatMode) {\n\t\t\t\tthis.enable();\n\t\t\t}\n\t\t},\n\n\t\t_fireCreatedEvent : function() {\n\n\t\t\tthis._drawStatus = true;\n\t\t\tvar myIcon = L.divIcon({\n\t\t\t\ticonSize : L.point(100, 40),\n\t\t\t\ticonAnchor : L.point(2, 3),\n\t\t\t\thtml : '<div style=\"width:100%;height:100%;text-align: center;background-color:#9BD1FA\"  id=\"rectangleId\">经度：'\n\t\t\t\t\t\t+ this._marker.getLatLng().lng.toFixed(2) + '</br>纬度：'\n\t\t\t\t\t\t+ this._marker.getLatLng().lat.toFixed(2)\n\t\t\t\t\t\t+ '&nbsp;</div>'\n\t\t\t});\n\t\t\tvar tipMark = L.marker(this._marker.getLatLng(), {\n\t\t\t\ticon : myIcon\n\t\t\t}).addTo(this._map);\n\t\t\tthis._drawnItems.addLayer(tipMark);\n\t\t\tvar marker = new L.Marker(this._marker.getLatLng(), {\n\t\t\t\ticon : this.options.icon\n\t\t\t});\n\t\t\tL.Draw.Feature.prototype._fireCreatedEvent.call(this, marker);\n\n\t\t\tthis._drawnItems.addLayer(marker);\n\t\t\tL.Draw.tempData1 = {\n\t\t\t\ttipMarkerGroup : this._tipMarkerGroup,\n\t\t\t\tlayer : this._drawnItems\n\t\t\t}\n\n\t\t}\n\t});\n\n\t// 重置\n\n\tL.Edit = L.Edit || {};\n\n\t/*\n\t * L.Edit.Poly is an editing handler for polylines and polygons.\n\t */\n\n\tL.Edit.Poly = L.Handler\n\t\t\t.extend({\n\t\t\t\toptions : {\n\t\t\t\t\ticon : new L.DivIcon({\n\t\t\t\t\t\ticonSize : new L.Point(8, 8),\n\t\t\t\t\t\tclassName : 'leaflet-div-icon leaflet-editing-icon'\n\t\t\t\t\t})\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(poly, options) {\n\t\t\t\t\tthis._poly = poly;\n\t\t\t\t\tL.setOptions(this, options);\n\t\t\t\t},\n\n\t\t\t\taddHooks : function() {\n\t\t\t\t\tif (this._poly._map) {\n\t\t\t\t\t\tif (!this._markerGroup) {\n\t\t\t\t\t\t\tthis._initMarkers();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis._poly._map.addLayer(this._markerGroup);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremoveHooks : function() {\n\t\t\t\t\tif (this._poly._map) {\n\t\t\t\t\t\tthis._poly._map.removeLayer(this._markerGroup);\n\t\t\t\t\t\tdelete this._markerGroup;\n\t\t\t\t\t\tdelete this._markers;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tupdateMarkers : function() {\n\t\t\t\t\tthis._markerGroup.clearLayers();\n\t\t\t\t\tthis._initMarkers();\n\t\t\t\t},\n\n\t\t\t\t_initMarkers : function() {\n\t\t\t\t\tif (!this._markerGroup) {\n\t\t\t\t\t\tthis._markerGroup = new L.LayerGroup();\n\t\t\t\t\t}\n\t\t\t\t\tthis._markers = [];\n\n\t\t\t\t\tvar latlngs = this._poly._latlngs, i, j, len, marker;\n\n\t\t\t\t\t// TODO refactor holes implementation in Polygon to support\n\t\t\t\t\t// it here\n\n\t\t\t\t\tfor (i = 0, len = latlngs.length; i < len; i++) {\n\n\t\t\t\t\t\tmarker = this._createMarker(latlngs[i], i);\n\t\t\t\t\t\tmarker.on('click', this._onMarkerClick, this);\n\t\t\t\t\t\tthis._markers.push(marker);\n\t\t\t\t\t}\n\n\t\t\t\t\tvar markerLeft, markerRight;\n\n\t\t\t\t\tfor (i = 0, j = len - 1; i < len; j = i++) {\n\t\t\t\t\t\tif (i === 0\n\t\t\t\t\t\t\t\t&& !(L.Polygon && (this._poly instanceof L.Polygon))) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmarkerLeft = this._markers[j];\n\t\t\t\t\t\tmarkerRight = this._markers[i];\n\n\t\t\t\t\t\tthis._createMiddleMarker(markerLeft, markerRight);\n\t\t\t\t\t\tthis._updatePrevNext(markerLeft, markerRight);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_createMarker : function(latlng, index) {\n\t\t\t\t\tvar marker = new L.Marker(latlng, {\n\t\t\t\t\t\tdraggable : true,\n\t\t\t\t\t\ticon : this.options.icon\n\t\t\t\t\t});\n\n\t\t\t\t\tmarker._origLatLng = latlng;\n\t\t\t\t\tmarker._index = index;\n\n\t\t\t\t\tmarker.on('drag', this._onMarkerDrag, this);\n\t\t\t\t\tmarker.on('dragend', this._fireEdit, this);\n\n\t\t\t\t\tthis._markerGroup.addLayer(marker);\n\n\t\t\t\t\treturn marker;\n\t\t\t\t},\n\n\t\t\t\t_removeMarker : function(marker) {\n\t\t\t\t\tvar i = marker._index;\n\n\t\t\t\t\tthis._markerGroup.removeLayer(marker);\n\t\t\t\t\tthis._markers.splice(i, 1);\n\t\t\t\t\tthis._poly.spliceLatLngs(i, 1);\n\t\t\t\t\tthis._updateIndexes(i, -1);\n\n\t\t\t\t\tmarker.off('drag', this._onMarkerDrag, this).off('dragend',\n\t\t\t\t\t\t\tthis._fireEdit, this).off('click',\n\t\t\t\t\t\t\tthis._onMarkerClick, this);\n\t\t\t\t},\n\n\t\t\t\t_fireEdit : function() {\n\t\t\t\t\tthis._poly.edited = true;\n\t\t\t\t\tthis._poly.fire('edit');\n\t\t\t\t},\n\n\t\t\t\t_onMarkerDrag : function(e) {\n\t\t\t\t\tvar marker = e.target;\n\n\t\t\t\t\tL.extend(marker._origLatLng, marker._latlng);\n\n\t\t\t\t\tif (marker._middleLeft) {\n\t\t\t\t\t\tmarker._middleLeft.setLatLng(this._getMiddleLatLng(\n\t\t\t\t\t\t\t\tmarker._prev, marker));\n\t\t\t\t\t}\n\t\t\t\t\tif (marker._middleRight) {\n\t\t\t\t\t\tmarker._middleRight.setLatLng(this._getMiddleLatLng(\n\t\t\t\t\t\t\t\tmarker, marker._next));\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._poly.redraw();\n\t\t\t\t},\n\n\t\t\t\t_onMarkerClick : function(e) {\n\t\t\t\t\tvar minPoints = L.Polygon\n\t\t\t\t\t\t\t&& (this._poly instanceof L.Polygon) ? 4 : 3, marker = e.target;\n\n\t\t\t\t\t// If removing this point would create an invalid\n\t\t\t\t\t// polyline/polygon don't remove\n\t\t\t\t\tif (this._poly._latlngs.length < minPoints) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// remove the marker\n\t\t\t\t\tthis._removeMarker(marker);\n\n\t\t\t\t\t// update prev/next links of adjacent markers\n\t\t\t\t\tthis._updatePrevNext(marker._prev, marker._next);\n\n\t\t\t\t\t// remove ghost markers near the removed marker\n\t\t\t\t\tif (marker._middleLeft) {\n\t\t\t\t\t\tthis._markerGroup.removeLayer(marker._middleLeft);\n\t\t\t\t\t}\n\t\t\t\t\tif (marker._middleRight) {\n\t\t\t\t\t\tthis._markerGroup.removeLayer(marker._middleRight);\n\t\t\t\t\t}\n\n\t\t\t\t\t// create a ghost marker in place of the removed one\n\t\t\t\t\tif (marker._prev && marker._next) {\n\t\t\t\t\t\tthis._createMiddleMarker(marker._prev, marker._next);\n\n\t\t\t\t\t} else if (!marker._prev) {\n\t\t\t\t\t\tmarker._next._middleLeft = null;\n\n\t\t\t\t\t} else if (!marker._next) {\n\t\t\t\t\t\tmarker._prev._middleRight = null;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._fireEdit();\n\t\t\t\t},\n\n\t\t\t\t_updateIndexes : function(index, delta) {\n\t\t\t\t\tthis._markerGroup.eachLayer(function(marker) {\n\t\t\t\t\t\tif (marker._index > index) {\n\t\t\t\t\t\t\tmarker._index += delta;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\t_createMiddleMarker : function(marker1, marker2) {\n\t\t\t\t\tvar latlng = this._getMiddleLatLng(marker1, marker2), marker = this\n\t\t\t\t\t\t\t._createMarker(latlng), onClick, onDragStart, onDragEnd;\n\n\t\t\t\t\tmarker.setOpacity(0.6);\n\n\t\t\t\t\tmarker1._middleRight = marker2._middleLeft = marker;\n\n\t\t\t\t\tonDragStart = function() {\n\t\t\t\t\t\tvar i = marker2._index;\n\n\t\t\t\t\t\tmarker._index = i;\n\n\t\t\t\t\t\tmarker.off('click', onClick, this).on('click',\n\t\t\t\t\t\t\t\tthis._onMarkerClick, this);\n\n\t\t\t\t\t\tlatlng.lat = marker.getLatLng().lat;\n\t\t\t\t\t\tlatlng.lng = marker.getLatLng().lng;\n\t\t\t\t\t\tthis._poly.spliceLatLngs(i, 0, latlng);\n\t\t\t\t\t\tthis._markers.splice(i, 0, marker);\n\n\t\t\t\t\t\tmarker.setOpacity(1);\n\n\t\t\t\t\t\tthis._updateIndexes(i, 1);\n\t\t\t\t\t\tmarker2._index++;\n\t\t\t\t\t\tthis._updatePrevNext(marker1, marker);\n\t\t\t\t\t\tthis._updatePrevNext(marker, marker2);\n\t\t\t\t\t};\n\n\t\t\t\t\tonDragEnd = function() {\n\t\t\t\t\t\tmarker.off('dragstart', onDragStart, this);\n\t\t\t\t\t\tmarker.off('dragend', onDragEnd, this);\n\n\t\t\t\t\t\tthis._createMiddleMarker(marker1, marker);\n\t\t\t\t\t\tthis._createMiddleMarker(marker, marker2);\n\t\t\t\t\t};\n\n\t\t\t\t\tonClick = function() {\n\t\t\t\t\t\tonDragStart.call(this);\n\t\t\t\t\t\tonDragEnd.call(this);\n\t\t\t\t\t\tthis._fireEdit();\n\t\t\t\t\t};\n\n\t\t\t\t\tmarker.on('click', onClick, this).on('dragstart',\n\t\t\t\t\t\t\tonDragStart, this).on('dragend', onDragEnd, this);\n\n\t\t\t\t\tthis._markerGroup.addLayer(marker);\n\t\t\t\t},\n\n\t\t\t\t_updatePrevNext : function(marker1, marker2) {\n\t\t\t\t\tif (marker1) {\n\t\t\t\t\t\tmarker1._next = marker2;\n\t\t\t\t\t}\n\t\t\t\t\tif (marker2) {\n\t\t\t\t\t\tmarker2._prev = marker1;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_getMiddleLatLng : function(marker1, marker2) {\n\t\t\t\t\tvar map = this._poly._map, p1 = map.project(marker1\n\t\t\t\t\t\t\t.getLatLng()), p2 = map\n\t\t\t\t\t\t\t.project(marker2.getLatLng());\n\n\t\t\t\t\treturn map.unproject(p1._add(p2)._divideBy(2));\n\t\t\t\t}\n\t\t\t});\n\n\tL.Polyline.addInitHook(function() {\n\n\t\t// Check to see if handler has already been initialized. This is to\n\t\t// support versions of Leaflet that still have L.Handler.PolyEdit\n\t\tif (this.editing) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (L.Edit.Poly) {\n\t\t\tthis.editing = new L.Edit.Poly(this);\n\n\t\t\tif (this.options.editable) {\n\t\t\t\tthis.editing.enable();\n\t\t\t}\n\t\t}\n\n\t\tthis.on('add', function() {\n\t\t\tif (this.editing && this.editing.enabled()) {\n\t\t\t\tthis.editing.addHooks();\n\t\t\t}\n\t\t});\n\n\t\tthis.on('remove', function() {\n\t\t\tif (this.editing && this.editing.enabled()) {\n\t\t\t\tthis.editing.removeHooks();\n\t\t\t}\n\t\t});\n\t});\n\n\tL.Edit = L.Edit || {};\n\n\tL.Edit.SimpleShape = L.Handler\n\t\t\t.extend({\n\t\t\t\toptions : {\n\t\t\t\t\tmoveIcon : new L.DivIcon(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ticonSize : new L.Point(8, 8),\n\t\t\t\t\t\t\t\tclassName : 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move'\n\t\t\t\t\t\t\t}),\n\t\t\t\t\tresizeIcon : new L.DivIcon(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ticonSize : new L.Point(8, 8),\n\t\t\t\t\t\t\t\tclassName : 'leaflet-div-icon leaflet-editing-icon leaflet-edit-resize'\n\t\t\t\t\t\t\t})\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(shape, options) {\n\t\t\t\t\tthis._shape = shape;\n\t\t\t\t\tL.Util.setOptions(this, options);\n\t\t\t\t},\n\n\t\t\t\taddHooks : function() {\n\t\t\t\t\tif (this._shape._map) {\n\t\t\t\t\t\tthis._map = this._shape._map;\n\n\t\t\t\t\t\tif (!this._markerGroup) {\n\t\t\t\t\t\t\tthis._initMarkers();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis._map.addLayer(this._markerGroup);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremoveHooks : function() {\n\t\t\t\t\tif (this._shape._map) {\n\t\t\t\t\t\tthis._unbindMarker(this._moveMarker);\n\n\t\t\t\t\t\tfor ( var i = 0, l = this._resizeMarkers.length; i < l; i++) {\n\t\t\t\t\t\t\tthis._unbindMarker(this._resizeMarkers[i]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis._resizeMarkers = null;\n\n\t\t\t\t\t\tthis._map.removeLayer(this._markerGroup);\n\t\t\t\t\t\tdelete this._markerGroup;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._map = null;\n\t\t\t\t},\n\n\t\t\t\tupdateMarkers : function() {\n\t\t\t\t\tthis._markerGroup.clearLayers();\n\t\t\t\t\tthis._initMarkers();\n\t\t\t\t},\n\n\t\t\t\t_initMarkers : function() {\n\t\t\t\t\tif (!this._markerGroup) {\n\t\t\t\t\t\tthis._markerGroup = new L.LayerGroup();\n\t\t\t\t\t}\n\n\t\t\t\t\t// Create center marker\n\t\t\t\t\tthis._createMoveMarker();\n\n\t\t\t\t\t// Create edge marker\n\t\t\t\t\tthis._createResizeMarker();\n\t\t\t\t},\n\n\t\t\t\t_createMoveMarker : function() {\n\t\t\t\t\t// Children override\n\t\t\t\t},\n\n\t\t\t\t_createResizeMarker : function() {\n\t\t\t\t\t// Children override\n\t\t\t\t},\n\n\t\t\t\t_createMarker : function(latlng, icon) {\n\t\t\t\t\tvar marker = new L.Marker(latlng, {\n\t\t\t\t\t\tdraggable : true,\n\t\t\t\t\t\ticon : icon,\n\t\t\t\t\t\tzIndexOffset : 10\n\t\t\t\t\t});\n\n\t\t\t\t\tthis._bindMarker(marker);\n\n\t\t\t\t\tthis._markerGroup.addLayer(marker);\n\n\t\t\t\t\treturn marker;\n\t\t\t\t},\n\n\t\t\t\t_bindMarker : function(marker) {\n\t\t\t\t\tmarker.on('dragstart', this._onMarkerDragStart, this).on(\n\t\t\t\t\t\t\t'drag', this._onMarkerDrag, this).on('dragend',\n\t\t\t\t\t\t\tthis._onMarkerDragEnd, this);\n\t\t\t\t},\n\n\t\t\t\t_unbindMarker : function(marker) {\n\t\t\t\t\tmarker.off('dragstart', this._onMarkerDragStart, this).off(\n\t\t\t\t\t\t\t'drag', this._onMarkerDrag, this).off('dragend',\n\t\t\t\t\t\t\tthis._onMarkerDragEnd, this);\n\t\t\t\t},\n\n\t\t\t\t_onMarkerDragStart : function(e) {\n\t\t\t\t\tvar marker = e.target;\n\t\t\t\t\tmarker.setOpacity(0);\n\t\t\t\t},\n\n\t\t\t\t_fireEdit : function() {\n\t\t\t\t\tthis._shape.edited = true;\n\t\t\t\t\tthis._shape.fire('edit');\n\t\t\t\t},\n\n\t\t\t\t_onMarkerDrag : function(e) {\n\t\t\t\t\tvar marker = e.target, latlng = marker.getLatLng();\n\n\t\t\t\t\tif (marker === this._moveMarker) {\n\t\t\t\t\t\tthis._move(latlng);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._resize(latlng);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._shape.redraw();\n\t\t\t\t},\n\n\t\t\t\t_onMarkerDragEnd : function(e) {\n\t\t\t\t\tvar marker = e.target;\n\t\t\t\t\tmarker.setOpacity(1);\n\n\t\t\t\t\tthis._fireEdit();\n\t\t\t\t},\n\n\t\t\t\t_move : function() {\n\t\t\t\t\t// Children override\n\t\t\t\t},\n\n\t\t\t\t_resize : function() {\n\t\t\t\t\t// Children override\n\t\t\t\t}\n\t\t\t});\n\n\tL.Edit = L.Edit || {};\n\n\tL.Edit.Rectangle = L.Edit.SimpleShape\n\t\t\t.extend({\n\t\t\t\t_createMoveMarker : function() {\n\t\t\t\t\tvar bounds = this._shape.getBounds(), center = bounds\n\t\t\t\t\t\t\t.getCenter();\n\n\t\t\t\t\tthis._moveMarker = this._createMarker(center,\n\t\t\t\t\t\t\tthis.options.moveIcon);\n\t\t\t\t},\n\n\t\t\t\t_createResizeMarker : function() {\n\t\t\t\t\tvar corners = this._getCorners();\n\n\t\t\t\t\tthis._resizeMarkers = [];\n\n\t\t\t\t\tfor ( var i = 0, l = corners.length; i < l; i++) {\n\t\t\t\t\t\tthis._resizeMarkers.push(this._createMarker(corners[i],\n\t\t\t\t\t\t\t\tthis.options.resizeIcon));\n\t\t\t\t\t\t// Monkey in the corner index as we will need to know\n\t\t\t\t\t\t// this for dragging\n\t\t\t\t\t\tthis._resizeMarkers[i]._cornerIndex = i;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_onMarkerDragStart : function(e) {\n\t\t\t\t\tL.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,\n\t\t\t\t\t\t\te);\n\n\t\t\t\t\t// Save a reference to the opposite point\n\t\t\t\t\tvar corners = this._getCorners(), marker = e.target, currentCornerIndex = marker._cornerIndex;\n\n\t\t\t\t\tthis._oppositeCorner = corners[(currentCornerIndex + 2) % 4];\n\n\t\t\t\t\tthis._toggleCornerMarkers(0, currentCornerIndex);\n\t\t\t\t},\n\n\t\t\t\t_onMarkerDragEnd : function(e) {\n\t\t\t\t\tvar marker = e.target, bounds, center;\n\n\t\t\t\t\t// Reset move marker position to the center\n\t\t\t\t\tif (marker === this._moveMarker) {\n\t\t\t\t\t\tbounds = this._shape.getBounds();\n\t\t\t\t\t\tcenter = bounds.getCenter();\n\n\t\t\t\t\t\tmarker.setLatLng(center);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._toggleCornerMarkers(1);\n\n\t\t\t\t\tthis._repositionCornerMarkers();\n\n\t\t\t\t\tL.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this, e);\n\t\t\t\t},\n\n\t\t\t\t_move : function(newCenter) {\n\t\t\t\t\tvar latlngs = this._shape.getLatLngs(), bounds = this._shape\n\t\t\t\t\t\t\t.getBounds(), center = bounds.getCenter(), offset, newLatLngs = [];\n\n\t\t\t\t\t// Offset the latlngs to the new center\n\t\t\t\t\tfor ( var i = 0, l = latlngs.length; i < l; i++) {\n\t\t\t\t\t\toffset = [ latlngs[i].lat - center.lat,\n\t\t\t\t\t\t\t\tlatlngs[i].lng - center.lng ];\n\t\t\t\t\t\tnewLatLngs.push([ newCenter.lat + offset[0],\n\t\t\t\t\t\t\t\tnewCenter.lng + offset[1] ]);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._shape.setLatLngs(newLatLngs);\n\n\t\t\t\t\t// Reposition the resize markers\n\t\t\t\t\tthis._repositionCornerMarkers();\n\t\t\t\t},\n\n\t\t\t\t_resize : function(latlng) {\n\t\t\t\t\tvar bounds;\n\n\t\t\t\t\t// Update the shape based on the current position of this\n\t\t\t\t\t// corner and the opposite point\n\t\t\t\t\tthis._shape.setBounds(L.latLngBounds(latlng,\n\t\t\t\t\t\t\tthis._oppositeCorner));\n\n\t\t\t\t\t// Reposition the move marker\n\t\t\t\t\tbounds = this._shape.getBounds();\n\t\t\t\t\tthis._moveMarker.setLatLng(bounds.getCenter());\n\t\t\t\t},\n\n\t\t\t\t_getCorners : function() {\n\t\t\t\t\tvar bounds = this._shape.getBounds(), nw = bounds\n\t\t\t\t\t\t\t.getNorthWest(), ne = bounds.getNorthEast(), se = bounds\n\t\t\t\t\t\t\t.getSouthEast(), sw = bounds.getSouthWest();\n\n\t\t\t\t\treturn [ nw, ne, se, sw ];\n\t\t\t\t},\n\n\t\t\t\t_toggleCornerMarkers : function(opacity) {\n\t\t\t\t\tfor ( var i = 0, l = this._resizeMarkers.length; i < l; i++) {\n\t\t\t\t\t\tthis._resizeMarkers[i].setOpacity(opacity);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_repositionCornerMarkers : function() {\n\t\t\t\t\tvar corners = this._getCorners();\n\n\t\t\t\t\tfor ( var i = 0, l = this._resizeMarkers.length; i < l; i++) {\n\t\t\t\t\t\tthis._resizeMarkers[i].setLatLng(corners[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\tL.Rectangle.addInitHook(function() {\n\t\tif (L.Edit.Rectangle) {\n\t\t\tthis.editing = new L.Edit.Rectangle(this);\n\n\t\t\tif (this.options.editable) {\n\t\t\t\tthis.editing.enable();\n\t\t\t}\n\t\t}\n\t});\n\n\tL.Edit = L.Edit || {};\n\n\tL.Edit.Circle = L.Edit.SimpleShape\n\t\t\t.extend({\n\t\t\t\t_createMoveMarker : function() {\n\t\t\t\t\tvar center = this._shape.getLatLng();\n\n\t\t\t\t\tthis._moveMarker = this._createMarker(center,\n\t\t\t\t\t\t\tthis.options.moveIcon);\n\t\t\t\t},\n\n\t\t\t\t_createResizeMarker : function() {\n\t\t\t\t\tvar center = this._shape.getLatLng(), resizemarkerPoint = this\n\t\t\t\t\t\t\t._getResizeMarkerPoint(center);\n\n\t\t\t\t\tthis._resizeMarkers = [];\n\t\t\t\t\tthis._resizeMarkers.push(this._createMarker(\n\t\t\t\t\t\t\tresizemarkerPoint, this.options.resizeIcon));\n\t\t\t\t},\n\n\t\t\t\t_getResizeMarkerPoint : function(latlng) {\n\t\t\t\t\t// From L.shape.getBounds()\n\t\t\t\t\tvar delta = this._shape._radius * Math.cos(Math.PI / 4), point = this._map\n\t\t\t\t\t\t\t.project(latlng);\n\t\t\t\t\treturn this._map.unproject([ point.x + delta,\n\t\t\t\t\t\t\tpoint.y - delta ]);\n\t\t\t\t},\n\n\t\t\t\t_move : function(latlng) {\n\t\t\t\t\tvar resizemarkerPoint = this._getResizeMarkerPoint(latlng);\n\n\t\t\t\t\t// Move the resize marker\n\t\t\t\t\tthis._resizeMarkers[0].setLatLng(resizemarkerPoint);\n\n\t\t\t\t\t// Move the circle\n\t\t\t\t\tthis._shape.setLatLng(latlng);\n\t\t\t\t},\n\n\t\t\t\t_resize : function(latlng) {\n\t\t\t\t\tvar moveLatLng = this._moveMarker.getLatLng(), radius = moveLatLng\n\t\t\t\t\t\t\t.distanceTo(latlng);\n\n\t\t\t\t\tthis._shape.setRadius(radius);\n\t\t\t\t}\n\t\t\t});\n\n\tL.Circle.addInitHook(function() {\n\t\tif (L.Edit.Circle) {\n\t\t\tthis.editing = new L.Edit.Circle(this);\n\n\t\t\tif (this.options.editable) {\n\t\t\t\tthis.editing.enable();\n\t\t\t}\n\t\t}\n\n\t\tthis.on('add', function() {\n\t\t\tif (this.editing && this.editing.enabled()) {\n\t\t\t\tthis.editing.addHooks();\n\t\t\t}\n\t\t});\n\n\t\tthis.on('remove', function() {\n\t\t\tif (this.editing && this.editing.enabled()) {\n\t\t\t\tthis.editing.removeHooks();\n\t\t\t}\n\t\t});\n\t});\n\n\t/*\n\t * L.LatLngUtil contains different utility functions for LatLngs.\n\t */\n\n\tL.LatLngUtil = {\n\t\t// Clones a LatLngs[], returns [][]\n\t\tcloneLatLngs : function(latlngs) {\n\t\t\tvar clone = [];\n\t\t\tfor ( var i = 0, l = latlngs.length; i < l; i++) {\n\t\t\t\tclone.push(this.cloneLatLng(latlngs[i]));\n\t\t\t}\n\t\t\treturn clone;\n\t\t},\n\n\t\tcloneLatLng : function(latlng) {\n\t\t\treturn L.latLng(latlng.lat, latlng.lng);\n\t\t}\n\t};\n\n\tL.GeometryUtil = L\n\t\t\t.extend(\n\t\t\t\t\tL.GeometryUtil || {},\n\t\t\t\t\t{\n\t\t\t\t\t\t// Ported from the OpenLayers implementation. See\n\t\t\t\t\t\t// https://github.com/openlayers/openlayers/blob/master/lib/OpenLayers/Geometry/LinearRing.js#L270\n\t\t\t\t\t\tgeodesicArea : function(latLngs) {\n\t\t\t\t\t\t\tvar pointsCount = latLngs.length, area = 0.0, d2r = L.LatLng.DEG_TO_RAD, p1, p2;\n\n\t\t\t\t\t\t\tif (pointsCount > 2) {\n\t\t\t\t\t\t\t\tfor ( var i = 0; i < pointsCount; i++) {\n\t\t\t\t\t\t\t\t\tp1 = latLngs[i];\n\t\t\t\t\t\t\t\t\tp2 = latLngs[(i + 1) % pointsCount];\n\t\t\t\t\t\t\t\t\tarea += ((p2.lng - p1.lng) * d2r)\n\t\t\t\t\t\t\t\t\t\t\t* (2 + Math.sin(p1.lat * d2r) + Math\n\t\t\t\t\t\t\t\t\t\t\t\t\t.sin(p2.lat * d2r));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tarea = area * 6378137.0 * 6378137.0 / 2.0;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn Math.abs(area);\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\treadableArea : function(area, isMetric) {\n\t\t\t\t\t\t\tvar areaStr;\n\n\t\t\t\t\t\t\tif (isMetric) {\n\t\t\t\t\t\t\t\tif (area >= 10000) {\n\t\t\t\t\t\t\t\t\ttemp = (area * 0.000001).toFixed(2);\n\t\t\t\t\t\t\t\t\tif (temp >= 10000) {\n\t\t\t\t\t\t\t\t\t\tareaStr = (temp / 10000).toFixed(2)\n\t\t\t\t\t\t\t\t\t\t\t\t+ '万平方千米';\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tareaStr = temp + '平方千米';\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tareaStr = area.toFixed(2) + ' 平方米';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tarea *= 0.836127; // Square yards in 1 meter\n\n\t\t\t\t\t\t\t\tif (area >= 3097600) { // 3097600 square yards\n\t\t\t\t\t\t\t\t\t// in 1 square mile\n\t\t\t\t\t\t\t\t\tareaStr = (area / 3097600).toFixed(2)\n\t\t\t\t\t\t\t\t\t\t\t+ ' mi&sup2;';\n\t\t\t\t\t\t\t\t} else if (area >= 4840) {// 48040 square\n\t\t\t\t\t\t\t\t\t// yards in 1 acre\n\t\t\t\t\t\t\t\t\tareaStr = (area / 4840).toFixed(2)\n\t\t\t\t\t\t\t\t\t\t\t+ ' acres';\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tareaStr = Math.ceil(area) + ' yd&sup2;';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn areaStr;\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\treadableDistance : function(distance, isMetric) {\n\t\t\t\t\t\t\tvar distanceStr;\n\n\t\t\t\t\t\t\tif (isMetric) {\n\t\t\t\t\t\t\t\t// show metres when distance is < 1km, then show\n\t\t\t\t\t\t\t\t// km\n\t\t\t\t\t\t\t\tif (distance > 1000) {\n\t\t\t\t\t\t\t\t\tdistanceStr = (distance / 1000).toFixed(2)\n\t\t\t\t\t\t\t\t\t\t\t+ ' 千米';\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tdistanceStr = Math.ceil(distance) + ' 米';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdistance *= 1.09361;\n\n\t\t\t\t\t\t\t\tif (distance > 1760) {\n\t\t\t\t\t\t\t\t\ta = ((distance / 1760) * 1609.344)\n\t\t\t\t\t\t\t\t\t\t\t.toFixed(2);\n\t\t\t\t\t\t\t\t\tif (a < 1000) {\n\t\t\t\t\t\t\t\t\t\tdistanceStr = a + ' 米';\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tdistanceStr = (a / 1000).toFixed(2)\n\t\t\t\t\t\t\t\t\t\t\t\t+ ' 千米';\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tb = Math.ceil(distance) * 0.914;\n\t\t\t\t\t\t\t\t\tb = b.toFixed(2);\n\t\t\t\t\t\t\t\t\tif (b < 1000) {\n\t\t\t\t\t\t\t\t\t\tdistanceStr = b + ' 米';\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tdistanceStr = (b / 1000).toFixed(2)\n\t\t\t\t\t\t\t\t\t\t\t\t+ ' 千米';\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn distanceStr;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\tL.Util.extend(L.LineUtil, {\n\t\t// Checks to see if two line segments intersect. Does not handle\n\t\t// degenerate cases.\n\t\t// http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf\n\t\tsegmentsIntersect : function(/* Point */p, /* Point */p1, /* Point */\n\t\tp2, /* Point */\n\t\tp3) {\n\t\t\treturn this._checkCounterclockwise(p, p2, p3) !== this\n\t\t\t\t\t._checkCounterclockwise(p1, p2, p3)\n\t\t\t\t\t&& this._checkCounterclockwise(p, p1, p2) !== this\n\t\t\t\t\t\t\t._checkCounterclockwise(p, p1, p3);\n\t\t},\n\n\t\t// check to see if points are in counterclockwise order\n\t\t_checkCounterclockwise : function(/* Point */p, /* Point */p1, /* Point */\n\t\tp2) {\n\t\t\treturn (p2.y - p.y) * (p1.x - p.x) > (p1.y - p.y) * (p2.x - p.x);\n\t\t}\n\t});\n\n\tL.Polyline\n\t\t\t.include({\n\t\t\t\t// Check to see if this polyline has any linesegments that\n\t\t\t\t// intersect.\n\t\t\t\t// NOTE: does not support detecting intersection for degenerate\n\t\t\t\t// cases.\n\t\t\t\tintersects : function() {\n\t\t\t\t\tvar points = this._originalPoints, len = points ? points.length\n\t\t\t\t\t\t\t: 0, i, p, p1;\n\n\t\t\t\t\tif (this._tooFewPointsForIntersection()) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (i = len - 1; i >= 3; i--) {\n\t\t\t\t\t\tp = points[i - 1];\n\t\t\t\t\t\tp1 = points[i];\n\n\t\t\t\t\t\tif (this._lineSegmentsIntersectsRange(p, p1, i - 2)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false;\n\t\t\t\t},\n\n\t\t\t\t// Check for intersection if new latlng was added to this\n\t\t\t\t// polyline.\n\t\t\t\t// NOTE: does not support detecting intersection for degenerate\n\t\t\t\t// cases.\n\t\t\t\tnewLatLngIntersects : function(latlng, skipFirst) {\n\t\t\t\t\t// Cannot check a polyline for intersecting lats/lngs when\n\t\t\t\t\t// not added to the map\n\t\t\t\t\tif (!this._map) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this.newPointIntersects(this._map\n\t\t\t\t\t\t\t.latLngToLayerPoint(latlng), skipFirst);\n\t\t\t\t},\n\n\t\t\t\t// Check for intersection if new point was added to this\n\t\t\t\t// polyline.\n\t\t\t\t// newPoint must be a layer point.\n\t\t\t\t// NOTE: does not support detecting intersection for degenerate\n\t\t\t\t// cases.\n\t\t\t\tnewPointIntersects : function(newPoint, skipFirst) {\n\t\t\t\t\tvar points = this._originalPoints, len = points ? points.length\n\t\t\t\t\t\t\t: 0, lastPoint = points ? points[len - 1] : null,\n\t\t\t\t\t// The previous previous line segment. Previous line segment\n\t\t\t\t\t// doesn't need testing.\n\t\t\t\t\tmaxIndex = len - 2;\n\n\t\t\t\t\tif (this._tooFewPointsForIntersection(1)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this._lineSegmentsIntersectsRange(lastPoint,\n\t\t\t\t\t\t\tnewPoint, maxIndex, skipFirst ? 1 : 0);\n\t\t\t\t},\n\n\t\t\t\t// Polylines with 2 sides can only intersect in cases where\n\t\t\t\t// points are collinear (we don't support detecting these).\n\t\t\t\t// Cannot have intersection when < 3 line segments (< 4 points)\n\t\t\t\t_tooFewPointsForIntersection : function(extraPoints) {\n\t\t\t\t\tvar points = this._originalPoints, len = points ? points.length\n\t\t\t\t\t\t\t: 0;\n\t\t\t\t\t// Increment length by extraPoints if present\n\t\t\t\t\tlen += extraPoints || 0;\n\n\t\t\t\t\treturn !this._originalPoints || len <= 3;\n\t\t\t\t},\n\n\t\t\t\t// Checks a line segment intersections with any line segments\n\t\t\t\t// before its predecessor.\n\t\t\t\t// Don't need to check the predecessor as will never intersect.\n\t\t\t\t_lineSegmentsIntersectsRange : function(p, p1, maxIndex,\n\t\t\t\t\t\tminIndex) {\n\t\t\t\t\tvar points = this._originalPoints, p2, p3;\n\n\t\t\t\t\tminIndex = minIndex || 0;\n\n\t\t\t\t\t// Check all previous line segments (beside the immediately\n\t\t\t\t\t// previous) for intersections\n\t\t\t\t\tfor ( var j = maxIndex; j > minIndex; j--) {\n\t\t\t\t\t\tp2 = points[j - 1];\n\t\t\t\t\t\tp3 = points[j];\n\n\t\t\t\t\t\tif (L.LineUtil.segmentsIntersect(p, p1, p2, p3)) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\n\tL.Polygon\n\t\t\t.include({\n\t\t\t\t// Checks a polygon for any intersecting line segments. Ignores\n\t\t\t\t// holes.\n\t\t\t\tintersects : function() {\n\t\t\t\t\tvar polylineIntersects, points = this._originalPoints, len, firstPoint, lastPoint, maxIndex;\n\n\t\t\t\t\tif (this._tooFewPointsForIntersection()) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tpolylineIntersects = L.Polyline.prototype.intersects\n\t\t\t\t\t\t\t.call(this);\n\n\t\t\t\t\t// If already found an intersection don't need to check for\n\t\t\t\t\t// any more.\n\t\t\t\t\tif (polylineIntersects) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tlen = points.length;\n\t\t\t\t\tfirstPoint = points[0];\n\t\t\t\t\tlastPoint = points[len - 1];\n\t\t\t\t\tmaxIndex = len - 2;\n\n\t\t\t\t\t// Check the line segment between last and first point.\n\t\t\t\t\t// Don't need to check the first line segment (minIndex = 1)\n\t\t\t\t\treturn this._lineSegmentsIntersectsRange(lastPoint,\n\t\t\t\t\t\t\tfirstPoint, maxIndex, 1);\n\t\t\t\t}\n\t\t\t});\n\n\tL.Control.Draw = L.Control\n\t\t\t.extend({\n\n\t\t\t\toptions : {\n\t\t\t\t\tposition : 'topleft',\n\t\t\t\t\tdraw : {},\n\t\t\t\t\tedit : false\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(options) {\n\t\t\t\t\tif (L.version < \"0.7\") {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t'Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/');\n\t\t\t\t\t}\n\n\t\t\t\t\tL.Control.prototype.initialize.call(this, options);\n\n\t\t\t\t\tvar id, toolbar;\n\n\t\t\t\t\tthis._toolbars = {};\n\n\t\t\t\t\t// Initialize toolbars\n\t\t\t\t\tif (L.DrawToolbar && this.options.draw) {\n\t\t\t\t\t\ttoolbar = new L.DrawToolbar(this.options.draw);\n\t\t\t\t\t\tid = L.stamp(toolbar);\n\t\t\t\t\t\tthis._toolbars[id] = toolbar;\n\n\t\t\t\t\t\t// Listen for when toolbar is enabled\n\t\t\t\t\t\tthis._toolbars[id].on('enable', this._toolbarEnabled,\n\t\t\t\t\t\t\t\tthis);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (L.EditToolbar && this.options.edit) {\n\t\t\t\t\t\ttoolbar = new L.EditToolbar(this.options.edit);\n\t\t\t\t\t\tid = L.stamp(toolbar);\n\t\t\t\t\t\tthis._toolbars[id] = toolbar;\n\n\t\t\t\t\t\t// Listen for when toolbar is enabled\n\t\t\t\t\t\tthis._toolbars[id].on('enable', this._toolbarEnabled,\n\t\t\t\t\t\t\t\tthis);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tonAdd : function(map) {\n\t\t\t\t\tvar container = L.DomUtil.create('div', 'leaflet-draw'), addedTopClass = false, topClassName = 'leaflet-draw-toolbar-top', toolbarContainer;\n\n\t\t\t\t\tfor ( var toolbarId in this._toolbars) {\n\t\t\t\t\t\tif (this._toolbars.hasOwnProperty(toolbarId)) {\n\t\t\t\t\t\t\ttoolbarContainer = this._toolbars[toolbarId]\n\t\t\t\t\t\t\t\t\t.addToolbar(map);\n\n\t\t\t\t\t\t\t// Add class to the first toolbar to remove the\n\t\t\t\t\t\t\t// margin\n\t\t\t\t\t\t\tif (!addedTopClass) {\n\t\t\t\t\t\t\t\tif (!L.DomUtil.hasClass(toolbarContainer,\n\t\t\t\t\t\t\t\t\t\ttopClassName)) {\n\t\t\t\t\t\t\t\t\tL.DomUtil.addClass(\n\t\t\t\t\t\t\t\t\t\t\ttoolbarContainer.childNodes[0],\n\t\t\t\t\t\t\t\t\t\t\ttopClassName);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\taddedTopClass = true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcontainer.appendChild(toolbarContainer);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn container;\n\t\t\t\t},\n\n\t\t\t\tonRemove : function() {\n\t\t\t\t\tfor ( var toolbarId in this._toolbars) {\n\t\t\t\t\t\tif (this._toolbars.hasOwnProperty(toolbarId)) {\n\t\t\t\t\t\t\tthis._toolbars[toolbarId].removeToolbar();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tsetDrawingOptions : function(options) {\n\t\t\t\t\tfor ( var toolbarId in this._toolbars) {\n\t\t\t\t\t\tif (this._toolbars[toolbarId] instanceof L.DrawToolbar) {\n\t\t\t\t\t\t\tthis._toolbars[toolbarId].setOptions(options);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_toolbarEnabled : function(e) {\n\t\t\t\t\tvar id = '' + L.stamp(e.target);\n\n\t\t\t\t\tfor ( var toolbarId in this._toolbars) {\n\t\t\t\t\t\tif (this._toolbars.hasOwnProperty(toolbarId)\n\t\t\t\t\t\t\t\t&& toolbarId !== id) {\n\t\t\t\t\t\t\tthis._toolbars[toolbarId].disable();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\tL.Map.mergeOptions({\n\t\tdrawControlTooltips : true,\n\t\tdrawControl : false\n\t});\n\n\tL.Map.addInitHook(function() {\n\t\tif (this.options.drawControl) {\n\t\t\tthis.drawControl = new L.Control.Draw();\n\t\t\tthis.addControl(this.drawControl);\n\t\t}\n\t});\n\n\tL.Toolbar = L.Class\n\t\t\t.extend({\n\t\t\t\tincludes : [ L.Mixin.Events ],\n\n\t\t\t\tinitialize : function(options) {\n\t\t\t\t\tL.setOptions(this, options);\n\n\t\t\t\t\tthis._modes = {};\n\t\t\t\t\tthis._actionButtons = [];\n\t\t\t\t\tthis._activeMode = null;\n\t\t\t\t},\n\n\t\t\t\tenabled : function() {\n\t\t\t\t\treturn this._activeMode !== null;\n\t\t\t\t},\n\n\t\t\t\tdisable : function() {\n\t\t\t\t\tif (!this.enabled()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._activeMode.handler.disable();\n\t\t\t\t},\n\n\t\t\t\tremoveToolbar : function() {\n\t\t\t\t\t// Dispose each handler\n\t\t\t\t\tfor ( var handlerId in this._modes) {\n\t\t\t\t\t\tif (this._modes.hasOwnProperty(handlerId)) {\n\t\t\t\t\t\t\t// Unbind handler button\n\t\t\t\t\t\t\tthis._disposeButton(this._modes[handlerId].button,\n\t\t\t\t\t\t\t\t\tthis._modes[handlerId].handler.enable);\n\n\t\t\t\t\t\t\t// Make sure is disabled\n\t\t\t\t\t\t\tthis._modes[handlerId].handler.disable();\n\n\t\t\t\t\t\t\t// Unbind handler\n\t\t\t\t\t\t\tthis._modes[handlerId].handler.off('enabled',\n\t\t\t\t\t\t\t\t\tthis._handlerActivated, this).off(\n\t\t\t\t\t\t\t\t\t'disabled', this._handlerDeactivated, this);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._modes = {};\n\n\t\t\t\t\t// Dispose the actions toolbar\n\t\t\t\t\tfor ( var i = 0, l = this._actionButtons.length; i < l; i++) {\n\t\t\t\t\t\tthis._disposeButton(this._actionButtons[i].button,\n\t\t\t\t\t\t\t\tthis._actionButtons[i].callback);\n\t\t\t\t\t}\n\t\t\t\t\tthis._actionButtons = [];\n\t\t\t\t\tthis._actionsContainer = null;\n\t\t\t\t},\n\n\t\t\t\t_initModeHandler : function(handler, container, buttonIndex,\n\t\t\t\t\t\tclassNamePredix, buttonTitle) {\n\t\t\t\t\tvar type = handler.type;\n\n\t\t\t\t\tthis._modes[type] = {};\n\n\t\t\t\t\tthis._modes[type].handler = handler;\n\n\t\t\t\t\tthis._modes[type].button = this._createButton({\n\t\t\t\t\t\ttitle : buttonTitle,\n\t\t\t\t\t\tclassName : classNamePredix + '-' + type,\n\t\t\t\t\t\tcontainer : container,\n\t\t\t\t\t\tcallback : this._modes[type].handler.enable,\n\t\t\t\t\t\tcontext : this._modes[type].handler\n\t\t\t\t\t});\n\n\t\t\t\t\tthis._modes[type].buttonIndex = buttonIndex;\n\n\t\t\t\t\tthis._modes[type].handler.on('enabled',\n\t\t\t\t\t\t\tthis._handlerActivated, this).on('disabled',\n\t\t\t\t\t\t\tthis._handlerDeactivated, this);\n\t\t\t\t},\n\n\t\t\t\t_createButton : function(options) {\n\t\t\t\t\tvar link = L.DomUtil.create('a', options.className || '',\n\t\t\t\t\t\t\toptions.container);\n\t\t\t\t\tlink.href = '#';\n\n\t\t\t\t\tif (options.text) {\n\t\t\t\t\t\tlink.innerHTML = options.text;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (options.title) {\n\t\t\t\t\t\tlink.title = options.title;\n\t\t\t\t\t}\n\n\t\t\t\t\tL.DomEvent.on(link, 'click', L.DomEvent.stopPropagation)\n\t\t\t\t\t\t\t.on(link, 'mousedown', L.DomEvent.stopPropagation)\n\t\t\t\t\t\t\t.on(link, 'dblclick', L.DomEvent.stopPropagation)\n\t\t\t\t\t\t\t.on(link, 'click', L.DomEvent.preventDefault).on(\n\t\t\t\t\t\t\t\t\tlink, 'click', options.callback,\n\t\t\t\t\t\t\t\t\toptions.context);\n\n\t\t\t\t\treturn link;\n\t\t\t\t},\n\n\t\t\t\t_disposeButton : function(button, callback) {\n\t\t\t\t\tL.DomEvent.off(button, 'click', L.DomEvent.stopPropagation)\n\t\t\t\t\t\t\t.off(button, 'mousedown',\n\t\t\t\t\t\t\t\t\tL.DomEvent.stopPropagation).off(button,\n\t\t\t\t\t\t\t\t\t'dblclick', L.DomEvent.stopPropagation)\n\t\t\t\t\t\t\t.off(button, 'click', L.DomEvent.preventDefault)\n\t\t\t\t\t\t\t.off(button, 'click', callback);\n\t\t\t\t},\n\n\t\t\t\t_handlerActivated : function(e) {\n\t\t\t\t\t// Disable active mode (if present)\n\t\t\t\t\tif (this._activeMode && this._activeMode.handler.enabled()) {\n\t\t\t\t\t\tthis._activeMode.handler.disable();\n\t\t\t\t\t}\n\n\t\t\t\t\t// Cache new active feature\n\t\t\t\t\tthis._activeMode = this._modes[e.handler];\n\n\t\t\t\t\tL.DomUtil.addClass(this._activeMode.button,\n\t\t\t\t\t\t\t'leaflet-draw-toolbar-button-enabled');\n\n\t\t\t\t\tthis._showActionsToolbar();\n\n\t\t\t\t\tthis.fire('enable');\n\t\t\t\t},\n\n\t\t\t\t_handlerDeactivated : function() {\n\t\t\t\t\tthis._hideActionsToolbar();\n\t\t\t\t\tif (this._activeMode && this._activeMode.button) {\n\t\t\t\t\t\tL.DomUtil.removeClass(this._activeMode.button,\n\t\t\t\t\t\t\t\t'leaflet-draw-toolbar-button-enabled');\n\t\t\t\t\t}\n\t\t\t\t\tthis._activeMode = null;\n\n\t\t\t\t\tthis.fire('disable');\n\t\t\t\t},\n\n\t\t\t\t_createActions : function(buttons) {\n\t\t\t\t\tvar container = L.DomUtil.create('ul',\n\t\t\t\t\t\t\t'leaflet-draw-actions'), l = buttons.length, li, button;\n\n\t\t\t\t\tfor ( var i = 0; i < l; i++) {\n\t\t\t\t\t\tli = L.DomUtil.create('li', '', container);\n\n\t\t\t\t\t\tbutton = this._createButton({\n\t\t\t\t\t\t\ttitle : buttons[i].title,\n\t\t\t\t\t\t\ttext : buttons[i].text,\n\t\t\t\t\t\t\tcontainer : li,\n\t\t\t\t\t\t\tcallback : buttons[i].callback,\n\t\t\t\t\t\t\tcontext : buttons[i].context\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis._actionButtons.push({\n\t\t\t\t\t\t\tbutton : button,\n\t\t\t\t\t\t\tcallback : buttons[i].callback\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\treturn container;\n\t\t\t\t},\n\n\t\t\t\t_showActionsToolbar : function() {\n\t\t\t\t\tvar buttonIndex = this._activeMode.buttonIndex, lastButtonIndex = this._lastButtonIndex, buttonHeight = 26, // TODO:\n\t\t\t\t\t// this\n\t\t\t\t\t// should\n\t\t\t\t\t// be\n\t\t\t\t\t// calculated\n\t\t\t\t\tborderHeight = 1, // TODO: this should also be calculated\n\t\t\t\t\ttoolbarPosition = (buttonIndex * buttonHeight)\n\t\t\t\t\t\t\t+ (buttonIndex * borderHeight) - 1;\n\n\t\t\t\t\t// Correctly position the cancel button\n\t\t\t\t\tthis._actionsContainer.style.top = toolbarPosition + 'px';\n\n\t\t\t\t\tif (buttonIndex === 0) {\n\t\t\t\t\t\tL.DomUtil.addClass(this._toolbarContainer,\n\t\t\t\t\t\t\t\t'leaflet-draw-toolbar-notop');\n\t\t\t\t\t\tL.DomUtil.addClass(this._actionsContainer,\n\t\t\t\t\t\t\t\t'leaflet-draw-actions-top');\n\t\t\t\t\t}\n\n\t\t\t\t\tif (buttonIndex === lastButtonIndex) {\n\t\t\t\t\t\tL.DomUtil.addClass(this._toolbarContainer,\n\t\t\t\t\t\t\t\t'leaflet-draw-toolbar-nobottom');\n\t\t\t\t\t\tL.DomUtil.addClass(this._actionsContainer,\n\t\t\t\t\t\t\t\t'leaflet-draw-actions-bottom');\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._actionsContainer.style.display = 'block';\n\t\t\t\t},\n\n\t\t\t\t_hideActionsToolbar : function() {\n\t\t\t\t\tthis._actionsContainer.style.display = 'none';\n\n\t\t\t\t\tL.DomUtil.removeClass(this._toolbarContainer,\n\t\t\t\t\t\t\t'leaflet-draw-toolbar-notop');\n\t\t\t\t\tL.DomUtil.removeClass(this._toolbarContainer,\n\t\t\t\t\t\t\t'leaflet-draw-toolbar-nobottom');\n\t\t\t\t\tL.DomUtil.removeClass(this._actionsContainer,\n\t\t\t\t\t\t\t'leaflet-draw-actions-top');\n\t\t\t\t\tL.DomUtil.removeClass(this._actionsContainer,\n\t\t\t\t\t\t\t'leaflet-draw-actions-bottom');\n\t\t\t\t}\n\t\t\t});\n\n\tL.Tooltip = L.Class\n\t\t\t.extend({\n\t\t\t\tinitialize : function(map) {\n\t\t\t\t\tthis._map = map;\n\t\t\t\t\tthis._popupPane = map._panes.popupPane;\n\n\t\t\t\t\tthis._container = map.options.drawControlTooltips ? L.DomUtil\n\t\t\t\t\t\t\t.create('div', 'leaflet-draw-tooltip',\n\t\t\t\t\t\t\t\t\tthis._popupPane)\n\t\t\t\t\t\t\t: null;\n\t\t\t\t\tthis._singleLineLabel = false;\n\t\t\t\t},\n\n\t\t\t\tdispose : function() {\n\t\t\t\t\tif (this._container) {\n\t\t\t\t\t\tthis._popupPane.removeChild(this._container);\n\t\t\t\t\t\tthis._container = null;\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tupdateContent : function(labelText) {\n\t\t\t\t\tif (!this._container) {\n\t\t\t\t\t\treturn this;\n\t\t\t\t\t}\n\t\t\t\t\tlabelText.subtext = labelText.subtext || '';\n\n\t\t\t\t\t// update the vertical position (only if changed)\n\t\t\t\t\tif (labelText.subtext.length === 0\n\t\t\t\t\t\t\t&& !this._singleLineLabel) {\n\t\t\t\t\t\tL.DomUtil.addClass(this._container,\n\t\t\t\t\t\t\t\t'leaflet-draw-tooltip-single');\n\t\t\t\t\t\tthis._singleLineLabel = true;\n\t\t\t\t\t} else if (labelText.subtext.length > 0\n\t\t\t\t\t\t\t&& this._singleLineLabel) {\n\t\t\t\t\t\tL.DomUtil.removeClass(this._container,\n\t\t\t\t\t\t\t\t'leaflet-draw-tooltip-single');\n\t\t\t\t\t\tthis._singleLineLabel = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._container.innerHTML = (labelText.subtext.length > 0 ? '<span class=\"leaflet-draw-tooltip-subtext\">'\n\t\t\t\t\t\t\t+ labelText.subtext + '</span>' + '<br />'\n\t\t\t\t\t\t\t: '')\n\t\t\t\t\t\t\t+ '<span>' + labelText.text + '</span>';\n\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\tupdatePosition : function(latlng) {\n\t\t\t\t\tvar pos = this._map.latLngToLayerPoint(latlng), tooltipContainer = this._container;\n\n\t\t\t\t\tif (this._container) {\n\t\t\t\t\t\ttooltipContainer.style.visibility = 'inherit';\n\t\t\t\t\t\tL.DomUtil.setPosition(tooltipContainer, pos);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\tshowAsError : function() {\n\t\t\t\t\tif (this._container) {\n\t\t\t\t\t\tL.DomUtil.addClass(this._container,\n\t\t\t\t\t\t\t\t'leaflet-error-draw-tooltip');\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\tremoveError : function() {\n\t\t\t\t\tif (this._container) {\n\t\t\t\t\t\tL.DomUtil.removeClass(this._container,\n\t\t\t\t\t\t\t\t'leaflet-error-draw-tooltip');\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t});\n\n\tL.DrawToolbar = L.Toolbar\n\t\t\t.extend({\n\n\t\t\t\toptions : {\n\t\t\t\t\tzoomIn : {},\n\t\t\t\t\tzoomOut : {},\n\t\t\t\t\tpolyline : {},\n\t\t\t\t\tpolygon : {},\n\t\t\t\t\trectangle : {},\n\t\t\t\t\tcircle : {},\n\t\t\t\t\tpolygonQuery : {},\n\t\t\t\t\trectangleQuery : {},\n\t\t\t\t\tcircleQuery : {},\n\t\t\t\t\tmarker : {},\n\t\t\t\t\tclearMap : {},\n\t\t\t\t\treset : {},\n\t\t\t\t\tcleanAll : {}\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(options) {\n\t\t\t\t\t// Ensure that the options are merged correctly since\n\t\t\t\t\t// L.extend is only shallow\n\t\t\t\t\tfor ( var type in this.options) {\n\t\t\t\t\t\tif (this.options.hasOwnProperty(type)) {\n\t\t\t\t\t\t\tif (options[type]) {\n\t\t\t\t\t\t\t\toptions[type] = L.extend({},\n\t\t\t\t\t\t\t\t\t\tthis.options[type], options[type]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tL.Toolbar.prototype.initialize.call(this, options);\n\t\t\t\t},\n\n\t\t\t\taddToolbar : function(map) {\n\t\t\t\t\tvar container = L.DomUtil.create('div',\n\t\t\t\t\t\t\t'leaflet-draw-section'), buttonIndex = 0, buttonClassPrefix = 'leaflet-draw-draw';\n\n\t\t\t\t\tthis._toolbarContainer = L.DomUtil.create('div',\n\t\t\t\t\t\t\t'leaflet-draw-toolbar leaflet-bar');\n\n\t\t\t\t\t// 放大\n\t\t\t\t\tif (this.options.zoomIn) {\n\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.ZoomIn(map,\n\t\t\t\t\t\t\t\tthis.options.zoomIn), this._toolbarContainer,\n\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.zoomIn);\n\t\t\t\t\t}\n\n\t\t\t\t\t// 缩小\n\t\t\t\t\tif (this.options.zoomOut) {\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.ZoomOut(map,\n\t\t\t\t\t\t\t\tthis.options.zoomOut), this._toolbarContainer,\n\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.zoomOut);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.options.polyline) {\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.Polyline(map,\n\t\t\t\t\t\t\t\tthis.options.polyline), this._toolbarContainer,\n\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.polyline);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.options.polygon) {\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.Polygon(map,\n\t\t\t\t\t\t\t\tthis.options.polygon), this._toolbarContainer,\n\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.polygon);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.options.rectangle) {\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.Rectangle(map,\n\t\t\t\t\t\t\t\tthis.options.rectangle),\n\t\t\t\t\t\t\t\tthis._toolbarContainer, buttonIndex++,\n\t\t\t\t\t\t\t\tbuttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.rectangle);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.options.circle) {\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.Circle(map,\n\t\t\t\t\t\t\t\tthis.options.circle), this._toolbarContainer,\n\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.circle);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.options.marker) {\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.Marker(map,\n\t\t\t\t\t\t\t\tthis.options.marker), this._toolbarContainer,\n\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.marker);\n\t\t\t\t\t}\n\t\t\t\t\t/*\n\t\t\t\t\t * \n\t\t\t\t\t * 空间查询-王孝胜\n\t\t\t\t\t * \n\t\t\t\t\t */\n\n\t\t\t\t\t// 圆查询\n\t\t\t\t\tif (this.options.circleQuery) {\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.Circle.Query(map,\n\t\t\t\t\t\t\t\tthis.options.circleQuery),\n\t\t\t\t\t\t\t\tthis._toolbarContainer, buttonIndex++,\n\t\t\t\t\t\t\t\tbuttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.circleQuery);\n\t\t\t\t\t}\n\n\t\t\t\t\t// 矩形查询\n\t\t\t\t\tif (this.options.rectangleQuery) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t\t._initModeHandler(\n\t\t\t\t\t\t\t\t\t\tnew L.Draw.Rectangle.Query(map,\n\t\t\t\t\t\t\t\t\t\t\t\tthis.options.rectangleQuery),\n\t\t\t\t\t\t\t\t\t\tthis._toolbarContainer,\n\t\t\t\t\t\t\t\t\t\tbuttonIndex++,\n\t\t\t\t\t\t\t\t\t\tbuttonClassPrefix,\n\t\t\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.rectangleQuery);\n\t\t\t\t\t}\n\n\t\t\t\t\t// 多边形查询\n\t\t\t\t\tif (this.options.polygonQuery) {\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.Polygon.Query(map,\n\t\t\t\t\t\t\t\tthis.options.polygonQuery),\n\t\t\t\t\t\t\t\tthis._toolbarContainer, buttonIndex++,\n\t\t\t\t\t\t\t\tbuttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.polygonQuery);\n\t\t\t\t\t}\n\t\t\t\t\t// 重置\n\t\t\t\t\tif (this.options.reset) {\n\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.Reset(map,\n\t\t\t\t\t\t\t\tthis.options.reset), this._toolbarContainer,\n\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.reset);\n\t\t\t\t\t}\n\t\t\t\t\t// 清空所有地图\n\t\t\t\t\tif (this.options.cleanAll) {\n\n\t\t\t\t\t\tthis._initModeHandler(new L.Draw.CleanAll(map,\n\t\t\t\t\t\t\t\tthis.options.cleanAll), this._toolbarContainer,\n\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.draw.toolbar.buttons.cleanAll);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Save button index of the last button, -1 as we would have\n\t\t\t\t\t// ++ after the last button\n\t\t\t\t\tthis._lastButtonIndex = --buttonIndex;\n\n\t\t\t\t\t// Create the actions part of the toolbar\n\t\t\t\t\tthis._actionsContainer = this._createActions([ {\n\t\t\t\t\t\ttitle : L.drawLocal.draw.toolbar.actions.title,\n\t\t\t\t\t\ttext : L.drawLocal.draw.toolbar.actions.text,\n\t\t\t\t\t\tcallback : this.disable,\n\t\t\t\t\t\tcontext : this\n\t\t\t\t\t} ]);\n\n\t\t\t\t\t// Add draw and cancel containers to the control container\n\t\t\t\t\tcontainer.appendChild(this._toolbarContainer);\n\t\t\t\t\t// 控制是否显示取消按钮\n\t\t\t\t\t// container.appendChild(this._actionsContainer);\n\t\t\t\t\treturn container;\n\t\t\t\t},\n\n\t\t\t\tsetOptions : function(options) {\n\t\t\t\t\tL.setOptions(this, options);\n\n\t\t\t\t\tfor ( var type in this._modes) {\n\t\t\t\t\t\tif (this._modes.hasOwnProperty(type)\n\t\t\t\t\t\t\t\t&& options.hasOwnProperty(type)) {\n\t\t\t\t\t\t\tthis._modes[type].handler.setOptions(options[type]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\t/*\n\t * L.Map.mergeOptions({ editControl: true });\n\t */\n\n\tL.EditToolbar = L.Toolbar\n\t\t\t.extend({\n\t\t\t\toptions : {\n\t\t\t\t\tedit : {\n\t\t\t\t\t\tselectedPathOptions : {\n\t\t\t\t\t\t\tcolor : '#fe57a1', /* Hot pink all the things! */\n\t\t\t\t\t\t\topacity : 0.6,\n\t\t\t\t\t\t\tdashArray : '10, 10',\n\n\t\t\t\t\t\t\tfill : true,\n\t\t\t\t\t\t\tfillColor : '#fe57a1',\n\t\t\t\t\t\t\tfillOpacity : 0.1\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\tremove : {},\n\t\t\t\t\tfeatureGroup : null\n\t\t\t\t/*\n\t\t\t\t * REQUIRED! TODO: perhaps if not set then all layers on the map\n\t\t\t\t * are selectable?\n\t\t\t\t */\n\t\t\t\t},\n\n\t\t\t\tinitialize : function(options) {\n\t\t\t\t\t// Need to set this manually since null is an acceptable\n\t\t\t\t\t// value here\n\t\t\t\t\tif (options.edit) {\n\t\t\t\t\t\tif (typeof options.edit.selectedPathOptions === 'undefined') {\n\t\t\t\t\t\t\toptions.edit.selectedPathOptions = this.options.edit.selectedPathOptions;\n\t\t\t\t\t\t}\n\t\t\t\t\t\toptions.edit = L.extend({}, this.options.edit,\n\t\t\t\t\t\t\t\toptions.edit);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (options.remove) {\n\t\t\t\t\t\toptions.remove = L.extend({}, this.options.remove,\n\t\t\t\t\t\t\t\toptions.remove);\n\t\t\t\t\t}\n\n\t\t\t\t\tL.Toolbar.prototype.initialize.call(this, options);\n\n\t\t\t\t\tthis._selectedFeatureCount = 0;\n\t\t\t\t},\n\n\t\t\t\taddToolbar : function(map) {\n\t\t\t\t\tvar container = L.DomUtil.create('div',\n\t\t\t\t\t\t\t'leaflet-draw-section'), buttonIndex = 0, buttonClassPrefix = 'leaflet-draw-edit', featureGroup = this.options.featureGroup;\n\n\t\t\t\t\tthis._toolbarContainer = L.DomUtil.create('div',\n\t\t\t\t\t\t\t'leaflet-draw-toolbar leaflet-bar');\n\n\t\t\t\t\tthis._map = map;\n\n\t\t\t\t\tif (this.options.edit) {\n\t\t\t\t\t\tthis\n\t\t\t\t\t\t\t\t._initModeHandler(\n\t\t\t\t\t\t\t\t\t\tnew L.EditToolbar.Edit(\n\t\t\t\t\t\t\t\t\t\t\t\tmap,\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tfeatureGroup : featureGroup,\n\t\t\t\t\t\t\t\t\t\t\t\t\tselectedPathOptions : this.options.edit.selectedPathOptions\n\t\t\t\t\t\t\t\t\t\t\t\t}), this._toolbarContainer,\n\t\t\t\t\t\t\t\t\t\tbuttonIndex++, buttonClassPrefix,\n\t\t\t\t\t\t\t\t\t\tL.drawLocal.edit.toolbar.buttons.edit);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.options.remove) {\n\t\t\t\t\t\tthis._initModeHandler(new L.EditToolbar.Delete(map, {\n\t\t\t\t\t\t\tfeatureGroup : featureGroup\n\t\t\t\t\t\t}), this._toolbarContainer, buttonIndex++,\n\t\t\t\t\t\t\t\tbuttonClassPrefix,\n\t\t\t\t\t\t\t\tL.drawLocal.edit.toolbar.buttons.remove);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Save button index of the last button, -1 as we would have\n\t\t\t\t\t// ++ after the last button\n\t\t\t\t\tthis._lastButtonIndex = --buttonIndex;\n\n\t\t\t\t\t// Create the actions part of the toolbar\n\t\t\t\t\tthis._actionsContainer = this._createActions([ {\n\t\t\t\t\t\ttitle : L.drawLocal.edit.toolbar.actions.save.title,\n\t\t\t\t\t\ttext : L.drawLocal.edit.toolbar.actions.save.text,\n\t\t\t\t\t\tcallback : this._save,\n\t\t\t\t\t\tcontext : this\n\t\t\t\t\t}, {\n\t\t\t\t\t\ttitle : L.drawLocal.edit.toolbar.actions.cancel.title,\n\t\t\t\t\t\ttext : L.drawLocal.edit.toolbar.actions.cancel.text,\n\t\t\t\t\t\tcallback : this.disable,\n\t\t\t\t\t\tcontext : this\n\t\t\t\t\t} ]);\n\n\t\t\t\t\t// Add draw and cancel containers to the control container\n\t\t\t\t\tcontainer.appendChild(this._toolbarContainer);\n\t\t\t\t\tcontainer.appendChild(this._actionsContainer);\n\n\t\t\t\t\tthis._checkDisabled();\n\n\t\t\t\t\tfeatureGroup.on('layeradd layerremove',\n\t\t\t\t\t\t\tthis._checkDisabled, this);\n\n\t\t\t\t\treturn container;\n\t\t\t\t},\n\n\t\t\t\tremoveToolbar : function() {\n\t\t\t\t\tL.Toolbar.prototype.removeToolbar.call(this);\n\n\t\t\t\t\tthis.options.featureGroup.off('layeradd layerremove',\n\t\t\t\t\t\t\tthis._checkDisabled, this);\n\t\t\t\t},\n\n\t\t\t\tdisable : function() {\n\t\t\t\t\tif (!this.enabled()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._activeMode.handler.revertLayers();\n\n\t\t\t\t\tL.Toolbar.prototype.disable.call(this);\n\t\t\t\t},\n\n\t\t\t\t_save : function() {\n\t\t\t\t\tthis._activeMode.handler.save();\n\t\t\t\t\tthis._activeMode.handler.disable();\n\t\t\t\t},\n\n\t\t\t\t_checkDisabled : function() {\n\t\t\t\t\tvar featureGroup = this.options.featureGroup, hasLayers = featureGroup\n\t\t\t\t\t\t\t.getLayers().length !== 0, button;\n\n\t\t\t\t\tif (this.options.edit) {\n\t\t\t\t\t\tbutton = this._modes[L.EditToolbar.Edit.TYPE].button;\n\n\t\t\t\t\t\tif (hasLayers) {\n\t\t\t\t\t\t\tL.DomUtil.removeClass(button, 'leaflet-disabled');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tL.DomUtil.addClass(button, 'leaflet-disabled');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbutton\n\t\t\t\t\t\t\t\t.setAttribute(\n\t\t\t\t\t\t\t\t\t\t'title',\n\t\t\t\t\t\t\t\t\t\thasLayers ? L.drawLocal.edit.toolbar.buttons.edit\n\t\t\t\t\t\t\t\t\t\t\t\t: L.drawLocal.edit.toolbar.buttons.editDisabled);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this.options.remove) {\n\t\t\t\t\t\tbutton = this._modes[L.EditToolbar.Delete.TYPE].button;\n\n\t\t\t\t\t\tif (hasLayers) {\n\t\t\t\t\t\t\tL.DomUtil.removeClass(button, 'leaflet-disabled');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tL.DomUtil.addClass(button, 'leaflet-disabled');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbutton\n\t\t\t\t\t\t\t\t.setAttribute(\n\t\t\t\t\t\t\t\t\t\t'title',\n\t\t\t\t\t\t\t\t\t\thasLayers ? L.drawLocal.edit.toolbar.buttons.remove\n\t\t\t\t\t\t\t\t\t\t\t\t: L.drawLocal.edit.toolbar.buttons.removeDisabled);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\tL.EditToolbar.Edit = L.Handler\n\t\t\t.extend({\n\t\t\t\tstatics : {\n\t\t\t\t\tTYPE : 'edit'\n\t\t\t\t},\n\n\t\t\t\tincludes : L.Mixin.Events,\n\n\t\t\t\tinitialize : function(map, options) {\n\t\t\t\t\tL.Handler.prototype.initialize.call(this, map);\n\n\t\t\t\t\t// Set options to the default unless already set\n\t\t\t\t\tthis._selectedPathOptions = options.selectedPathOptions;\n\n\t\t\t\t\t// Store the selectable layer group for ease of access\n\t\t\t\t\tthis._featureGroup = options.featureGroup;\n\n\t\t\t\t\tif (!(this._featureGroup instanceof L.FeatureGroup)) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t'options.featureGroup must be a L.FeatureGroup');\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._uneditedLayerProps = {};\n\n\t\t\t\t\t// Save the type so super can fire, need to do this as\n\t\t\t\t\t// cannot do this.TYPE :(\n\t\t\t\t\tthis.type = L.EditToolbar.Edit.TYPE;\n\t\t\t\t},\n\n\t\t\t\tenable : function() {\n\t\t\t\t\tif (this._enabled || !this._hasAvailableLayers()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tL.Handler.prototype.enable.call(this);\n\n\t\t\t\t\tthis._featureGroup.on('layeradd', this._enableLayerEdit,\n\t\t\t\t\t\t\tthis).on('layerremove', this._disableLayerEdit,\n\t\t\t\t\t\t\tthis);\n\n\t\t\t\t\tthis.fire('enabled', {\n\t\t\t\t\t\thandler : this.type\n\t\t\t\t\t});\n\t\t\t\t\tthis._map.fire('draw:editstart', {\n\t\t\t\t\t\thandler : this.type\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\tdisable : function() {\n\t\t\t\t\tif (!this._enabled) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.fire('disabled', {\n\t\t\t\t\t\thandler : this.type\n\t\t\t\t\t});\n\t\t\t\t\tthis._map.fire('draw:editstop', {\n\t\t\t\t\t\thandler : this.type\n\t\t\t\t\t});\n\n\t\t\t\t\tthis._featureGroup.off('layeradd', this._enableLayerEdit,\n\t\t\t\t\t\t\tthis).off('layerremove', this._disableLayerEdit,\n\t\t\t\t\t\t\tthis);\n\n\t\t\t\t\tL.Handler.prototype.disable.call(this);\n\t\t\t\t},\n\n\t\t\t\taddHooks : function() {\n\t\t\t\t\tvar map = this._map;\n\n\t\t\t\t\tif (map) {\n\t\t\t\t\t\tmap.getContainer().focus();\n\n\t\t\t\t\t\tthis._featureGroup.eachLayer(this._enableLayerEdit,\n\t\t\t\t\t\t\t\tthis);\n\n\t\t\t\t\t\tthis._tooltip = new L.Tooltip(this._map);\n\t\t\t\t\t\tthis._tooltip\n\t\t\t\t\t\t\t\t.updateContent({\n\t\t\t\t\t\t\t\t\ttext : L.drawLocal.edit.handlers.edit.tooltip.text,\n\t\t\t\t\t\t\t\t\tsubtext : L.drawLocal.edit.handlers.edit.tooltip.subtext\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis._map.on('mousemove', this._onMouseMove, this);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremoveHooks : function() {\n\t\t\t\t\tif (this._map) {\n\t\t\t\t\t\t// Clean up selected layers.\n\t\t\t\t\t\tthis._featureGroup.eachLayer(this._disableLayerEdit,\n\t\t\t\t\t\t\t\tthis);\n\n\t\t\t\t\t\t// Clear the backups of the original layers\n\t\t\t\t\t\tthis._uneditedLayerProps = {};\n\n\t\t\t\t\t\tthis._tooltip.dispose();\n\t\t\t\t\t\tthis._tooltip = null;\n\n\t\t\t\t\t\tthis._map.off('mousemove', this._onMouseMove, this);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\trevertLayers : function() {\n\t\t\t\t\tthis._featureGroup.eachLayer(function(layer) {\n\t\t\t\t\t\tthis._revertLayer(layer);\n\t\t\t\t\t}, this);\n\t\t\t\t},\n\n\t\t\t\tsave : function() {\n\t\t\t\t\tvar editedLayers = new L.LayerGroup();\n\t\t\t\t\tthis._featureGroup.eachLayer(function(layer) {\n\t\t\t\t\t\tif (layer.edited) {\n\t\t\t\t\t\t\teditedLayers.addLayer(layer);\n\t\t\t\t\t\t\tlayer.edited = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t\tthis._map.fire('draw:edited', {\n\t\t\t\t\t\tlayers : editedLayers\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\t_backupLayer : function(layer) {\n\t\t\t\t\tvar id = L.Util.stamp(layer);\n\n\t\t\t\t\tif (!this._uneditedLayerProps[id]) {\n\t\t\t\t\t\t// Polyline, Polygon or Rectangle\n\t\t\t\t\t\tif (layer instanceof L.Polyline\n\t\t\t\t\t\t\t\t|| layer instanceof L.Polygon\n\t\t\t\t\t\t\t\t|| layer instanceof L.Rectangle) {\n\t\t\t\t\t\t\tthis._uneditedLayerProps[id] = {\n\t\t\t\t\t\t\t\tlatlngs : L.LatLngUtil.cloneLatLngs(layer\n\t\t\t\t\t\t\t\t\t\t.getLatLngs())\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else if (layer instanceof L.Circle) {\n\t\t\t\t\t\t\tthis._uneditedLayerProps[id] = {\n\t\t\t\t\t\t\t\tlatlng : L.LatLngUtil.cloneLatLng(layer\n\t\t\t\t\t\t\t\t\t\t.getLatLng()),\n\t\t\t\t\t\t\t\tradius : layer.getRadius()\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t} else { // Marker\n\t\t\t\t\t\t\tthis._uneditedLayerProps[id] = {\n\t\t\t\t\t\t\t\tlatlng : L.LatLngUtil.cloneLatLng(layer\n\t\t\t\t\t\t\t\t\t\t.getLatLng())\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_revertLayer : function(layer) {\n\t\t\t\t\tvar id = L.Util.stamp(layer);\n\t\t\t\t\tlayer.edited = false;\n\t\t\t\t\tif (this._uneditedLayerProps.hasOwnProperty(id)) {\n\t\t\t\t\t\t// Polyline, Polygon or Rectangle\n\t\t\t\t\t\tif (layer instanceof L.Polyline\n\t\t\t\t\t\t\t\t|| layer instanceof L.Polygon\n\t\t\t\t\t\t\t\t|| layer instanceof L.Rectangle) {\n\t\t\t\t\t\t\tlayer\n\t\t\t\t\t\t\t\t\t.setLatLngs(this._uneditedLayerProps[id].latlngs);\n\t\t\t\t\t\t} else if (layer instanceof L.Circle) {\n\t\t\t\t\t\t\tlayer\n\t\t\t\t\t\t\t\t\t.setLatLng(this._uneditedLayerProps[id].latlng);\n\t\t\t\t\t\t\tlayer\n\t\t\t\t\t\t\t\t\t.setRadius(this._uneditedLayerProps[id].radius);\n\t\t\t\t\t\t} else { // Marker\n\t\t\t\t\t\t\tlayer\n\t\t\t\t\t\t\t\t\t.setLatLng(this._uneditedLayerProps[id].latlng);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_toggleMarkerHighlight : function(marker) {\n\t\t\t\t\tif (!marker._icon) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t// This is quite naughty, but I don't see another way of\n\t\t\t\t\t// doing it. (short of setting a new icon)\n\t\t\t\t\tvar icon = marker._icon;\n\n\t\t\t\t\ticon.style.display = 'none';\n\n\t\t\t\t\tif (L.DomUtil\n\t\t\t\t\t\t\t.hasClass(icon, 'leaflet-edit-marker-selected')) {\n\t\t\t\t\t\tL.DomUtil.removeClass(icon,\n\t\t\t\t\t\t\t\t'leaflet-edit-marker-selected');\n\t\t\t\t\t\t// Offset as the border will make the icon move.\n\t\t\t\t\t\tthis._offsetMarker(icon, -4);\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tL.DomUtil\n\t\t\t\t\t\t\t\t.addClass(icon, 'leaflet-edit-marker-selected');\n\t\t\t\t\t\t// Offset as the border will make the icon move.\n\t\t\t\t\t\tthis._offsetMarker(icon, 4);\n\t\t\t\t\t}\n\n\t\t\t\t\ticon.style.display = '';\n\t\t\t\t},\n\n\t\t\t\t_offsetMarker : function(icon, offset) {\n\t\t\t\t\tvar iconMarginTop = parseInt(icon.style.marginTop, 10)\n\t\t\t\t\t\t\t- offset, iconMarginLeft = parseInt(\n\t\t\t\t\t\t\ticon.style.marginLeft, 10)\n\t\t\t\t\t\t\t- offset;\n\n\t\t\t\t\ticon.style.marginTop = iconMarginTop + 'px';\n\t\t\t\t\ticon.style.marginLeft = iconMarginLeft + 'px';\n\t\t\t\t},\n\n\t\t\t\t_enableLayerEdit : function(e) {\n\t\t\t\t\tvar layer = e.layer || e.target || e, isMarker = layer instanceof L.Marker, pathOptions;\n\n\t\t\t\t\t// Don't do anything if this layer is a marker but doesn't\n\t\t\t\t\t// have an icon. Markers\n\t\t\t\t\t// should usually have icons. If using Leaflet.draw with\n\t\t\t\t\t// Leafler.markercluster there\n\t\t\t\t\t// is a chance that a marker doesn't.\n\t\t\t\t\tif (isMarker && !layer._icon) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Back up this layer (if haven't before)\n\t\t\t\t\tthis._backupLayer(layer);\n\n\t\t\t\t\t// Update layer style so appears editable\n\t\t\t\t\tif (this._selectedPathOptions) {\n\t\t\t\t\t\tpathOptions = L.Util.extend({},\n\t\t\t\t\t\t\t\tthis._selectedPathOptions);\n\n\t\t\t\t\t\tif (isMarker) {\n\t\t\t\t\t\t\tthis._toggleMarkerHighlight(layer);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlayer.options.previousOptions = layer.options;\n\n\t\t\t\t\t\t\t// Make sure that Polylines are not filled\n\t\t\t\t\t\t\tif (!(layer instanceof L.Circle)\n\t\t\t\t\t\t\t\t\t&& !(layer instanceof L.Polygon)\n\t\t\t\t\t\t\t\t\t&& !(layer instanceof L.Rectangle)) {\n\t\t\t\t\t\t\t\tpathOptions.fill = false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlayer.setStyle(pathOptions);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (isMarker) {\n\t\t\t\t\t\tlayer.dragging.enable();\n\t\t\t\t\t\tlayer.on('dragend', this._onMarkerDragEnd);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlayer.editing.enable();\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_disableLayerEdit : function(e) {\n\t\t\t\t\tvar layer = e.layer || e.target || e;\n\t\t\t\t\tlayer.edited = false;\n\n\t\t\t\t\t// Reset layer styles to that of before select\n\t\t\t\t\tif (this._selectedPathOptions) {\n\t\t\t\t\t\tif (layer instanceof L.Marker) {\n\t\t\t\t\t\t\tthis._toggleMarkerHighlight(layer);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// reset the layer style to what is was before being\n\t\t\t\t\t\t\t// selected\n\t\t\t\t\t\t\tlayer.setStyle(layer.options.previousOptions);\n\t\t\t\t\t\t\t// remove the cached options for the layer object\n\t\t\t\t\t\t\tdelete layer.options.previousOptions;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (layer instanceof L.Marker) {\n\t\t\t\t\t\tlayer.dragging.disable();\n\t\t\t\t\t\tlayer.off('dragend', this._onMarkerDragEnd, this);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlayer.editing.disable();\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\t_onMarkerDragEnd : function(e) {\n\t\t\t\t\tvar layer = e.target;\n\t\t\t\t\tlayer.edited = true;\n\t\t\t\t},\n\n\t\t\t\t_onMouseMove : function(e) {\n\t\t\t\t\tthis._tooltip.updatePosition(e.latlng);\n\t\t\t\t},\n\n\t\t\t\t_hasAvailableLayers : function() {\n\t\t\t\t\treturn this._featureGroup.getLayers().length !== 0;\n\t\t\t\t}\n\t\t\t});\n\n\tL.EditToolbar.Delete = L.Handler\n\t\t\t.extend({\n\t\t\t\tstatics : {\n\t\t\t\t\tTYPE : 'remove' // not delete as delete is reserved in js\n\t\t\t\t},\n\n\t\t\t\tincludes : L.Mixin.Events,\n\n\t\t\t\tinitialize : function(map, options) {\n\t\t\t\t\tL.Handler.prototype.initialize.call(this, map);\n\n\t\t\t\t\tL.Util.setOptions(this, options);\n\n\t\t\t\t\t// Store the selectable layer group for ease of access\n\t\t\t\t\tthis._deletableLayers = this.options.featureGroup;\n\n\t\t\t\t\tif (!(this._deletableLayers instanceof L.FeatureGroup)) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t'options.featureGroup must be a L.FeatureGroup');\n\t\t\t\t\t}\n\n\t\t\t\t\t// Save the type so super can fire, need to do this as\n\t\t\t\t\t// cannot do this.TYPE :(\n\t\t\t\t\tthis.type = L.EditToolbar.Delete.TYPE;\n\t\t\t\t},\n\n\t\t\t\tenable : function() {\n\t\t\t\t\tif (this._enabled || !this._hasAvailableLayers()) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tL.Handler.prototype.enable.call(this);\n\n\t\t\t\t\tthis._deletableLayers.on('layeradd',\n\t\t\t\t\t\t\tthis._enableLayerDelete, this).on('layerremove',\n\t\t\t\t\t\t\tthis._disableLayerDelete, this);\n\n\t\t\t\t\tthis.fire('enabled', {\n\t\t\t\t\t\thandler : this.type\n\t\t\t\t\t});\n\t\t\t\t\tthis._map.fire('draw:editstart', {\n\t\t\t\t\t\thandler : this.type\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\tdisable : function() {\n\t\t\t\t\tif (!this._enabled) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tL.Handler.prototype.disable.call(this);\n\n\t\t\t\t\tthis._deletableLayers.off('layeradd',\n\t\t\t\t\t\t\tthis._enableLayerDelete, this).off('layerremove',\n\t\t\t\t\t\t\tthis._disableLayerDelete, this);\n\n\t\t\t\t\tthis.fire('disabled', {\n\t\t\t\t\t\thandler : this.type\n\t\t\t\t\t});\n\t\t\t\t\tthis._map.fire('draw:editstop', {\n\t\t\t\t\t\thandler : this.type\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\taddHooks : function() {\n\t\t\t\t\tvar map = this._map;\n\n\t\t\t\t\tif (map) {\n\t\t\t\t\t\tmap.getContainer().focus();\n\n\t\t\t\t\t\tthis._deletableLayers.eachLayer(\n\t\t\t\t\t\t\t\tthis._enableLayerDelete, this);\n\t\t\t\t\t\tthis._deletedLayers = new L.layerGroup();\n\n\t\t\t\t\t\tthis._tooltip = new L.Tooltip(this._map);\n\t\t\t\t\t\tthis._tooltip\n\t\t\t\t\t\t\t\t.updateContent({\n\t\t\t\t\t\t\t\t\ttext : L.drawLocal.edit.handlers.remove.tooltip.text\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis._map.on('mousemove', this._onMouseMove, this);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\tremoveHooks : function() {\n\t\t\t\t\tif (this._map) {\n\t\t\t\t\t\tthis._deletableLayers.eachLayer(\n\t\t\t\t\t\t\t\tthis._disableLayerDelete, this);\n\t\t\t\t\t\tthis._deletedLayers = null;\n\n\t\t\t\t\t\tthis._tooltip.dispose();\n\t\t\t\t\t\tthis._tooltip = null;\n\n\t\t\t\t\t\tthis._map.off('mousemove', this._onMouseMove, this);\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\t\trevertLayers : function() {\n\t\t\t\t\t// Iterate of the deleted layers and add them back into the\n\t\t\t\t\t// featureGroup\n\t\t\t\t\tthis._deletedLayers.eachLayer(function(layer) {\n\t\t\t\t\t\tthis._deletableLayers.addLayer(layer);\n\t\t\t\t\t}, this);\n\t\t\t\t},\n\n\t\t\t\tsave : function() {\n\t\t\t\t\tthis._map.fire('draw:deleted', {\n\t\t\t\t\t\tlayers : this._deletedLayers\n\t\t\t\t\t});\n\t\t\t\t},\n\n\t\t\t\t_enableLayerDelete : function(e) {\n\t\t\t\t\tvar layer = e.layer || e.target || e;\n\n\t\t\t\t\tlayer.on('click', this._removeLayer, this);\n\t\t\t\t},\n\n\t\t\t\t_disableLayerDelete : function(e) {\n\t\t\t\t\tvar layer = e.layer || e.target || e;\n\n\t\t\t\t\tlayer.off('click', this._removeLayer, this);\n\n\t\t\t\t\t// Remove from the deleted layers so we can't accidently\n\t\t\t\t\t// revert if the user presses cancel\n\t\t\t\t\tthis._deletedLayers.removeLayer(layer);\n\t\t\t\t},\n\n\t\t\t\t_removeLayer : function(e) {\n\t\t\t\t\tvar layer = e.layer || e.target || e;\n\n\t\t\t\t\tthis._deletableLayers.removeLayer(layer);\n\n\t\t\t\t\tthis._deletedLayers.addLayer(layer);\n\t\t\t\t},\n\n\t\t\t\t_onMouseMove : function(e) {\n\t\t\t\t\tthis._tooltip.updatePosition(e.latlng);\n\t\t\t\t},\n\n\t\t\t\t_hasAvailableLayers : function() {\n\t\t\t\t\treturn this._deletableLayers.getLayers().length !== 0;\n\t\t\t\t}\n\t\t\t});\n\n}(this, document));"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.draw/leaflet.draw.css",
    "content": "/* ================================================================== */\n/* Toolbars\n/* ================================================================== */\n\n.leaflet-draw-section {\n\tposition: relative;\n}\n\n.leaflet-draw-toolbar {\n\tmargin-top: 12px;\n}\n\n.leaflet-draw-toolbar-top {\n\tmargin-top: 0;\n}\n\n.leaflet-draw-toolbar-notop a:first-child {\n\tborder-top-right-radius: 0;\n}\n\n.leaflet-draw-toolbar-nobottom a:last-child {\n\tborder-bottom-right-radius: 0;\n}\n\n.leaflet-draw-toolbar a {\n\tbackground-image: url('images/spritesheet.png');\n\tbackground-repeat: no-repeat;\n}\n\n.leaflet-retina .leaflet-draw-toolbar a {\n\tbackground-image: url('images/spritesheet-2x.png');\n\tbackground-size: 270px 30px;\n}\n\n.leaflet-draw a {\n\tdisplay: block;\n\ttext-align: center;\n\ttext-decoration: none;\n}\n\n/* ================================================================== */\n/* Toolbar actions menu\n/* ================================================================== */\n\n.leaflet-draw-actions {\n\tdisplay: none;\n\tlist-style: none;\n\tmargin: 0;\n\tpadding: 0;\n\tposition: absolute;\n\tleft: 26px; /* leaflet-draw-toolbar.left + leaflet-draw-toolbar.width */\n\ttop: 0;\n\tmargin-top: 1px;\n\twhite-space: nowrap;\n}\n\n.leaflet-right .leaflet-draw-actions {\n\tright:26px;\n\tleft:auto;\n}\n\n.leaflet-draw-actions li {\n\tdisplay: inline-block;\n}\n\n.leaflet-draw-actions li:first-child a {\n\tborder-left: none;\n}\n\n.leaflet-draw-actions li:last-child a {\n\t-webkit-border-radius: 0 4px 4px 0;\n\t        border-radius: 0 4px 4px 0;\n}\n\n.leaflet-right .leaflet-draw-actions li:last-child a {\n\t-webkit-border-radius: 0;\n\t        border-radius: 0;\n}\n\n.leaflet-right .leaflet-draw-actions li:first-child a {\n\t-webkit-border-radius: 4px 0 0 4px;\n\t        border-radius: 4px 0 0 4px;\n}\n\n.leaflet-draw-actions a {\n\tbackground-color: #919187;\n\tborder-left: 1px solid #AAA;\n\tcolor: #FFF;\n\tfont: 11px/19px \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n\tline-height: 28px;\n\ttext-decoration: none;\n\tpadding-left: 10px;\n\tpadding-right: 10px;\n\theight: 28px;\n}\n\n.leaflet-draw-actions-bottom {\n\tmargin-top: 0;\n\twhite-space: nowrap;\n}\n\n.leaflet-draw-actions-top {\n\tmargin-top: 1px;\n\twhite-space: nowrap;\n}\n\n.leaflet-draw-actions-top a,\n.leaflet-draw-actions-bottom a {\n\theight: 27px;\n\tline-height: 27px;\n}\n\n.leaflet-draw-actions a:hover {\n\tbackground-color: #A0A098;\n}\n\n.leaflet-draw-actions-top.leaflet-draw-actions-bottom a {\n\theight: 26px;\n\tline-height: 26px;\n}\n\n/* ================================================================== */\n/* Draw toolbar\n/* ================================================================== */\n/*放大*/\n.leaflet-draw-toolbar .leaflet-draw-draw-zoomIn {\n\tbackground-position:   -272px -2px;\n}\n/*缩小*/\n.leaflet-draw-toolbar .leaflet-draw-draw-zoomOut {\n\tbackground-position:  -304px -2px;\n}\n\n\n.leaflet-draw-toolbar .leaflet-draw-draw-polyline {\n\tbackground-position: -2px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-draw-polygon {\n\tbackground-position: -31px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-draw-rectangle {\n\tbackground-position: -62px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-draw-circle {\n\tbackground-position: -92px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-draw-marker {\n\tbackground-position: -122px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-draw-circleQuery {\n\tbackground-position: -92px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-draw-rectangleQuery{\n\tbackground-position: -62px -2px;\n}\n.leaflet-draw-toolbar .leaflet-draw-draw-polygonQuery{\n\tbackground-position: -31px -2px;\n}\n.leaflet-draw-toolbar .leaflet-draw-draw-reset{\n  background-position: -182px -2px;\n}\n\n\n/* ================================================================== */\n/* Edit toolbar\n/* ================================================================== */\n\n.leaflet-draw-toolbar .leaflet-draw-edit-edit {\n\tbackground-position: -152px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-edit-remove {\n\tbackground-position: -182px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {\n\tbackground-position: -212px -2px;\n}\n\n.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {\n\tbackground-position: -242px -2px;\n}\n\n/* ================================================================== */\n/* Drawing styles\n/* ================================================================== */\n\n.leaflet-mouse-marker {\n\tbackground-color: #fff;\n\tcursor: crosshair;\n}\n\n.leaflet-draw-tooltip {\n\tbackground: rgb(54, 54, 54);\n\tbackground: rgba(0, 0, 0, 0.5);\n\tborder: 1px solid transparent;\n\t-webkit-border-radius: 4px;\n\t        border-radius: 4px;\n\tcolor: #fff;\n\tfont: 12px/18px \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n\tmargin-left: 20px;\n\tmargin-top: -21px;\n\tpadding: 4px 8px;\n\tposition: absolute;\n\tvisibility: hidden;\n\twhite-space: nowrap;\n\tz-index: 6;\n}\n\n.leaflet-draw-tooltip:before {\n\tborder-right: 6px solid black;\n\tborder-right-color: rgba(0, 0, 0, 0.5);\n\tborder-top: 6px solid transparent;\n\tborder-bottom: 6px solid transparent;\n\tcontent: \"\";\n\tposition: absolute;\n\ttop: 7px;\n\tleft: -7px;\n}\n\n.leaflet-error-draw-tooltip {\n\tbackground-color: #F2DEDE;\n\tborder: 1px solid #E6B6BD;\n\tcolor: #B94A48;\n}\n\n.leaflet-error-draw-tooltip:before {\n\tborder-right-color: #E6B6BD;\n}\n\n.leaflet-draw-tooltip-single {\n\tmargin-top: -12px\n}\n\n.leaflet-draw-tooltip-subtext {\n\tcolor: #f8d5e4;\n}\n\n.leaflet-draw-guide-dash {\n\tfont-size: 1%;\n\topacity: 0.6;\n\tposition: absolute;\n\twidth: 5px;\n\theight: 5px;\n}\n\n/* ================================================================== */\n/* Edit styles\n/* ================================================================== */\n\n.leaflet-edit-marker-selected {\n\tbackground: rgba(254, 87, 161, 0.1);\n\tborder: 4px dashed rgba(254, 87, 161, 0.6);\n\t-webkit-border-radius: 4px;\n\t        border-radius: 4px;\n}\n\n.leaflet-edit-move {\n\tcursor: move;\n}\n\n.leaflet-edit-resize {\n\tcursor: pointer;\n}\n\n/* ================================================================== */\n/* Old IE styles\n/* ================================================================== */\n\n.leaflet-oldie .leaflet-draw-toolbar {\n\tborder: 3px solid #999;\n}\n\n.leaflet-oldie .leaflet-draw-toolbar a {\n\tbackground-color: #eee;\n}\n\n.leaflet-oldie .leaflet-draw-toolbar a:hover {\n\tbackground-color: #fff;\n}\n\n.leaflet-oldie .leaflet-draw-actions {\n\tleft: 1px;\n\tmargin-top: 3px;\n}\n\n.leaflet-oldie .leaflet-draw-actions li {\n\tdisplay: inline;\n\tzoom: 1;\n}\n\n.leaflet-oldie .leaflet-edit-marker-selected {\n\tborder: 4px dashed #fe93c2;\n}\n\n.leaflet-oldie .leaflet-draw-actions a {\n\tbackground-color: #999;\n}\n\n.leaflet-oldie .leaflet-draw-actions a:hover {\n\tbackground-color: #a5a5a5;\n}\n\n.leaflet-oldie .leaflet-draw-actions-top a {\n\tmargin-top: 1px;\n}\n\n.leaflet-oldie .leaflet-draw-actions-bottom a {\n\theight: 28px;\n\tline-height: 28px;\n}\n\n.leaflet-oldie .leaflet-draw-actions-top.leaflet-draw-actions-bottom a {\n\theight: 27px;\n\tline-height: 27px;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.draw/leaflet.draw.js",
    "content": "/*\n\tLeaflet.draw, a plugin that adds drawing and editing tools to Leaflet powered maps.\n\t(c) 2012-2013, Jacob Toye, Smartrak\n\n\thttps://github.com/Leaflet/Leaflet.draw\n\thttp://leafletjs.com\n\thttps://github.com/jacobtoye\n*/\n(function(t,e){L.drawVersion=\"0.2.3-dev\",L.drawLocal={draw:{toolbar:{actions:{title:\"Cancel drawing\",text:\"Cancel\"},buttons:{polyline:\"Draw a polyline\",polygon:\"Draw a polygon\",rectangle:\"Draw a rectangle\",circle:\"Draw a circle\",marker:\"Draw a marker\"}},handlers:{circle:{tooltip:{start:\"Click and drag to draw circle.\"}},marker:{tooltip:{start:\"Click map to place marker.\"}},polygon:{tooltip:{start:\"Click to start drawing shape.\",cont:\"Click to continue drawing shape.\",end:\"Click first point to close this shape.\"}},polyline:{error:\"<strong>Error:</strong> shape edges cannot cross!\",tooltip:{start:\"Click to start drawing line.\",cont:\"Click to continue drawing line.\",end:\"Click last point to finish line.\"}},rectangle:{tooltip:{start:\"Click and drag to draw rectangle.\"}},simpleshape:{tooltip:{end:\"Release mouse to finish drawing.\"}}}},edit:{toolbar:{actions:{save:{title:\"Save changes.\",text:\"Save\"},cancel:{title:\"Cancel editing, discards all changes.\",text:\"Cancel\"}},buttons:{edit:\"Edit layers.\",editDisabled:\"No layers to edit.\",remove:\"Delete layers.\",removeDisabled:\"No layers to delete.\"}},handlers:{edit:{tooltip:{text:\"Drag handles, or marker to edit feature.\",subtext:\"Click cancel to undo changes.\"}},remove:{tooltip:{text:\"Click on a feature to remove\"}}}}},L.Draw={},L.Draw.Feature=L.Handler.extend({includes:L.Mixin.Events,initialize:function(t,e){this._map=t,this._container=t._container,this._overlayPane=t._panes.overlayPane,this._popupPane=t._panes.popupPane,e&&e.shapeOptions&&(e.shapeOptions=L.Util.extend({},this.options.shapeOptions,e.shapeOptions)),L.Util.extend(this.options,e)},enable:function(){this._enabled||(L.Handler.prototype.enable.call(this),this.fire(\"enabled\",{handler:this.type}),this._map.fire(\"draw:drawstart\",{layerType:this.type}))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this.fire(\"disabled\",{handler:this.type}),this._map.fire(\"draw:drawstop\",{layerType:this.type}))},addHooks:function(){var t=this._map;t&&(L.DomUtil.disableTextSelection(),t.getContainer().focus(),this._tooltip=new L.Tooltip(this._map),L.DomEvent.addListener(this._container,\"keyup\",this._cancelDrawing,this))},removeHooks:function(){this._map&&(L.DomUtil.enableTextSelection(),this._tooltip.dispose(),this._tooltip=null,L.DomEvent.removeListener(this._container,\"keyup\",this._cancelDrawing))},setOptions:function(t){L.setOptions(this,t)},_fireCreatedEvent:function(t){this._map.fire(\"draw:created\",{layer:t,layerType:this.type})},_cancelDrawing:function(t){27===t.keyCode&&this.disable()}}),L.Draw.Polyline=L.Draw.Feature.extend({statics:{TYPE:\"polyline\"},Poly:L.Polyline,options:{allowIntersection:!0,repeatMode:!1,drawError:{color:\"#b00b00\",timeout:2500},icon:new L.DivIcon({iconSize:new L.Point(8,8),className:\"leaflet-div-icon leaflet-editing-icon\"}),guidelineDistance:20,shapeOptions:{stroke:!0,color:\"#f06eaa\",weight:4,opacity:.5,fill:!1,clickable:!0},metric:!0,showLength:!0,zIndexOffset:2e3},initialize:function(t,e){this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error,e&&e.drawError&&(e.drawError=L.Util.extend({},this.options.drawError,e.drawError)),this.type=L.Draw.Polyline.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._markers=[],this._markerGroup=new L.LayerGroup,this._map.addLayer(this._markerGroup),this._poly=new L.Polyline([],this.options.shapeOptions),this._tooltip.updateContent(this._getTooltipText()),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:\"leaflet-mouse-marker\",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on(\"click\",this._onClick,this).addTo(this._map),this._map.on(\"mousemove\",this._onMouseMove,this).on(\"zoomend\",this._onZoomEnd,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._clearHideErrorTimeout(),this._cleanUpShape(),this._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers,this._map.removeLayer(this._poly),delete this._poly,this._mouseMarker.off(\"click\",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._clearGuides(),this._map.off(\"mousemove\",this._onMouseMove,this).off(\"zoomend\",this._onZoomEnd,this)},_finishShape:function(){var t=this._poly.newLatLngIntersects(this._poly.getLatLngs()[0],!0);return!this.options.allowIntersection&&t||!this._shapeIsValid()?(this._showErrorTooltip(),undefined):(this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable(),undefined)},_shapeIsValid:function(){return!0},_onZoomEnd:function(){this._updateGuide()},_onMouseMove:function(t){var e=t.layerPoint,i=t.latlng;this._currentLatLng=i,this._updateTooltip(i),this._updateGuide(e),this._mouseMarker.setLatLng(i),L.DomEvent.preventDefault(t.originalEvent)},_onClick:function(t){var e=t.target.getLatLng(),i=this._markers.length;return i>0&&!this.options.allowIntersection&&this._poly.newLatLngIntersects(e)?(this._showErrorTooltip(),undefined):(this._errorShown&&this._hideErrorTooltip(),this._markers.push(this._createMarker(e)),this._poly.addLatLng(e),2===this._poly.getLatLngs().length&&this._map.addLayer(this._poly),this._updateFinishHandler(),this._vertexAdded(e),this._clearGuides(),this._updateTooltip(),undefined)},_updateFinishHandler:function(){var t=this._markers.length;t>1&&this._markers[t-1].on(\"click\",this._finishShape,this),t>2&&this._markers[t-2].off(\"click\",this._finishShape,this)},_createMarker:function(t){var e=new L.Marker(t,{icon:this.options.icon,zIndexOffset:2*this.options.zIndexOffset});return this._markerGroup.addLayer(e),e},_updateGuide:function(t){var e=this._markers.length;e>0&&(t=t||this._map.latLngToLayerPoint(this._currentLatLng),this._clearGuides(),this._drawGuide(this._map.latLngToLayerPoint(this._markers[e-1].getLatLng()),t))},_updateTooltip:function(t){var e=this._getTooltipText();t&&this._tooltip.updatePosition(t),this._errorShown||this._tooltip.updateContent(e)},_drawGuide:function(t,e){var i,o,a,s,r=Math.floor(Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2)));for(this._guidesContainer||(this._guidesContainer=L.DomUtil.create(\"div\",\"leaflet-draw-guides\",this._overlayPane)),i=this.options.guidelineDistance;r>i;i+=this.options.guidelineDistance)o=i/r,a={x:Math.floor(t.x*(1-o)+o*e.x),y:Math.floor(t.y*(1-o)+o*e.y)},s=L.DomUtil.create(\"div\",\"leaflet-draw-guide-dash\",this._guidesContainer),s.style.backgroundColor=this._errorShown?this.options.drawError.color:this.options.shapeOptions.color,L.DomUtil.setPosition(s,a)},_updateGuideColor:function(t){if(this._guidesContainer)for(var e=0,i=this._guidesContainer.childNodes.length;i>e;e++)this._guidesContainer.childNodes[e].style.backgroundColor=t},_clearGuides:function(){if(this._guidesContainer)for(;this._guidesContainer.firstChild;)this._guidesContainer.removeChild(this._guidesContainer.firstChild)},_getTooltipText:function(){var t,e,i=this.options.showLength;return 0===this._markers.length?t={text:L.drawLocal.draw.handlers.polyline.tooltip.start}:(e=i?this._getMeasurementString():\"\",t=1===this._markers.length?{text:L.drawLocal.draw.handlers.polyline.tooltip.cont,subtext:e}:{text:L.drawLocal.draw.handlers.polyline.tooltip.end,subtext:e}),t},_getMeasurementString:function(){var t,e=this._currentLatLng,i=this._markers[this._markers.length-1].getLatLng();return t=this._measurementRunningTotal+e.distanceTo(i),L.GeometryUtil.readableDistance(t,this.options.metric)},_showErrorTooltip:function(){this._errorShown=!0,this._tooltip.showAsError().updateContent({text:this.options.drawError.message}),this._updateGuideColor(this.options.drawError.color),this._poly.setStyle({color:this.options.drawError.color}),this._clearHideErrorTimeout(),this._hideErrorTimeout=setTimeout(L.Util.bind(this._hideErrorTooltip,this),this.options.drawError.timeout)},_hideErrorTooltip:function(){this._errorShown=!1,this._clearHideErrorTimeout(),this._tooltip.removeError().updateContent(this._getTooltipText()),this._updateGuideColor(this.options.shapeOptions.color),this._poly.setStyle({color:this.options.shapeOptions.color})},_clearHideErrorTimeout:function(){this._hideErrorTimeout&&(clearTimeout(this._hideErrorTimeout),this._hideErrorTimeout=null)},_vertexAdded:function(t){1===this._markers.length?this._measurementRunningTotal=0:this._measurementRunningTotal+=t.distanceTo(this._markers[this._markers.length-2].getLatLng())},_cleanUpShape:function(){this._markers.length>1&&this._markers[this._markers.length-1].off(\"click\",this._finishShape,this)},_fireCreatedEvent:function(){var t=new this.Poly(this._poly.getLatLngs(),this.options.shapeOptions);L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Polygon=L.Draw.Polyline.extend({statics:{TYPE:\"polygon\"},Poly:L.Polygon,options:{showArea:!1,shapeOptions:{stroke:!0,color:\"#f06eaa\",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){L.Draw.Polyline.prototype.initialize.call(this,t,e),this.type=L.Draw.Polygon.TYPE},_updateFinishHandler:function(){var t=this._markers.length;1===t&&this._markers[0].on(\"click\",this._finishShape,this),t>2&&(this._markers[t-1].on(\"dblclick\",this._finishShape,this),t>3&&this._markers[t-2].off(\"dblclick\",this._finishShape,this))},_getTooltipText:function(){var t,e;return 0===this._markers.length?t=L.drawLocal.draw.handlers.polygon.tooltip.start:3>this._markers.length?t=L.drawLocal.draw.handlers.polygon.tooltip.cont:(t=L.drawLocal.draw.handlers.polygon.tooltip.end,e=this._getMeasurementString()),{text:t,subtext:e}},_getMeasurementString:function(){var t=this._area;return t?L.GeometryUtil.readableArea(t,this.options.metric):null},_shapeIsValid:function(){return this._markers.length>=3},_vertexAdded:function(){if(!this.options.allowIntersection&&this.options.showArea){var t=this._poly.getLatLngs();this._area=L.GeometryUtil.geodesicArea(t)}},_cleanUpShape:function(){var t=this._markers.length;t>0&&(this._markers[0].off(\"click\",this._finishShape,this),t>2&&this._markers[t-1].off(\"dblclick\",this._finishShape,this))}}),L.SimpleShape={},L.Draw.SimpleShape=L.Draw.Feature.extend({options:{repeatMode:!1},initialize:function(t,e){this._endLabelText=L.drawLocal.draw.handlers.simpleshape.tooltip.end,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._map.dragging.disable(),this._container.style.cursor=\"crosshair\",this._tooltip.updateContent({text:this._initialLabelText}),this._map.on(\"mousedown\",this._onMouseDown,this).on(\"mousemove\",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._map.dragging.enable(),this._container.style.cursor=\"\",this._map.off(\"mousedown\",this._onMouseDown,this).off(\"mousemove\",this._onMouseMove,this),L.DomEvent.off(e,\"mouseup\",this._onMouseUp),this._shape&&(this._map.removeLayer(this._shape),delete this._shape)),this._isDrawing=!1},_onMouseDown:function(t){this._isDrawing=!0,this._startLatLng=t.latlng,L.DomEvent.on(e,\"mouseup\",this._onMouseUp,this).preventDefault(t.originalEvent)},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._isDrawing&&(this._tooltip.updateContent({text:this._endLabelText}),this._drawShape(e))},_onMouseUp:function(){this._shape&&this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()}}),L.Draw.Rectangle=L.Draw.SimpleShape.extend({statics:{TYPE:\"rectangle\"},options:{shapeOptions:{stroke:!0,color:\"#f06eaa\",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){this.type=L.Draw.Rectangle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.rectangle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setBounds(new L.LatLngBounds(this._startLatLng,t)):(this._shape=new L.Rectangle(new L.LatLngBounds(this._startLatLng,t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Rectangle(this._shape.getBounds(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Circle=L.Draw.SimpleShape.extend({statics:{TYPE:\"circle\"},options:{shapeOptions:{stroke:!0,color:\"#f06eaa\",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0},showRadius:!0,metric:!0},initialize:function(t,e){this.type=L.Draw.Circle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.circle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setRadius(this._startLatLng.distanceTo(t)):(this._shape=new L.Circle(this._startLatLng,this._startLatLng.distanceTo(t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Circle(this._startLatLng,this._shape.getRadius(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)},_onMouseMove:function(t){var e,i=t.latlng,o=(this.options.metric,this.options.showRadius),a=this.options.metric;this._tooltip.updatePosition(i),this._isDrawing&&(this._drawShape(i),e=this._shape.getRadius().toFixed(1),this._tooltip.updateContent({text:this._endLabelText,subtext:o?\"Radius: \"+L.GeometryUtil.readableDistance(e,a):\"\"}))}}),L.Draw.Marker=L.Draw.Feature.extend({statics:{TYPE:\"marker\"},options:{icon:new L.Icon.Default,repeatMode:!1,zIndexOffset:2e3},initialize:function(t,e){this.type=L.Draw.Marker.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._tooltip.updateContent({text:L.drawLocal.draw.handlers.marker.tooltip.start}),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:\"leaflet-mouse-marker\",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on(\"click\",this._onClick,this).addTo(this._map),this._map.on(\"mousemove\",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._marker&&(this._marker.off(\"click\",this._onClick,this),this._map.off(\"click\",this._onClick,this).removeLayer(this._marker),delete this._marker),this._mouseMarker.off(\"click\",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._map.off(\"mousemove\",this._onMouseMove,this))},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._mouseMarker.setLatLng(e),this._marker?this._marker.setLatLng(e):(this._marker=new L.Marker(e,{icon:this.options.icon,zIndexOffset:this.options.zIndexOffset}),this._marker.on(\"click\",this._onClick,this),this._map.on(\"click\",this._onClick,this).addLayer(this._marker))},_onClick:function(){this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()},_fireCreatedEvent:function(){var t=new L.Marker(this._marker.getLatLng(),{icon:this.options.icon});L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Edit=L.Edit||{},L.Edit.Poly=L.Handler.extend({options:{icon:new L.DivIcon({iconSize:new L.Point(8,8),className:\"leaflet-div-icon leaflet-editing-icon\"})},initialize:function(t,e){this._poly=t,L.setOptions(this,e)},addHooks:function(){this._poly._map&&(this._markerGroup||this._initMarkers(),this._poly._map.addLayer(this._markerGroup))},removeHooks:function(){this._poly._map&&(this._poly._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers)},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._markers=[];var t,e,i,o,a=this._poly._latlngs;for(t=0,i=a.length;i>t;t++)o=this._createMarker(a[t],t),o.on(\"click\",this._onMarkerClick,this),this._markers.push(o);var s,r;for(t=0,e=i-1;i>t;e=t++)(0!==t||L.Polygon&&this._poly instanceof L.Polygon)&&(s=this._markers[e],r=this._markers[t],this._createMiddleMarker(s,r),this._updatePrevNext(s,r))},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:this.options.icon});return i._origLatLng=t,i._index=e,i.on(\"drag\",this._onMarkerDrag,this),i.on(\"dragend\",this._fireEdit,this),this._markerGroup.addLayer(i),i},_removeMarker:function(t){var e=t._index;this._markerGroup.removeLayer(t),this._markers.splice(e,1),this._poly.spliceLatLngs(e,1),this._updateIndexes(e,-1),t.off(\"drag\",this._onMarkerDrag,this).off(\"dragend\",this._fireEdit,this).off(\"click\",this._onMarkerClick,this)},_fireEdit:function(){this._poly.edited=!0,this._poly.fire(\"edit\")},_onMarkerDrag:function(t){var e=t.target;L.extend(e._origLatLng,e._latlng),e._middleLeft&&e._middleLeft.setLatLng(this._getMiddleLatLng(e._prev,e)),e._middleRight&&e._middleRight.setLatLng(this._getMiddleLatLng(e,e._next)),this._poly.redraw()},_onMarkerClick:function(t){var e=L.Polygon&&this._poly instanceof L.Polygon?4:3,i=t.target;e>this._poly._latlngs.length||(this._removeMarker(i),this._updatePrevNext(i._prev,i._next),i._middleLeft&&this._markerGroup.removeLayer(i._middleLeft),i._middleRight&&this._markerGroup.removeLayer(i._middleRight),i._prev&&i._next?this._createMiddleMarker(i._prev,i._next):i._prev?i._next||(i._prev._middleRight=null):i._next._middleLeft=null,this._fireEdit())},_updateIndexes:function(t,e){this._markerGroup.eachLayer(function(i){i._index>t&&(i._index+=e)})},_createMiddleMarker:function(t,e){var i,o,a,s=this._getMiddleLatLng(t,e),r=this._createMarker(s);r.setOpacity(.6),t._middleRight=e._middleLeft=r,o=function(){var o=e._index;r._index=o,r.off(\"click\",i,this).on(\"click\",this._onMarkerClick,this),s.lat=r.getLatLng().lat,s.lng=r.getLatLng().lng,this._poly.spliceLatLngs(o,0,s),this._markers.splice(o,0,r),r.setOpacity(1),this._updateIndexes(o,1),e._index++,this._updatePrevNext(t,r),this._updatePrevNext(r,e)},a=function(){r.off(\"dragstart\",o,this),r.off(\"dragend\",a,this),this._createMiddleMarker(t,r),this._createMiddleMarker(r,e)},i=function(){o.call(this),a.call(this),this._fireEdit()},r.on(\"click\",i,this).on(\"dragstart\",o,this).on(\"dragend\",a,this),this._markerGroup.addLayer(r)},_updatePrevNext:function(t,e){t&&(t._next=e),e&&(e._prev=t)},_getMiddleLatLng:function(t,e){var i=this._poly._map,o=i.project(t.getLatLng()),a=i.project(e.getLatLng());return i.unproject(o._add(a)._divideBy(2))}}),L.Polyline.addInitHook(function(){this.editing||(L.Edit.Poly&&(this.editing=new L.Edit.Poly(this),this.options.editable&&this.editing.enable()),this.on(\"add\",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on(\"remove\",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()}))}),L.Edit=L.Edit||{},L.Edit.SimpleShape=L.Handler.extend({options:{moveIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:\"leaflet-div-icon leaflet-editing-icon leaflet-edit-move\"}),resizeIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:\"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize\"})},initialize:function(t,e){this._shape=t,L.Util.setOptions(this,e)},addHooks:function(){this._shape._map&&(this._map=this._shape._map,this._markerGroup||this._initMarkers(),this._map.addLayer(this._markerGroup))},removeHooks:function(){if(this._shape._map){this._unbindMarker(this._moveMarker);for(var t=0,e=this._resizeMarkers.length;e>t;t++)this._unbindMarker(this._resizeMarkers[t]);this._resizeMarkers=null,this._map.removeLayer(this._markerGroup),delete this._markerGroup}this._map=null},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._createMoveMarker(),this._createResizeMarker()},_createMoveMarker:function(){},_createResizeMarker:function(){},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:e,zIndexOffset:10});return this._bindMarker(i),this._markerGroup.addLayer(i),i},_bindMarker:function(t){t.on(\"dragstart\",this._onMarkerDragStart,this).on(\"drag\",this._onMarkerDrag,this).on(\"dragend\",this._onMarkerDragEnd,this)},_unbindMarker:function(t){t.off(\"dragstart\",this._onMarkerDragStart,this).off(\"drag\",this._onMarkerDrag,this).off(\"dragend\",this._onMarkerDragEnd,this)},_onMarkerDragStart:function(t){var e=t.target;e.setOpacity(0)},_fireEdit:function(){this._shape.edited=!0,this._shape.fire(\"edit\")},_onMarkerDrag:function(t){var e=t.target,i=e.getLatLng();e===this._moveMarker?this._move(i):this._resize(i),this._shape.redraw()},_onMarkerDragEnd:function(t){var e=t.target;e.setOpacity(1),this._fireEdit()},_move:function(){},_resize:function(){}}),L.Edit=L.Edit||{},L.Edit.Rectangle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getBounds(),e=t.getCenter();this._moveMarker=this._createMarker(e,this.options.moveIcon)},_createResizeMarker:function(){var t=this._getCorners();this._resizeMarkers=[];for(var e=0,i=t.length;i>e;e++)this._resizeMarkers.push(this._createMarker(t[e],this.options.resizeIcon)),this._resizeMarkers[e]._cornerIndex=e},_onMarkerDragStart:function(t){L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,t);var e=this._getCorners(),i=t.target,o=i._cornerIndex;this._oppositeCorner=e[(o+2)%4],this._toggleCornerMarkers(0,o)},_onMarkerDragEnd:function(t){var e,i,o=t.target;o===this._moveMarker&&(e=this._shape.getBounds(),i=e.getCenter(),o.setLatLng(i)),this._toggleCornerMarkers(1),this._repositionCornerMarkers(),L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this,t)},_move:function(t){for(var e,i=this._shape.getLatLngs(),o=this._shape.getBounds(),a=o.getCenter(),s=[],r=0,n=i.length;n>r;r++)e=[i[r].lat-a.lat,i[r].lng-a.lng],s.push([t.lat+e[0],t.lng+e[1]]);this._shape.setLatLngs(s),this._repositionCornerMarkers()},_resize:function(t){var e;this._shape.setBounds(L.latLngBounds(t,this._oppositeCorner)),e=this._shape.getBounds(),this._moveMarker.setLatLng(e.getCenter())},_getCorners:function(){var t=this._shape.getBounds(),e=t.getNorthWest(),i=t.getNorthEast(),o=t.getSouthEast(),a=t.getSouthWest();return[e,i,o,a]},_toggleCornerMarkers:function(t){for(var e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setOpacity(t)},_repositionCornerMarkers:function(){for(var t=this._getCorners(),e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setLatLng(t[e])}}),L.Rectangle.addInitHook(function(){L.Edit.Rectangle&&(this.editing=new L.Edit.Rectangle(this),this.options.editable&&this.editing.enable())}),L.Edit=L.Edit||{},L.Edit.Circle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getLatLng();this._moveMarker=this._createMarker(t,this.options.moveIcon)},_createResizeMarker:function(){var t=this._shape.getLatLng(),e=this._getResizeMarkerPoint(t);this._resizeMarkers=[],this._resizeMarkers.push(this._createMarker(e,this.options.resizeIcon))},_getResizeMarkerPoint:function(t){var e=this._shape._radius*Math.cos(Math.PI/4),i=this._map.project(t);return this._map.unproject([i.x+e,i.y-e])},_move:function(t){var e=this._getResizeMarkerPoint(t);this._resizeMarkers[0].setLatLng(e),this._shape.setLatLng(t)},_resize:function(t){var e=this._moveMarker.getLatLng(),i=e.distanceTo(t);this._shape.setRadius(i)}}),L.Circle.addInitHook(function(){L.Edit.Circle&&(this.editing=new L.Edit.Circle(this),this.options.editable&&this.editing.enable()),this.on(\"add\",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on(\"remove\",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()})}),L.LatLngUtil={cloneLatLngs:function(t){for(var e=[],i=0,o=t.length;o>i;i++)e.push(this.cloneLatLng(t[i]));return e},cloneLatLng:function(t){return L.latLng(t.lat,t.lng)}},L.GeometryUtil={geodesicArea:function(t){var e,i,o=t.length,a=0,s=L.LatLng.DEG_TO_RAD;if(o>2){for(var r=0;o>r;r++)e=t[r],i=t[(r+1)%o],a+=(i.lng-e.lng)*s*(2+Math.sin(e.lat*s)+Math.sin(i.lat*s));a=6378137*6378137*a/2}return Math.abs(a)},readableArea:function(t,e){var i;return e?i=t>=1e4?(1e-4*t).toFixed(2)+\" ha\":t.toFixed(2)+\" m&sup2;\":(t*=.836127,i=t>=3097600?(t/3097600).toFixed(2)+\" mi&sup2;\":t>=4840?(t/4840).toFixed(2)+\" acres\":Math.ceil(t)+\" yd&sup2;\"),i},readableDistance:function(t,e){var i;return e?i=t>1e3?(t/1e3).toFixed(2)+\" km\":Math.ceil(t)+\" m\":(t*=1.09361,i=t>1760?(t/1760).toFixed(2)+\" miles\":Math.ceil(t)+\" yd\"),i}},L.Util.extend(L.LineUtil,{segmentsIntersect:function(t,e,i,o){return this._checkCounterclockwise(t,i,o)!==this._checkCounterclockwise(e,i,o)&&this._checkCounterclockwise(t,e,i)!==this._checkCounterclockwise(t,e,o)},_checkCounterclockwise:function(t,e,i){return(i.y-t.y)*(e.x-t.x)>(e.y-t.y)*(i.x-t.x)}}),L.Polyline.include({intersects:function(){var t,e,i,o=this._originalPoints,a=o?o.length:0;if(this._tooFewPointsForIntersection())return!1;for(t=a-1;t>=3;t--)if(e=o[t-1],i=o[t],this._lineSegmentsIntersectsRange(e,i,t-2))return!0;return!1},newLatLngIntersects:function(t,e){return this._map?this.newPointIntersects(this._map.latLngToLayerPoint(t),e):!1},newPointIntersects:function(t,e){var i=this._originalPoints,o=i?i.length:0,a=i?i[o-1]:null,s=o-2;return this._tooFewPointsForIntersection(1)?!1:this._lineSegmentsIntersectsRange(a,t,s,e?1:0)},_tooFewPointsForIntersection:function(t){var e=this._originalPoints,i=e?e.length:0;return i+=t||0,!this._originalPoints||3>=i},_lineSegmentsIntersectsRange:function(t,e,i,o){var a,s,r=this._originalPoints;o=o||0;for(var n=i;n>o;n--)if(a=r[n-1],s=r[n],L.LineUtil.segmentsIntersect(t,e,a,s))return!0;return!1}}),L.Polygon.include({intersects:function(){var t,e,i,o,a,s=this._originalPoints;return this._tooFewPointsForIntersection()?!1:(t=L.Polyline.prototype.intersects.call(this))?!0:(e=s.length,i=s[0],o=s[e-1],a=e-2,this._lineSegmentsIntersectsRange(o,i,a,1))}}),L.Control.Draw=L.Control.extend({options:{position:\"topleft\",draw:{},edit:!1},initialize:function(t){if(\"0.5.1\">=L.version)throw Error(\"Leaflet.draw 0.2.0+ requires Leaflet 0.6.0+. Download latest from https://github.com/Leaflet/Leaflet/\");L.Control.prototype.initialize.call(this,t);var e,i;this._toolbars={},L.DrawToolbar&&this.options.draw&&(i=new L.DrawToolbar(this.options.draw),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on(\"enable\",this._toolbarEnabled,this)),L.EditToolbar&&this.options.edit&&(i=new L.EditToolbar(this.options.edit),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on(\"enable\",this._toolbarEnabled,this))},onAdd:function(t){var e,i=L.DomUtil.create(\"div\",\"leaflet-draw\"),o=!1,a=\"leaflet-draw-toolbar-top\";for(var s in this._toolbars)this._toolbars.hasOwnProperty(s)&&(e=this._toolbars[s].addToolbar(t),o||(L.DomUtil.hasClass(e,a)||L.DomUtil.addClass(e.childNodes[0],a),o=!0),i.appendChild(e));return i},onRemove:function(){for(var t in this._toolbars)this._toolbars.hasOwnProperty(t)&&this._toolbars[t].removeToolbar()},setDrawingOptions:function(t){for(var e in this._toolbars)this._toolbars[e]instanceof L.DrawToolbar&&this._toolbars[e].setOptions(t)},_toolbarEnabled:function(t){var e=\"\"+L.stamp(t.target);for(var i in this._toolbars)this._toolbars.hasOwnProperty(i)&&i!==e&&this._toolbars[i].disable()}}),L.Map.mergeOptions({drawControlTooltips:!0,drawControl:!1}),L.Map.addInitHook(function(){this.options.drawControl&&(this.drawControl=new L.Control.Draw,this.addControl(this.drawControl))}),L.Toolbar=L.Class.extend({includes:[L.Mixin.Events],initialize:function(t){L.setOptions(this,t),this._modes={},this._actionButtons=[],this._activeMode=null},enabled:function(){return null!==this._activeMode},disable:function(){this.enabled()&&this._activeMode.handler.disable()},removeToolbar:function(){for(var t in this._modes)this._modes.hasOwnProperty(t)&&(this._disposeButton(this._modes[t].button,this._modes[t].handler.enable),this._modes[t].handler.disable(),this._modes[t].handler.off(\"enabled\",this._handlerActivated,this).off(\"disabled\",this._handlerDeactivated,this));this._modes={};for(var e=0,i=this._actionButtons.length;i>e;e++)this._disposeButton(this._actionButtons[e].button,this._actionButtons[e].callback);this._actionButtons=[],this._actionsContainer=null},_initModeHandler:function(t,e,i,o,a){var s=t.type;this._modes[s]={},this._modes[s].handler=t,this._modes[s].button=this._createButton({title:a,className:o+\"-\"+s,container:e,callback:this._modes[s].handler.enable,context:this._modes[s].handler}),this._modes[s].buttonIndex=i,this._modes[s].handler.on(\"enabled\",this._handlerActivated,this).on(\"disabled\",this._handlerDeactivated,this)},_createButton:function(t){var e=L.DomUtil.create(\"a\",t.className||\"\",t.container);return e.href=\"#\",t.text&&(e.innerHTML=t.text),t.title&&(e.title=t.title),L.DomEvent.on(e,\"click\",L.DomEvent.stopPropagation).on(e,\"mousedown\",L.DomEvent.stopPropagation).on(e,\"dblclick\",L.DomEvent.stopPropagation).on(e,\"click\",L.DomEvent.preventDefault).on(e,\"click\",t.callback,t.context),e},_disposeButton:function(t,e){L.DomEvent.off(t,\"click\",L.DomEvent.stopPropagation).off(t,\"mousedown\",L.DomEvent.stopPropagation).off(t,\"dblclick\",L.DomEvent.stopPropagation).off(t,\"click\",L.DomEvent.preventDefault).off(t,\"click\",e)},_handlerActivated:function(t){this._activeMode&&this._activeMode.handler.enabled()&&this._activeMode.handler.disable(),this._activeMode=this._modes[t.handler],L.DomUtil.addClass(this._activeMode.button,\"leaflet-draw-toolbar-button-enabled\"),this._showActionsToolbar(),this.fire(\"enable\")},_handlerDeactivated:function(){this._hideActionsToolbar(),L.DomUtil.removeClass(this._activeMode.button,\"leaflet-draw-toolbar-button-enabled\"),this._activeMode=null,this.fire(\"disable\")},_createActions:function(t){for(var e,i,o=L.DomUtil.create(\"ul\",\"leaflet-draw-actions\"),a=t.length,s=0;a>s;s++)e=L.DomUtil.create(\"li\",\"\",o),i=this._createButton({title:t[s].title,text:t[s].text,container:e,callback:t[s].callback,context:t[s].context}),this._actionButtons.push({button:i,callback:t[s].callback});return o},_showActionsToolbar:function(){var t=this._activeMode.buttonIndex,e=this._lastButtonIndex,i=26,o=1,a=t*i+t*o-1;this._actionsContainer.style.top=a+\"px\",0===t&&(L.DomUtil.addClass(this._toolbarContainer,\"leaflet-draw-toolbar-notop\"),L.DomUtil.addClass(this._actionsContainer,\"leaflet-draw-actions-top\")),t===e&&(L.DomUtil.addClass(this._toolbarContainer,\"leaflet-draw-toolbar-nobottom\"),L.DomUtil.addClass(this._actionsContainer,\"leaflet-draw-actions-bottom\")),this._actionsContainer.style.display=\"block\"},_hideActionsToolbar:function(){this._actionsContainer.style.display=\"none\",L.DomUtil.removeClass(this._toolbarContainer,\"leaflet-draw-toolbar-notop\"),L.DomUtil.removeClass(this._toolbarContainer,\"leaflet-draw-toolbar-nobottom\"),L.DomUtil.removeClass(this._actionsContainer,\"leaflet-draw-actions-top\"),L.DomUtil.removeClass(this._actionsContainer,\"leaflet-draw-actions-bottom\")}}),L.Tooltip=L.Class.extend({initialize:function(t){this._map=t,this._popupPane=t._panes.popupPane,this._container=t.options.drawControlTooltips?L.DomUtil.create(\"div\",\"leaflet-draw-tooltip\",this._popupPane):null,this._singleLineLabel=!1},dispose:function(){this._container&&(this._popupPane.removeChild(this._container),this._container=null)},updateContent:function(t){return this._container?(t.subtext=t.subtext||\"\",0!==t.subtext.length||this._singleLineLabel?t.subtext.length>0&&this._singleLineLabel&&(L.DomUtil.removeClass(this._container,\"leaflet-draw-tooltip-single\"),this._singleLineLabel=!1):(L.DomUtil.addClass(this._container,\"leaflet-draw-tooltip-single\"),this._singleLineLabel=!0),this._container.innerHTML=(t.subtext.length>0?'<span class=\"leaflet-draw-tooltip-subtext\">'+t.subtext+\"</span>\"+\"<br />\":\"\")+\"<span>\"+t.text+\"</span>\",this):this},updatePosition:function(t){var e=this._map.latLngToLayerPoint(t),i=this._container;return this._container&&(i.style.visibility=\"inherit\",L.DomUtil.setPosition(i,e)),this},showAsError:function(){return this._container&&L.DomUtil.addClass(this._container,\"leaflet-error-draw-tooltip\"),this},removeError:function(){return this._container&&L.DomUtil.removeClass(this._container,\"leaflet-error-draw-tooltip\"),this}}),L.DrawToolbar=L.Toolbar.extend({options:{polyline:{},polygon:{},rectangle:{},circle:{},marker:{}},initialize:function(t){for(var e in this.options)this.options.hasOwnProperty(e)&&t[e]&&(t[e]=L.extend({},this.options[e],t[e]));\nL.Toolbar.prototype.initialize.call(this,t)},addToolbar:function(t){var e=L.DomUtil.create(\"div\",\"leaflet-draw-section\"),i=0,o=\"leaflet-draw-draw\";return this._toolbarContainer=L.DomUtil.create(\"div\",\"leaflet-draw-toolbar leaflet-bar\"),this.options.polyline&&this._initModeHandler(new L.Draw.Polyline(t,this.options.polyline),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.polyline),this.options.polygon&&this._initModeHandler(new L.Draw.Polygon(t,this.options.polygon),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.polygon),this.options.rectangle&&this._initModeHandler(new L.Draw.Rectangle(t,this.options.rectangle),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.rectangle),this.options.circle&&this._initModeHandler(new L.Draw.Circle(t,this.options.circle),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.circle),this.options.marker&&this._initModeHandler(new L.Draw.Marker(t,this.options.marker),this._toolbarContainer,i++,o,L.drawLocal.draw.toolbar.buttons.marker),this._lastButtonIndex=--i,this._actionsContainer=this._createActions([{title:L.drawLocal.draw.toolbar.actions.title,text:L.drawLocal.draw.toolbar.actions.text,callback:this.disable,context:this}]),e.appendChild(this._toolbarContainer),e.appendChild(this._actionsContainer),e},setOptions:function(t){L.setOptions(this,t);for(var e in this._modes)this._modes.hasOwnProperty(e)&&t.hasOwnProperty(e)&&this._modes[e].handler.setOptions(t[e])}}),L.EditToolbar=L.Toolbar.extend({options:{edit:{selectedPathOptions:{color:\"#fe57a1\",opacity:.6,dashArray:\"10, 10\",fill:!0,fillColor:\"#fe57a1\",fillOpacity:.1}},remove:{},featureGroup:null},initialize:function(t){t.edit&&(t.edit.selectedPathOptions===undefined&&(t.edit.selectedPathOptions=this.options.edit.selectedPathOptions),t.edit=L.extend({},this.options.edit,t.edit)),t.remove&&(t.remove=L.extend({},this.options.remove,t.remove)),L.Toolbar.prototype.initialize.call(this,t),this._selectedFeatureCount=0},addToolbar:function(t){var e=L.DomUtil.create(\"div\",\"leaflet-draw-section\"),i=0,o=\"leaflet-draw-edit\",a=this.options.featureGroup;return this._toolbarContainer=L.DomUtil.create(\"div\",\"leaflet-draw-toolbar leaflet-bar\"),this._map=t,this.options.edit&&this._initModeHandler(new L.EditToolbar.Edit(t,{featureGroup:a,selectedPathOptions:this.options.edit.selectedPathOptions}),this._toolbarContainer,i++,o,L.drawLocal.edit.toolbar.buttons.edit),this.options.remove&&this._initModeHandler(new L.EditToolbar.Delete(t,{featureGroup:a}),this._toolbarContainer,i++,o,L.drawLocal.edit.toolbar.buttons.remove),this._lastButtonIndex=--i,this._actionsContainer=this._createActions([{title:L.drawLocal.edit.toolbar.actions.save.title,text:L.drawLocal.edit.toolbar.actions.save.text,callback:this._save,context:this},{title:L.drawLocal.edit.toolbar.actions.cancel.title,text:L.drawLocal.edit.toolbar.actions.cancel.text,callback:this.disable,context:this}]),e.appendChild(this._toolbarContainer),e.appendChild(this._actionsContainer),this._checkDisabled(),a.on(\"layeradd layerremove\",this._checkDisabled,this),e},removeToolbar:function(){L.Toolbar.prototype.removeToolbar.call(this),this.options.featureGroup.off(\"layeradd layerremove\",this._checkDisabled,this)},disable:function(){this.enabled()&&(this._activeMode.handler.revertLayers(),L.Toolbar.prototype.disable.call(this))},_save:function(){this._activeMode.handler.save(),this._activeMode.handler.disable()},_checkDisabled:function(){var t,e=this.options.featureGroup,i=0!==e.getLayers().length;this.options.edit&&(t=this._modes[L.EditToolbar.Edit.TYPE].button,i?L.DomUtil.removeClass(t,\"leaflet-disabled\"):L.DomUtil.addClass(t,\"leaflet-disabled\"),t.setAttribute(\"title\",i?L.drawLocal.edit.toolbar.buttons.edit:L.drawLocal.edit.toolbar.buttons.editDisabled)),this.options.remove&&(t=this._modes[L.EditToolbar.Delete.TYPE].button,i?L.DomUtil.removeClass(t,\"leaflet-disabled\"):L.DomUtil.addClass(t,\"leaflet-disabled\"),t.setAttribute(\"title\",i?L.drawLocal.edit.toolbar.buttons.remove:L.drawLocal.edit.toolbar.buttons.removeDisabled))}}),L.EditToolbar.Edit=L.Handler.extend({statics:{TYPE:\"edit\"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),this._selectedPathOptions=e.selectedPathOptions,this._featureGroup=e.featureGroup,!(this._featureGroup instanceof L.FeatureGroup))throw Error(\"options.featureGroup must be a L.FeatureGroup\");this._uneditedLayerProps={},this.type=L.EditToolbar.Edit.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(L.Handler.prototype.enable.call(this),this._featureGroup.on(\"layeradd\",this._enableLayerEdit,this).on(\"layerremove\",this._disableLayerEdit,this),this.fire(\"enabled\",{handler:this.type}),this._map.fire(\"draw:editstart\",{handler:this.type}))},disable:function(){this._enabled&&(this.fire(\"disabled\",{handler:this.type}),this._map.fire(\"draw:editstop\",{handler:this.type}),this._featureGroup.off(\"layeradd\",this._enableLayerEdit,this).off(\"layerremove\",this._disableLayerEdit,this),L.Handler.prototype.disable.call(this))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._featureGroup.eachLayer(this._enableLayerEdit,this),this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.edit.tooltip.text,subtext:L.drawLocal.edit.handlers.edit.tooltip.subtext}),this._map.on(\"mousemove\",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._featureGroup.eachLayer(this._disableLayerEdit,this),this._uneditedLayerProps={},this._tooltip.dispose(),this._tooltip=null,this._map.off(\"mousemove\",this._onMouseMove,this))},revertLayers:function(){this._featureGroup.eachLayer(function(t){this._revertLayer(t)},this)},save:function(){var t=new L.LayerGroup;this._featureGroup.eachLayer(function(e){e.edited&&(t.addLayer(e),e.edited=!1)}),this._map.fire(\"draw:edited\",{layers:t})},_backupLayer:function(t){var e=L.Util.stamp(t);this._uneditedLayerProps[e]||(this._uneditedLayerProps[e]=t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?{latlngs:L.LatLngUtil.cloneLatLngs(t.getLatLngs())}:t instanceof L.Circle?{latlng:L.LatLngUtil.cloneLatLng(t.getLatLng()),radius:t.getRadius()}:{latlng:L.LatLngUtil.cloneLatLng(t.getLatLng())})},_revertLayer:function(t){var e=L.Util.stamp(t);t.edited=!1,this._uneditedLayerProps.hasOwnProperty(e)&&(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?t.setLatLngs(this._uneditedLayerProps[e].latlngs):t instanceof L.Circle?(t.setLatLng(this._uneditedLayerProps[e].latlng),t.setRadius(this._uneditedLayerProps[e].radius)):t.setLatLng(this._uneditedLayerProps[e].latlng))},_toggleMarkerHighlight:function(t){if(t._icon){var e=t._icon;e.style.display=\"none\",L.DomUtil.hasClass(e,\"leaflet-edit-marker-selected\")?(L.DomUtil.removeClass(e,\"leaflet-edit-marker-selected\"),this._offsetMarker(e,-4)):(L.DomUtil.addClass(e,\"leaflet-edit-marker-selected\"),this._offsetMarker(e,4)),e.style.display=\"\"}},_offsetMarker:function(t,e){var i=parseInt(t.style.marginTop,10)-e,o=parseInt(t.style.marginLeft,10)-e;t.style.marginTop=i+\"px\",t.style.marginLeft=o+\"px\"},_enableLayerEdit:function(t){var e,i=t.layer||t.target||t,o=i instanceof L.Marker;(!o||i._icon)&&(this._backupLayer(i),this._selectedPathOptions&&(e=L.Util.extend({},this._selectedPathOptions),o?this._toggleMarkerHighlight(i):(i.options.previousOptions=i.options,i instanceof L.Circle||i instanceof L.Polygon||i instanceof L.Rectangle||(e.fill=!1),i.setStyle(e))),o?(i.dragging.enable(),i.on(\"dragend\",this._onMarkerDragEnd)):i.editing.enable())},_disableLayerEdit:function(t){var e=t.layer||t.target||t;e.edited=!1,this._selectedPathOptions&&(e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.setStyle(e.options.previousOptions),delete e.options.previousOptions)),e instanceof L.Marker?(e.dragging.disable(),e.off(\"dragend\",this._onMarkerDragEnd,this)):e.editing.disable()},_onMarkerDragEnd:function(t){var e=t.target;e.edited=!0},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._featureGroup.getLayers().length}}),L.EditToolbar.Delete=L.Handler.extend({statics:{TYPE:\"remove\"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.Util.setOptions(this,e),this._deletableLayers=this.options.featureGroup,!(this._deletableLayers instanceof L.FeatureGroup))throw Error(\"options.featureGroup must be a L.FeatureGroup\");this.type=L.EditToolbar.Delete.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(L.Handler.prototype.enable.call(this),this._deletableLayers.on(\"layeradd\",this._enableLayerDelete,this).on(\"layerremove\",this._disableLayerDelete,this),this.fire(\"enabled\",{handler:this.type}),this._map.fire(\"draw:editstart\",{handler:this.type}))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this._deletableLayers.off(\"layeradd\",this._enableLayerDelete,this).off(\"layerremove\",this._disableLayerDelete,this),this.fire(\"disabled\",{handler:this.type}),this._map.fire(\"draw:editstop\",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._deletableLayers.eachLayer(this._enableLayerDelete,this),this._deletedLayers=new L.layerGroup,this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.remove.tooltip.text}),this._map.on(\"mousemove\",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._disableLayerDelete,this),this._deletedLayers=null,this._tooltip.dispose(),this._tooltip=null,this._map.off(\"mousemove\",this._onMouseMove,this))},revertLayers:function(){this._deletedLayers.eachLayer(function(t){this._deletableLayers.addLayer(t)},this)},save:function(){this._map.fire(\"draw:deleted\",{layers:this._deletedLayers})},_enableLayerDelete:function(t){var e=t.layer||t.target||t;e.on(\"click\",this._removeLayer,this)},_disableLayerDelete:function(t){var e=t.layer||t.target||t;e.off(\"click\",this._removeLayer,this),this._deletedLayers.removeLayer(e)},_removeLayer:function(t){var e=t.layer||t.target||t;this._deletableLayers.removeLayer(e),this._deletedLayers.addLayer(e)},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._deletableLayers.getLayers().length}})})(this,document);"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/Leaflet.plugins/arc.js",
    "content": "var D2R = Math.PI / 180;\nvar R2D = 180 / Math.PI;\n\nvar Coord = function(lon,lat) {\n    this.lon = lon;\n    this.lat = lat;\n    this.x = D2R * lon;\n    this.y = D2R * lat;\n};\n\nCoord.prototype.view = function() {\n    return String(this.lon).slice(0, 4) + ',' + String(this.lat).slice(0, 4);\n};\n\nCoord.prototype.antipode = function() {\n\n    var anti_lat = -1 * this.lat;\n    if (this.lon < 0) {\n        var anti_lon = 180 + this.lon;\n    } else {\n        var anti_lon = (180 - this.lon) * -1;\n    }\n    return new Coord(anti_lon, anti_lat);\n};\n\nvar LineString = function() {\n    this.coords = [];\n    this.length = 0;\n};\n\nLineString.prototype.move_to = function(coord) {\n    this.length++;\n    this.coords.push(coord);\n};\n\nvar Arc = function(properties) {\n    this.properties = properties || {};\n    this.geometries = []\n};\n\nArc.prototype.json = function() {\n    if (this.geometries.length <= 0) {\n        return {'geometry': { 'type': 'LineString', 'coordinates': null },\n                'type': 'Feature', 'properties': this.properties\n               };\n    } else if (this.geometries.length == 1) {\n        return {'geometry': { 'type': 'LineString', 'coordinates': this.geometries[0].coords },\n                'type': 'Feature', 'properties': this.properties\n               };\n    } else {\n        var multiline = []\n        for (i = 0; i < this.geometries.length; i++) {\n            multiline.push(this.geometries[i].coords);\n        }\n        return {'geometry': { 'type': 'MultiLineString', 'coordinates': multiline },\n                'type': 'Feature', 'properties': this.properties\n               };\n    }\n};\n\n// TODO - output proper multilinestring\nArc.prototype.wkt = function() {\n    var wkt_string = '';\n    for (i = 0; i < this.geometries.length; i++) {\n        if (this.geometries[i].coords.length === 0) {\n            return 'LINESTRING(empty)';\n        } else {\n            var wkt = 'LINESTRING(';\n            this.geometries[i].coords.forEach(function(c,idx) {\n                wkt += c[0] + ' ' + c[1] + ',';\n            });\n            wkt_string += wkt.substring(0, wkt.length - 1) + ')';\n        }\n    }\n    return wkt_string;\n};\n\n/*\n * http://en.wikipedia.org/wiki/Great-circle_distance\n *\n */\nvar GreatCircle = function(start,end,properties) {\n\n    this.start = start;\n    this.end = end;\n    this.properties = properties || {};\n\n    var w = this.start.x - this.end.x;\n    var h = this.start.y - this.end.y;\n    var z = Math.pow(Math.sin(h / 2.0), 2) +\n                Math.cos(this.start.y) *\n                   Math.cos(this.end.y) *\n                     Math.pow(Math.sin(w / 2.0), 2);\n    this.g = 2.0 * Math.asin(Math.sqrt(z));\n\n    if (this.g == Math.PI) {\n        throw new Error('it appears ' + start.view() + ' and ' + end.view() + \" are 'antipodal', e.g diametrically opposite, thus there is no single route but rather infinite\");\n    } else if (isNaN(this.g)) {\n        throw new Error('could not calculate great circle between ' + start + ' and ' + end);\n    }\n};\n\n/*\n * http://williams.best.vwh.net/avform.htm#Intermediate\n */\nGreatCircle.prototype.interpolate = function(f) {\n    var A = Math.sin((1 - f) * this.g) / Math.sin(this.g);\n    var B = Math.sin(f * this.g) / Math.sin(this.g);\n    var x = A * Math.cos(this.start.y) * Math.cos(this.start.x) + B * Math.cos(this.end.y) * Math.cos(this.end.x);\n    var y = A * Math.cos(this.start.y) * Math.sin(this.start.x) + B * Math.cos(this.end.y) * Math.sin(this.end.x);\n    var z = A * Math.sin(this.start.y) + B * Math.sin(this.end.y);\n    var lat = R2D * Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));\n    var lon = R2D * Math.atan2(y, x);\n    return [lon, lat];\n};\n\n\n\n/*\n * Generate points along the great circle\n */\nGreatCircle.prototype.Arc = function(npoints,options) {\n    var first_pass = [];\n    //var minx = 0;\n    //var maxx = 0;\n    if (npoints <= 2) {\n        first_pass.push([this.start.lon, this.start.lat]);\n        first_pass.push([this.end.lon, this.end.lat]);\n    } else {\n        var delta = 1.0 / (npoints - 1);\n        for (var i = 0; i < npoints; i++) {\n            var step = delta * i;\n            var pair = this.interpolate(step);\n            //minx = Math.min(minx,pair[0]);\n            //maxx = Math.max(maxx,pair[0]);\n            first_pass.push(pair);\n        }\n    }\n    /* partial port of dateline handling from:\n      gdal/ogr/ogrgeometryfactory.cpp\n\n      TODO - does not handle all wrapping scenarios yet\n    */\n    var bHasBigDiff = false;\n    var dfMaxSmallDiffLong = 0;\n    for (var i = 1; i < first_pass.length; i++) {\n        //if (minx > 170 && maxx > 180) {\n        // }\n        var dfPrevX = first_pass[i-1][0];\n        var dfX = first_pass[i][0];\n        var dfDiffLong = Math.abs(dfX - dfPrevX);\n        if (dfDiffLong > 350 &&\n            ((dfX > 170 && dfPrevX < -170) || (dfPrevX > 170 && dfX < -170))) {\n            bHasBigDiff = true;\n        } else if (dfDiffLong > dfMaxSmallDiffLong) {\n            dfMaxSmallDiffLong = dfDiffLong;\n        }\n    }\n\n    var poMulti = []\n\n    if (bHasBigDiff && dfMaxSmallDiffLong < 10) {\n        var poNewLS = []\n        poMulti.push(poNewLS);\n        for (var i = 0; i < first_pass.length; i++) {\n            var dfX = parseFloat(first_pass[i][0]);\n            if (i > 0 &&  Math.abs(dfX - first_pass[i-1][0]) > 350) {\n                var dfX1 = parseFloat(first_pass[i-1][0]);\n                var dfY1 = parseFloat(first_pass[i-1][1]);\n                var dfX2 = parseFloat(first_pass[i][0]);\n                var dfY2 = parseFloat(first_pass[i][1]);\n                if (dfX1 > -180 && dfX1 < -170 && dfX2 == 180 &&\n                    i+1 < first_pass.length &&\n                   first_pass[i-1][0] > -180 && first_pass[i-1][0] < -170)\n                {\n                     poNewLS.push([-180, first_pass[i][1]]);\n                     i++;\n                     poNewLS.push([first_pass[i][0], first_pass[i][1]]);\n                     continue;\n                } else if (dfX1 > 170 && dfX1 < 180 && dfX2 == -180 &&\n                     i+1 < first_pass.length &&\n                     first_pass[i-1][0] > 170 && first_pass[i-1][0] < 180)\n                {\n                     poNewLS.push([180, first_pass[i][1]]);\n                     i++;\n                     poNewLS.push([first_pass[i][0], first_pass[i][1]]);\n                     continue;\n                }\n\n                if (dfX1 < -170 && dfX2 > 170)\n                {\n                    // swap dfX1, dfX2\n                    var tmpX = dfX1;\n                    dfX1 = dfX2;\n                    dfX2 = tmpX;\n                    // swap dfY1, dfY2\n                    var tmpY = dfY1;\n                    dfY1 = dfY2;\n                    dfY2 = tmpY;\n                }\n                if (dfX1 > 170 && dfX2 < -170) {\n                    dfX2 += 360;\n                }\n\n                if (dfX1 <= 180 && dfX2 >= 180 && dfX1 < dfX2)\n                {\n                    var dfRatio = (180 - dfX1) / (dfX2 - dfX1);\n                    var dfY = dfRatio * dfY2 + (1 - dfRatio) * dfY1;\n                    poNewLS.push([first_pass[i-1][0] > 170 ? 180 : -180, dfY]);\n                    poNewLS = [];\n                    poNewLS.push([first_pass[i-1][0] > 170 ? -180 : 180, dfY]);\n                    poMulti.push(poNewLS);\n                }\n                else\n                {\n                    poNewLS = [];\n                    poMulti.push(poNewLS);\n                }\n                poNewLS.push([dfX, first_pass[i][1]]);\n            } else {\n                poNewLS.push([first_pass[i][0], first_pass[i][1]]);\n            }\n        }\n    } else {\n       // add normally\n        var poNewLS = []\n        poMulti.push(poNewLS);\n        for (var i = 0; i < first_pass.length; i++) {\n            poNewLS.push([first_pass[i][0],first_pass[i][1]]);\n        }\n    }\n\n    var arc = new Arc(this.properties);\n    for (var i = 0; i < poMulti.length; i++) {\n        var line = new LineString();\n        arc.geometries.push(line);\n        var points = poMulti[i];\n        for (var j = 0; j < points.length; j++) {\n            line.move_to(points[j]);\n        }\n    }\n    return arc;\n};\n\nif (typeof window === 'undefined') {\n  // nodejs\n  module.exports.Coord = Coord;\n  module.exports.Arc = Arc;\n  module.exports.GreatCircle = GreatCircle;\n\n} else {\n  // browser\n  var arc = {};\n  arc.Coord = Coord;\n  arc.Arc = Arc;\n  arc.GreatCircle = GreatCircle;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/README.md",
    "content": "# arc.js\n\nCalculate great circles routes.\n\nAlgorithms from http://williams.best.vwh.net/avform.htm#Intermediate\n\n\n# Installation\n\nFor NodeJS usage, install with npm:\n\n    npm install -g\n\n\n# Usage\n\nThe idea is you may have one or many start and end points.\n\nCreate Coordinate pairs from the longitude (x) and latitude (y) values\nof each place and pass these (and optionally a properties object), to the GreatCircle\nconstructor:\n \n    var arc = require('arc');\n    var start = new arc.Coord(-122, 48);\n    var end = new arc.Coord(-77, 39);\n    var gc = new arc.GreatCircle(start, end, {'name': 'Seattle to DC'});\n    var line = gc.Arc(6);\n\nThen `line` will be a raw sequence of the start and end coordinates plus an arc of\nintermediate coordinate pairs.\n\n    > line\n    { properties: { name: 'Seattle to DC' },\n      coords: \n       [ [ -122, 48.00000000000001 ],\n         [ -112.06161978373486, 47.7241672604096 ],\n         [ -102.38404317022653, 46.60813199882492 ],\n         [ -93.22718895342909, 44.716217302635705 ],\n         [ -84.74823988299501, 42.14415510795357 ],\n         [ -77, 38.99999999999999 ] ],\n      length: 6 }\n\n\nYou can then serialize to a GeoJSON geometry format:\n\n    > line.json();\n    { geometry: \n       { type: 'LineString',\n         coordinates: [ [Object], [Object], [Object], [Object], [Object], [Object] ] },\n      type: 'Feature',\n      properties: { name: 'Seattle to DC' } }\n    \nOr to WKT (Well known text):\n\n    > line.wkt();\n    'LINESTRING(-122 48.00000000000001,-112.06161978373486 47.7241672604096,-102.38404317022653 46.60813199882492,-93.22718895342909 44.716217302635705,-84.74823988299501 42.14415510795357,-77 38.99999999999999)'\n    \nIt is then up to you to add up these features to create fully fledged geodata. See the examples/ directory\nfor sample code to create a GeoJSON file from multiple routes.\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/arc.js",
    "content": "var D2R = Math.PI / 180;\nvar R2D = 180 / Math.PI;\n\nvar Coord = function(lon,lat) {\n    this.lon = lon;\n    this.lat = lat;\n    this.x = D2R * lon;\n    this.y = D2R * lat;\n};\n\nCoord.prototype.view = function() {\n    return String(this.lon).slice(0, 4) + ',' + String(this.lat).slice(0, 4);\n};\n\nCoord.prototype.antipode = function() {\n\n    var anti_lat = -1 * this.lat;\n    if (this.lon < 0) {\n        var anti_lon = 180 + this.lon;\n    } else {\n        var anti_lon = (180 - this.lon) * -1;\n    }\n    return new Coord(anti_lon, anti_lat);\n};\n\nvar LineString = function() {\n    this.coords = [];\n    this.length = 0;\n};\n\nLineString.prototype.move_to = function(coord) {\n    this.length++;\n    this.coords.push(coord);\n};\n\nvar Arc = function(properties) {\n    this.properties = properties || {};\n    this.geometries = []\n};\n\nArc.prototype.json = function() {\n    if (this.geometries.length <= 0) {\n        return {'geometry': { 'type': 'LineString', 'coordinates': null },\n                'type': 'Feature', 'properties': this.properties\n               };\n    } else if (this.geometries.length == 1) {\n        return {'geometry': { 'type': 'LineString', 'coordinates': this.geometries[0].coords },\n                'type': 'Feature', 'properties': this.properties\n               };\n    } else {\n        var multiline = []\n        for (i = 0; i < this.geometries.length; i++) {\n            multiline.push(this.geometries[i].coords);\n        }\n        return {'geometry': { 'type': 'MultiLineString', 'coordinates': multiline },\n                'type': 'Feature', 'properties': this.properties\n               };\n    }\n};\n\n// TODO - output proper multilinestring\nArc.prototype.wkt = function() {\n    var wkt_string = '';\n    for (i = 0; i < this.geometries.length; i++) {\n        if (this.geometries[i].coords.length === 0) {\n            return 'LINESTRING(empty)';\n        } else {\n            var wkt = 'LINESTRING(';\n            this.geometries[i].coords.forEach(function(c,idx) {\n                wkt += c[0] + ' ' + c[1] + ',';\n            });\n            wkt_string += wkt.substring(0, wkt.length - 1) + ')';\n        }\n    }\n    return wkt_string;\n};\n\n/*\n * http://en.wikipedia.org/wiki/Great-circle_distance\n *\n */\nvar GreatCircle = function(start,end,properties) {\n\n    this.start = start;\n    this.end = end;\n    this.properties = properties || {};\n\n    var w = this.start.x - this.end.x;\n    var h = this.start.y - this.end.y;\n    var z = Math.pow(Math.sin(h / 2.0), 2) +\n                Math.cos(this.start.y) *\n                   Math.cos(this.end.y) *\n                     Math.pow(Math.sin(w / 2.0), 2);\n    this.g = 2.0 * Math.asin(Math.sqrt(z));\n\n    if (this.g == Math.PI) {\n        throw new Error('it appears ' + start.view() + ' and ' + end.view() + \" are 'antipodal', e.g diametrically opposite, thus there is no single route but rather infinite\");\n    } else if (isNaN(this.g)) {\n        throw new Error('could not calculate great circle between ' + start + ' and ' + end);\n    }\n};\n\n/*\n * http://williams.best.vwh.net/avform.htm#Intermediate\n */\nGreatCircle.prototype.interpolate = function(f) {\n    var A = Math.sin((1 - f) * this.g) / Math.sin(this.g);\n    var B = Math.sin(f * this.g) / Math.sin(this.g);\n    var x = A * Math.cos(this.start.y) * Math.cos(this.start.x) + B * Math.cos(this.end.y) * Math.cos(this.end.x);\n    var y = A * Math.cos(this.start.y) * Math.sin(this.start.x) + B * Math.cos(this.end.y) * Math.sin(this.end.x);\n    var z = A * Math.sin(this.start.y) + B * Math.sin(this.end.y);\n    var lat = R2D * Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));\n    var lon = R2D * Math.atan2(y, x);\n    return [lon, lat];\n};\n\n\n\n/*\n * Generate points along the great circle\n */\nGreatCircle.prototype.Arc = function(npoints,options) {\n    var first_pass = [];\n    //var minx = 0;\n    //var maxx = 0;\n    if (npoints <= 2) {\n        first_pass.push([this.start.lon, this.start.lat]);\n        first_pass.push([this.end.lon, this.end.lat]);\n    } else {\n        var delta = 1.0 / (npoints - 1);\n        for (var i = 0; i < npoints; i++) {\n            var step = delta * i;\n            var pair = this.interpolate(step);\n            //minx = Math.min(minx,pair[0]);\n            //maxx = Math.max(maxx,pair[0]);\n            first_pass.push(pair);\n        }\n    }\n    /* partial port of dateline handling from:\n      gdal/ogr/ogrgeometryfactory.cpp\n\n      TODO - does not handle all wrapping scenarios yet\n    */\n    var bHasBigDiff = false;\n    var dfMaxSmallDiffLong = 0;\n    for (var i = 1; i < first_pass.length; i++) {\n        //if (minx > 170 && maxx > 180) {\n        // }\n        var dfPrevX = first_pass[i-1][0];\n        var dfX = first_pass[i][0];\n        var dfDiffLong = Math.abs(dfX - dfPrevX);\n        if (dfDiffLong > 350 &&\n            ((dfX > 170 && dfPrevX < -170) || (dfPrevX > 170 && dfX < -170))) {\n            bHasBigDiff = true;\n        } else if (dfDiffLong > dfMaxSmallDiffLong) {\n            dfMaxSmallDiffLong = dfDiffLong;\n        }\n    }\n\n    var poMulti = []\n\n    if (bHasBigDiff && dfMaxSmallDiffLong < 10) {\n        var poNewLS = []\n        poMulti.push(poNewLS);\n        for (var i = 0; i < first_pass.length; i++) {\n            var dfX = parseFloat(first_pass[i][0]);\n            if (i > 0 &&  Math.abs(dfX - first_pass[i-1][0]) > 350) {\n                var dfX1 = parseFloat(first_pass[i-1][0]);\n                var dfY1 = parseFloat(first_pass[i-1][1]);\n                var dfX2 = parseFloat(first_pass[i][0]);\n                var dfY2 = parseFloat(first_pass[i][1]);\n                if (dfX1 > -180 && dfX1 < -170 && dfX2 == 180 &&\n                    i+1 < first_pass.length &&\n                   first_pass[i-1][0] > -180 && first_pass[i-1][0] < -170)\n                {\n                     poNewLS.push([-180, first_pass[i][1]]);\n                     i++;\n                     poNewLS.push([first_pass[i][0], first_pass[i][1]]);\n                     continue;\n                } else if (dfX1 > 170 && dfX1 < 180 && dfX2 == -180 &&\n                     i+1 < first_pass.length &&\n                     first_pass[i-1][0] > 170 && first_pass[i-1][0] < 180)\n                {\n                     poNewLS.push([180, first_pass[i][1]]);\n                     i++;\n                     poNewLS.push([first_pass[i][0], first_pass[i][1]]);\n                     continue;\n                }\n\n                if (dfX1 < -170 && dfX2 > 170)\n                {\n                    // swap dfX1, dfX2\n                    var tmpX = dfX1;\n                    dfX1 = dfX2;\n                    dfX2 = tmpX;\n                    // swap dfY1, dfY2\n                    var tmpY = dfY1;\n                    dfY1 = dfY2;\n                    dfY2 = tmpY;\n                }\n                if (dfX1 > 170 && dfX2 < -170) {\n                    dfX2 += 360;\n                }\n\n                if (dfX1 <= 180 && dfX2 >= 180 && dfX1 < dfX2)\n                {\n                    var dfRatio = (180 - dfX1) / (dfX2 - dfX1);\n                    var dfY = dfRatio * dfY2 + (1 - dfRatio) * dfY1;\n                    poNewLS.push([first_pass[i-1][0] > 170 ? 180 : -180, dfY]);\n                    poNewLS = [];\n                    poNewLS.push([first_pass[i-1][0] > 170 ? -180 : 180, dfY]);\n                    poMulti.push(poNewLS);\n                }\n                else\n                {\n                    poNewLS = [];\n                    poMulti.push(poNewLS);\n                }\n                poNewLS.push([dfX, first_pass[i][1]]);\n            } else {\n                poNewLS.push([first_pass[i][0], first_pass[i][1]]);\n            }\n        }\n    } else {\n       // add normally\n        var poNewLS = [];\n        poMulti.push(poNewLS);\n        for (var i = 0; i < first_pass.length; i++) {\n            poNewLS.push([first_pass[i][0],first_pass[i][1]]);\n        }\n    }\n\n    var arc = new Arc(this.properties);\n    for (var i = 0; i < poMulti.length; i++) {\n        var line = new LineString();\n        arc.geometries.push(line);\n        var points = poMulti[i];\n        for (var j = 0; j < points.length; j++) {\n            line.move_to(points[j]);\n        }\n    }\n    return arc;\n};\n\nif (typeof window === 'undefined') {\n  // nodejs\n  module.exports.Coord = Coord;\n  module.exports.Arc = Arc;\n  module.exports.GreatCircle = GreatCircle;\n\n} else {\n  // browser\n  var arc = {};\n  arc.Coord = Coord;\n  arc.Arc = Arc;\n  arc.GreatCircle = GreatCircle;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/bezier.geojson",
    "content": "{\n  \"type\": \"FeatureCollection\",\n  \"features\": [\n  {\n    \"type\": \"Feature\",\n    \"properties\": { },\n    \"geometry\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [ [ -77.032660, 38.913245 ], [ 77.032660, 38.913245 ] ]\n    }\n  },\n  {\n    \"type\": \"Feature\",\n    \"properties\": { },\n    \"geometry\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [ [ -77.032660, 38.913245 ], [ 77.032660, 38.913245 ] ]\n    }\n  },\n  {\n    \"type\": \"Feature\",\n    \"properties\": { },\n    \"geometry\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [ [ -77.032660, 38.913245 ], [ 77.032660, 38.913245 ] ]\n    }\n  },\n  {\n    \"type\": \"Feature\",\n    \"properties\": { },\n    \"geometry\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [ [ -77.032660, 38.913245 ], [ 77.032660, 38.913245 ] ]\n    }\n  },\n  {\n    \"type\": \"Feature\",\n    \"properties\": { },\n    \"geometry\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [ [ -77.032660, 38.913245 ], [ 77.032660, 38.913245 ] ]\n    }\n  },\n  {\n    \"type\": \"Feature\",\n    \"properties\": { },\n    \"geometry\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [ [ -77.032660, 38.913245 ], [ 77.032660, 38.913245 ] ]\n    }\n  },\n  {\n    \"type\": \"Feature\",\n    \"properties\": { },\n    \"geometry\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [ [ -77.032660, 50.913245 ], [ 0, 20.913245 ] ]\n    }\n  },\n  {\n    \"type\": \"Feature\",\n    \"properties\": { },\n    \"geometry\": {\n      \"type\": \"LineString\",\n      \"coordinates\": [ [ -77.032660, 50.913245 ], [ 0, 20.913245 ] ]\n    }\n  }\n  ]\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/bezier.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>Draw Great Circle Arcs with Leaflet</title>\n    <meta charset=\"utf-8\" />\n    <script src='polymaps.js'></script>\n    <script src='sphericalmercator.js'></script>\n    <script src='bezier.js'></script>\n    <style>\n      path {\n        stroke:#2fa;\n        fill:transparent;\n      }\n      body {\n        margin:40px auto;\n        width:800px;\n        font:14px/20px 'Helvetica';\n      }\n    </style>\n</head>\n<body>\n    <div style=\"padding:20px;\">\n      <p><a href=\"https://github.com/springmeyer/arc.js\">source code on github</a></p>\n    <div id=\"map\" style=\"width: 800px; height: 600px\"></div>\n    <input type='range' id='spread' min=0 max=7000000 />\n    spread - the amount that control points are spread around origins\n    <br />\n    <input type='range' id='rotate' min=0 max=314 />\n    rotate - the amount each exit point rotates around the origin\n    <br />\n    input\n    <textarea id='input'></textarea>\n    <br />\n    output\n    <textarea id='output'></textarea>\n    <button id='load_from_input'>load from input</button>\n    </div>\n    <script>\n      var po = org.polymaps;\n\n      var map = po.map()\n          .container(document.getElementById(\"map\").appendChild(po.svg(\"svg\")))\n          .zoomRange([0, 9])\n          .zoom(3)\n          .center({ lat: 0, lon: 0 })\n          .add(po.image().url(\"http://c.tiles.mapbox.com/v3/tmcw.map-cx8atc2i/{Z}/{X}/{Y}.png\"))\n          .add(po.interact());\n\n      var lines = po.geoJson();\n\n      map.add(lines);\n\n      function interpolate_rotate(coordinates, rotate, spread) {\n        var angle = rotate + Math.atan2(\n          coordinates[0][1] - coordinates[0][1],\n          coordinates[1][1] - coordinates[1][1]);\n        var addone = [\n          spread * Math.cos(angle) + coordinates[0][0],\n          spread * Math.sin(angle) + coordinates[0][1]];\n        var addtwo = [\n          spread * Math.cos(-angle + Math.PI) + coordinates[1][0],\n          spread * Math.sin(-angle + Math.PI) + coordinates[1][1]];\n        return [\n          coordinates[0],\n          addone,\n          addtwo,\n          coordinates[1]];\n      }\n\n      var espread = document.getElementById('spread');\n      var erotate = document.getElementById('rotate');\n      var eload = document.getElementById('load_from_input');\n      var einput = document.getElementById('input');\n      var eoutput = document.getElementById('output');\n\n      po.queue.json('bezier.geojson', function(gj) {\n        bindgj(gj);\n      });\n\n      var sm = new SphericalMercator();\n\n      function bindgj(gj) {\n        var overlaps = {};\n        for (var i = 0; i < gj.features.length; i++) {\n          var count = 0;\n          if (overlaps[gj.features[i].geometry.coordinates.join(',')] === undefined) {\n            count = overlaps[gj.features[i].geometry.coordinates.join(',')] = 0;\n          } else {\n            count = ++overlaps[gj.features[i].geometry.coordinates.join(',')];\n          }\n          gj.features[i]._idx = gj.features[i].geometry.coordinates.join(',');\n          gj.features[i]._count = count;\n        }\n\n        refeature = function() {\n          var spread = espread.value;\n          var rotate = erotate.value / 100;\n          var feat = gj.features.map(function(x) {\n            var f = {\n              'type': 'Feature',\n              'geometry': {\n                'type': 'LineString',\n                'coordinates': x.geometry.coordinates.slice()\n              }\n            };\n\n            for (var i = 0; i < f.geometry.coordinates.length; i++) {\n              f.geometry.coordinates[i] = sm.forward(f.geometry.coordinates[i]);\n            }\n\n            if (x._count) {\n              var turn = Math.ceil(x._count / 2) * ((x._count % 2) ? 1 : -1)\n                / (overlaps[x._idx] / 2);\n              f.geometry.coordinates = interpolate_rotate(f.geometry.coordinates, turn * rotate, spread);\n              f.geometry.coordinates = bezier(f.geometry.coordinates);\n            } else {\n              f.geometry.coordinates = f.geometry.coordinates;\n            }\n\n            for (var i = 0; i < f.geometry.coordinates.length; i++) {\n              f.geometry.coordinates[i] = sm.inverse(f.geometry.coordinates[i]);\n            }\n            return f;\n          });\n          lines.features(feat);\n          eoutput.value = JSON.stringify({type: 'FeatureCollection', features: feat });\n        }\n        espread.onchange = refeature;\n        erotate.onchange = refeature;\n        refeature();\n      }\n\n      eload.onclick = function() {\n        var gj = JSON.parse(einput.value);\n        bindgj(gj);\n      }\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/bezier.js",
    "content": "function bezier(pts) {\n    function curve(points) {\n        var c = [];\n        var steps = 40;\n\n        for (var i = 0; i <= steps; i++) {\n            var t = i / steps;\n\n            var pt = [\n                Math.pow(1 - t, 3) * points[0][0]\n                 + 3 * t * Math.pow(1 - t, 2) * points[1][0]\n                 + 3 * (1 - t) * Math.pow(t, 2) * points[2][0]\n                 + Math.pow(t, 3) * points[3][0],\n                Math.pow(1 - t, 3) * points[0][1]\n                 + 3 * t * Math.pow(1-t,2) * points[1][1]\n                 + 3 * (1-t) * Math.pow(t,2) * points[2][1]\n                 + Math.pow(t, 3) * points[3][1]\n            ];\n            c.push(pt);\n        }\n        return c;\n    }\n\n    var c = [];\n\n    if (pts.length < 4) return pts;\n\n    for (var i = 0; i < pts.length; i += 3) {\n        if (i + 4 <= pts.length) {\n            c = c.concat(curve(pts.slice(i, i + 4)));\n        }\n    }\n\n    return c;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/bezier.py",
    "content": "from PIL import Image\nimport math\n\n# http://stackoverflow.com/questions/3515909/question-about-the-implementation-of-bezier-curves\n\n#   draws a single point on our image\ndef drawPoint( img, loc, size=5, color=(0,0,0) ):\n    px = img.load()\n    for x in range(size):\n        for y in range(size):\n            xloc = loc[0] + x - size/2\n            yloc = loc[1] + y - size/2\n            px[ xloc, yloc ] = color\n\n\n#   draws a simple bezier curve with 4 points\ndef drawCurve( img, points ):\n\n    steps = 20\n    for i in range(steps):\n\n        t = i / float(steps)\n\n        xloc = math.pow(1-t,3) * points[0][0] \\\n             + 3*t*math.pow(1-t,2) * points[1][0] \\\n             + 3*(1-t)*math.pow(t,2) * points[2][0] \\\n             + math.pow(t,3) * points[3][0]\n        yloc = math.pow(1-t,3) * points[0][1] \\\n             + 3*t*math.pow(1-t,2) * points[1][1] \\\n             + 3*(1-t)*math.pow(t,2) * points[2][1] \\\n             + math.pow(t,3) * points[3][1]\n\n        drawPoint( img, (xloc,yloc), size=2 )\n\n\n#   draws a bezier curve with any number of points\ndef drawBezier( img, points ):\n\n    for i in range(0,len(points),3):\n        if( i+4 < len(points) ):\n            drawCurve( img, points[i:i+4] )\n\n\n#   draws a smooth bezier curve by adding points that\n#   force smoothness\ndef drawSmoothBezier( img, points ):\n\n    newpoints = []\n\n    for i in range(len(points)):\n\n        # add the next point (and draw it)\n        newpoints.append(points[i])\n        drawPoint( img, points[i], color=(255,0,0) )\n\n        if( i % 2 == 0 and i>0 and i+1<len(points) ):\n\n            # calculate the midpoint\n            xloc = (points[i][0] + points[i+1][0]) / 2.0\n            yloc = (points[i][1] + points[i+1][1]) / 2.0\n\n            # add the new point (and draw it)\n            newpoints.append( (xloc, yloc) )\n            drawPoint( img, (xloc, yloc), color=(0,255,0) )\n\n    drawBezier( img, newpoints )\n\n\n\n#   Create the image\nmyImage = Image.new(\"RGB\",(627,271),(255,255,255))\n\n#   Create the points\npoints = [  (54,172),\n            (121,60),\n            (220,204),\n            (284,56),\n            (376,159),\n            (444,40),\n            (515,228),\n            (595,72) ]\n\n#   Draw the curve\ndrawSmoothBezier( myImage, points )\n\n#   Save the image\nmyImage.save(\"myfile.png\",\"PNG\")\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/example/csv2arc.js",
    "content": "#!/usr/bin/env node\n\n/*\n\nSample code to parse a pre-formatted csv file into\na GeoJSON feature collection.\n\nThis script is intended as a starting point only.\n\nYou will need to modify depending on your csv format.\n\n*/\n\nvar arc = require('arc');\nvar fs = require('fs');\nvar path = require('path');\n\nvar features = [];\nvar geojson = { 'type': 'FeatureCollection',\n                'features': features\n              };\n\n// helper to check if a string value\n// likely should be converted to a number\n// http://stackoverflow.com/questions/1303646/check-variable-whether-is-number-or-string-in-javascript\nfunction isNumber(o) {\n  return ! isNaN (o-0);\n}\n\n// path to csv file\nvar csv_file = 'example/routes.csv';\n\n// csv delimiter used between values\nvar dl = ',';\n\n// line break character - unix\nvar lb = '\\n';\n\n// open file as buffer\nvar csv_data = fs.readFileSync(csv_file);\n\n// read as string\nvar csv_string = csv_data.toString();\n\n// break string at each line\nvar csv_rows = csv_string.split(lb);\n\n// extract and split headers\nvar csv_headers = csv_rows[0].split(dl);\n\n// assume properties names are header 5 and above\nvar csv_properties_names = csv_headers.slice(4);\n\n// all lines of data, excluding header row\nvar csv_lines = csv_rows.slice(-3);\n\n// loop over every row\ncsv_lines.forEach(function(row,idx) {\n    // split all values in the row into an array\n    var values = row.split(dl);\n    \n    /* handle geometry data first */\n    \n    // assume first 4 values are coordinate pairs\n    var coords = values.slice(0,4);\n    \n    // convert each by trimming string and converting to a number\n    var start_x = parseFloat(coords[0].trim());  // first longitude\n    var start_y = parseFloat(coords[1].trim());  // first latitude\n    var end_x = parseFloat(coords[2].trim());    // second longitude\n    var end_y = parseFloat(coords[3].trim());    // second latitude\n    \n    // now create special arc Coordinate objects from the start and end pairs\n    var start = new arc.Coord(start_x, start_y);\n    var end = new arc.Coord(end_x, end_y);\n\n\n    /* handle properties (csv attributes) second */\n\n    // assume all values from 5 on are attributes\n    var attributes = values.slice(4);\n\n    // create a json object to push the attributes into\n    var properties = {}\n    \n    // loop over column header names for the attributes\n    // adding them to the properties object\n    csv_properties_names.forEach(function(name,idx) {\n        var att_value = attributes[idx].trim();\n\n        if (isNumber(att_value)) {\n            // if int\n            if (parseInt(att_value) == parseFloat(att_value)) {\n               att_value = parseInt(att_value);\n            } else {\n            // likely a float\n               att_value = parseFloat(att_value);\n            }\n        } else {\n            // if it is a quoted string, strip quotes\n            var f = att_value.charAt(0);\n            var l = att_value.charAt(-0);\n            if ((f == \"\\\"\" && l == \"\\\"\") || (f == \"\\'\" && l == \"\\'\")) {\n               att_value = att_value.slice(1,-1).trim();\n            }        \n        }\n        properties[name.trim()] = att_value;\n    });\n    \n    // now actually form up the GreatCircle object\n    var gc = new arc.GreatCircle(start, end, properties);\n\n    // build out a linestring with 10 intermediate points\n    var line = gc.Arc(10);\n    \n    // add this line to the json features\n    features.push(line.json());\n});\n\n// print out the full geojson before leaving script\nconsole.log(JSON.stringify(geojson));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/example/round.js",
    "content": "// Round GeoJSON lines file.\n\nvar fs = require('fs'),\n    arc = require('../arc');\n\nvar geojson = JSON.parse(fs.readFileSync('tracks.geojson', 'utf-8'));\n\nvar tolerance = 1;\n\nfor (var i = 0; i < geojson.features.length; i++) {\n    if (geojson.features[i].geometry.type == 'LineString') {\n        for (var j = 0; j < geojson.features[i].geometry.coordinates.length - 1; j++) {\n            var a = geojson.features[i].geometry.coordinates[j],\n                b = geojson.features[i].geometry.coordinates[j + 1];\n            var dist = Math.sqrt(\n                Math.abs(a[0] - b[0]) *\n                Math.abs(a[1] - b[1]));\n            if (dist > tolerance) {\n                var gc = new arc.GreatCircle(\n                    new arc.Coord(a[0], a[1]),\n                    new arc.Coord(b[0], b[1]));\n                var line = gc.Arc(10);\n                geojson.features[i].geometry.coordinates[j].arc = line.coords;\n            }\n        }\n        var co = [];\n        for (var k = geojson.features[i].geometry.coordinates.length - 1; k >= 0; k--) {\n            if (geojson.features[i].geometry.coordinates[k].arc) {\n                co = geojson.features[i].geometry.coordinates[k].arc.concat(co);\n            } else {\n                co.unshift(geojson.features[i].geometry.coordinates[k]);\n            }\n        }\n        geojson.features[i].geometry.coordinates = co;\n    }\n}\n\nfs.writeFileSync('tracks_round.geojson', JSON.stringify(geojson));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/example/routes.csv",
    "content": "lon1, lat1, lon2, lat2, name,                other attribute\n-122, 48,   -77,  39,   \"Seattle to DC\",      1.0\n-122, 48,   0,    51,   \"Seattle to London\",  2\n-77,  39,   0,    51,   \"DC to London\",       3.1"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/example/tracks.geojson",
    "content": "{\n\"type\": \"FeatureCollection\",\n\"features\": [\n{ \"type\": \"Feature\", \"properties\": { \"name\": \"TrackMe export\", \"cmt\": \"\", \"desc\": \"\", \"src\": \"\", \"link1_href\": \"\", \"link1_text\": \"\", \"link1_type\": \"\", \"link2_href\": \"\", \"link2_text\": \"\", \"link2_type\": \"\", \"number\": 0, \"type\": \"\" }, \"geometry\": { \"type\": \"LineString\", \"coordinates\": [ [ -77.032660, 38.913245 ], [ -77.034612, 38.918602 ], [ -77.032599, 38.913949 ], [ -77.018279, 38.898226 ], [ -77.040944, 38.862367 ], [ -77.050392, 38.854440 ], [ -77.054272, 38.838073 ], [ -77.017570, 38.833381 ], [ -77.053437, 38.827721 ], [ -77.050250, 38.847827 ], [ -77.054272, 38.838073 ], [ -77.033720, 38.890679 ], [ -77.031259, 38.902575 ], [ -77.029469, 38.918511 ], [ -77.030980, 38.924843 ], [ -77.029266, 38.913984 ], [ -77.034128, 38.903978 ], [ -77.044539, 38.903735 ], [ -77.029266, 38.913984 ], [ -77.029234, 38.925337 ], [ -77.012885, 38.916419 ], [ -77.028699, 38.924231 ], [ -77.027471, 38.914844 ], [ -77.034128, 38.903978 ], [ -77.034522, 38.917940 ], [ -77.026324, 38.900964 ], [ -77.029561, 38.917554 ], [ -77.028921, 38.929646 ], [ -77.029367, 38.913733 ], [ -77.014371, 38.911169 ], [ -77.018512, 38.915192 ], [ -77.021939, 38.911565 ], [ -77.011958, 38.910804 ], [ -77.013915, 38.906295 ], [ -77.013470, 38.899731 ], [ -77.014351, 38.885039 ], [ -77.046214, 38.867153 ], [ -77.052083, 38.866712 ], [ -77.078684, 38.848110 ], [ -77.083428, 38.843929 ], [ -77.089188, 38.844738 ], [ -77.085842, 38.841012 ], [ -77.089981, 38.844297 ], [ -77.089489, 38.844242 ], [ -77.072871, 38.862038 ], [ -77.051865, 38.868731 ], [ -77.033901, 38.888678 ], [ -77.031197, 38.901439 ], [ -77.040243, 38.915455 ], [ -77.027706, 38.914845 ], [ -77.028410, 38.925087 ], [ -77.033480, 38.935664 ], [ -77.029372, 38.926715 ], [ -77.028996, 38.914429 ], [ -77.028597, 38.929520 ], [ -77.034648, 38.917760 ], [ -77.028298, 38.925456 ], [ -77.034648, 38.917760 ], [ -77.040607, 38.927325 ], [ -77.029241, 38.925560 ], [ -77.026484, 38.910549 ], [ -77.034522, 38.917940 ], [ -77.026296, 38.907455 ], [ -77.030006, 38.919196 ], [ -77.029249, 38.929425 ], [ -77.034596, 38.921222 ], [ -77.025943, 38.907349 ], [ -77.015375, 38.915107 ], [ -77.030643, 38.908942 ], [ -77.034425, 38.921060 ], [ -77.014333, 38.914943 ], [ -77.028358, 38.926457 ], [ -77.008070, 38.923904 ], [ -77.028642, 38.926862 ], [ -77.012633, 38.916032 ], [ -77.024911, 38.922549 ], [ -77.013671, 38.915555 ], [ -77.028642, 38.926862 ], [ -77.015375, 38.915107 ], [ -77.030643, 38.908942 ], [ -77.014333, 38.914943 ], [ -77.028412, 38.925796 ], [ -77.030643, 38.908942 ], [ -77.014333, 38.914943 ], [ -77.028358, 38.926457 ], [ -77.013671, 38.915555 ], [ -77.028642, 38.926862 ], [ -77.012633, 38.916032 ], [ -77.028358, 38.926457 ], [ -77.013671, 38.915555 ], [ -77.028642, 38.926862 ], [ -77.013448, 38.919314 ], [ -77.028731, 38.925438 ], [ -77.012633, 38.916032 ], [ -77.030643, 38.908942 ], [ -77.016478, 38.918230 ], [ -77.028412, 38.925796 ], [ -77.014333, 38.914943 ], [ -77.028412, 38.925796 ], [ -77.012982, 38.915848 ], [ -77.027092, 38.912737 ], [ -77.025964, 38.922705 ], [ -77.026520, 38.910412 ], [ -77.028412, 38.925796 ], [ -77.027092, 38.912737 ], [ -77.014667, 38.911136 ], [ -77.029825, 38.919180 ], [ -77.029550, 38.929886 ], [ -77.028511, 38.924930 ], [ -77.025784, 38.908988 ], [ -77.022533, 38.897128 ], [ -77.027092, 38.912737 ], [ -77.028845, 38.924642 ], [ -77.036027, 38.915000 ], [ -77.029570, 38.925606 ], [ -77.027736, 38.915122 ], [ -77.029570, 38.925606 ], [ -77.030188, 38.914173 ], [ -77.018018, 38.904988 ], [ -77.033472, 38.912425 ], [ -77.029570, 38.925606 ], [ -77.027456, 38.915566 ], [ -77.028217, 38.925163 ], [ -77.027456, 38.915566 ], [ -77.028655, 38.924598 ], [ -77.027591, 38.912803 ], [ -77.034118, 38.921218 ], [ -77.023386, 38.927075 ], [ -77.028539, 38.918085 ], [ -77.029835, 38.929526 ], [ -77.029827, 38.918881 ], [ -77.028468, 38.924870 ], [ -77.027456, 38.915566 ], [ -77.027456, 38.915566 ], [ -77.028494, 38.925089 ], [ -77.036825, 38.912627 ], [ -77.025114, 38.923437 ], [ -77.028267, 38.909684 ], [ -77.027165, 38.902324 ], [ -77.031934, 38.896627 ], [ -77.039813, 38.903209 ], [ -77.045632, 38.903901 ], [ -77.030568, 38.916315 ], [ -77.012601, 38.911333 ], [ -76.993892, 38.901037 ], [ -77.014761, 38.916255 ], [ -77.034345, 38.924869 ], [ -77.026995, 38.906982 ], [ -77.034477, 38.919692 ], [ -77.030568, 38.906860 ], [ -77.033799, 38.919577 ], [ -77.032001, 38.903800 ], [ -77.052535, 38.900782 ], [ -77.076978, 38.897903 ], [ -77.097814, 38.897177 ], [ -77.128704, 38.878212 ], [ -77.145900, 38.880647 ], [ -77.168161, 38.897200 ], [ -77.183484, 38.915130 ], [ -77.197271, 38.934459 ], [ -77.210561, 38.926904 ], [ -77.239636, 38.936190 ], [ -77.298079, 38.947167 ], [ -77.364831, 38.958184 ], [ -77.442106, 38.956276 ], [ -77.485164, 38.988903 ], [ -77.442106, 38.956276 ], [ -77.449138, 38.942914 ], [ -77.449640, 38.905389 ], [ -77.441774, 38.943653 ], [ -77.440313, 38.957837 ], [ -104.769154, 39.904540 ], [ -104.685341, 39.859218 ], [ -104.671741, 39.850356 ], [ -104.609001, 39.766203 ], [ -104.671272, 39.850093 ], [ -104.760958, 39.835503 ], [ -104.792237, 39.780302 ], [ -104.932759, 39.768306 ], [ -104.941705, 39.727885 ], [ -104.942658, 39.743819 ], [ -104.958363, 39.734873 ], [ -104.978095, 39.737937 ], [ -104.987340, 39.734172 ], [ -104.993514, 39.719104 ], [ -104.986151, 39.736755 ], [ -104.996785, 39.739945 ], [ -105.009601, 39.752989 ], [ -104.995515, 39.745836 ], [ -105.009601, 39.752989 ], [ -105.002575, 39.745082 ], [ -104.998169, 39.753824 ], [ -105.002082, 39.749351 ], [ -104.995672, 39.744484 ], [ -104.990929, 39.739726 ], [ -104.987102, 39.733509 ], [ -104.988016, 39.740059 ], [ -105.005996, 39.745252 ], [ -105.001051, 39.748447 ], [ -104.987803, 39.737460 ], [ -104.991562, 39.733843 ], [ -104.995903, 39.720161 ], [ -104.986151, 39.732176 ], [ -105.002434, 39.735160 ], [ -104.995903, 39.720161 ], [ -104.988191, 39.733918 ], [ -104.989714, 39.739132 ], [ -104.991287, 39.744475 ], [ -104.993961, 39.748940 ], [ -104.965729, 39.737157 ], [ -104.987806, 39.736104 ], [ -104.990152, 39.731857 ], [ -104.990795, 39.745118 ], [ -105.000344, 39.752323 ], [ -104.994067, 39.748316 ], [ -104.982776, 39.744695 ], [ -104.987768, 39.737323 ], [ -104.988623, 39.742702 ], [ -104.996473, 39.748392 ], [ -105.003293, 39.748520 ], [ -105.003914, 39.762553 ], [ -105.006119, 39.745118 ], [ -104.998268, 39.751083 ], [ -104.990932, 39.746291 ], [ -104.987581, 39.741675 ], [ -104.986977, 39.734177 ], [ -104.989855, 39.741067 ], [ -104.967807, 39.737685 ], [ -104.949958, 39.735145 ], [ -104.959348, 39.734572 ], [ -104.959462, 39.739871 ], [ -104.958357, 39.734823 ], [ -104.980270, 39.736428 ], [ -104.953181, 39.736819 ], [ -104.974336, 39.733552 ], [ -104.990096, 39.737661 ], [ -105.003914, 39.762553 ], [ -105.046026, 39.848132 ], [ -105.258707, 40.083275 ], [ -105.195809, 40.177767 ], [ -105.122630, 40.172639 ], [ -105.288283, 40.230063 ], [ -105.492617, 40.368270 ], [ -105.548160, 40.339277 ], [ -105.520572, 40.341207 ], [ -105.605344, 40.317352 ], [ -105.521753, 40.341375 ], [ -105.542122, 40.377886 ], [ -105.271894, 40.224166 ], [ -105.258246, 40.105936 ], [ -105.158206, 40.185631 ], [ -105.266621, 40.078443 ], [ -105.023463, 39.824034 ], [ -105.023937, 39.840472 ], [ -104.930527, 39.766908 ], [ -104.953745, 39.735932 ], [ -104.972745, 39.736486 ], [ -104.997802, 39.750880 ], [ -104.992440, 39.767994 ], [ -104.984526, 39.788738 ], [ -104.988695, 39.792524 ], [ -104.981368, 39.812379 ], [ -105.045386, 39.849688 ], [ -105.062522, 39.908723 ], [ -105.078209, 39.897386 ], [ -105.096934, 39.919160 ], [ -105.127032, 39.937561 ], [ -105.179077, 39.954629 ], [ -105.313518, 40.016823 ], [ -105.261057, 40.011129 ], [ -105.263062, 39.999529 ], [ -105.271977, 40.005675 ], [ -105.284913, 40.018266 ], [ -105.279323, 40.015136 ], [ -105.274778, 40.018358 ], [ -105.268053, 40.020249 ], [ -105.275364, 40.018884 ], [ -105.265450, 40.017619 ], [ -105.257585, 40.017621 ], [ -105.264371, 40.017379 ], [ -105.277925, 40.005764 ], [ -105.274095, 40.024061 ], [ -105.263413, 40.016754 ], [ -105.265287, 40.021262 ], [ -105.282444, 40.029186 ], [ -105.269476, 40.010921 ], [ -105.277679, 40.026178 ], [ -105.273473, 40.019368 ], [ -105.280015, 40.018010 ], [ -105.274341, 40.019220 ], [ -105.265258, 40.021343 ], [ -105.259471, 40.022289 ], [ -105.253204, 40.023806 ], [ -105.251546, 40.029169 ], [ -105.244821, 40.031767 ], [ -105.263375, 40.000814 ], [ -105.244693, 40.037455 ], [ -105.245579, 40.032030 ], [ -105.255646, 40.017750 ], [ -105.237622, 40.036159 ], [ -105.248628, 40.024178 ], [ -105.198752, 40.041813 ], [ -105.188454, 40.014305 ], [ -105.224005, 40.050517 ], [ -105.125822, 40.046400 ], [ -105.156175, 40.001903 ], [ -105.126295, 40.003149 ], [ -105.159465, 39.933660 ], [ -105.127615, 39.959034 ], [ -105.103774, 39.922874 ], [ -105.043217, 39.822580 ], [ -105.023720, 39.841660 ], [ -104.985179, 39.830321 ], [ -104.971543, 39.827532 ], [ -104.948702, 39.822560 ], [ -104.903744, 39.789220 ], [ -104.786145, 39.766407 ], [ -104.773194, 39.774471 ], [ -104.801121, 39.758773 ], [ -104.793651, 39.782413 ], [ -104.772920, 39.799323 ], [ -104.673483, 39.848773 ], [ -104.660480, 39.854556 ], [ -77.474336, 38.987056 ], [ -77.442167, 38.943002 ], [ -77.437938, 38.956494 ], [ -77.410992, 38.952815 ], [ -77.345315, 38.948421 ], [ -77.280054, 38.942087 ], [ -77.190585, 38.909422 ], [ -77.145453, 38.881513 ], [ -77.077161, 38.898950 ], [ -77.048000, 38.906860 ], [ -77.028280, 38.924887 ], [ -77.034225, 38.912007 ], [ -77.030035, 38.924887 ], [ -77.035032, 38.919939 ], [ -77.028297, 38.933089 ], [ -77.028475, 38.924926 ], [ -77.039551, 38.906860 ], [ -77.030568, 38.917598 ], [ -77.028473, 38.925032 ], [ -77.039933, 38.912780 ], [ -77.021585, 38.897847 ], [ -77.039551, 38.899649 ], [ -77.039006, 38.915855 ], [ -77.030250, 38.930712 ], [ -77.028401, 38.925090 ], [ -77.034591, 38.911883 ], [ -77.028076, 38.924537 ], [ -77.030843, 38.910437 ], [ -77.034820, 38.923173 ], [ -77.028209, 38.910545 ], [ -77.030193, 38.924887 ], [ -77.027480, 38.911537 ], [ -77.034820, 38.923173 ], [ -77.030596, 38.910535 ], [ -77.028092, 38.924998 ], [ -77.027299, 38.910631 ], [ -77.045872, 38.907235 ], [ -77.034013, 38.920259 ], [ -77.028796, 38.924660 ], [ -77.035105, 38.919045 ], [ -77.042489, 38.921796 ], [ -77.029836, 38.930749 ], [ -77.029663, 38.913655 ], [ -77.033820, 38.934527 ], [ -77.021888, 38.948933 ], [ -77.021528, 38.933596 ], [ -77.021888, 38.948933 ], [ -77.018960, 38.945021 ], [ -77.032853, 38.934747 ], [ -77.028438, 38.925068 ], [ -77.027698, 38.911447 ], [ -77.028329, 38.924740 ], [ -77.033933, 38.911429 ], [ -77.028329, 38.924740 ], [ -77.033933, 38.911429 ], [ -77.026182, 38.901672 ], [ -77.020110, 38.913904 ], [ -77.029953, 38.924869 ], [ -77.035128, 38.912497 ], [ -77.027847, 38.925517 ], [ -77.028013, 38.925117 ], [ -77.033603, 38.911923 ], [ -77.029585, 38.925016 ], [ -77.026216, 38.919809 ], [ -77.022480, 38.916367 ], [ -77.017307, 38.914251 ], [ -77.006042, 38.909357 ], [ -77.000301, 38.910252 ], [ -76.907009, 38.942534 ], [ -76.886837, 38.982528 ], [ -76.867361, 39.002961 ], [ -76.833155, 39.075523 ], [ -76.695361, 39.221924 ], [ -76.597525, 39.240860 ], [ -76.544418, 39.282424 ], [ -76.457712, 39.372244 ], [ -76.269164, 39.474439 ], [ -76.223305, 39.502409 ], [ -76.184533, 39.495725 ], [ -76.188481, 39.521595 ], [ -76.197157, 39.522204 ], [ -76.117258, 39.575296 ], [ -75.804294, 39.641061 ], [ -75.798237, 39.640333 ], [ -75.753082, 39.652346 ], [ -75.712791, 39.662019 ], [ -75.693944, 39.668821 ], [ -75.679860, 39.660098 ], [ -75.662383, 39.676553 ], [ -75.643622, 39.685676 ], [ -75.603951, 39.693915 ], [ -75.602098, 39.700408 ], [ -75.588247, 39.705815 ], [ -75.586744, 39.710269 ], [ -75.582813, 39.713702 ], [ -75.576906, 39.715034 ], [ -75.571104, 39.716061 ], [ -75.565066, 39.716835 ], [ -75.505334, 39.752050 ], [ -75.438660, 39.824228 ], [ -75.348071, 39.863855 ], [ -75.343767, 39.867210 ], [ -75.359243, 39.894532 ], [ -75.361254, 39.920601 ], [ -75.375504, 39.935802 ], [ -75.342367, 39.987913 ], [ -75.354487, 40.014691 ], [ -75.363689, 40.031102 ], [ -75.357955, 40.056203 ], [ -75.332833, 40.054965 ], [ -75.295009, 40.101674 ], [ -75.285445, 40.105032 ], [ -75.297929, 40.156687 ], [ -75.294370, 40.173233 ], [ -75.318788, 40.198906 ], [ -75.372781, 40.278662 ], [ -75.438805, 40.453241 ], [ -75.442051, 40.457339 ], [ -75.445423, 40.461263 ], [ -75.448559, 40.465180 ], [ -75.451835, 40.469206 ], [ -75.464441, 40.485786 ], [ -75.502224, 40.514608 ], [ -75.540567, 40.550436 ], [ -75.533699, 40.550160 ], [ -75.561803, 40.557564 ], [ -75.550267, 40.565689 ], [ -75.567638, 40.592235 ], [ -75.536650, 40.610152 ], [ -75.524847, 40.609977 ], [ -75.518979, 40.610841 ], [ -75.513458, 40.612937 ], [ -75.506873, 40.615327 ], [ -75.478231, 40.621653 ], [ -75.478610, 40.627618 ], [ -75.407468, 40.655794 ], [ -75.398588, 40.655783 ], [ -75.385592, 40.673118 ], [ -75.339602, 40.671157 ], [ -75.331059, 40.680484 ], [ -75.324876, 40.680863 ], [ -75.319013, 40.681799 ], [ -75.267777, 40.684421 ], [ -75.289659, 40.726975 ], [ -75.287690, 40.718001 ], [ -75.311905, 40.797540 ], [ -75.295583, 40.801602 ], [ -75.267486, 40.818646 ], [ -75.291298, 40.845265 ], [ -75.299810, 40.919016 ], [ -75.251553, 40.991911 ], [ -75.234575, 40.985118 ], [ -75.207951, 40.977422 ], [ -75.191369, 40.981831 ], [ -75.174821, 40.989684 ], [ -75.142739, 41.005358 ], [ -75.175258, 40.989729 ], [ -75.142739, 41.005358 ], [ -75.176921, 40.993584 ], [ -75.182809, 40.994453 ], [ -75.188120, 40.990835 ], [ -75.193590, 40.996089 ], [ -75.204734, 41.008388 ], [ -75.236314, 41.041635 ], [ -75.214204, 41.042670 ], [ -75.221975, 41.074316 ], [ -75.237778, 41.088784 ], [ -75.219669, 41.092590 ], [ -75.256662, 41.140973 ], [ -75.188661, 41.091275 ], [ -75.188661, 41.091275 ], [ -75.209854, 41.112772 ], [ -75.188661, 41.091275 ], [ -75.236581, 41.113096 ], [ -75.197029, 41.118017 ], [ -75.193469, 41.089796 ], [ -75.197029, 41.118017 ], [ -75.193469, 41.089796 ], [ -75.263229, 41.148713 ], [ -75.193469, 41.089796 ], [ -75.263229, 41.148713 ], [ -75.237778, 41.088784 ], [ -75.205655, 41.007949 ], [ -75.186293, 40.989236 ], [ -75.207951, 40.977422 ], [ -75.229154, 40.986702 ], [ -75.224784, 40.982193 ], [ -75.173474, 40.989934 ], [ -75.302302, 40.913383 ], [ -75.313709, 40.884837 ], [ -75.291051, 40.852060 ], [ -75.284651, 40.813343 ], [ -75.274322, 40.778826 ], [ -75.254451, 40.734900 ], [ -75.298694, 40.690794 ], [ -75.339602, 40.671157 ], [ -75.407309, 40.655189 ], [ -75.424078, 40.654532 ], [ -75.433781, 40.637891 ], [ -75.455326, 40.634168 ], [ -75.486998, 40.628006 ], [ -75.497280, 40.620773 ], [ -75.553202, 40.606082 ], [ -75.427670, 40.461322 ], [ -75.420325, 40.437959 ], [ -75.365504, 40.309962 ], [ -75.295355, 40.173004 ], [ -75.281000, 40.117424 ], [ -75.357955, 40.056203 ], [ -75.346657, 40.043485 ], [ -75.342367, 39.987913 ], [ -75.335804, 39.972875 ], [ -75.335804, 39.972875 ], [ -75.334662, 39.966021 ], [ -75.334491, 39.958616 ], [ -75.337885, 39.954111 ], [ -75.358817, 39.943566 ], [ -75.361022, 39.918495 ], [ -75.346574, 39.877053 ], [ -75.345619, 39.866813 ], [ -75.371727, 39.858837 ], [ -75.455567, 39.815649 ], [ -75.463927, 39.804583 ], [ -75.482902, 39.792345 ], [ -75.501874, 39.789168 ], [ -75.519190, 39.779592 ], [ -75.535511, 39.765682 ], [ -75.563486, 39.760023 ], [ -75.679077, 39.674228 ], [ -75.694800, 39.668982 ], [ -75.712791, 39.662019 ], [ -75.774331, 39.642253 ], [ -75.871626, 39.646824 ], [ -75.893474, 39.645807 ], [ -75.915097, 39.642379 ], [ -75.978851, 39.626961 ], [ -76.117258, 39.575296 ], [ -76.152646, 39.565456 ], [ -76.194244, 39.518143 ], [ -76.209306, 39.510840 ], [ -76.261071, 39.474748 ], [ -76.251081, 39.484489 ], [ -76.272912, 39.474904 ], [ -76.293712, 39.463703 ], [ -76.312815, 39.455656 ], [ -76.321710, 39.450941 ], [ -76.335329, 39.445102 ], [ -76.355750, 39.442237 ], [ -76.374235, 39.425948 ], [ -76.396664, 39.425171 ], [ -76.402629, 39.421299 ], [ -76.409215, 39.418321 ], [ -76.429879, 39.398835 ], [ -76.453923, 39.374187 ], [ -76.494194, 39.352232 ], [ -76.522967, 39.339841 ], [ -76.530717, 39.308766 ], [ -76.530554, 39.294196 ], [ -76.559920, 39.280244 ], [ -76.642992, 39.248289 ], [ -76.675049, 39.221590 ], [ -76.698642, 39.200064 ], [ -76.720091, 39.176706 ], [ -76.734340, 39.162136 ], [ -76.762448, 39.125668 ], [ -76.797774, 39.108078 ], [ -76.769040, 39.113960 ], [ -76.876989, 38.998047 ], [ -76.904279, 38.972368 ], [ -76.901837, 38.955890 ], [ -76.913992, 38.942647 ], [ -76.931744, 38.923683 ], [ -76.936208, 38.920311 ], [ -76.956594, 38.917657 ], [ -77.017111, 38.918127 ], [ -77.009613, 38.934531 ], [ -77.029490, 38.925016 ], [ -77.032138, 38.913235 ], [ -77.030431, 38.924759 ], [ -77.039037, 38.923319 ], [ -77.034218, 38.912017 ], [ -77.032671, 38.913305 ], [ -77.032016, 38.919214 ], [ -77.028433, 38.924914 ], [ -77.032023, 38.919390 ], [ -77.032075, 38.913090 ], [ -77.031931, 38.918421 ], [ -77.032207, 38.923201 ], [ -77.031720, 38.918373 ], [ -77.032651, 38.913218 ], [ -77.031979, 38.919250 ], [ -77.028520, 38.924877 ], [ -77.031502, 38.930894 ], [ -77.028446, 38.924823 ], [ -77.028446, 38.924823 ], [ -77.031619, 38.930715 ], [ -77.028491, 38.924847 ], [ -77.032668, 38.929654 ], [ -77.028563, 38.924927 ], [ -77.030906, 38.916096 ], [ -77.033318, 38.909610 ], [ -77.032134, 38.914103 ], [ -77.024253, 38.916751 ], [ -77.028459, 38.924854 ], [ -77.032226, 38.918857 ], [ -77.032635, 38.913259 ], [ -77.032030, 38.919458 ], [ -77.028519, 38.924811 ], [ -77.028212, 38.914596 ], [ -77.038377, 38.901825 ], [ -77.081582, 38.896771 ], [ -77.180579, 38.899105 ], [ -77.278811, 38.937363 ], [ -77.387050, 38.956506 ], [ -77.435235, 38.955011 ], [ -77.446711, 38.953254 ], [ -84.431846, 33.622715 ], [ -84.423735, 33.630544 ], [ -84.426919, 33.639945 ], [ -84.440031, 33.641093 ], [ -84.432606, 33.640361 ], [ -84.439992, 33.658076 ], [ -80.960270, 35.207867 ], [ -80.950312, 35.214422 ], [ -80.938343, 35.219275 ], [ -80.953547, 35.220252 ], [ -80.945358, 35.218106 ], [ -80.945551, 35.218160 ], [ -122.420309, 37.764226 ], [ -122.407314, 37.761288 ], [ -122.400963, 37.752364 ], [ -122.421835, 37.760629 ], [ -122.400555, 37.752496 ], [ -122.409406, 37.752856 ], [ -122.415780, 37.752390 ], [ -122.391639, 37.790907 ], [ -122.406460, 37.780187 ], [ -122.411199, 37.775837 ], [ -122.407342, 37.782267 ], [ -122.410238, 37.777235 ], [ -122.424256, 37.758564 ], [ -122.433104, 37.734513 ], [ -122.416838, 37.636672 ], [ -122.391594, 37.617994 ], [ -122.385523, 37.614844 ], [ -84.432407, 33.638066 ], [ -87.900769, 42.950230 ], [ -87.884548, 42.953236 ], [ -87.900713, 42.950241 ], [ -77.041535, 38.851058 ], [ -77.033593, 38.892891 ], [ -77.012796, 38.897818 ], [ -77.032689, 38.928726 ], [ -77.028473, 38.924967 ], [ -77.023470, 38.916834 ], [ -77.017194, 38.916064 ], [ -77.025021, 38.919310 ], [ -77.028481, 38.924886 ], [ -77.038645, 38.921752 ], [ -77.028570, 38.924861 ], [ -77.029627, 38.917986 ], [ -77.028456, 38.924893 ], [ -77.027085, 38.920487 ], [ -77.032637, 38.913261 ], [ -77.029099, 38.917035 ], [ -77.019960, 38.915522 ], [ -77.026674, 38.924317 ], [ -77.031968, 38.921671 ], [ -77.032652, 38.913232 ], [ -77.031876, 38.918587 ], [ -77.028460, 38.924835 ], [ -77.032188, 38.917843 ], [ -77.032650, 38.913245 ], [ -77.031869, 38.917756 ], [ -77.029705, 38.922772 ], [ -77.032706, 38.913259 ], [ -77.031953, 38.918773 ], [ -77.028500, 38.924792 ], [ -77.027879, 38.914692 ], [ -77.029065, 38.924818 ], [ -77.029712, 38.908178 ], [ -77.033774, 38.881386 ], [ -77.045737, 38.856087 ], [ -77.033857, 38.851276 ], [ -71.015872, 42.358913 ], [ -71.030086, 42.365115 ], [ -71.080707, 42.358453 ], [ -71.088773, 42.366029 ], [ -71.092959, 42.374700 ], [ -71.088405, 42.360645 ], [ -71.099311, 42.363205 ], [ -71.093003, 42.358239 ], [ -71.068477, 42.358891 ], [ -71.086297, 42.356759 ], [ -71.071681, 42.359120 ], [ -71.058189, 42.362825 ], [ -71.010260, 42.375009 ], [ -71.016434, 42.365670 ], [ -71.025973, 42.357045 ], [ -71.023141, 42.364674 ], [ -77.036480, 38.852564 ], [ -77.051868, 38.860381 ], [ -77.041998, 38.874187 ], [ -77.029906, 38.895101 ], [ -77.034012, 38.930042 ], [ -77.034645, 38.918375 ], [ -77.032491, 38.913477 ], [ -77.025955, 38.923322 ], [ -77.028933, 38.911223 ], [ -77.034660, 38.919730 ], [ -77.029247, 38.927784 ], [ -77.031517, 38.918380 ], [ -77.031161, 38.908544 ], [ -77.031996, 38.917728 ], [ -77.028577, 38.925126 ], [ -77.022725, 38.916670 ], [ -77.029740, 38.924885 ], [ -77.025220, 38.933910 ], [ -77.029749, 38.924887 ], [ -77.019686, 38.917077 ], [ -77.030067, 38.908150 ], [ -77.024048, 38.916167 ], [ -77.028537, 38.924595 ], [ -77.029175, 38.915129 ], [ -77.031083, 38.905674 ], [ -77.034051, 38.901202 ], [ -77.032057, 38.895051 ], [ -77.030868, 38.905476 ], [ -77.031651, 38.915221 ], [ -77.031514, 38.924366 ], [ -77.033292, 38.935266 ], [ -77.029983, 38.926570 ], [ -77.031932, 38.921922 ], [ -77.032653, 38.913206 ], [ -77.031932, 38.905615 ], [ -77.032673, 38.913266 ], [ -77.031944, 38.917735 ], [ -77.028437, 38.924878 ], [ -77.031907, 38.919784 ], [ -77.032665, 38.913214 ], [ -77.031890, 38.920039 ], [ -77.028482, 38.924851 ], [ -77.032613, 38.913207 ], [ -77.032013, 38.919689 ], [ -77.028469, 38.924911 ], [ -77.033623, 38.907354 ], [ -77.018292, 38.901018 ], [ -77.024467, 38.880321 ], [ -77.129992, 38.953985 ], [ -77.198206, 38.949048 ], [ -77.274077, 38.942604 ], [ -77.341171, 38.948908 ], [ -77.416794, 38.955922 ], [ -77.446848, 38.953343 ], [ -77.451923, 38.945543 ], [ -122.373639, 37.595287 ], [ -122.393216, 37.618463 ], [ -122.476823, 37.695757 ], [ -122.449902, 37.727795 ], [ -122.409045, 37.780740 ], [ -122.317066, 37.806245 ], [ -122.294524, 37.804157 ], [ -122.331458, 37.798654 ], [ -122.404660, 37.789043 ], [ -122.420670, 37.763780 ], [ -122.419953, 37.769898 ], [ -122.416001, 37.761069 ], [ -122.419123, 37.766937 ], [ -122.421796, 37.762586 ], [ -122.412364, 37.760010 ], [ -122.414175, 37.752663 ], [ -122.413513, 37.746875 ], [ -122.415600, 37.739036 ], [ -122.414383, 37.755902 ], [ -122.413318, 37.746475 ], [ -122.413962, 37.751172 ], [ -122.414353, 37.755725 ], [ -122.414942, 37.760353 ], [ -122.429640, 37.761120 ], [ -122.419031, 37.760198 ], [ -122.411511, 37.759192 ], [ -122.425367, 37.759489 ], [ -122.418622, 37.763945 ], [ -122.422347, 37.769672 ], [ -122.419459, 37.774323 ], [ -122.420388, 37.780992 ], [ -122.421395, 37.786297 ], [ -122.422781, 37.792169 ], [ -122.424847, 37.802168 ], [ -122.435035, 37.805947 ], [ -122.454172, 37.804387 ], [ -122.467169, 37.818252 ], [ -122.461657, 37.806668 ], [ -122.467443, 37.804288 ], [ -122.472787, 37.806711 ], [ -122.438611, 37.813337 ], [ -122.431265, 37.804171 ], [ -122.426419, 37.801059 ], [ -122.423788, 37.796877 ], [ -122.422404, 37.789823 ], [ -122.420510, 37.781901 ], [ -122.417714, 37.772951 ], [ -122.415980, 37.761051 ], [ -122.419090, 37.766954 ], [ -122.419358, 37.761828 ], [ -122.419116, 37.766933 ], [ -122.427961, 37.768850 ], [ -122.435581, 37.772254 ], [ -122.453920, 37.771470 ], [ -122.497533, 37.771497 ], [ -122.510697, 37.771413 ], [ -122.493683, 37.694353 ], [ -122.479292, 37.664971 ], [ -122.471367, 37.657230 ], [ -122.457573, 37.637214 ], [ -122.483367, 37.636830 ], [ -122.477525, 37.625445 ], [ -122.487662, 37.625750 ], [ -122.491795, 37.611573 ], [ -122.488027, 37.602901 ], [ -122.507606, 37.576754 ], [ -122.509336, 37.528732 ], [ -122.459271, 37.491158 ], [ -122.438241, 37.475066 ], [ -122.433694, 37.468081 ], [ -122.431114, 37.427699 ], [ -122.406767, 37.390510 ], [ -122.405486, 37.322555 ], [ -122.417721, 37.366648 ], [ -122.404805, 37.325885 ], [ -122.408073, 37.281417 ], [ -122.383151, 37.251870 ], [ -122.397114, 37.285229 ], [ -122.390605, 37.258466 ], [ -122.347660, 37.228061 ], [ -122.356355, 37.184368 ], [ -122.323015, 37.140769 ], [ -122.266279, 37.081490 ], [ -122.222201, 37.039915 ], [ -122.111015, 36.968568 ], [ -122.062186, 36.957241 ], [ -122.048756, 36.960825 ], [ -122.026454, 36.975280 ], [ -122.025236, 36.970345 ], [ -122.011022, 37.046858 ], [ -121.982330, 37.147381 ], [ -121.946279, 37.279446 ], [ -121.900239, 37.320301 ], [ -121.896691, 37.330487 ], [ -121.903673, 37.332472 ], [ -121.937180, 37.353281 ], [ -122.011678, 37.373376 ], [ -122.065693, 37.389828 ], [ -122.107088, 37.407171 ], [ -122.141568, 37.429035 ], [ -122.179558, 37.452599 ], [ -122.208191, 37.471757 ], [ -122.243461, 37.493580 ], [ -122.295042, 37.533563 ], [ -122.317934, 37.570195 ], [ -122.368072, 37.590684 ], [ -122.399924, 37.615838 ], [ -122.404521, 37.656662 ], [ -122.405629, 37.711751 ], [ -122.393724, 37.756658 ], [ -122.393740, 37.762942 ], [ -122.399914, 37.762442 ], [ -122.413515, 37.763723 ], [ -122.425110, 37.764390 ], [ -122.415017, 37.775075 ], [ -122.419052, 37.767127 ], [ -122.419052, 37.767127 ], [ -122.426188, 37.769785 ], [ -122.435237, 37.762734 ], [ -122.439232, 37.757927 ], [ -122.435151, 37.762442 ], [ -122.437062, 37.788509 ], [ -122.454134, 37.818405 ], [ -122.449403, 37.804791 ], [ -122.425093, 37.798471 ], [ -122.435970, 37.799235 ], [ -122.437384, 37.789700 ], [ -122.431999, 37.788055 ], [ -122.430666, 37.781439 ], [ -122.429178, 37.774447 ], [ -122.426787, 37.770258 ], [ -122.419202, 37.766890 ], [ -122.421674, 37.776886 ], [ -122.420087, 37.787131 ], [ -122.416200, 37.775391 ], [ -122.408455, 37.784203 ], [ -122.420700, 37.788208 ], [ -122.420710, 37.782455 ], [ -122.420105, 37.770169 ], [ -122.419693, 37.765014 ], [ -122.419928, 37.769740 ], [ -122.416023, 37.775307 ], [ -122.416213, 37.779859 ], [ -122.422531, 37.772538 ], [ -122.419136, 37.766917 ], [ -122.422223, 37.757241 ], [ -122.418355, 37.752520 ], [ -122.418955, 37.757357 ], [ -122.420789, 37.768441 ], [ -122.420789, 37.768441 ] ] } }\n\n]\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title>arc.js</title>\n    <meta charset=\"utf-8\" />\n    <link rel=\"stylesheet\" href=\"http://cdn.leafletjs.com/leaflet-0.5.1/leaflet.css\" />\n    <!--[if lte IE 8]>\n        <link rel=\"stylesheet\" href=\"http://cdn.leafletjs.com/leaflet-0.5.1/leaflet.ie.css\" />\n    <![endif]-->\n\n    <script src=\"http://cdn.leafletjs.com/leaflet-0.5.1/leaflet.js\"></script>\n    <script src=\"./arc.js\"></script>\n    <style>\n\n      body {\n        margin:10px auto;\n        width:90%;\n        font:14px/20px 'Helvetica';\n      }\n\n      #map {\n        border: 1px solid;\n        width:  100%;\n        height: 420px;\n        margin: 10px auto;\n      }\n\n      #json-dump {\n        width: 100%;\n        height: 100px;\n      }\n\n    </style>\n</head>\n<body>\n\n\n\n    <div id=\"map\"></div>\n\n    <div id=\"geojson\">\n    <textarea id=\"json-dump\"></textarea>\n    </div>\n\n    <script>\n        var map = new L.Map('map');\n        var idx = 1;\n        var features = [];\n        \n        //var url = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';\n        var attribution = 'Map data &copy; 2011 OpenStreetMap contributors';\n        \n        var url = 'http://{s}.tiles.mapbox.com/v3/springmeyer.map-7jkxlsx1/{z}/{x}/{y}.png'\n        var osm = new L.TileLayer(url, {maxZoom: 17, attribution: attribution, noWrap:true});\n        \n        map.setView(new L.LatLng(0, 0), 1).addLayer(osm);\n        \n        // number of intermediate arc points\n        var npoints = 50;\n        var coords = [];\n        var points = [];\n        var snap_tolerance = 500000;\n        \n        map.on('click', onMapClick);\n\n        var start;\n        var end;\n        function draw(coords) {\n            var len = coords.length;\n            if (len == 1) {\n                var hit = false;\n                start = coords[0];\n                for (var i=0;i<points.length;++i) {\n                    var distance = points[i].distanceTo(start);\n                    if (distance<snap_tolerance) {\n                        //console.log('hit previous point, re-using location')\n                        start = points[i];\n                        hit = true;\n                    } else {\n                        //console.log(distance);\n                    }\n                }\n                if (!hit) {\n                    points.push(start);\n                }\n                var circleOptions = {color: '#f03', opacity: 0.5, clickable:false};\n                var circle = new L.CircleMarker(start, circleOptions);\n                map.addLayer(circle);\n\n            } else if (len == 2) {\n                var hit = false;\n                end = coords[1];\n                for (var i=0;i<points.length;++i) {\n                    var distance = points[i].distanceTo(end);\n                    if (distance<snap_tolerance && (points[i].lng !== start.lng)) {\n                        //console.log('hit previous point, re-using location')\n                        end = points[i];\n                        hit = true;\n                    } else {\n                        //console.log(distance);\n                    }\n                }\n                if (!hit) {\n                    points.push(end);\n                }\n                var circleOptions = {color: '#f03', opacity: 0.5, clickable:false};\n                var circle = new L.CircleMarker(end, circleOptions);\n                map.addLayer(circle);\n\n                try {\n                    var from = new arc.Coord(start.lng,start.lat);\n                    var to = new arc.Coord(end.lng,end.lat);\n                    var properties = {\n                        arc:idx++,\n                        start:''+from.lon+','+from.lat,\n                        end:''+to.lon+','+to.lat\n                    };\n                    var greatCircle = new arc.GreatCircle(from,to,properties);\n                } catch (e) {\n                    // catch possible antipodes error\n                    alert(e.message);\n                    coords.length = 0;\n                    return;\n                }\n                \n                var gc = greatCircle.Arc(npoints);\n                var line = new L.geoJson().addTo(map);\n                var geojson_feature = gc.json();\n                features.push(geojson_feature)\n                // TODO  - figure out how to disable interactivity on json lines\n                line.addData(geojson_feature);\n                line.bindPopup(\"great circle from \" + coords[0] + \" to \" + coords[1]);\n                setTimeout(function() {\n                    map.addLayer(line);\n                    coords.length = 0;\n                    document.getElementById(\"json-dump\").value = JSON.stringify(\n                                                                { \"type\": \"FeatureCollection\",\n                                                                  \"features\": features\n                                                                });\n\n                },0)\n            }\n        }\n\n        function onMapClick(e) {\n          var coord = new L.LatLng(e.latlng.lat, e.latlng.lng);\n          coords.push(coord.wrap());\n          draw(coords);\n        }\n    </script>\n</body>\n</html>\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/index.js",
    "content": "module.exports = require('./arc');\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/package.json",
    "content": "{\n  \"name\": \"arc\",\n  \"description\": \"draw great circle arcs\",\n  \"url\": \"https://github.com/springmeyer/arc.js\",\n  \"keywords\": [\n    \"maps\",\n    \"spherical\",\n    \"globe\",\n    \"rhumb line\",\n    \"crow flies\",\n    \"great circle\"\n  ],\n  \"contributors\": [\n    \"Dane Springmeyer <dane@dbsgeo.com>\"\n  ],\n  \"repository\"   :  {\n           \"type\" : \"git\",\n           \"url\"  : \"git://github.com/springmeyer/arc.js.git\"\n  },\n  \"version\": \"0.0.2\",\n  \"licenses\": [{\n    \"type\": \"BSD\"\n  }],\n  \"main\": \"./index\",\n  \"engines\": {\n    \"node\": \">=0.4.0\"\n  },\n  \"dependencies\": {\n  },\n  \"devDependencies\": {\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/polymaps.js",
    "content": "if (!org) var org = {};\nif (!org.polymaps) org.polymaps = {};\n(function(po){\n\n  po.version = \"2.5.1\"; // semver.org\n\n  var zero = {x: 0, y: 0};\npo.ns = {\n  svg: \"http://www.w3.org/2000/svg\",\n  xlink: \"http://www.w3.org/1999/xlink\"\n};\n\nfunction ns(name) {\n  var i = name.indexOf(\":\");\n  return i < 0 ? name : {\n    space: po.ns[name.substring(0, i)],\n    local: name.substring(i + 1)\n  };\n}\npo.id = (function() {\n  var id = 0;\n  return function() {\n    return ++id;\n  };\n})();\npo.svg = function(type) {\n  return document.createElementNS(po.ns.svg, type);\n};\npo.transform = function(a, b, c, d, e, f) {\n  var transform = {},\n      zoomDelta,\n      zoomFraction,\n      k;\n\n  if (!arguments.length) {\n    a = 1; c = 0; e = 0;\n    b = 0; d = 1; f = 0;\n  }\n\n  transform.zoomFraction = function(x) {\n    if (!arguments.length) return zoomFraction;\n    zoomFraction = x;\n    zoomDelta = Math.floor(zoomFraction + Math.log(Math.sqrt(a * a + b * b + c * c + d * d)) / Math.LN2);\n    k = Math.pow(2, -zoomDelta);\n    return transform;\n  };\n\n  transform.apply = function(x) {\n    var k0 = Math.pow(2, -x.zoom),\n        k1 = Math.pow(2, x.zoom - zoomDelta);\n    return {\n      column: (a * x.column * k0 + c * x.row * k0 + e) * k1,\n      row: (b * x.column * k0 + d * x.row * k0 + f) * k1,\n      zoom: x.zoom - zoomDelta\n    };\n  };\n\n  transform.unapply = function(x) {\n    var k0 = Math.pow(2, -x.zoom),\n        k1 = Math.pow(2, x.zoom + zoomDelta);\n    return {\n      column: (x.column * k0 * d - x.row * k0 * c - e * d + f * c) / (a * d - b * c) * k1,\n      row: (x.column * k0 * b - x.row * k0 * a - e * b + f * a) / (c * b - d * a) * k1,\n      zoom: x.zoom + zoomDelta\n    };\n  };\n\n  transform.toString = function() {\n    return \"matrix(\" + [a * k, b * k, c * k, d * k].join(\" \") + \" 0 0)\";\n  };\n\n  return transform.zoomFraction(0);\n};\npo.cache = function(load, unload) {\n  var cache = {},\n      locks = {},\n      map = {},\n      head = null,\n      tail = null,\n      size = 64,\n      n = 0;\n\n  function remove(tile) {\n    n--;\n    if (unload) unload(tile);\n    delete map[tile.key];\n    if (tile.next) tile.next.prev = tile.prev;\n    else if (tail = tile.prev) tail.next = null;\n    if (tile.prev) tile.prev.next = tile.next;\n    else if (head = tile.next) head.prev = null;\n  }\n\n  function flush() {\n    for (var tile = tail; n > size; tile = tile.prev) {\n      if (!tile) break;\n      if (tile.lock) continue;\n      remove(tile);\n    }\n  }\n\n  cache.peek = function(c) {\n    return map[[c.zoom, c.column, c.row].join(\"/\")];\n  };\n\n  cache.load = function(c, projection) {\n    var key = [c.zoom, c.column, c.row].join(\"/\"),\n        tile = map[key];\n    if (tile) {\n      if (tile.prev) {\n        tile.prev.next = tile.next;\n        if (tile.next) tile.next.prev = tile.prev;\n        else tail = tile.prev;\n        tile.prev = null;\n        tile.next = head;\n        head.prev = tile;\n        head = tile;\n      }\n      tile.lock = 1;\n      locks[key] = tile;\n      return tile;\n    }\n    tile = {\n      key: key,\n      column: c.column,\n      row: c.row,\n      zoom: c.zoom,\n      next: head,\n      prev: null,\n      lock: 1\n    };\n    load.call(null, tile, projection);\n    locks[key] = map[key] = tile;\n    if (head) head.prev = tile;\n    else tail = tile;\n    head = tile;\n    n++;\n    return tile;\n  };\n\n  cache.unload = function(key) {\n    if (!(key in locks)) return false;\n    var tile = locks[key];\n    tile.lock = 0;\n    delete locks[key];\n    if (tile.request && tile.request.abort(false)) remove(tile);\n    return tile;\n  };\n\n  cache.locks = function() {\n    return locks;\n  };\n\n  cache.size = function(x) {\n    if (!arguments.length) return size;\n    size = x;\n    flush();\n    return cache;\n  };\n\n  cache.flush = function() {\n    flush();\n    return cache;\n  };\n\n  cache.clear = function() {\n    for (var key in map) {\n      var tile = map[key];\n      if (tile.request) tile.request.abort(false);\n      if (unload) unload(map[key]);\n      if (tile.lock) {\n        tile.lock = 0;\n        tile.element.parentNode.removeChild(tile.element);\n      }\n    }\n    locks = {};\n    map = {};\n    head = tail = null;\n    n = 0;\n    return cache;\n  };\n\n  return cache;\n};\npo.url = function(template) {\n  var hosts = [],\n      repeat = true;\n\n  function format(c) {\n    var max = c.zoom < 0 ? 1 : 1 << c.zoom,\n        column = c.column;\n    if (repeat) {\n      column = c.column % max;\n      if (column < 0) column += max;\n    } else if ((column < 0) || (column >= max)) {\n      return null;\n    }\n    return template.replace(/{(.)}/g, function(s, v) {\n      switch (v) {\n        case \"S\": return hosts[(Math.abs(c.zoom) + c.row + column) % hosts.length];\n        case \"Z\": return c.zoom;\n        case \"X\": return column;\n        case \"Y\": return c.row;\n        case \"B\": {\n          var nw = po.map.coordinateLocation({row: c.row, column: column, zoom: c.zoom}),\n              se = po.map.coordinateLocation({row: c.row + 1, column: column + 1, zoom: c.zoom}),\n              pn = Math.ceil(Math.log(c.zoom) / Math.LN2);\n          return se.lat.toFixed(pn)\n              + \",\" + nw.lon.toFixed(pn)\n              + \",\" + nw.lat.toFixed(pn)\n              + \",\" + se.lon.toFixed(pn);\n        }\n      }\n      return v;\n    });\n  }\n\n  format.template = function(x) {\n    if (!arguments.length) return template;\n    template = x;\n    return format;\n  };\n\n  format.hosts = function(x) {\n    if (!arguments.length) return hosts;\n    hosts = x;\n    return format;\n  };\n\n  format.repeat = function(x) {\n    if (!arguments.length) return repeat;\n    repeat = x;\n    return format;\n  };\n\n  return format;\n};\npo.dispatch = function(that) {\n  var types = {};\n\n  that.on = function(type, handler) {\n    var listeners = types[type] || (types[type] = []);\n    for (var i = 0; i < listeners.length; i++) {\n      if (listeners[i].handler == handler) return that; // already registered\n    }\n    listeners.push({handler: handler, on: true});\n    return that;\n  };\n\n  that.off = function(type, handler) {\n    var listeners = types[type];\n    if (listeners) for (var i = 0; i < listeners.length; i++) {\n      var l = listeners[i];\n      if (l.handler == handler) {\n        l.on = false;\n        listeners.splice(i, 1);\n        break;\n      }\n    }\n    return that;\n  };\n\n  return function(event) {\n    var listeners = types[event.type];\n    if (!listeners) return;\n    listeners = listeners.slice(); // defensive copy\n    for (var i = 0; i < listeners.length; i++) {\n      var l = listeners[i];\n      if (l.on) l.handler.call(that, event);\n    }\n  };\n};\npo.queue = (function() {\n  var queued = [], active = 0, size = 6;\n\n  function process() {\n    if ((active >= size) || !queued.length) return;\n    active++;\n    queued.pop()();\n  }\n\n  function dequeue(send) {\n    for (var i = 0; i < queued.length; i++) {\n      if (queued[i] == send) {\n        queued.splice(i, 1);\n        return true;\n      }\n    }\n    return false;\n  }\n\n  function request(url, callback, mimeType) {\n    var req;\n\n    function send() {\n      req = new XMLHttpRequest();\n      if (mimeType && req.overrideMimeType) {\n        req.overrideMimeType(mimeType);\n      }\n      req.open(\"GET\", url, true);\n      req.onreadystatechange = function(e) {\n        if (req.readyState == 4) {\n          active--;\n          if (req.status < 300) callback(req);\n          process();\n        }\n      };\n      req.send(null);\n    }\n\n    function abort(hard) {\n      if (dequeue(send)) return true;\n      if (hard && req) { req.abort(); return true; }\n      return false;\n    }\n\n    queued.push(send);\n    process();\n    return {abort: abort};\n  }\n\n  function text(url, callback, mimeType) {\n    return request(url, function(req) {\n      if (req.responseText) callback(req.responseText);\n    }, mimeType);\n  }\n\n  /*\n   * We the override MIME type here so that you can load local files; some\n   * browsers don't assign a proper MIME type for local files.\n   */\n\n  function json(url, callback) {\n    return request(url, function(req) {\n      if (req.responseText) callback(JSON.parse(req.responseText));\n    }, \"application/json\");\n  }\n\n  function xml(url, callback) {\n    return request(url, function(req) {\n      if (req.responseXML) callback(req.responseXML);\n    }, \"application/xml\");\n  }\n\n  function image(image, src, callback) {\n    var img;\n\n    function send() {\n      img = document.createElement(\"img\");\n      img.onerror = function() {\n        active--;\n        process();\n      };\n      img.onload = function() {\n        active--;\n        callback(img);\n        process();\n      };\n      img.src = src;\n      image.setAttributeNS(po.ns.xlink, \"href\", src);\n    }\n\n    function abort(hard) {\n      if (dequeue(send)) return true;\n      if (hard && img) { img.src = \"about:\"; return true; } // cancels request\n      return false;\n    }\n\n    queued.push(send);\n    process();\n    return {abort: abort};\n  }\n\n  return {text: text, xml: xml, json: json, image: image};\n})();\npo.map = function() {\n  var map = {},\n      container,\n      size,\n      sizeActual = zero,\n      sizeRadius = zero, // sizeActual / 2\n      tileSize = {x: 256, y: 256},\n      center = {lat: 37.76487, lon: -122.41948},\n      zoom = 12,\n      zoomFraction = 0,\n      zoomFactor = 1, // Math.pow(2, zoomFraction)\n      zoomRange = [1, 18],\n      angle = 0,\n      angleCos = 1, // Math.cos(angle)\n      angleSin = 0, // Math.sin(angle)\n      angleCosi = 1, // Math.cos(-angle)\n      angleSini = 0, // Math.sin(-angle)\n      ymin = -180, // lat2y(centerRange[0].lat)\n      ymax = 180; // lat2y(centerRange[1].lat)\n\n  var centerRange = [\n    {lat: y2lat(ymin), lon: -Infinity},\n    {lat: y2lat(ymax), lon: Infinity}\n  ];\n\n  map.locationCoordinate = function(l) {\n    var c = po.map.locationCoordinate(l),\n        k = Math.pow(2, zoom);\n    c.column *= k;\n    c.row *= k;\n    c.zoom += zoom;\n    return c;\n  };\n\n  map.coordinateLocation = po.map.coordinateLocation;\n\n  map.coordinatePoint = function(tileCenter, c) {\n    var kc = Math.pow(2, zoom - c.zoom),\n        kt = Math.pow(2, zoom - tileCenter.zoom),\n        dx = (c.column * kc - tileCenter.column * kt) * tileSize.x * zoomFactor,\n        dy = (c.row * kc - tileCenter.row * kt) * tileSize.y * zoomFactor;\n    return {\n      x: sizeRadius.x + angleCos * dx - angleSin * dy,\n      y: sizeRadius.y + angleSin * dx + angleCos * dy\n    };\n  };\n\n  map.pointCoordinate = function(tileCenter, p) {\n    var kt = Math.pow(2, zoom - tileCenter.zoom),\n        dx = (p.x - sizeRadius.x) / zoomFactor,\n        dy = (p.y - sizeRadius.y) / zoomFactor;\n    return {\n      column: tileCenter.column * kt + (angleCosi * dx - angleSini * dy) / tileSize.x,\n      row: tileCenter.row * kt + (angleSini * dx + angleCosi * dy) / tileSize.y,\n      zoom: zoom\n    };\n  };\n\n  map.locationPoint = function(l) {\n    var k = Math.pow(2, zoom + zoomFraction - 3) / 45,\n        dx = (l.lon - center.lon) * k * tileSize.x,\n        dy = (lat2y(center.lat) - lat2y(l.lat)) * k * tileSize.y;\n    return {\n      x: sizeRadius.x + angleCos * dx - angleSin * dy,\n      y: sizeRadius.y + angleSin * dx + angleCos * dy\n    };\n  };\n\n  map.pointLocation = function(p) {\n    var k = 45 / Math.pow(2, zoom + zoomFraction - 3),\n        dx = (p.x - sizeRadius.x) * k,\n        dy = (p.y - sizeRadius.y) * k;\n    return {\n      lon: center.lon + (angleCosi * dx - angleSini * dy) / tileSize.x,\n      lat: y2lat(lat2y(center.lat) - (angleSini * dx + angleCosi * dy) / tileSize.y)\n    };\n  };\n\n  function rezoom() {\n    if (zoomRange) {\n      if (zoom < zoomRange[0]) zoom = zoomRange[0];\n      else if (zoom > zoomRange[1]) zoom = zoomRange[1];\n    }\n    zoomFraction = zoom - (zoom = Math.round(zoom));\n    zoomFactor = Math.pow(2, zoomFraction);\n  }\n\n  function recenter() {\n    if (!centerRange) return;\n    var k = 45 / Math.pow(2, zoom + zoomFraction - 3);\n\n    // constrain latitude\n    var y = Math.max(Math.abs(angleSin * sizeRadius.x + angleCos * sizeRadius.y),\n                     Math.abs(angleSini * sizeRadius.x + angleCosi * sizeRadius.y)),\n        lat0 = y2lat(ymin - y * k / tileSize.y),\n        lat1 = y2lat(ymax + y * k / tileSize.y);\n    center.lat = Math.max(lat0, Math.min(lat1, center.lat));\n\n    // constrain longitude\n    var x = Math.max(Math.abs(angleSin * sizeRadius.y + angleCos * sizeRadius.x),\n                     Math.abs(angleSini * sizeRadius.y + angleCosi * sizeRadius.x)),\n        lon0 = centerRange[0].lon - x * k / tileSize.x,\n        lon1 = centerRange[1].lon + x * k / tileSize.x;\n    center.lon = Math.max(lon0, Math.min(lon1, center.lon));\n }\n\n  // a place to capture mouse events if no tiles exist\n  var rect = po.svg(\"rect\");\n  rect.setAttribute(\"visibility\", \"hidden\");\n  rect.setAttribute(\"pointer-events\", \"all\");\n\n  map.container = function(x) {\n    if (!arguments.length) return container;\n    container = x;\n    container.setAttribute(\"class\", \"map\");\n    container.appendChild(rect);\n    return map.resize(); // infer size\n  };\n\n  map.focusableParent = function() {\n    for (var p = container; p; p = p.parentNode) {\n      if (p.tabIndex >= 0) return p;\n    }\n    return window;\n  };\n\n  map.mouse = function(e) {\n    var point = (container.ownerSVGElement || container).createSVGPoint();\n    if ((bug44083 < 0) && (window.scrollX || window.scrollY)) {\n      var svg = document.body.appendChild(po.svg(\"svg\"));\n      svg.style.position = \"absolute\";\n      svg.style.top = svg.style.left = \"0px\";\n      var ctm = svg.getScreenCTM();\n      bug44083 = !(ctm.f || ctm.e);\n      document.body.removeChild(svg);\n    }\n    if (bug44083) {\n      point.x = e.pageX;\n      point.y = e.pageY;\n    } else {\n      point.x = e.clientX;\n      point.y = e.clientY;\n    }\n    return point.matrixTransform(container.getScreenCTM().inverse());\n  };\n\n  map.size = function(x) {\n    if (!arguments.length) return sizeActual;\n    size = x;\n    return map.resize(); // size tiles\n  };\n\n  map.resize = function() {\n    if (!size) {\n      rect.setAttribute(\"width\", \"100%\");\n      rect.setAttribute(\"height\", \"100%\");\n      b = rect.getBBox();\n      sizeActual = {x: b.width, y: b.height};\n      resizer.add(map);\n    } else {\n      sizeActual = size;\n      resizer.remove(map);\n    }\n    rect.setAttribute(\"width\", sizeActual.x);\n    rect.setAttribute(\"height\", sizeActual.y);\n    sizeRadius = {x: sizeActual.x / 2, y: sizeActual.y / 2};\n    recenter();\n    map.dispatch({type: \"resize\"});\n    return map;\n  };\n\n  map.tileSize = function(x) {\n    if (!arguments.length) return tileSize;\n    tileSize = x;\n    map.dispatch({type: \"move\"});\n    return map;\n  };\n\n  map.center = function(x) {\n    if (!arguments.length) return center;\n    center = x;\n    recenter();\n    map.dispatch({type: \"move\"});\n    return map;\n  };\n\n  map.panBy = function(x) {\n    var k = 45 / Math.pow(2, zoom + zoomFraction - 3),\n        dx = x.x * k,\n        dy = x.y * k;\n    return map.center({\n      lon: center.lon + (angleSini * dy - angleCosi * dx) / tileSize.x,\n      lat: y2lat(lat2y(center.lat) + (angleSini * dx + angleCosi * dy) / tileSize.y)\n    });\n  };\n\n  map.centerRange = function(x) {\n    if (!arguments.length) return centerRange;\n    centerRange = x;\n    if (centerRange) {\n      ymin = centerRange[0].lat > -90 ? lat2y(centerRange[0].lat) : -Infinity;\n      ymax = centerRange[0].lat < 90 ? lat2y(centerRange[1].lat) : Infinity;\n    } else {\n      ymin = -Infinity;\n      ymax = Infinity;\n    }\n    recenter();\n    map.dispatch({type: \"move\"});\n    return map;\n  };\n\n  map.zoom = function(x) {\n    if (!arguments.length) return zoom + zoomFraction;\n    zoom = x;\n    rezoom();\n    return map.center(center);\n  };\n\n  map.zoomBy = function(z, x0, l) {\n    if (arguments.length < 2) return map.zoom(zoom + zoomFraction + z);\n\n    // compute the location of x0\n    if (arguments.length < 3) l = map.pointLocation(x0);\n\n    // update the zoom level\n    zoom = zoom + zoomFraction + z;\n    rezoom();\n\n    // compute the new point of the location\n    var x1 = map.locationPoint(l);\n\n    return map.panBy({x: x0.x - x1.x, y: x0.y - x1.y});\n  };\n\n  map.zoomRange = function(x) {\n    if (!arguments.length) return zoomRange;\n    zoomRange = x;\n    return map.zoom(zoom + zoomFraction);\n  };\n\n  map.extent = function(x) {\n    if (!arguments.length) return [\n      map.pointLocation({x: 0, y: sizeActual.y}),\n      map.pointLocation({x: sizeActual.x, y: 0})\n    ];\n\n    // compute the extent in points, scale factor, and center\n    var bl = map.locationPoint(x[0]),\n        tr = map.locationPoint(x[1]),\n        k = Math.max((tr.x - bl.x) / sizeActual.x, (bl.y - tr.y) / sizeActual.y),\n        l = map.pointLocation({x: (bl.x + tr.x) / 2, y: (bl.y + tr.y) / 2});\n\n    // update the zoom level\n    zoom = zoom + zoomFraction - Math.log(k) / Math.LN2;\n    rezoom();\n\n    // set the new center\n    return map.center(l);\n  };\n\n  map.angle = function(x) {\n    if (!arguments.length) return angle;\n    angle = x;\n    angleCos = Math.cos(angle);\n    angleSin = Math.sin(angle);\n    angleCosi = Math.cos(-angle);\n    angleSini = Math.sin(-angle);\n    recenter();\n    map.dispatch({type: \"move\"});\n    return map;\n  };\n\n  map.add = function(x) {\n    x.map(map);\n    return map;\n  };\n\n  map.remove = function(x) {\n    x.map(null);\n    return map;\n  };\n\n  map.dispatch = po.dispatch(map);\n\n  return map;\n};\n\nfunction resizer(e) {\n  for (var i = 0; i < resizer.maps.length; i++) {\n    resizer.maps[i].resize();\n  }\n}\n\nresizer.maps = [];\n\nresizer.add = function(map) {\n  for (var i = 0; i < resizer.maps.length; i++) {\n    if (resizer.maps[i] == map) return;\n  }\n  resizer.maps.push(map);\n};\n\nresizer.remove = function(map) {\n  for (var i = 0; i < resizer.maps.length; i++) {\n    if (resizer.maps[i] == map) {\n      resizer.maps.splice(i, 1);\n      return;\n    }\n  }\n};\n\n// Note: assumes single window (no frames, iframes, etc.)!\nif (window.addEventListener) {\n  window.addEventListener(\"resize\", resizer, false);\n  window.addEventListener(\"load\", resizer, false);\n}\n\n// See http://wiki.openstreetmap.org/wiki/Mercator\n\nfunction y2lat(y) {\n  return 360 / Math.PI * Math.atan(Math.exp(y * Math.PI / 180)) - 90;\n}\n\nfunction lat2y(lat) {\n  return 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360));\n}\n\npo.map.locationCoordinate = function(l) {\n  var k = 1 / 360;\n  return {\n    column: (l.lon + 180) * k,\n    row: (180 - lat2y(l.lat)) * k,\n    zoom: 0\n  };\n};\n\npo.map.coordinateLocation = function(c) {\n  var k = 45 / Math.pow(2, c.zoom - 3);\n  return {\n    lon: k * c.column - 180,\n    lat: y2lat(180 - k * c.row)\n  };\n};\n\n// https://bugs.webkit.org/show_bug.cgi?id=44083\nvar bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0;\npo.layer = function(load, unload) {\n  var layer = {},\n      cache = layer.cache = po.cache(load, unload).size(512),\n      tile = true,\n      visible = true,\n      zoom,\n      id,\n      map,\n      container = po.svg(\"g\"),\n      transform,\n      levelZoom,\n      levels = {};\n\n  container.setAttribute(\"class\", \"layer\");\n  for (var i = -4; i <= -1; i++) levels[i] = container.appendChild(po.svg(\"g\"));\n  for (var i = 2; i >= 1; i--) levels[i] = container.appendChild(po.svg(\"g\"));\n  levels[0] = container.appendChild(po.svg(\"g\"));\n\n  function zoomIn(z) {\n    var end = levels[0].nextSibling;\n    for (; levelZoom < z; levelZoom++) {\n      // -4, -3, -2, -1, +2, +1, =0 // current order\n      // -3, -2, -1, +2, +1, =0, -4 // insertBefore(-4, end)\n      // -3, -2, -1, +1, =0, -4, +2 // insertBefore(+2, end)\n      // -3, -2, -1, =0, -4, +2, +1 // insertBefore(+1, end)\n      // -4, -3, -2, -1, +2, +1, =0 // relabel\n      container.insertBefore(levels[-4], end);\n      container.insertBefore(levels[2], end);\n      container.insertBefore(levels[1], end);\n      var t = levels[-4];\n      for (var dz = -4; dz < 2;) levels[dz] = levels[++dz];\n      levels[dz] = t;\n    }\n  }\n\n  function zoomOut(z) {\n    var end = levels[0].nextSibling;\n    for (; levelZoom > z; levelZoom--) {\n      // -4, -3, -2, -1, +2, +1, =0 // current order\n      // -4, -3, -2, +2, +1, =0, -1 // insertBefore(-1, end)\n      // +2, -4, -3, -2, +1, =0, -1 // insertBefore(+2, -4)\n      // -4, -3, -2, -1, +2, +1, =0 // relabel\n      container.insertBefore(levels[-1], end);\n      container.insertBefore(levels[2], levels[-4]);\n      var t = levels[2];\n      for (var dz = 2; dz > -4;) levels[dz] = levels[--dz];\n      levels[dz] = t;\n    }\n  }\n\n  function move() {\n    var map = layer.map(), // in case the layer is removed\n        mapZoom = map.zoom(),\n        mapZoomFraction = mapZoom - (mapZoom = Math.round(mapZoom)),\n        mapSize = map.size(),\n        mapAngle = map.angle(),\n        tileSize = map.tileSize(),\n        tileCenter = map.locationCoordinate(map.center());\n\n    // set the layer zoom levels\n    if (levelZoom != mapZoom) {\n      if (levelZoom < mapZoom) zoomIn(mapZoom);\n      else if (levelZoom > mapZoom) zoomOut(mapZoom);\n      else levelZoom = mapZoom;\n      for (var z = -4; z <= 2; z++) {\n        var l = levels[z];\n        l.setAttribute(\"class\", \"zoom\" + (z < 0 ? \"\" : \"+\") + z + \" zoom\" + (mapZoom + z));\n        l.setAttribute(\"transform\", \"scale(\" + Math.pow(2, -z) + \")\");\n      }\n    }\n\n    // set the layer transform\n    container.setAttribute(\"transform\",\n        \"translate(\" + (mapSize.x / 2) + \",\" + (mapSize.y / 2) + \")\"\n        + (mapAngle ? \"rotate(\" + mapAngle / Math.PI * 180 + \")\" : \"\")\n        + (mapZoomFraction ? \"scale(\" + Math.pow(2, mapZoomFraction) + \")\" : \"\")\n        + (transform ? transform.zoomFraction(mapZoomFraction) : \"\"));\n\n    // get the coordinates of the four corners\n    var c0 = map.pointCoordinate(tileCenter, zero),\n        c1 = map.pointCoordinate(tileCenter, {x: mapSize.x, y: 0}),\n        c2 = map.pointCoordinate(tileCenter, mapSize),\n        c3 = map.pointCoordinate(tileCenter, {x: 0, y: mapSize.y});\n\n    // round to pixel boundary to avoid anti-aliasing artifacts\n    if (!mapZoomFraction && !mapAngle && !transform) {\n      tileCenter.column = (Math.round(tileSize.x * tileCenter.column) + (mapSize.x & 1) / 2) / tileSize.x;\n      tileCenter.row = (Math.round(tileSize.y * tileCenter.row) + (mapSize.y & 1) / 2) / tileSize.y;\n    }\n\n    // layer-specific coordinate transform\n    if (transform) {\n      c0 = transform.unapply(c0);\n      c1 = transform.unapply(c1);\n      c2 = transform.unapply(c2);\n      c3 = transform.unapply(c3);\n      tileCenter = transform.unapply(tileCenter);\n    }\n\n    // layer-specific zoom transform\n    var tileLevel = zoom ? zoom(c0.zoom) - c0.zoom : 0;\n    if (tileLevel) {\n      var k = Math.pow(2, tileLevel);\n      c0.column *= k; c0.row *= k;\n      c1.column *= k; c1.row *= k;\n      c2.column *= k; c2.row *= k;\n      c3.column *= k; c3.row *= k;\n      c0.zoom = c1.zoom = c2.zoom = c3.zoom += tileLevel;\n    }\n\n    // tile-specific projection\n    function projection(c) {\n      var zoom = c.zoom,\n          max = zoom < 0 ? 1 : 1 << zoom,\n          column = c.column % max,\n          row = c.row;\n      if (column < 0) column += max;\n      return {\n        locationPoint: function(l) {\n          var c = po.map.locationCoordinate(l),\n              k = Math.pow(2, zoom - c.zoom);\n          return {\n            x: tileSize.x * (k * c.column - column),\n            y: tileSize.y * (k * c.row - row)\n          };\n        }\n      };\n    }\n\n    // record which tiles are visible\n    var oldLocks = cache.locks(), newLocks = {};\n\n    // reset the proxy counts\n    for (var key in oldLocks) {\n      oldLocks[key].proxyCount = 0;\n    }\n\n    // load the tiles!\n    if (visible && tileLevel > -5 && tileLevel < 3) {\n      var ymax = c0.zoom < 0 ? 1 : 1 << c0.zoom;\n      if (tile) {\n        scanTriangle(c0, c1, c2, 0, ymax, scanLine);\n        scanTriangle(c2, c3, c0, 0, ymax, scanLine);\n      } else {\n        var x = Math.floor((c0.column + c2.column) / 2),\n            y = Math.max(0, Math.min(ymax - 1, Math.floor((c1.row + c3.row) / 2))),\n            z = Math.min(4, c0.zoom);\n        x = x >> z << z;\n        y = y >> z << z;\n        scanLine(x, x + 1, y);\n      }\n    }\n\n    // scan-line conversion\n    function scanLine(x0, x1, y) {\n      var z = c0.zoom,\n          z0 = 2 - tileLevel,\n          z1 = 4 + tileLevel;\n\n      for (var x = x0; x < x1; x++) {\n        var t = cache.load({column: x, row: y, zoom: z}, projection);\n        if (!t.ready && !(t.key in newLocks)) {\n          t.proxyRefs = {};\n          var c, full, proxy;\n\n          // downsample high-resolution tiles\n          for (var dz = 1; dz <= z0; dz++) {\n            full = true;\n            for (var dy = 0, k = 1 << dz; dy <= k; dy++) {\n              for (var dx = 0; dx <= k; dx++) {\n                proxy = cache.peek(c = {\n                  column: (x << dz) + dx,\n                  row: (y << dz) + dy,\n                  zoom: z + dz\n                });\n                if (proxy && proxy.ready) {\n                  newLocks[proxy.key] = cache.load(c);\n                  proxy.proxyCount++;\n                  t.proxyRefs[proxy.key] = proxy;\n                } else {\n                  full = false;\n                }\n              }\n            }\n            if (full) break;\n          }\n\n          // upsample low-resolution tiles\n          if (!full) {\n            for (var dz = 1; dz <= z1; dz++) {\n              proxy = cache.peek(c = {\n                column: x >> dz,\n                row: y >> dz,\n                zoom: z - dz\n              });\n              if (proxy && proxy.ready) {\n                newLocks[proxy.key] = cache.load(c);\n                proxy.proxyCount++;\n                t.proxyRefs[proxy.key] = proxy;\n                break;\n              }\n            }\n          }\n        }\n        newLocks[t.key] = t;\n      }\n    }\n\n    // position tiles\n    for (var key in newLocks) {\n      var t = newLocks[key],\n          k = Math.pow(2, t.level = t.zoom - tileCenter.zoom);\n      t.element.setAttribute(\"transform\", \"translate(\"\n        + (t.x = tileSize.x * (t.column - tileCenter.column * k)) + \",\"\n        + (t.y = tileSize.y * (t.row - tileCenter.row * k)) + \")\");\n    }\n\n    // remove tiles that are no longer visible\n    for (var key in oldLocks) {\n      if (!(key in newLocks)) {\n        var t = cache.unload(key);\n        t.element.parentNode.removeChild(t.element);\n        delete t.proxyRefs;\n      }\n    }\n\n    // append tiles that are now visible\n    for (var key in newLocks) {\n      var t = newLocks[key];\n      if (t.element.parentNode != levels[t.level]) {\n        levels[t.level].appendChild(t.element);\n        if (layer.show) layer.show(t);\n      }\n    }\n\n    // flush the cache, clearing no-longer-needed tiles\n    cache.flush();\n\n    // dispatch the move event\n    layer.dispatch({type: \"move\"});\n  }\n\n  // remove proxy tiles when tiles load\n  function cleanup(e) {\n    if (e.tile.proxyRefs) {\n      for (var proxyKey in e.tile.proxyRefs) {\n        var proxyTile = e.tile.proxyRefs[proxyKey];\n        if ((--proxyTile.proxyCount <= 0) && cache.unload(proxyKey)) {\n          proxyTile.element.parentNode.removeChild(proxyTile.element);\n        }\n      }\n      delete e.tile.proxyRefs;\n    }\n  }\n\n  layer.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      if (map == x) {\n        container.parentNode.appendChild(container); // move to end\n        return layer;\n      }\n      map.off(\"move\", move).off(\"resize\", move);\n      container.parentNode.removeChild(container);\n    }\n    map = x;\n    if (map) {\n      map.container().appendChild(container);\n      if (layer.init) layer.init(container);\n      map.on(\"move\", move).on(\"resize\", move);\n      move();\n    }\n    return layer;\n  };\n\n  layer.container = function() {\n    return container;\n  };\n\n  layer.levels = function() {\n    return levels;\n  };\n\n  layer.id = function(x) {\n    if (!arguments.length) return id;\n    id = x;\n    container.setAttribute(\"id\", x);\n    return layer;\n  };\n\n  layer.visible = function(x) {\n    if (!arguments.length) return visible;\n    if (visible = x) container.removeAttribute(\"visibility\")\n    else container.setAttribute(\"visibility\", \"hidden\");\n    if (map) move();\n    return layer;\n  };\n\n  layer.transform = function(x) {\n    if (!arguments.length) return transform;\n    transform = x;\n    if (map) move();\n    return layer;\n  };\n\n  layer.zoom = function(x) {\n    if (!arguments.length) return zoom;\n    zoom = typeof x == \"function\" || x == null ? x : function() { return x; };\n    if (map) move();\n    return layer;\n  };\n\n  layer.tile = function(x) {\n    if (!arguments.length) return tile;\n    tile = x;\n    if (map) move();\n    return layer;\n  };\n\n  layer.reload = function() {\n    cache.clear();\n    if (map) move();\n    return layer;\n  };\n\n  layer.dispatch = po.dispatch(layer);\n  layer.on(\"load\", cleanup);\n\n  return layer;\n};\n\n// scan-line conversion\nfunction edge(a, b) {\n  if (a.row > b.row) { var t = a; a = b; b = t; }\n  return {\n    x0: a.column,\n    y0: a.row,\n    x1: b.column,\n    y1: b.row,\n    dx: b.column - a.column,\n    dy: b.row - a.row\n  };\n}\n\n// scan-line conversion\nfunction scanSpans(e0, e1, ymin, ymax, scanLine) {\n  var y0 = Math.max(ymin, Math.floor(e1.y0)),\n      y1 = Math.min(ymax, Math.ceil(e1.y1));\n\n  // sort edges by x-coordinate\n  if ((e0.x0 == e1.x0 && e0.y0 == e1.y0)\n      ? (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1)\n      : (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0)) {\n    var t = e0; e0 = e1; e1 = t;\n  }\n\n  // scan lines!\n  var m0 = e0.dx / e0.dy,\n      m1 = e1.dx / e1.dy,\n      d0 = e0.dx > 0, // use y + 1 to compute x0\n      d1 = e1.dx < 0; // use y + 1 to compute x1\n  for (var y = y0; y < y1; y++) {\n    var x0 = m0 * Math.max(0, Math.min(e0.dy, y + d0 - e0.y0)) + e0.x0,\n        x1 = m1 * Math.max(0, Math.min(e1.dy, y + d1 - e1.y0)) + e1.x0;\n    scanLine(Math.floor(x1), Math.ceil(x0), y);\n  }\n}\n\n// scan-line conversion\nfunction scanTriangle(a, b, c, ymin, ymax, scanLine) {\n  var ab = edge(a, b),\n      bc = edge(b, c),\n      ca = edge(c, a);\n\n  // sort edges by y-length\n  if (ab.dy > bc.dy) { var t = ab; ab = bc; bc = t; }\n  if (ab.dy > ca.dy) { var t = ab; ab = ca; ca = t; }\n  if (bc.dy > ca.dy) { var t = bc; bc = ca; ca = t; }\n\n  // scan span! scan span!\n  if (ab.dy) scanSpans(ca, ab, ymin, ymax, scanLine);\n  if (bc.dy) scanSpans(ca, bc, ymin, ymax, scanLine);\n}\npo.image = function() {\n  var image = po.layer(load, unload),\n      url;\n\n  function load(tile) {\n    var element = tile.element = po.svg(\"image\"), size = image.map().tileSize();\n    element.setAttribute(\"preserveAspectRatio\", \"none\");\n    element.setAttribute(\"width\", size.x);\n    element.setAttribute(\"height\", size.y);\n\n    if (typeof url == \"function\") {\n      element.setAttribute(\"opacity\", 0);\n      var tileUrl = url(tile);\n      if (tileUrl != null) {\n        tile.request = po.queue.image(element, tileUrl, function(img) {\n          delete tile.request;\n          tile.ready = true;\n          tile.img = img;\n          element.removeAttribute(\"opacity\");\n          image.dispatch({type: \"load\", tile: tile});\n        });\n      } else {\n        tile.ready = true;\n        image.dispatch({type: \"load\", tile: tile});\n      }\n    } else {\n      tile.ready = true;\n      if (url != null) element.setAttributeNS(po.ns.xlink, \"href\", url);\n      image.dispatch({type: \"load\", tile: tile});\n    }\n  }\n\n  function unload(tile) {\n    if (tile.request) tile.request.abort(true);\n  }\n\n  image.url = function(x) {\n    if (!arguments.length) return url;\n    url = typeof x == \"string\" && /{.}/.test(x) ? po.url(x) : x;\n    return image.reload();\n  };\n\n  return image;\n};\npo.geoJson = function(fetch) {\n  var geoJson = po.layer(load, unload),\n      container = geoJson.container(),\n      url,\n      clip = true,\n      clipId = \"org.polymaps.\" + po.id(),\n      clipHref = \"url(#\" + clipId + \")\",\n      clipPath = container.insertBefore(po.svg(\"clipPath\"), container.firstChild),\n      clipRect = clipPath.appendChild(po.svg(\"rect\")),\n      scale = \"auto\",\n      zoom = null,\n      features;\n\n  container.setAttribute(\"fill-rule\", \"evenodd\");\n  clipPath.setAttribute(\"id\", clipId);\n\n  if (!arguments.length) fetch = po.queue.json;\n\n  function projection(proj) {\n    var l = {lat: 0, lon: 0};\n    return function(coordinates) {\n      l.lat = coordinates[1];\n      l.lon = coordinates[0];\n      var p = proj(l);\n      coordinates.x = p.x;\n      coordinates.y = p.y;\n      return p;\n    };\n  }\n\n  function geometry(o, proj) {\n    return o && o.type in types && types[o.type](o, proj);\n  }\n\n  var types = {\n\n    Point: function(o, proj) {\n      var p = proj(o.coordinates),\n          c = po.svg(\"circle\");\n      c.setAttribute(\"r\", 4.5);\n      c.setAttribute(\"transform\", \"translate(\" + p.x + \",\" + p.y + \")\");\n      return c;\n    },\n\n    MultiPoint: function(o, proj) {\n      var g = po.svg(\"g\"),\n          c = o.coordinates,\n          p, // proj(c[i])\n          x, // svg:circle\n          i = -1,\n          n = c.length;\n      while (++i < n) {\n        x = g.appendChild(po.svg(\"circle\"));\n        x.setAttribute(\"r\", 4.5);\n        x.setAttribute(\"transform\", \"translate(\" + (p = proj(c[i])).x + \",\" + p.y + \")\");\n      }\n      return g;\n    },\n\n    LineString: function(o, proj) {\n      var x = po.svg(\"path\"),\n          d = [\"M\"],\n          c = o.coordinates,\n          p, // proj(c[i])\n          i = -1,\n          n = c.length;\n      while (++i < n) d.push((p = proj(c[i])).x, \",\", p.y, \"L\");\n      d.pop();\n      if (!d.length) return;\n      x.setAttribute(\"d\", d.join(\"\"));\n      return x;\n    },\n\n    MultiLineString: function(o, proj) {\n      var x = po.svg(\"path\"),\n          d = [],\n          ci = o.coordinates,\n          cj, // ci[i]\n          i = -1,\n          j,\n          n = ci.length,\n          m;\n      while (++i < n) {\n        cj = ci[i];\n        j = -1;\n        m = cj.length;\n        d.push(\"M\");\n        while (++j < m) d.push((p = proj(cj[j])).x, \",\", p.y, \"L\");\n        d.pop();\n      }\n      if (!d.length) return;\n      x.setAttribute(\"d\", d.join(\"\"));\n      return x;\n    },\n\n    Polygon: function(o, proj) {\n      var x = po.svg(\"path\"),\n          d = [],\n          ci = o.coordinates,\n          cj, // ci[i]\n          i = -1,\n          j,\n          n = ci.length,\n          m;\n      while (++i < n) {\n        cj = ci[i];\n        j = -1;\n        m = cj.length - 1;\n        d.push(\"M\");\n        while (++j < m) d.push((p = proj(cj[j])).x, \",\", p.y, \"L\");\n        d[d.length - 1] = \"Z\";\n      }\n      if (!d.length) return;\n      x.setAttribute(\"d\", d.join(\"\"));\n      return x;\n    },\n\n    MultiPolygon: function(o, proj) {\n      var x = po.svg(\"path\"),\n          d = [],\n          ci = o.coordinates,\n          cj, // ci[i]\n          ck, // cj[j]\n          i = -1,\n          j,\n          k,\n          n = ci.length,\n          m,\n          l;\n      while (++i < n) {\n        cj = ci[i];\n        j = -1;\n        m = cj.length;\n        while (++j < m) {\n          ck = cj[j];\n          k = -1;\n          l = ck.length - 1;\n          d.push(\"M\");\n          while (++k < l) d.push((p = proj(ck[k])).x, \",\", p.y, \"L\");\n          d[d.length - 1] = \"Z\";\n        }\n      }\n      if (!d.length) return;\n      x.setAttribute(\"d\", d.join(\"\"));\n      return x;\n    },\n\n    GeometryCollection: function(o, proj) {\n      var g = po.svg(\"g\"),\n          i = -1,\n          c = o.geometries,\n          n = c.length,\n          x;\n      while (++i < n) {\n        x = geometry(c[i], proj);\n        if (x) g.appendChild(x);\n      }\n      return g;\n    }\n\n  };\n\n  function rescale(o, e, k) {\n    return o.type in rescales && rescales[o.type](o, e, k);\n  }\n\n  var rescales = {\n\n    Point: function (o, e, k) {\n      var p = o.coordinates;\n      e.setAttribute(\"transform\", \"translate(\" + p.x + \",\" + p.y + \")\" + k);\n    },\n\n    MultiPoint: function (o, e, k) {\n      var c = o.coordinates,\n          i = -1,\n          n = p.length,\n          x = e.firstChild,\n          p;\n      while (++i < n) {\n        p = c[i];\n        x.setAttribute(\"transform\", \"translate(\" + p.x + \",\" + p.y + \")\" + k);\n        x = x.nextSibling;\n      }\n    }\n\n  };\n\n  function load(tile, proj) {\n    var g = tile.element = po.svg(\"g\");\n    tile.features = [];\n\n    proj = projection(proj(tile).locationPoint);\n\n    function update(data) {\n      var updated = [];\n\n      /* Fetch the next batch of features, if so directed. */\n      if (data.next) tile.request = fetch(data.next.href, update);\n\n      /* Convert the GeoJSON to SVG. */\n      switch (data.type) {\n        case \"FeatureCollection\": {\n          for (var i = 0; i < data.features.length; i++) {\n            var feature = data.features[i],\n                element = geometry(feature.geometry, proj);\n            if (element) updated.push({element: g.appendChild(element), data: feature});\n          }\n          break;\n        }\n        case \"Feature\": {\n          var element = geometry(data.geometry, proj);\n          if (element) updated.push({element: g.appendChild(element), data: data});\n          break;\n        }\n        default: {\n          var element = geometry(data, proj);\n          if (element) updated.push({element: g.appendChild(element), data: {type: \"Feature\", geometry: data}});\n          break;\n        }\n      }\n\n      tile.ready = true;\n      updated.push.apply(tile.features, updated);\n      geoJson.dispatch({type: \"load\", tile: tile, features: updated});\n    }\n\n    if (url != null) {\n      tile.request = fetch(typeof url == \"function\" ? url(tile) : url, update);\n    } else {\n      update({type: \"FeatureCollection\", features: features || []});\n    }\n  }\n\n  function unload(tile) {\n    if (tile.request) tile.request.abort(true);\n  }\n\n  function move() {\n    var zoom = geoJson.map().zoom(),\n        tiles = geoJson.cache.locks(), // visible tiles\n        key, // key in locks\n        tile, // locks[key]\n        features, // tile.features\n        i, // current feature index\n        n, // current feature count, features.length\n        feature, // features[i]\n        k; // scale transform\n    if (scale == \"fixed\") {\n      for (key in tiles) {\n        if ((tile = tiles[key]).scale != zoom) {\n          k = \"scale(\" + Math.pow(2, tile.zoom - zoom) + \")\";\n          i = -1;\n          n = (features = tile.features).length;\n          while (++i < n) rescale((feature = features[i]).data.geometry, feature.element, k);\n          tile.scale = zoom;\n        }\n      }\n    } else {\n      for (key in tiles) {\n        i = -1;\n        n = (features = (tile = tiles[key]).features).length;\n        while (++i < n) rescale((feature = features[i]).data.geometry, feature.element, \"\");\n        delete tile.scale;\n      }\n    }\n  }\n\n  geoJson.url = function(x) {\n    if (!arguments.length) return url;\n    url = typeof x == \"string\" && /{.}/.test(x) ? po.url(x) : x;\n    if (url != null) features = null;\n    if (typeof url == \"string\") geoJson.tile(false);\n    return geoJson.reload();\n  };\n\n  geoJson.features = function(x) {\n    if (!arguments.length) return features;\n    if (features = x) {\n      url = null;\n      geoJson.tile(false);\n    }\n    return geoJson.reload();\n  };\n\n  geoJson.clip = function(x) {\n    if (!arguments.length) return clip;\n    if (clip) container.removeChild(clipPath);\n    if (clip = x) container.insertBefore(clipPath, container.firstChild);\n    var locks = geoJson.cache.locks();\n    for (var key in locks) {\n      if (clip) locks[key].element.setAttribute(\"clip-path\", clipHref);\n      else locks[key].element.removeAttribute(\"clip-path\");\n    }\n    return geoJson;\n  };\n\n  var __tile__ = geoJson.tile;\n  geoJson.tile = function(x) {\n    if (arguments.length && !x) geoJson.clip(x);\n    return __tile__.apply(geoJson, arguments);\n  };\n\n  var __map__ = geoJson.map;\n  geoJson.map = function(x) {\n    if (x && clipRect) {\n      var size = x.tileSize();\n      clipRect.setAttribute(\"width\", size.x);\n      clipRect.setAttribute(\"height\", size.y);\n    }\n    return __map__.apply(geoJson, arguments);\n  };\n\n  geoJson.scale = function(x) {\n    if (!arguments.length) return scale;\n    if (scale = x) geoJson.on(\"move\", move);\n    else geoJson.off(\"move\", move);\n    if (geoJson.map()) move();\n    return geoJson;\n  };\n\n  geoJson.show = function(tile) {\n    if (clip) tile.element.setAttribute(\"clip-path\", clipHref);\n    else tile.element.removeAttribute(\"clip-path\");\n    geoJson.dispatch({type: \"show\", tile: tile, features: tile.features});\n    return geoJson;\n  };\n\n  geoJson.reshow = function() {\n    var locks = geoJson.cache.locks();\n    for (var key in locks) geoJson.show(locks[key]);\n    return geoJson;\n  };\n\n  return geoJson;\n};\npo.dblclick = function() {\n  var dblclick = {},\n      zoom = \"mouse\",\n      map,\n      container;\n\n  function handle(e) {\n    var z = map.zoom();\n    if (e.shiftKey) z = Math.ceil(z) - z - 1;\n    else z = 1 - z + Math.floor(z);\n    zoom === \"mouse\" ? map.zoomBy(z, map.mouse(e)) : map.zoomBy(z);\n  }\n\n  dblclick.zoom = function(x) {\n    if (!arguments.length) return zoom;\n    zoom = x;\n    return dblclick;\n  };\n\n  dblclick.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      container.removeEventListener(\"dblclick\", handle, false);\n      container = null;\n    }\n    if (map = x) {\n      container = map.container();\n      container.addEventListener(\"dblclick\", handle, false);\n    }\n    return dblclick;\n  };\n\n  return dblclick;\n};\npo.drag = function() {\n  var drag = {},\n      map,\n      container,\n      dragging;\n\n  function mousedown(e) {\n    if (e.shiftKey) return;\n    dragging = {\n      x: e.clientX,\n      y: e.clientY\n    };\n    map.focusableParent().focus();\n    e.preventDefault();\n    document.body.style.setProperty(\"cursor\", \"move\", null);\n  }\n\n  function mousemove(e) {\n    if (!dragging) return;\n    map.panBy({x: e.clientX - dragging.x, y: e.clientY - dragging.y});\n    dragging.x = e.clientX;\n    dragging.y = e.clientY;\n  }\n\n  function mouseup(e) {\n    if (!dragging) return;\n    mousemove(e);\n    dragging = null;\n    document.body.style.removeProperty(\"cursor\");\n  }\n\n  drag.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      container.removeEventListener(\"mousedown\", mousedown, false);\n      container = null;\n    }\n    if (map = x) {\n      container = map.container();\n      container.addEventListener(\"mousedown\", mousedown, false);\n    }\n    return drag;\n  };\n\n  window.addEventListener(\"mousemove\", mousemove, false);\n  window.addEventListener(\"mouseup\", mouseup, false);\n\n  return drag;\n};\npo.wheel = function() {\n  var wheel = {},\n      timePrev = 0,\n      last = 0,\n      smooth = true,\n      zoom = \"mouse\",\n      location,\n      map,\n      container;\n\n  function move(e) {\n    location = null;\n  }\n\n  // mousewheel events are totally broken!\n  // https://bugs.webkit.org/show_bug.cgi?id=40441\n  // not only that, but Chrome and Safari differ in re. to acceleration!\n  var inner = document.createElement(\"div\"),\n      outer = document.createElement(\"div\");\n  outer.style.visibility = \"hidden\";\n  outer.style.top = \"0px\";\n  outer.style.height = \"0px\";\n  outer.style.width = \"0px\";\n  outer.style.overflowY = \"scroll\";\n  inner.style.height = \"2000px\";\n  outer.appendChild(inner);\n  document.body.appendChild(outer);\n\n  function mousewheel(e) {\n    var delta = e.wheelDelta || -e.detail,\n        point;\n\n    /* Detect the pixels that would be scrolled by this wheel event. */\n    if (delta) {\n      if (smooth) {\n        try {\n          outer.scrollTop = 1000;\n          outer.dispatchEvent(e);\n          delta = 1000 - outer.scrollTop;\n        } catch (error) {\n          // Derp! Hope for the best?\n        }\n        delta *= .005;\n      }\n\n      /* If smooth zooming is disabled, batch events into unit steps. */\n      else {\n        var timeNow = Date.now();\n        if (timeNow - timePrev > 200) {\n          delta = delta > 0 ? +1 : -1;\n          timePrev = timeNow;\n        } else {\n          delta = 0;\n        }\n      }\n    }\n\n    if (delta) {\n      switch (zoom) {\n        case \"mouse\": {\n          point = map.mouse(e);\n          if (!location) location = map.pointLocation(point);\n          map.off(\"move\", move).zoomBy(delta, point, location).on(\"move\", move);\n          break;\n        }\n        case \"location\": {\n          map.zoomBy(delta, map.locationPoint(location), location);\n          break;\n        }\n        default: { // center\n          map.zoomBy(delta);\n          break;\n        }\n      }\n    }\n\n    e.preventDefault();\n    return false; // for Firefox\n  }\n\n  wheel.smooth = function(x) {\n    if (!arguments.length) return smooth;\n    smooth = x;\n    return wheel;\n  };\n\n  wheel.zoom = function(x, l) {\n    if (!arguments.length) return zoom;\n    zoom = x;\n    location = l;\n    if (map) {\n      if (zoom == \"mouse\") map.on(\"move\", move);\n      else map.off(\"move\", move);\n    }\n    return wheel;\n  };\n\n  wheel.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      container.removeEventListener(\"mousemove\", move, false);\n      container.removeEventListener(\"mousewheel\", mousewheel, false);\n      container.removeEventListener(\"MozMousePixelScroll\", mousewheel, false);\n      container = null;\n      map.off(\"move\", move);\n    }\n    if (map = x) {\n      if (zoom == \"mouse\") map.on(\"move\", move);\n      container = map.container();\n      container.addEventListener(\"mousemove\", move, false);\n      container.addEventListener(\"mousewheel\", mousewheel, false);\n      container.addEventListener(\"MozMousePixelScroll\", mousewheel, false);\n    }\n    return wheel;\n  };\n\n  return wheel;\n};\npo.arrow = function() {\n  var arrow = {},\n      key = {left: 0, right: 0, up: 0, down: 0},\n      last = 0,\n      repeatTimer,\n      repeatDelay = 250,\n      repeatInterval = 50,\n      speed = 16,\n      map,\n      parent;\n\n  function keydown(e) {\n    if (e.ctrlKey || e.altKey || e.metaKey) return;\n    var now = Date.now(), dx = 0, dy = 0;\n    switch (e.keyCode) {\n      case 37: {\n        if (!key.left) {\n          last = now;\n          key.left = 1;\n          if (!key.right) dx = speed;\n        }\n        break;\n      }\n      case 39: {\n        if (!key.right) {\n          last = now;\n          key.right = 1;\n          if (!key.left) dx = -speed;\n        }\n        break;\n      }\n      case 38: {\n        if (!key.up) {\n          last = now;\n          key.up = 1;\n          if (!key.down) dy = speed;\n        }\n        break;\n      }\n      case 40: {\n        if (!key.down) {\n          last = now;\n          key.down = 1;\n          if (!key.up) dy = -speed;\n        }\n        break;\n      }\n      default: return;\n    }\n    if (dx || dy) map.panBy({x: dx, y: dy});\n    if (!repeatTimer && (key.left | key.right | key.up | key.down)) {\n      repeatTimer = setInterval(repeat, repeatInterval);\n    }\n    e.preventDefault();\n  }\n\n  function keyup(e) {\n    last = Date.now();\n    switch (e.keyCode) {\n      case 37: key.left = 0; break;\n      case 39: key.right = 0; break;\n      case 38: key.up = 0; break;\n      case 40: key.down = 0; break;\n      default: return;\n    }\n    if (repeatTimer && !(key.left | key.right | key.up | key.down)) {\n      repeatTimer = clearInterval(repeatTimer);\n    }\n    e.preventDefault();\n  }\n\n  function keypress(e) {\n    switch (e.charCode) {\n      case 45: case 95: map.zoom(Math.ceil(map.zoom()) - 1); break; // - _\n      case 43: case 61: map.zoom(Math.floor(map.zoom()) + 1); break; // = +\n      default: return;\n    }\n    e.preventDefault();\n  }\n\n  function repeat() {\n    if (!map) return;\n    if (Date.now() < last + repeatDelay) return;\n    var dx = (key.left - key.right) * speed,\n        dy = (key.up - key.down) * speed;\n    if (dx || dy) map.panBy({x: dx, y: dy});\n  }\n\n  arrow.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      parent.removeEventListener(\"keypress\", keypress, false);\n      parent.removeEventListener(\"keydown\", keydown, false);\n      parent.removeEventListener(\"keyup\", keyup, false);\n      parent = null;\n    }\n    if (map = x) {\n      parent = map.focusableParent();\n      parent.addEventListener(\"keypress\", keypress, false);\n      parent.addEventListener(\"keydown\", keydown, false);\n      parent.addEventListener(\"keyup\", keyup, false);\n    }\n    return arrow;\n  };\n\n  arrow.speed = function(x) {\n    if (!arguments.length) return speed;\n    speed = x;\n    return arrow;\n  };\n\n  return arrow;\n};\npo.hash = function() {\n  var hash = {},\n      s0, // cached location.hash\n      lat = 90 - 1e-8, // allowable latitude range\n      map;\n\n  var parser = function(map, s) {\n    var args = s.split(\"/\").map(Number);\n    if (args.length < 3 || args.some(isNaN)) return true; // replace bogus hash\n    else {\n      var size = map.size();\n      map.zoomBy(args[0] - map.zoom(),\n          {x: size.x / 2, y: size.y / 2},\n          {lat: Math.min(lat, Math.max(-lat, args[1])), lon: args[2]});\n    }\n  };\n\n  var formatter = function(map) {\n    var center = map.center(),\n        zoom = map.zoom(),\n        precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));\n    return \"#\" + zoom.toFixed(2)\n             + \"/\" + center.lat.toFixed(precision)\n             + \"/\" + center.lon.toFixed(precision);\n  };\n\n  function move() {\n    var s1 = formatter(map);\n    if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!\n  }\n\n  function hashchange() {\n    if (location.hash === s0) return; // ignore spurious hashchange events\n    if (parser(map, (s0 = location.hash).substring(1)))\n      move(); // replace bogus hash\n  }\n\n  hash.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      map.off(\"move\", move);\n      window.removeEventListener(\"hashchange\", hashchange, false);\n    }\n    if (map = x) {\n      map.on(\"move\", move);\n      window.addEventListener(\"hashchange\", hashchange, false);\n      location.hash ? hashchange() : move();\n    }\n    return hash;\n  };\n\n  hash.parser = function(x) {\n    if (!arguments.length) return parser;\n    parser = x;\n    return hash;\n  };\n\n  hash.formatter = function(x) {\n    if (!arguments.length) return formatter;\n    formatter = x;\n    return hash;\n  };\n\n  return hash;\n};\npo.touch = function() {\n  var touch = {},\n      map,\n      container,\n      rotate = false,\n      last = 0,\n      zoom,\n      angle,\n      locations = {}; // touch identifier -> location\n\n\n  function touchstart(e) {\n    var i = -1,\n        n = e.touches.length,\n        t = Date.now();\n\n    // doubletap detection\n    if ((n == 1) && (t - last < 300)) {\n      var z = map.zoom();\n      map.zoomBy(1 - z + Math.floor(z), map.mouse(e.touches[0]));\n      e.preventDefault();\n    }\n    last = t;\n\n    // store original zoom & touch locations\n    zoom = map.zoom();\n    angle = map.angle();\n    while (++i < n) {\n      t = e.touches[i];\n      locations[t.identifier] = map.pointLocation(map.mouse(t));\n    }\n  }\n\n  function touchmove(e) {\n    switch (e.touches.length) {\n      case 1: { // single-touch pan\n        var t0 = e.touches[0];\n        map.zoomBy(0, map.mouse(t0), locations[t0.identifier]);\n        e.preventDefault();\n        break;\n      }\n      case 2: { // double-touch pan + zoom + rotate\n        var t0 = e.touches[0],\n            t1 = e.touches[1],\n            p0 = map.mouse(t0),\n            p1 = map.mouse(t1),\n            p2 = {x: (p0.x + p1.x) / 2, y: (p0.y + p1.y) / 2}, // center point\n            c0 = po.map.locationCoordinate(locations[t0.identifier]),\n            c1 = po.map.locationCoordinate(locations[t1.identifier]),\n            c2 = {row: (c0.row + c1.row) / 2, column: (c0.column + c1.column) / 2, zoom: 0},\n            l2 = po.map.coordinateLocation(c2); // center location\n        map.zoomBy(Math.log(e.scale) / Math.LN2 + zoom - map.zoom(), p2, l2);\n        if (rotate) map.angle(e.rotation / 180 * Math.PI + angle);\n        e.preventDefault();\n        break;\n      }\n    }\n  }\n\n  touch.rotate = function(x) {\n    if (!arguments.length) return rotate;\n    rotate = x;\n    return touch;\n  };\n\n  touch.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      container.removeEventListener(\"touchstart\", touchstart, false);\n      window.removeEventListener(\"touchmove\", touchmove, false);\n      container = null;\n    }\n    if (map = x) {\n      container = map.container();\n      container.addEventListener(\"touchstart\", touchstart, false);\n      window.addEventListener(\"touchmove\", touchmove, false);\n    }\n    return touch;\n  };\n\n  return touch;\n};\n// Default map controls.\npo.interact = function() {\n  var interact = {},\n      drag = po.drag(),\n      wheel = po.wheel(),\n      dblclick = po.dblclick(),\n      touch = po.touch(),\n      arrow = po.arrow();\n\n  interact.map = function(x) {\n    drag.map(x);\n    wheel.map(x);\n    dblclick.map(x);\n    touch.map(x);\n    arrow.map(x);\n    return interact;\n  };\n\n  return interact;\n};\npo.compass = function() {\n  var compass = {},\n      g = po.svg(\"g\"),\n      ticks = {},\n      r = 30,\n      speed = 16,\n      last = 0,\n      repeatDelay = 250,\n      repeatInterval = 50,\n      position = \"top-left\", // top-left, top-right, bottom-left, bottom-right\n      zoomStyle = \"small\", // none, small, big\n      zoomContainer,\n      panStyle = \"small\", // none, small\n      panTimer,\n      panDirection,\n      panContainer,\n      drag,\n      dragRect = po.svg(\"rect\"),\n      map,\n      container,\n      window;\n\n  g.setAttribute(\"class\", \"compass\");\n  dragRect.setAttribute(\"class\", \"back fore\");\n  dragRect.setAttribute(\"pointer-events\", \"none\");\n  dragRect.setAttribute(\"display\", \"none\");\n\n  function panStart(e) {\n    g.setAttribute(\"class\", \"compass active\");\n    if (!panTimer) panTimer = setInterval(panRepeat, repeatInterval);\n    if (panDirection) map.panBy(panDirection);\n    last = Date.now();\n    return cancel(e);\n  }\n\n  function panRepeat() {\n    if (panDirection && (Date.now() > last + repeatDelay)) {\n      map.panBy(panDirection);\n    }\n  }\n\n  function mousedown(e) {\n    if (e.shiftKey) {\n      drag = {x0: map.mouse(e)};\n      map.focusableParent().focus();\n      return cancel(e);\n    }\n  }\n\n  function mousemove(e) {\n    if (!drag) return;\n    drag.x1 = map.mouse(e);\n    dragRect.setAttribute(\"x\", Math.min(drag.x0.x, drag.x1.x));\n    dragRect.setAttribute(\"y\", Math.min(drag.x0.y, drag.x1.y));\n    dragRect.setAttribute(\"width\", Math.abs(drag.x0.x - drag.x1.x));\n    dragRect.setAttribute(\"height\", Math.abs(drag.x0.y - drag.x1.y));\n    dragRect.removeAttribute(\"display\");\n  }\n\n  function mouseup(e) {\n    g.setAttribute(\"class\", \"compass\");\n    if (drag) {\n      if (drag.x1) {\n        map.extent([\n          map.pointLocation({\n            x: Math.min(drag.x0.x, drag.x1.x),\n            y: Math.max(drag.x0.y, drag.x1.y)\n          }),\n          map.pointLocation({\n            x: Math.max(drag.x0.x, drag.x1.x),\n            y: Math.min(drag.x0.y, drag.x1.y)\n          })\n        ]);\n        dragRect.setAttribute(\"display\", \"none\");\n      }\n      drag = null;\n    }\n    if (panTimer) {\n      clearInterval(panTimer);\n      panTimer = 0;\n    }\n  }\n\n  function panBy(x) {\n    return function() {\n      x ? this.setAttribute(\"class\", \"active\") : this.removeAttribute(\"class\");\n      panDirection = x;\n    };\n  }\n\n  function zoomBy(x) {\n    return function(e) {\n      g.setAttribute(\"class\", \"compass active\");\n      var z = map.zoom();\n      map.zoom(x < 0 ? Math.ceil(z) - 1 : Math.floor(z) + 1);\n      return cancel(e);\n    };\n  }\n\n  function zoomTo(x) {\n    return function(e) {\n      map.zoom(x);\n      return cancel(e);\n    };\n  }\n\n  function zoomOver() {\n    this.setAttribute(\"class\", \"active\");\n  }\n\n  function zoomOut() {\n    this.removeAttribute(\"class\");\n  }\n\n  function cancel(e) {\n    e.stopPropagation();\n    e.preventDefault();\n    return false;\n  }\n\n  function pan(by) {\n    var x = Math.SQRT1_2 * r,\n        y = r * .7,\n        z = r * .2,\n        g = po.svg(\"g\"),\n        dir = g.appendChild(po.svg(\"path\")),\n        chv = g.appendChild(po.svg(\"path\"));\n    dir.setAttribute(\"class\", \"direction\");\n    dir.setAttribute(\"pointer-events\", \"all\");\n    dir.setAttribute(\"d\", \"M0,0L\" + x + \",\" + x + \"A\" + r + \",\" + r + \" 0 0,1 \" + -x + \",\" + x + \"Z\");\n    chv.setAttribute(\"class\", \"chevron\");\n    chv.setAttribute(\"d\", \"M\" + z + \",\" + (y - z) + \"L0,\" + y + \" \" + -z + \",\" + (y - z));\n    chv.setAttribute(\"pointer-events\", \"none\");\n    g.addEventListener(\"mousedown\", panStart, false);\n    g.addEventListener(\"mouseover\", panBy(by), false);\n    g.addEventListener(\"mouseout\", panBy(null), false);\n    g.addEventListener(\"dblclick\", cancel, false);\n    return g;\n  }\n\n  function zoom(by) {\n    var x = r * .4,\n        y = x / 2,\n        g = po.svg(\"g\"),\n        back = g.appendChild(po.svg(\"path\")),\n        dire = g.appendChild(po.svg(\"path\")),\n        chev = g.appendChild(po.svg(\"path\")),\n        fore = g.appendChild(po.svg(\"path\"));\n    back.setAttribute(\"class\", \"back\");\n    back.setAttribute(\"d\", \"M\" + -x + \",0V\" + -x + \"A\" + x + \",\" + x + \" 0 1,1 \" + x + \",\" + -x + \"V0Z\");\n    dire.setAttribute(\"class\", \"direction\");\n    dire.setAttribute(\"d\", back.getAttribute(\"d\"));\n    chev.setAttribute(\"class\", \"chevron\");\n    chev.setAttribute(\"d\", \"M\" + -y + \",\" + -x + \"H\" + y + (by > 0 ? \"M0,\" + (-x - y) + \"V\" + -y : \"\"));\n    fore.setAttribute(\"class\", \"fore\");\n    fore.setAttribute(\"fill\", \"none\");\n    fore.setAttribute(\"d\", back.getAttribute(\"d\"));\n    g.addEventListener(\"mousedown\", zoomBy(by), false);\n    g.addEventListener(\"mouseover\", zoomOver, false);\n    g.addEventListener(\"mouseout\", zoomOut, false);\n    g.addEventListener(\"dblclick\", cancel, false);\n    return g;\n  }\n\n  function tick(i) {\n    var x = r * .2,\n        y = r * .4,\n        g = po.svg(\"g\"),\n        back = g.appendChild(po.svg(\"rect\")),\n        chev = g.appendChild(po.svg(\"path\"));\n    back.setAttribute(\"pointer-events\", \"all\");\n    back.setAttribute(\"fill\", \"none\");\n    back.setAttribute(\"x\", -y);\n    back.setAttribute(\"y\", -.75 * y);\n    back.setAttribute(\"width\", 2 * y);\n    back.setAttribute(\"height\", 1.5 * y);\n    chev.setAttribute(\"class\", \"chevron\");\n    chev.setAttribute(\"d\", \"M\" + -x + \",0H\" + x);\n    g.addEventListener(\"mousedown\", zoomTo(i), false);\n    g.addEventListener(\"dblclick\", cancel, false);\n    return g;\n  }\n\n  function move() {\n    var x = r + 6, y = x, size = map.size();\n    switch (position) {\n      case \"top-left\": break;\n      case \"top-right\": x = size.x - x; break;\n      case \"bottom-left\": y = size.y - y; break;\n      case \"bottom-right\": x = size.x - x; y = size.y - y; break;\n    }\n    g.setAttribute(\"transform\", \"translate(\" + x + \",\" + y + \")\");\n    dragRect.setAttribute(\"transform\", \"translate(\" + -x + \",\" + -y + \")\");\n    for (var i in ticks) {\n      i == map.zoom()\n          ? ticks[i].setAttribute(\"class\", \"active\")\n          : ticks[i].removeAttribute(\"class\");\n    }\n  }\n\n  function draw() {\n    while (g.lastChild) g.removeChild(g.lastChild);\n\n    g.appendChild(dragRect);\n\n    if (panStyle != \"none\") {\n      panContainer = g.appendChild(po.svg(\"g\"));\n      panContainer.setAttribute(\"class\", \"pan\");\n\n      var back = panContainer.appendChild(po.svg(\"circle\"));\n      back.setAttribute(\"class\", \"back\");\n      back.setAttribute(\"r\", r);\n\n      var s = panContainer.appendChild(pan({x: 0, y: -speed}));\n      s.setAttribute(\"transform\", \"rotate(0)\");\n\n      var w = panContainer.appendChild(pan({x: speed, y: 0}));\n      w.setAttribute(\"transform\", \"rotate(90)\");\n\n      var n = panContainer.appendChild(pan({x: 0, y: speed}));\n      n.setAttribute(\"transform\", \"rotate(180)\");\n\n      var e = panContainer.appendChild(pan({x: -speed, y: 0}));\n      e.setAttribute(\"transform\", \"rotate(270)\");\n\n      var fore = panContainer.appendChild(po.svg(\"circle\"));\n      fore.setAttribute(\"fill\", \"none\");\n      fore.setAttribute(\"class\", \"fore\");\n      fore.setAttribute(\"r\", r);\n    } else {\n      panContainer = null;\n    }\n\n    if (zoomStyle != \"none\") {\n      zoomContainer = g.appendChild(po.svg(\"g\"));\n      zoomContainer.setAttribute(\"class\", \"zoom\");\n\n      var j = -.5;\n      if (zoomStyle == \"big\") {\n        ticks = {};\n        for (var i = map.zoomRange()[0], j = 0; i <= map.zoomRange()[1]; i++, j++) {\n          (ticks[i] = zoomContainer.appendChild(tick(i)))\n              .setAttribute(\"transform\", \"translate(0,\" + (-(j + .75) * r * .4) + \")\");\n        }\n      }\n\n      var p = panStyle == \"none\" ? .4 : 2;\n      zoomContainer.setAttribute(\"transform\", \"translate(0,\" + r * (/^top-/.test(position) ? (p + (j + .5) * .4) : -p) + \")\");\n      zoomContainer.appendChild(zoom(+1)).setAttribute(\"transform\", \"translate(0,\" + (-(j + .5) * r * .4) + \")\");\n      zoomContainer.appendChild(zoom(-1)).setAttribute(\"transform\", \"scale(-1)\");\n    } else {\n      zoomContainer = null;\n    }\n\n    move();\n  }\n\n  compass.radius = function(x) {\n    if (!arguments.length) return r;\n    r = x;\n    if (map) draw();\n    return compass;\n  };\n\n  compass.speed = function(x) {\n    if (!arguments.length) return r;\n    speed = x;\n    return compass;\n  };\n\n  compass.position = function(x) {\n    if (!arguments.length) return position;\n    position = x;\n    if (map) draw();\n    return compass;\n  };\n\n  compass.pan = function(x) {\n    if (!arguments.length) return panStyle;\n    panStyle = x;\n    if (map) draw();\n    return compass;\n  };\n\n  compass.zoom = function(x) {\n    if (!arguments.length) return zoomStyle;\n    zoomStyle = x;\n    if (map) draw();\n    return compass;\n  };\n\n  compass.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      container.removeEventListener(\"mousedown\", mousedown, false);\n      container.removeChild(g);\n      container = null;\n      window.removeEventListener(\"mousemove\", mousemove, false);\n      window.removeEventListener(\"mouseup\", mouseup, false);\n      window = null;\n      map.off(\"move\", move).off(\"resize\", move);\n    }\n    if (map = x) {\n      container = map.container();\n      container.appendChild(g);\n      container.addEventListener(\"mousedown\", mousedown, false);\n      window = container.ownerDocument.defaultView;\n      window.addEventListener(\"mousemove\", mousemove, false);\n      window.addEventListener(\"mouseup\", mouseup, false);\n      map.on(\"move\", move).on(\"resize\", move);\n      draw();\n    }\n    return compass;\n  };\n\n  return compass;\n};\npo.grid = function() {\n  var grid = {},\n      map,\n      g = po.svg(\"g\");\n\n  g.setAttribute(\"class\", \"grid\");\n\n  function move(e) {\n    var p,\n        line = g.firstChild,\n        size = map.size(),\n        nw = map.pointLocation(zero),\n        se = map.pointLocation(size),\n        step = Math.pow(2, 4 - Math.round(map.zoom()));\n\n    // Round to step.\n    nw.lat = Math.floor(nw.lat / step) * step;\n    nw.lon = Math.ceil(nw.lon / step) * step;\n\n    // Longitude ticks.\n    for (var x; (x = map.locationPoint(nw).x) <= size.x; nw.lon += step) {\n      if (!line) line = g.appendChild(po.svg(\"line\"));\n      line.setAttribute(\"x1\", x);\n      line.setAttribute(\"x2\", x);\n      line.setAttribute(\"y1\", 0);\n      line.setAttribute(\"y2\", size.y);\n      line = line.nextSibling;\n    }\n\n    // Latitude ticks.\n    for (var y; (y = map.locationPoint(nw).y) <= size.y; nw.lat -= step) {\n      if (!line) line = g.appendChild(po.svg(\"line\"));\n      line.setAttribute(\"y1\", y);\n      line.setAttribute(\"y2\", y);\n      line.setAttribute(\"x1\", 0);\n      line.setAttribute(\"x2\", size.x);\n      line = line.nextSibling;\n    }\n\n    // Remove extra ticks.\n    while (line) {\n      var next = line.nextSibling;\n      g.removeChild(line);\n      line = next;\n    }\n  }\n\n  grid.map = function(x) {\n    if (!arguments.length) return map;\n    if (map) {\n      g.parentNode.removeChild(g);\n      map.off(\"move\", move).off(\"resize\", move);\n    }\n    if (map = x) {\n      map.on(\"move\", move).on(\"resize\", move);\n      map.container().appendChild(g);\n      map.dispatch({type: \"move\"});\n    }\n    return grid;\n  };\n\n  return grid;\n};\npo.stylist = function() {\n  var attrs = [],\n      styles = [],\n      title;\n\n  function stylist(e) {\n    var ne = e.features.length,\n        na = attrs.length,\n        ns = styles.length,\n        f, // feature\n        d, // data\n        o, // element\n        x, // attr or style or title descriptor\n        v, // attr or style or title value\n        i,\n        j;\n    for (i = 0; i < ne; ++i) {\n      if (!(o = (f = e.features[i]).element)) continue;\n      d = f.data;\n      for (j = 0; j < na; ++j) {\n        v = (x = attrs[j]).value;\n        if (typeof v === \"function\") v = v.call(null, d);\n        v == null ? (x.name.local\n            ? o.removeAttributeNS(x.name.space, x.name.local)\n            : o.removeAttribute(x.name)) : (x.name.local\n            ? o.setAttributeNS(x.name.space, x.name.local, v)\n            : o.setAttribute(x.name, v));\n      }\n      for (j = 0; j < ns; ++j) {\n        v = (x = styles[j]).value;\n        if (typeof v === \"function\") v = v.call(null, d);\n        v == null\n            ? o.style.removeProperty(x.name)\n            : o.style.setProperty(x.name, v, x.priority);\n      }\n      if (v = title) {\n        if (typeof v === \"function\") v = v.call(null, d);\n        while (o.lastChild) o.removeChild(o.lastChild);\n        if (v != null) o.appendChild(po.svg(\"title\")).appendChild(document.createTextNode(v));\n      }\n    }\n  }\n\n  stylist.attr = function(n, v) {\n    attrs.push({name: ns(n), value: v});\n    return stylist;\n  };\n\n  stylist.style = function(n, v, p) {\n    styles.push({name: n, value: v, priority: arguments.length < 3 ? null : p});\n    return stylist;\n  };\n\n  stylist.title = function(v) {\n    title = v;\n    return stylist;\n  };\n\n  return stylist;\n};\n})(org.polymaps);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/sphericalmercator.js",
    "content": "var SphericalMercator = (function(){\n\n// Closures including constants and other precalculated values.\nvar cache = {},\n    EPSLN = 1.0e-10,\n    D2R = Math.PI / 180,\n    R2D = 180 / Math.PI,\n    // 900913 properties.\n    A = 6378137,\n    MAXEXTENT = 20037508.34;\n\n\n// SphericalMercator constructor: precaches calculations\n// for fast tile lookups.\nfunction SphericalMercator(options) {\n    options = options || {};\n    this.size = options.size || 256;\n    if (!cache[this.size]) {\n        var size = this.size;\n        var c = cache[this.size] = {};\n        c.Bc = [];\n        c.Cc = [];\n        c.zc = [];\n        c.Ac = [];\n        for (var d = 0; d < 30; d++) {\n            c.Bc.push(size / 360);\n            c.Cc.push(size / (2 * Math.PI));\n            c.zc.push(size / 2);\n            c.Ac.push(size);\n            size *= 2;\n        }\n    }\n    this.Bc = cache[this.size].Bc;\n    this.Cc = cache[this.size].Cc;\n    this.zc = cache[this.size].zc;\n    this.Ac = cache[this.size].Ac;\n};\n\n// Convert lon lat to screen pixel value\n//\n// - `ll` {Array} `[lon, lat]` array of geographic coordinates.\n// - `zoom` {Number} zoom level.\nSphericalMercator.prototype.px = function(ll, zoom) {\n    var d = this.zc[zoom];\n    var f = Math.min(Math.max(Math.sin(D2R * ll[1]), -0.9999), 0.9999);\n    var x = Math.round(d + ll[0] * this.Bc[zoom]);\n    var y = Math.round(d + 0.5 * Math.log((1 + f) / (1 - f)) * (-this.Cc[zoom]));\n    (x > this.Ac[zoom]) && (x = this.Ac[zoom]);\n    (y > this.Ac[zoom]) && (y = this.Ac[zoom]);\n    //(x < 0) && (x = 0);\n    //(y < 0) && (y = 0);\n    return [x, y];\n};\n\n// Convert screen pixel value to lon lat\n//\n// - `px` {Array} `[x, y]` array of geographic coordinates.\n// - `zoom` {Number} zoom level.\nSphericalMercator.prototype.ll = function(px, zoom) {\n    var g = (px[1] - this.zc[zoom]) / (-this.Cc[zoom]);\n    var lon = (px[0] - this.zc[zoom]) / this.Bc[zoom];\n    var lat = R2D * (2 * Math.atan(Math.exp(g)) - 0.5 * Math.PI);\n    return [lon, lat];\n};\n\n// Convert tile xyz value to bbox of the form `[w, s, e, n]`\n//\n// - `x` {Number} x (longitude) number.\n// - `y` {Number} y (latitude) number.\n// - `zoom` {Number} zoom.\n// - `tms_style` {Boolean} whether to compute using tms-style.\n// - `srs` {String} projection for resulting bbox (WGS84|900913).\n// - `return` {Array} bbox array of values in form `[w, s, e, n]`.\nSphericalMercator.prototype.bbox = function(x, y, zoom, tms_style, srs) {\n    // Convert xyz into bbox with srs WGS84\n    if (tms_style) {\n        y = (Math.pow(2, zoom) - 1) - y;\n    }\n    // Use +y to make sure it's a number to avoid inadvertent concatenation.\n    var ll = [x * this.size, (+y + 1) * this.size]; // lower left\n    // Use +x to make sure it's a number to avoid inadvertent concatenation.\n    var ur = [(+x + 1) * this.size, y * this.size]; // upper right\n    var bbox = this.ll(ll, zoom).concat(this.ll(ur, zoom));\n\n    // If web mercator requested reproject to 900913.\n    if (srs === '900913') {\n        return this.convert(bbox, '900913');\n    } else {\n        return bbox;\n    }\n};\n\n// Convert bbox to xyx bounds\n//\n// - `bbox` {Number} bbox in the form `[w, s, e, n]`.\n// - `zoom` {Number} zoom.\n// - `tms_style` {Boolean} whether to compute using tms-style.\n// - `srs` {String} projection of input bbox (WGS84|900913).\n// - `@return` {Object} XYZ bounds containing minX, maxX, minY, maxY properties.\nSphericalMercator.prototype.xyz = function(bbox, zoom, tms_style, srs) {\n    // If web mercator provided reproject to WGS84.\n    if (srs === '900913') {\n        bbox = this.convert(bbox, 'WGS84');\n    }\n\n    var ll = [bbox[0], bbox[1]]; // lower left\n    var ur = [bbox[2], bbox[3]]; // upper right\n    var px_ll = this.px(ll, zoom);\n    var px_ur = this.px(ur, zoom);\n    // Y = 0 for XYZ is the top hence minY uses px_ur[1].\n    var bounds = {\n        minX: Math.floor(px_ll[0] / this.size),\n        minY: Math.floor(px_ur[1] / this.size),\n        maxX: Math.floor((px_ur[0] - 1) / this.size),\n        maxY: Math.floor((px_ll[1] - 1) / this.size)\n    };\n    if (tms_style) {\n        var tms = {\n            minY: (Math.pow(2, zoom) - 1) - bounds.maxY,\n            maxY: (Math.pow(2, zoom) - 1) - bounds.minY\n        };\n        bounds.minY = tms.minY;\n        bounds.maxY = tms.maxY;\n    }\n    return bounds;\n};\n\n// Convert projection of given bbox.\n//\n// - `bbox` {Number} bbox in the form `[w, s, e, n]`.\n// - `to` {String} projection of output bbox (WGS84|900913). Input bbox\n//   assumed to be the \"other\" projection.\n// - `@return` {Object} bbox with reprojected coordinates.\nSphericalMercator.prototype.convert = function(bbox, to) {\n    if (to === '900913') {\n        return this.forward(bbox.slice(0, 2)).concat(this.forward(bbox.slice(2,4)));\n    } else {\n        return this.inverse(bbox.slice(0, 2)).concat(this.inverse(bbox.slice(2,4)));\n    }\n};\n\n// Convert lon/lat values to 900913 x/y.\nSphericalMercator.prototype.forward = function(ll) {\n    var xy = [\n        A * ll[0] * D2R,\n        A * Math.log(Math.tan((Math.PI*0.25) + (0.5 * ll[1] * D2R)))\n    ];\n    // if xy value is beyond maxextent (e.g. poles), return maxextent.\n    (xy[0] > MAXEXTENT) && (xy[0] = MAXEXTENT);\n    (xy[0] < -MAXEXTENT) && (xy[0] = -MAXEXTENT);\n    (xy[1] > MAXEXTENT) && (xy[1] = MAXEXTENT);\n    (xy[1] < -MAXEXTENT) && (xy[1] = -MAXEXTENT);\n    return xy;\n};\n\n// Convert 900913 x/y values to lon/lat.\nSphericalMercator.prototype.inverse = function(xy) {\n    return [\n        (xy[0] * R2D / A),\n        ((Math.PI*0.5) - 2.0 * Math.atan(Math.exp(-xy[1] / A))) * R2D\n    ];\n};\n\nreturn SphericalMercator;\n\n})();\n\nif (typeof module !== 'undefined' && typeof exports !== 'undefined') {\n    module.exports = exports = SphericalMercator;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arc.js-gh-pages/test.js",
    "content": "#!/usr/bin/env node\n\nvar arc = require('./arc.js');\n\nvar features = [];\nvar geojson = { 'type': 'FeatureCollection',\n                'features': features\n              };\n\nvar routes = [\n    [new arc.Coord(-122, 48), new arc.Coord(-77, 39), {'name': 'Seattle to DC'}],\n    [new arc.Coord(-122, 48), new arc.Coord(0, 51), {'name': 'Seattle to London'}],\n    [new arc.Coord(-75.9375,35.460669951495305), new arc.Coord(146.25,-43.06888777416961), {'name': 'crosses dateline'}],\n    [new arc.Coord(145.54687500000003,48.45835188280866 ), new arc.Coord(-112.5,-37.71859032558814), {'name': 'crosses dateline'}]\n  ];\n\nroutes.forEach(function(route,idx) {\n    var gc = new arc.GreatCircle(route[0], route[1], route[2]);\n    var line = gc.Arc(50);\n    features.push(line.json());\n});\n\nconsole.log(JSON.stringify(geojson));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/arcDecorator.js",
    "content": "var ArcLayer = function(opt) {\n\n\tthis.arcStyle = {\n\t\tcolor : '#fe6f16',\n\t\tthickness : 4,\n\t\tspeed : 10\n\t};\n\n\tthis.data = opt.data;\n\tthis.map = opt.map;\n\tL.Draw.customData = new L.LayerGroup();\n\tL.Draw.customData.addTo(this.map);\n\n\tthis.addLayer = function() {\n\t\tvar context = this;\n\t\tvar _map = this.map;\n\t\tvar centerLatLng = this.data.centerLatLng;\n\t\tif (this.data.latLng) {\n\t\t\tvar arrowOffset = 0;\n\t\t\tvar arrowArray = [];\n\t\t\tfor ( var j = 0; j < this.data.latLng.length; j++) {\n\t\t\t\tvar iJson = this.data.latLng[j];\n\t\t\t\tvar polyline;\n\t\t\t\tvar p0 = L.latLng(centerLatLng.lat, centerLatLng.lng);\n\t\t\t\tvar p1 = L.latLng(iJson.lat, iJson.lng);\n\t\t\t\tif (this.data.isOut == '1') {\n\t\t\t\t\tpolyline = LMapLib.CurveLine([ p0, p1 ]);\n\t\t\t\t} else {\n\t\t\t\t\tpolyline = LMapLib.CurveLine([ p1, p0 ]);\n\t\t\t\t}\n\n\t\t\t\tvar arrowHead = L.polylineDecorator(polyline);\n                var _line = L.polyline(polyline.getLatLngs, {\n                    lineCap : 'butt'\n                })\n\t\t\t\tL.Draw.customData.addLayer(polyline);\n\t\t\t\tL.Draw.customData.addLayer(arrowHead);\n\t\t\t\tarrowArray.push(arrowHead);\n\t\t\t}\n\t\t\t// L.symbol.arrowHeader({\n            //     pixelSize : 10,\n            //     polygon : true,\n            //     pathOptions : {\n            //     \tstroke : true\n            //     }\n            // })\n\t\t\tvar anim = window.setInterval(function() {\n\t\t\t\tfor ( var i = 0; i < arrowArray.length; i++) {\n\t\t\t\t\tarrowArray[i].setPatterns([ {\n\t\t\t\t\t\toffset : arrowOffset + '%',\n\t\t\t\t\t\trepeat : 0,\n\t\t\t\t\t\tsymbol : L.Symbol.marker({\n                        rotate: false, markerOptions: {\n                                icon: L.icon({\n                                    iconUrl: '../static/lab/gis/images/cz.png',\n                                    iconAnchor: [8, 8]\n                                })\n                            }\n\t\t\t\t\t\t})\n\t\t\t\t\t} ]);\n\t\t\t\t\tarrowOffset += 0.5;\n\t\t\t\t\tif (arrowOffset > 100)\n\t\t\t\t\t\tarrowOffset = 0;\n\t\t\t\t}\n\n\t\t\t}, 100);\n\t\t}\n\n\t};\n\n\tthis.removeLayer = function() {\n\t\tL.Draw.customData.clearLayers();\n\t};\n};\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/jslib/bar.js",
    "content": "var BarLayer = function(opt){\n\n\tthis.circleStyle = {\n\t\tstroke : false,\n\t\tfillColor : '#fe6f16',\n\t\tfillOpacity : 0.7\n\t};\n\n\tthis.data = opt.data;\n\tthis.map = opt.map;\n\tL.Draw.customData = new L.LayerGroup();\n\tL.Draw.customData.addTo(this.map);\n\n\tthis.addLayer = function(data){\n\n\t\tif(!data){\n\t\t\tdata = this.data;\n\t\t}\n\n\t\tvar context = this;\n\t\tvar _map = this.map;\n\n\t\tfor(var i = 0; i < data.length; i++){\n\n\t\t\tvar item = data[i];\n\n\t\t\tvar style = {};\n\n\t\t\tfor(var key in this.circleStyle){\n\t\t\t\tstyle[key] = this.circleStyle[key];\n\t\t\t}\n\n\t\t\tif(item.style){\n\t\t\t\tfor(var key in item.style){\n\t\t\t\t\tstyle[key] = item.style[key];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar layer = new L.CircleMarker(item.latlng, style);\n\n\t\t\t\tlayer.setRadius(item.radius);\n\n\t\t\t\tlayer.data = item;\n\n\t\t\t\t//添加点击事件\n\t\t\t\tif(item.click){\n\t\t\t\t\tlayer.on(\"click\", function(){\n\n\t\t\t\t\t\t//执行单击回调函数\n\t\t\t\t\t\tif(this.data.click){\n\t\t\t\t\t\t\tthis.data.click();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t//如果存在子元素则附加绑定单击事件 切换到资源富范围\n\t\t\t\tif(item.child){\n\t\t\t\t\tlayer.on(\"click\", function(){\n\t\t\t\t\tif(this.data.child){\n\t\t\t\t\t\t\tcontext.removeLayer();\n\t\t\t\t\t\t\tcontext.addLayer(this.data.child);\n\n\t\t\t\t\t\t\t//跳转到子元素范围\n\t\t\t\t\t\t\tif(this.data.childBbox){\n\t\t\t\t\t\t\t\t_map.fitBounds(this.data.childBbox);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t//绑定气泡\n\t\t\t\tif(item.popupContent){\n\n\t\t\t\t\tvar popup = L.popup({\n\t\t\t\t\t\toffset : L.point(0, -(item.radius)),\n\t\t\t\t\t\tcloseButton : false\n\t\t\t\t\t}).setLatLng(item.latlng).setContent(item.popupContent);\n\n\t\t\t\t\tlayer.popup = popup;\n\n\t\t\t\t\tlayer.on(\"mouseover\", function(){\n\t\t\t\t\t\t_map.openPopup(this.popup);\n\t\t\t\t\t});\n\n\t\t\t\t\tlayer.on(\"mouseout\", function(){\n\t\t\t\t\t\tif(this.popup){\n\t\t\t\t\t\t\t_map.closePopup(this.popup);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t//绑定鼠标选中的动画效果\n\t\t\t\tlayer.on(\"mouseover\", function(){\n\t\t\t\t\tthis.setStyle({\n\t\t\t\t\t\tfillOpacity : parseFloat(this.options.fillOpacity) + 0.2\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tlayer.on(\"mouseout\", function(){\n\t\t\t\t\tthis.setStyle({\n\t\t\t\t\t\tfillOpacity : parseFloat(this.options.fillOpacity) - 0.2\n\t\t\t\t\t});\n\t\t\t\t\tthis.redraw();\n\t\t\t\t});\n\n\n\t\t\tL.Draw.customData.addLayer(layer);\n\t\t}\n\n\t}\n\n\tthis.removeLayer = function(){\n\t\tL.Draw.customData.clearLayers();\n\t}\n\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/test/data/cirlData.js",
    "content": "var cirlData = [//测试数据\n    {\n        title : 'beijing',\n        radius : 40,//圆半径\n        style : {//圆样式\n            fillColor : 'red'\n        },\n        latlng : [41.802542590364354, 123.431396484375],//圆中心点\n        click : function(){\n            console.log(\"click bj\");\n        },\n        popupContent : \"气泡内容====\",//气泡提示内容\n        childBbox : [[42.36666166373274, 118.10852050781251],[38.57823196583313, 125.71105957031249 ]],//点击转曲，时设置转曲后的地图范围\n        child : [\n            {\n                title : 'beijing',\n                radius : 30,\n                latlng : [41.802542590364354, 123.431396484375],\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"旗袍内容1\"\n            },\n            {\n                title : 'beijing',\n                latlng : [41.57436130598913, 120.421142578125],\n                radius : 40,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！1\"\n            },\n            {\n                title : 'beijing',\n                latlng : [42.02481360781777, 121.70654296874999],\n                radius : 35,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！2\"\n            },\n            {\n                title : 'beijing',\n                latlng : [41.054501963290505, 121.11328124999999],\n                radius : 24,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！3\"\n            },\n            {\n                title : 'beijing',\n                latlng : [40.6723059714534, 120.838623046875],\n                radius : 30,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！4\"\n            },\n            {\n                title : 'beijing',\n                latlng : [41.09591205639546, 122.05810546875],\n                radius : 24,\n                click : function(){\n                    alert(this.radius);\n                }\n            },\n            {\n                title : 'beijing',\n                latlng : [38.90920161982435, 121.61590576171876],\n                radius : 60,\n                click : function(){\n                    alert(this.radius);\n                }\n            },\n            {\n                title : 'beijing',\n                latlng : [41.04621681452063, 123.035888671875],\n                radius : 36,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！3\"\n            },\n            {\n                title : 'beijing',\n                latlng : [41.97780646738183, 123.77197265625],\n                radius : 50,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！4\"\n            },\n        ]\n    },{\n        title : 'beijing',\n        latlng : [34.252676117101515, 108.896484375],\n        radius : 30,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    },{\n        title : 'beijing',\n        latlng : [30.183121842195515, 120.1904296875],\n        radius : 25,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    },{\n        title : 'beijing',\n        latlng : [23.200960808078566, 113.5546875],\n        radius : 40,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    },{\n        title : 'beijing',\n        latlng : [29.611670115197377, 106.5234375],\n        radius : 34,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    },{\n        title : 'beijing',\n        latlng : [35.746512259918504, 96.6796875],\n        radius : 21,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    },{\n        title : 'beijing',\n        latlng : [42.81152174509788, 113.466796875],\n        radius : 29,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    },{\n        title : 'beijing',\n        latlng : [45.767522962149904, 126.474609375],\n        radius : 36,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    },{\n        title : 'beijing',\n        latlng : [40.27952566881291, 86.0009765625],\n        radius : 40,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    },{\n        title : 'beijing',\n        latlng : [30.93992433102347, 89.033203125],\n        radius : 30,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"气泡内容\"\n    }\n\n];\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/js/test/demo.js",
    "content": "//加载地图\nfunction onloadMap(){\n\tvar mapServerUrl = \"http://172.16.247.100:8888/map\";//地图服务地址\n\tinitMap(mapServerUrl);//初始化地图\n\tminRoad();\n}\n\n\n//地图标点\nfunction addMarkers(){\n\tL.Draw.customData = L.layerGroup().addTo(map);//创建标点图层，删除标点时用\n\tvar poinListJson = [{id: 1,x: 37.94,y: 112.64,name:'太原'},{id: 2,x: 40.82149932,y: 111.6842769,name:'呼和浩特市'},{id: 3,x: 40.13254611,y: 116.5056088,name:'北京'}];//测试数据\n\t\n\t//标注点样式\n\tvar myIcon = L.icon({\n\t\ticonUrl: \"images/markers/blue.png\",\n\t\ticonSize: [36, 36],\n\t\tpopupAnchor: [0, -18]\n\t\t});\n\t\n\tfor(var i=0;i<poinListJson.length;i++){\n\t\tvar marker = L.marker(L.latLng(poinListJson[i].x,poinListJson[i].y));\n\t\t\tmarker.setIcon(myIcon);\n\t\t\tmarker.jsonObj = poinListJson[i];\n//\t\t\tmarker.bindPopup(\"泡泡提示信息。\");\n\t\t\tmarker.on(\"click\",function() {clickMark(this);});\n\t\t\tmarker.on(\"mouseover\",function() {mouseOverEvent(this);});\n\t\t\tmarker.addTo(L.Draw.customData);\n\t}\n\tkeyList.push('point');\n\tlayerList.push(L.Draw.customData);\n}\n\n//标注点点击事件\nfunction clickMark(mark){\n\tvar lat = mark.jsonObj.x;\n\tvar lng = mark.jsonObj.y;\n\tvar id = mark.jsonObj.id;\n\talert(lat+\"==\"+lng+\"===\"+id);\n}\n\n//鼠标移动到标注点 回调方法\nfunction mouseOverEvent(mark){\n\tvar name1 = mark.jsonObj.name;\n\tmark.bindPopup('名称：'+name1).openPopup();\n}\n\n\n\n//叠加点数量多 用 叠加点图层方式\nfunction fillPointTile(){\n   var table = 'tb_gis_company';\n   var where = '1=1';\n   drawPointTile(table,where);\n}\n\n\n//移除叠加的瓦片图层\nfunction removeTile(layName){\n\tremoveTiles(layName);//参数同叠加点图层定义的一致\n}\n\n//地图添加点击事件\nfunction addClickToMap(){\n\taddMapClickEvent();\n}\n//点击事件回调函数 获得当前点的坐标\nfunction clickMap(lng,lat){\n\talert(lng+\"-\"+lat);\n}\n\n//地图移除点击事件\nfunction remClickToMap(){\n\tremMapClickEvent();\n}\n\n//工具条查询回调函数\nfunction mapAreaSearchInfo(lonlats,type,layerGroup){\n\t$.ajax({\n\t\turl : \"wms/getMapSearch\",\n\t\ttype : 'post',\n\t\tdata : {\n\t\t\tlonlat:lonlats,\n\t\t\ttype:type,\n\t\t\tparam:'none'\n    \t},\n    \tdataType : 'text',\n    \tsuccess : function(d){\n    \t\tvar count  = d.split(\";\")[0];\n    \t\tvar sql = d.split(';')[1];\n    \t\t$(\"#sqlDiv\").val(sql);\n    \t\tinitPage(count);//总结果集数量\n    \t\tmapAreaSearchByPage(layerGroup);\n    \t}\n\t}); \n}\n\n//分页查询统一调用此方法\nfunction mapAreaSearchByPage(layerGroup){\n\tremoveMarkers();\n\tvar sql = $(\"#sqlDiv\").val();\n\t$.ajax({\n\t\turl : \"wms/getMapSearchByPage\",\n\t\ttype : 'post',\n\t\tdata : {\n\t\t\tsql:sql,\n\t\t\tnowNum:nowPageNumb,\n\t\t\tsort:'pripid',\n\t\t\tpageSize:pageDataNumb\n    \t},\n    \tdataType : 'json',\n    \tsuccess : function(d){\n    \t\tfillTableContent(d);\n    \t\taddMarker_s(d,layerGroup,0);\n    \t}\n\t});\n}\n\n/**\n * 结果集 地图标注\n * poinListJson 结果集\n * layerGroup 叠加的图层名 标注点清除时用\n * \n */\nvar markerArray = new Array();\nfunction addMarker_s(poinListJson,layerGroup) {\n\tvar pointCount = poinListJson.length;\n\tvar lng = \"\";\n\tvar lat = \"\";\n\tfor (var i = 0; i < pointCount; i++) {\n\t\t lng = poinListJson[i].GOOGLE_LNG;\n\t\t lat = poinListJson[i].GOOGLE_LAT;\n\t\t entName = poinListJson[i].ENT_NAME;\n\t\t var marker = L.marker(L.latLng(lat, lng));\n\t\t var myIcon = L.icon({\n\t\t\t\ticonUrl: \"images/gis_\"+(i+1)+\".png\",\n\t\t\t\ticonSize: [25, 34],\n\t\t\t\tpopupAnchor: [0, -18]\n\t\t\t\t});\n\t\tmarker.setIcon(myIcon);\n\t\tmarker.productId = poinListJson[i].PRIPID;\n\t\t\n\t\tif(null == layerGroup || \"\" == layerGroup){\n\t\t\tmarker.addTo(map);\n\t\t}else{\n\t\t\tlayerGroup.addLayer(marker);\n\t\t}\n\t\tmarkerArray.push(marker);\n\t}\n}\n\n//3.定位北京\nfunction serachPoint(){\n\tvar  lat=39.918;\n\tvar lng= 116.38;\n\tvar zoom = 5;\n\tdingwei(lat,lng,zoom);\n}\n\n//-------------------------------------------地图绘制圆开始-------------\nvar barLayer = null;\nvar data = [//测试数据 \n    {\n        title : 'beijing',\n        radius : 40,//圆半径\n        style : {//圆样式\n            fillColor : 'green'\n        },\n        latlng : [41.802542590364354, 123.431396484375],//圆中心点\n        click : function(){\n            console.log(\"click bj\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\",//气泡提示内容\n        childBbox : [[42.36666166373274, 118.10852050781251],[38.57823196583313, 125.71105957031249 ]],//点击转曲，时设置转曲后的地图范围\n        child : [\n            {\n                title : 'beijing',\n                radius : 30,\n                latlng : [41.802542590364354, 123.431396484375],\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n            },\n            {\n                title : 'beijing',\n                latlng : [41.57436130598913, 120.421142578125],\n                radius : 40,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！1\"\n            },\n            {\n                title : 'beijing',\n                latlng : [42.02481360781777, 121.70654296874999],\n                radius : 35,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！2\"\n            },\n            {\n                title : 'beijing',\n                latlng : [41.054501963290505, 121.11328124999999],\n                radius : 24,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！3\"\n            },\n            {\n                title : 'beijing',\n                latlng : [40.6723059714534, 120.838623046875],\n                radius : 30,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！4\"\n            },  \n            {\n                title : 'beijing',\n                latlng : [41.09591205639546, 122.05810546875],\n                radius : 24,\n                click : function(){\n                    alert(this.radius);\n                }\n            },\n            {\n                title : 'beijing',\n                latlng : [38.90920161982435, 121.61590576171876],\n                radius : 60,\n                click : function(){\n                    alert(this.radius);\n                }\n            },\n            {\n                title : 'beijing',\n                latlng : [41.04621681452063, 123.035888671875],\n                radius : 36,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！3\"\n            },\n            {\n                title : 'beijing',\n                latlng : [41.97780646738183, 123.77197265625],\n                radius : 50,\n                click : function(){\n                    alert(this.radius);\n                },\n                popupContent : \"这里是气泡内容！4\"\n            },                                                                      \n        ]\n    },{\n        title : 'beijing',\n        latlng : [34.252676117101515, 108.896484375],\n        radius : 30,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    },{\n        title : 'beijing',\n        latlng : [30.183121842195515, 120.1904296875],\n        radius : 25,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    },{\n        title : 'beijing',\n        latlng : [23.200960808078566, 113.5546875],\n        radius : 40,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    },{\n        title : 'beijing',\n        latlng : [29.611670115197377, 106.5234375],\n        radius : 34,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    },{\n        title : 'beijing',\n        latlng : [35.746512259918504, 96.6796875],\n        radius : 21,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    },{\n        title : 'beijing',\n        latlng : [42.81152174509788, 113.466796875],\n        radius : 29,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    },{\n        title : 'beijing',\n        latlng : [45.767522962149904, 126.474609375],\n        radius : 36,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    },{\n        title : 'beijing',\n        latlng : [40.27952566881291, 86.0009765625],\n        radius : 40,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    },{\n        title : 'beijing',\n        latlng : [30.93992433102347, 89.033203125],\n        radius : 30,\n        click : function(){\n            console.log(\"click xa\");\n        },\n        popupContent : \"2013年11月，重点煤矿调出煤炭总计1241.25万吨。\"\n    }\n\n];\nvar barLayer ;\nfunction drawCir(){\n\tbarLayer = new BarLayer({\n        data : data,\n        map : map\n    });\n\tbarLayer.addLayer();\n}\n\n//移除绘制的圆\nfunction removeCir(){\n\t barLayer.removeLayer();\n     barLayer = null;\n}\nvar arcData={\n\tstyle:{color:'red',thickness:4,speed:10},\n\tisOut:'1',\n\tcenterLatLng:{lat:31.1,lng:116.1},\n\tlatLng:[{lat:41.802542590364354,lng:123.431396484375},\n\t                {lat:34.252676117101515,lng:108.896484375},\n\t                {lat:29.611670115197377,lng:106.5234375},\n\t                {lat:42.81152174509788,lng:113.466796875},\n\t                {lat:40.27952566881291,lng:86.0009765625}]\n};\nvar arcLayer;\n//绘制弧线图\nfunction drawArc(){\n\tarcLayer = new ArcLayer({\n        data : arcData,\n        map : map\n    });\n\tarcLayer.addLayer();\n}\n//删除弧线图\nfunction removeArc(){\n\tarcLayer.removeLayer();\n\tarcLayer = null;\n}\n//绘制线路图\nfunction drawRoadLine(){\n\tvar p1 = L.latLng(41.802542590364354, 123.431396484375);\n    var p2 = L.latLng(34.252676117101515, 108.896484375);\n    var p3 = L.latLng(29.611670115197377, 106.5234375);\n    var p4 = L.latLng(42.81152174509788, 113.466796875);\n    var p5 = L.latLng(40.27952566881291, 86.0009765625);\n                \n    var polyline1 = LMapLib.CurveLine([p2, p1]);\n    var polyline2 = LMapLib.CurveLine([p3, p1]);\n    var polyline3 = LMapLib.CurveLine([p4, p1]);\n    var polyline4 = LMapLib.CurveLine([p5, p1]);\n\n    map.addLayer(polyline1);\n    map.addLayer(polyline2);\n    map.addLayer(polyline3);\n    map.addLayer(polyline4);\n\n    var arrowHead1 = L.polylineDecorator(polyline1).addTo(map);\n    var arrowHead2 = L.polylineDecorator(polyline2).addTo(map);\n    var arrowHead3 = L.polylineDecorator(polyline3).addTo(map);\n    var arrowHead4 = L.polylineDecorator(polyline4).addTo(map);\n\n    var arrowOffset = 0;\n    var anim = window.setInterval(function() {\n        arrowHead1.setPatterns([\n            {offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 20, polygon: false, pathOptions: {stroke: true}})}\n        ]);\n\n        arrowHead2.setPatterns([\n            {offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 20, polygon: false, pathOptions: {stroke: true}})}\n        ]);\n\n        arrowHead3.setPatterns([\n            {offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 20, polygon: false, pathOptions: {stroke: true}})}\n        ]);\n\n        arrowHead4.setPatterns([\n            {offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 20, polygon: false, pathOptions: {stroke: true}})}\n        ]);                                                            \n\n        arrowOffset += 0.5;\n        if(arrowOffset > 100)\n            arrowOffset = 0;\n    }, 100);\n}\n\nfunction getBox(){\n\tvar s = map.getBounds();\n\talert(s.getWest());\n\t//alert(s.getWest());\n}\n\n//显示柱状图\nfunction drawBarGraph() {\n\t\n\t\tvar colors = Highcharts.getOptions().colors;\n\n\t\tvar data = [ {\n\n\t\t\tlatlng : [ 41.78769700539063, 123.4423828125 ],\n\t\t\tlabelColor : 'red',\n\t\t\tlabel : [ '棉花', '小麦', '大豆' ],\n\t\t\twidth : 150,\n\t\t\theight : 150,\n\t\t\tclickFun : function(data) {\n\t\t\t\talert(data.y);\n\t\t\t},\n\t\t\tdata : [ {\n\t\t\t\ty : 55.11,\n\t\t\t\tcolor : colors[0]\n\t\t\t}, {\n\t\t\t\ty : 21.63,\n\t\t\t\tcolor : colors[1]\n\t\t\t}, {\n\t\t\t\ty : 11.94,\n\t\t\t\tcolor : colors[2]\n\t\t\t} ]\n\t\t}, {\n\t\t\tlatlng : [ 39.436192999314095, 88.06640625 ],\n\t\t\tlabel : [ '棉花', '小麦', '大豆' ],\n\t\t\tlabelColor : 'blue',\n\t\t\twidth : 150,\n\t\t\theight : 150,\n\t\t\tclickFun : function(data) {\n\t\t\t\talert(data.y + \"   \" + data.category);\n\t\t\t},\n\t\t\tdata : [ {\n\t\t\t\ty : 55.11,\n\t\t\t\tcolor : colors[0]\n\t\t\t}, {\n\t\t\t\ty : 60,\n\t\t\t\tcolor : colors[1]\n\t\t\t}, {\n\t\t\t\ty : 11.94,\n\t\t\t\tcolor : colors[2]\n\t\t\t} ]\n\t\t}, {\n\t\t\tlatlng : [ 25.958044673317843, 112.587890625 ],\n\t\t\tlabel : [ '棉花', '小麦', '大豆' ],\n\t\t\tlabelColor : 'green',\n\t\t\twidth : 150,\n\t\t\theight : 150,\n\t\t\tclickFun : function(data) {\n\t\t\t\talert(data.y);\n\t\t\t},\n\t\t\tdata : [ {\n\t\t\t\ty : 40,\n\t\t\t\tcolor : colors[0]\n\t\t\t}, {\n\t\t\t\ty : 21.63,\n\t\t\t\tcolor : colors[1]\n\t\t\t}, {\n\t\t\t\ty : 30,\n\t\t\t\tcolor : colors[2]\n\t\t\t} ]\n\t\t} ];\n\n\t\t$(\"#map\").mapColumn({\n\t\t\tmap : map\n\t\t});\n\n\t\t$(\"#map\").mapColumn(\"addCharts\", data);\n\n}\n//删除柱状图\nfunction cleanBarGraph(){\n\t$(\"#map\").mapColumn(\"clearCharts\");\n}\n\n//最短路径分析\n\nvar startMarker = null;\nvar endMarker = null;\nvar flag = \"\"; //用于描述当前取的点是起点还是终点\nfunction minRoad(){\n\t\n\t$(\"#setStartPointBtn\").click(function(){\n\t\tflag = \"s\";\t\n\t});\n\t\n\t$(\"#setEndPointBtn\").click(function(){\n\t\tflag = \"e\";\t\n\t});\n\t\n\tmap.on('click', function(e){\n\t\tif(flag == \"s\"){\n\t\t\t$(\"#startPoint\").val(e.latlng.lng + \" \" + e.latlng.lat);\n\t\t\tif(startMarker){\n\t\t\t\tmap.removeLayer(startMarker);\n\t\t\t}\t\t\n\t\t\tstartMarker = L.marker(e.latlng).addTo(map);\n\t\t}else if(flag == \"e\"){\n\t\t\t$(\"#endPoint\").val(e.latlng.lng + \" \" + e.latlng.lat);\n\t\t\tif(endMarker){\n\t\t\t\tmap.removeLayer(endMarker);\n\t\t\t}\t\t\t\t\n\t\t\tendMarker = L.marker(e.latlng).addTo(map);\n\t\t}\n\t\tconsole.log(e.latlng.lng + \"  \" + e.latlng.lat);\n\t});\n\t\n\t$(\"#getRouting\").click(function(){\n\t\t$.ajax({\n\t\t\turl : \"routing\",\n\t\t\ttype : \"post\",\n\t\t\tdataType : 'json',\n\t\t\tdata : {\n\t\t\t\tstartPoint : $(\"#startPoint\").val(),\n\t\t\t\tendPoint : $(\"#endPoint\").val()\n\t\t\t},\n\t\t\tsuccess : function(data){\n\t\t\t\tif(data.msg){\n\t\t\t\t\talert(data.msg);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif(routeLayer){\n\t\t\t\t\trouteLayer.clearLayers();\n\t\t\t\t}\n\t\t\t\tfor(var i = 0; i < data.length;i++){\n\t\t\t\t\tvar layer = routeLayer.addLayer(L.geoJson(eval('(' + data[i] + ')')).bindPopup(\"这里是线路信息\"));\n\n\t\t\t\t}\n\t\t\t},\n\t\t\terror : function(e){\n\t\t\t\talert(\"内部错误！\");\n\t\t\t}\n\t\t});\n\t});\n\t\n}\n\n\n\n\n\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/leaflet/L.Control.Zoominfo.css",
    "content": "/** Slider **/\n.leaflet-control-zoominfo-wrap {\n  padding-top: 5px;\n  padding-bottom: 5px;\n  background-color: #fff;\n  border-bottom: 1px solid #ccc;\n}\n.leaflet-control-zoominfo-body {\n  width: 2px;\n  border: solid #fff;\n  border-width: 0px 9px 0px 9px;\n  background-color: black;\n  margin: 0 auto;\n}\n\n.leaflet-control-zoominfo-body:hover {\n  cursor: pointer;\n}\n\n.leaflet-dragging .leaflet-control-zoominfo,\n.leaflet-dragging .leaflet-control-zoominfo-wrap,\n.leaflet-dragging .leaflet-control-zoominfo-body,\n.leaflet-dragging .leaflet-control-zoominfo a,\n.leaflet-dragging .leaflet-control-zoominfo a.leaflet-control-zoominfo-disabled {\n  cursor: move;\n  cursor: -webkit-grabbing;\n  cursor:    -moz-grabbing;\n}\n\n/** Leaflet Zoom Styles **/\n.leaflet-container .leaflet-control-zoominfo {\n  margin-left: 10px;\n  margin-top: 10px;\n}\n.leaflet-control-zoominfo a {\n  width: 26px;\n  height: 26px;\n  text-align: center;\n  text-decoration: none;\n  color: black;\n  display: block;\n}\n.leaflet-control-zoominfo a:hover {\n  background-color: #f4f4f4;\n}\n.leaflet-control-zoominfo-in {\n  font: bold 18px 'Lucida Console', Monaco, monospace;\n}\n.leaflet-control-zoominfo-in:after{\n  content:\"+\"\n}\n.leaflet-control-zoominfo-out {\n  font: bold 22px 'Lucida Console', Monaco, monospace;\n}\n.leaflet-control-zoominfo-out:after{\n  content:\"−\"\n}\n.leaflet-control-zoominfo a.leaflet-control-zoominfo-disabled {\n  cursor: default;\n  color: #bbb;\n}\n\n/* Touch */\n.leaflet-touch .leaflet-control-zoominfo-body {\n  background-position: 10px 0px;\n}\n.leaflet-touch .leaflet-control-zoominfo a {\n  width: 30px;\n  line-height: 30px;\n}\n.leaflet-touch .leaflet-control-zoominfo a:hover {\n  width: 30px;\n  line-height: 30px;\n}\n.leaflet-touch .leaflet-control-zoominfo-in {\n  font-size: 24px;\n  line-height: 29px;\n}\n.leaflet-touch .leaflet-control-zoominfo-out {\n  font-size: 28px;\n  line-height: 30px;\n}\n.leaflet-touch .leaflet-control-zoominfo {\n  box-shadow: none;\n  border: 4px solid rgba(0,0,0,0.3);\n}\n\n.leaflet-control-zoominfo-info { \n  margin-left: -13px;\n  background-color: #fff;\n  border: none;\n  width: 22px;\n  height: 22px;\n  display: block;\n  text-align: center;\n  text-decoration: none;\n  color: black;\n  padding: 4px 4px 0px 3px;\n\n  border-radius: 4px; \n  cursor: default;\n}\n\n.leaflet-control-zoominfoinfo h4 { \n  margin: 0 0 0px 0px; \n  color: #000; \n}\n\n/* Old IE */\n\n.leaflet-oldie .leaflet-control-zoominfo-wrap {\n  width: 26px;\n}\n\n.leaflet-oldie .leaflet-control-zoominfo {\n  border: 1px solid #999;\n}\n\n.leaflet-oldie .leaflet-control-zoominfo-in {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '+');\n}\n.leaflet-oldie .leaflet-control-zoominfo-out {\n  *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '-');\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/leaflet/L.Control.Zoominfo.js",
    "content": "(function (factory) {\n  // Packaging/modules magic dance\n  var L;\n  if (typeof define === 'function' && define.amd) {\n    // AMD\n    define(['leaflet/leaflet'], factory);\n  } else if (typeof module !== 'undefined') {\n    // Node/CommonJS\n    L = require('leaflet/leaflet');\n    module.exports = factory(L);\n  } else {\n    // Browser globals\n    if (typeof window.L === 'undefined') {\n      throw new Error('Leaflet must be loaded first');\n        }\n    factory(window.L);\n  }\n}(function (L) {\n  'use strict';\n\n  L.Control.Zoominfo = (function () {\n\n    var Zoominfo = L.Control.extend({\n      options: {\n        position: 'topleft',\n        styleNS: 'leaflet-control-zoominfo'\n      },\n\n      onAdd: function (map) {\n        this._map = map;\n        this._ui = this._createUI();\n\n        map.whenReady(this._initInfo,        this)\n          .whenReady(this._initEvents,      this)\n          .whenReady(this._updateInfoValue, this)\n          .whenReady(this._updateDisabled,  this);\n        return this._ui.bar;\n      },\n\n      onRemove: function (map) {\n        map.off('zoomlevelschange',         this._updateSize,      this)\n          .off('zoomend zoomlevelschange', this._updateInfoValue, this)\n          .off('zoomend zoomlevelschange', this._updateDisabled,  this);\n      },\n\n      _createUI: function () {\n        var ui = {},\n          ns = this.options.styleNS;\n\n        ui.bar     = L.DomUtil.create('div', ns + ' leaflet-bar');\n        ui.zoomIn  = this._createZoomBtn('in', 'top', ui.bar);\n        ui.wrap    = L.DomUtil.create('div', ns + '-wrap leaflet-bar-part', ui.bar);\n        ui.zoomOut = this._createZoomBtn('out', 'bottom', ui.bar);\n        ui.body    = L.DomUtil.create('div', ns + '-body', ui.wrap);\n        ui.info    = L.DomUtil.create('div', ns + '-info');\n\n        L.DomEvent.disableClickPropagation(ui.bar);\n        L.DomEvent.disableClickPropagation(ui.info);\n\n        return ui;\n      },\n      _createZoomBtn: function (zoomDir, end, container) {\n        var classDef = this.options.styleNS + '-' + zoomDir +\n            ' leaflet-bar-part' +\n            ' leaflet-bar-part-' + end,\n          link = L.DomUtil.create('a', classDef, container);\n\n        link.href = '#';\n        link.title = 'Zoom ' + zoomDir;\n\n        L.DomEvent.on(link, 'click', L.DomEvent.preventDefault);\n\n        return link;\n      },\n\n      _initInfo: function () {\n        this._ui.body.appendChild(this._ui.info);\n      },\n      _initEvents: function () {\n        this._map\n          .on('zoomend zoomlevelschange', this._updateInfoValue, this)\n          .on('zoomend zoomlevelschange', this._updateDisabled,  this);\n\n        L.DomEvent.on(this._ui.zoomIn,  'click', this._zoomIn,        this);\n        L.DomEvent.on(this._ui.zoomOut, 'click', this._zoomOut,       this);\n      },\n\n      _zoomIn: function (e) {\n        this._map.zoomIn(e.shiftKey ? 3 : 1);\n      },\n      _zoomOut: function (e) {\n        this._map.zoomOut(e.shiftKey ? 3 : 1);\n      },\n\n      _zoomLevels: function () {\n        var zoomLevels = this._map.getMaxZoom() - this._map.getMinZoom() + 1;\n        return zoomLevels < Infinity ? zoomLevels : 0;\n      },\n      _toZoomLevel: function (value) {\n        return value + this._map.getMinZoom();\n      },\n      _toValue: function (zoomLevel) {\n        return zoomLevel - this._map.getMinZoom();\n      },\n\n      _updateInfoValue: function () {\n        this._ui.info.innerHTML = '<strong>'+ this._map.getZoom() + '</strong>';\n      },\n      _updateDisabled: function () {\n        var zoomLevel = this._map.getZoom(),\n          className = this.options.styleNS + '-disabled';\n\n        L.DomUtil.removeClass(this._ui.zoomIn,  className);\n        L.DomUtil.removeClass(this._ui.zoomOut, className);\n\n        if (zoomLevel === this._map.getMinZoom()) {\n          L.DomUtil.addClass(this._ui.zoomOut, className);\n        }\n        if (zoomLevel === this._map.getMaxZoom()) {\n          L.DomUtil.addClass(this._ui.zoomIn, className);\n        }\n      }\n    });\n\n    return Zoominfo;\n  })();\n\n  L.Map.addInitHook(function () {\n    if (this.options.zoominfoControl) {\n      this.zoominfoControl = new L.Control.Zoominfo();\n      this.addControl(this.zoominfoControl);\n    }\n  });\n\n  L.control.zoominfo = function (options) {\n    return new L.Control.Zoominfo(options);\n  };\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/leaflet/leaflet.css",
    "content": "/* required styles */\n\n.leaflet-pane,\n.leaflet-tile,\n.leaflet-marker-icon,\n.leaflet-marker-shadow,\n.leaflet-tile-container,\n.leaflet-pane > svg,\n.leaflet-pane > canvas,\n.leaflet-zoom-box,\n.leaflet-image-layer,\n.leaflet-layer {\n\tposition: absolute;\n\tleft: 0;\n\ttop: 0;\n\t}\n.leaflet-container {\n\toverflow: hidden;\n\t}\n.leaflet-tile,\n.leaflet-marker-icon,\n.leaflet-marker-shadow {\n\t-webkit-user-select: none;\n\t   -moz-user-select: none;\n\t        user-select: none;\n\t  -webkit-user-drag: none;\n\t}\n/* Safari renders non-retina tile on retina better with this, but Chrome is worse */\n.leaflet-safari .leaflet-tile {\n\timage-rendering: -webkit-optimize-contrast;\n\t}\n/* hack that prevents hw layers \"stretching\" when loading new tiles */\n.leaflet-safari .leaflet-tile-container {\n\twidth: 1600px;\n\theight: 1600px;\n\t-webkit-transform-origin: 0 0;\n\t}\n.leaflet-marker-icon,\n.leaflet-marker-shadow {\n\tdisplay: block;\n\t}\n/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */\n/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */\n.leaflet-container .leaflet-overlay-pane svg,\n.leaflet-container .leaflet-marker-pane img,\n.leaflet-container .leaflet-shadow-pane img,\n.leaflet-container .leaflet-tile-pane img,\n.leaflet-container img.leaflet-image-layer {\n\tmax-width: none !important;\n\tmax-height: none !important;\n\t}\n\n.leaflet-container.leaflet-touch-zoom {\n\t-ms-touch-action: pan-x pan-y;\n\ttouch-action: pan-x pan-y;\n\t}\n.leaflet-container.leaflet-touch-drag {\n\t-ms-touch-action: pinch-zoom;\n\t/* Fallback for FF which doesn't support pinch-zoom */\n\ttouch-action: none;\n\ttouch-action: pinch-zoom;\n}\n.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {\n\t-ms-touch-action: none;\n\ttouch-action: none;\n}\n.leaflet-container {\n\t-webkit-tap-highlight-color: transparent;\n}\n.leaflet-container a {\n\t-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);\n}\n.leaflet-tile {\n\tfilter: inherit;\n\tvisibility: hidden;\n\t}\n.leaflet-tile-loaded {\n\tvisibility: inherit;\n\t}\n.leaflet-zoom-box {\n\twidth: 0;\n\theight: 0;\n\t-moz-box-sizing: border-box;\n\t     box-sizing: border-box;\n\tz-index: 800;\n\t}\n/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */\n.leaflet-overlay-pane svg {\n\t-moz-user-select: none;\n\t}\n\n.leaflet-pane         { z-index: 400; }\n\n.leaflet-tile-pane    { z-index: 200; }\n.leaflet-overlay-pane { z-index: 400; }\n.leaflet-shadow-pane  { z-index: 500; }\n.leaflet-marker-pane  { z-index: 600; }\n.leaflet-tooltip-pane   { z-index: 650; }\n.leaflet-popup-pane   { z-index: 700; }\n\n.leaflet-map-pane canvas { z-index: 100; }\n.leaflet-map-pane svg    { z-index: 200; }\n\n.leaflet-vml-shape {\n\twidth: 1px;\n\theight: 1px;\n\t}\n.lvml {\n\tbehavior: url(#default#VML);\n\tdisplay: inline-block;\n\tposition: absolute;\n\t}\n\n\n/* control positioning */\n\n.leaflet-control {\n\tposition: relative;\n\tz-index: 800;\n\tpointer-events: visiblePainted; /* IE 9-10 doesn't have auto */\n\tpointer-events: auto;\n\t}\n.leaflet-top,\n.leaflet-bottom {\n\tposition: absolute;\n\tz-index: 1000;\n\tpointer-events: none;\n\t}\n.leaflet-top {\n\ttop: 0;\n\t}\n.leaflet-right {\n\tright: 0;\n\t}\n.leaflet-bottom {\n\tbottom: 0;\n\t}\n.leaflet-left {\n\tleft: 0;\n\t}\n.leaflet-control {\n\tfloat: left;\n\tclear: both;\n\t}\n.leaflet-right .leaflet-control {\n\tfloat: right;\n\t}\n.leaflet-top .leaflet-control {\n\tmargin-top: 10px;\n\t}\n.leaflet-bottom .leaflet-control {\n\tmargin-bottom: 10px;\n\t}\n.leaflet-left .leaflet-control {\n\tmargin-left: 10px;\n\t}\n.leaflet-right .leaflet-control {\n\tmargin-right: 10px;\n\t}\n\n\n/* zoom and fade animations */\n\n.leaflet-fade-anim .leaflet-tile {\n\twill-change: opacity;\n\t}\n.leaflet-fade-anim .leaflet-popup {\n\topacity: 0;\n\t-webkit-transition: opacity 0.2s linear;\n\t   -moz-transition: opacity 0.2s linear;\n\t     -o-transition: opacity 0.2s linear;\n\t        transition: opacity 0.2s linear;\n\t}\n.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {\n\topacity: 1;\n\t}\n.leaflet-zoom-animated {\n\t-webkit-transform-origin: 0 0;\n\t    -ms-transform-origin: 0 0;\n\t        transform-origin: 0 0;\n\t}\n.leaflet-zoom-anim .leaflet-zoom-animated {\n\twill-change: transform;\n\t}\n.leaflet-zoom-anim .leaflet-zoom-animated {\n\t-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);\n\t   -moz-transition:    -moz-transform 0.25s cubic-bezier(0,0,0.25,1);\n\t     -o-transition:      -o-transform 0.25s cubic-bezier(0,0,0.25,1);\n\t        transition:         transform 0.25s cubic-bezier(0,0,0.25,1);\n\t}\n.leaflet-zoom-anim .leaflet-tile,\n.leaflet-pan-anim .leaflet-tile {\n\t-webkit-transition: none;\n\t   -moz-transition: none;\n\t     -o-transition: none;\n\t        transition: none;\n\t}\n\n.leaflet-zoom-anim .leaflet-zoom-hide {\n\tvisibility: hidden;\n\t}\n\n\n/* cursors */\n\n.leaflet-interactive {\n\tcursor: pointer;\n\t}\n.leaflet-grab {\n\tcursor: -webkit-grab;\n\tcursor:    -moz-grab;\n\t}\n.leaflet-crosshair,\n.leaflet-crosshair .leaflet-interactive {\n\tcursor: crosshair;\n\t}\n.leaflet-popup-pane,\n.leaflet-control {\n\tcursor: auto;\n\t}\n.leaflet-dragging .leaflet-grab,\n.leaflet-dragging .leaflet-grab .leaflet-interactive,\n.leaflet-dragging .leaflet-marker-draggable {\n\tcursor: move;\n\tcursor: -webkit-grabbing;\n\tcursor:    -moz-grabbing;\n\t}\n\n/* marker & overlays interactivity */\n.leaflet-marker-icon,\n.leaflet-marker-shadow,\n.leaflet-image-layer,\n.leaflet-pane > svg path,\n.leaflet-tile-container {\n\tpointer-events: none;\n\t}\n\n.leaflet-marker-icon.leaflet-interactive,\n.leaflet-image-layer.leaflet-interactive,\n.leaflet-pane > svg path.leaflet-interactive {\n\tpointer-events: visiblePainted; /* IE 9-10 doesn't have auto */\n\tpointer-events: auto;\n\t}\n\n/* visual tweaks */\n\n.leaflet-container {\n\tbackground: #ddd;\n\toutline: 0;\n\t}\n.leaflet-container a {\n\tcolor: #0078A8;\n\t}\n.leaflet-container a.leaflet-active {\n\toutline: 2px solid orange;\n\t}\n.leaflet-zoom-box {\n\tborder: 2px dotted #38f;\n\tbackground: rgba(255,255,255,0.5);\n\t}\n\n\n/* general typography */\n.leaflet-container {\n\tfont: 12px/1.5 \"Helvetica Neue\", Arial, Helvetica, sans-serif;\n\t}\n\n\n/* general toolbar styles */\n\n.leaflet-bar {\n\tbox-shadow: 0 1px 5px rgba(0,0,0,0.65);\n\tborder-radius: 4px;\n\t}\n.leaflet-bar a,\n.leaflet-bar a:hover {\n\tbackground-color: #fff;\n\tborder-bottom: 1px solid #ccc;\n\twidth: 26px;\n\theight: 26px;\n\tline-height: 26px;\n\tdisplay: block;\n\ttext-align: center;\n\ttext-decoration: none;\n\tcolor: black;\n\t}\n.leaflet-bar a,\n.leaflet-control-layers-toggle {\n\tbackground-position: 50% 50%;\n\tbackground-repeat: no-repeat;\n\tdisplay: block;\n\t}\n.leaflet-bar a:hover {\n\tbackground-color: #f4f4f4;\n\t}\n.leaflet-bar a:first-child {\n\tborder-top-left-radius: 4px;\n\tborder-top-right-radius: 4px;\n\t}\n.leaflet-bar a:last-child {\n\tborder-bottom-left-radius: 4px;\n\tborder-bottom-right-radius: 4px;\n\tborder-bottom: none;\n\t}\n.leaflet-bar a.leaflet-disabled {\n\tcursor: default;\n\tbackground-color: #f4f4f4;\n\tcolor: #bbb;\n\t}\n\n.leaflet-touch .leaflet-bar a {\n\twidth: 30px;\n\theight: 30px;\n\tline-height: 30px;\n\t}\n.leaflet-touch .leaflet-bar a:first-child {\n\tborder-top-left-radius: 2px;\n\tborder-top-right-radius: 2px;\n\t}\n.leaflet-touch .leaflet-bar a:last-child {\n\tborder-bottom-left-radius: 2px;\n\tborder-bottom-right-radius: 2px;\n\t}\n\n/* zoom control */\n\n.leaflet-control-zoom-in,\n.leaflet-control-zoom-out {\n\tfont: bold 18px 'Lucida Console', Monaco, monospace;\n\ttext-indent: 1px;\n\t}\n\n.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out  {\n\tfont-size: 22px;\n\t}\n\n\n/* layers control */\n\n.leaflet-control-layers {\n\tbox-shadow: 0 1px 5px rgba(0,0,0,0.4);\n\tbackground: #fff;\n\tborder-radius: 5px;\n\t}\n.leaflet-control-layers-toggle {\n\tbackground-image: url(../images/layers.png);\n\twidth: 36px;\n\theight: 36px;\n\t}\n.leaflet-retina .leaflet-control-layers-toggle {\n\tbackground-image: url(../images/layers-2x.png);\n\tbackground-size: 26px 26px;\n\t}\n.leaflet-touch .leaflet-control-layers-toggle {\n\twidth: 44px;\n\theight: 44px;\n\t}\n.leaflet-control-layers .leaflet-control-layers-list,\n.leaflet-control-layers-expanded .leaflet-control-layers-toggle {\n\tdisplay: none;\n\t}\n.leaflet-control-layers-expanded .leaflet-control-layers-list {\n\tdisplay: block;\n\tposition: relative;\n\t}\n.leaflet-control-layers-expanded {\n\tpadding: 6px 10px 6px 6px;\n\tcolor: #333;\n\tbackground: #fff;\n\t}\n.leaflet-control-layers-scrollbar {\n\toverflow-y: scroll;\n\toverflow-x: hidden;\n\tpadding-right: 5px;\n\t}\n.leaflet-control-layers-selector {\n\tmargin-top: 2px;\n\tposition: relative;\n\ttop: 1px;\n\t}\n.leaflet-control-layers label {\n\tdisplay: block;\n\t}\n.leaflet-control-layers-separator {\n\theight: 0;\n\tborder-top: 1px solid #ddd;\n\tmargin: 5px -10px 5px -6px;\n\t}\n\n/* Default icon URLs */\n.leaflet-default-icon-path {\n\tbackground-image: url(../images/marker-icon.png);\n\t}\n\n\n/* attribution and scale controls */\n\n.leaflet-container .leaflet-control-attribution {\n\tbackground: #fff;\n\tbackground: rgba(255, 255, 255, 0.7);\n\tmargin: 0;\n\t}\n.leaflet-control-attribution,\n.leaflet-control-scale-line {\n\tpadding: 0 5px;\n\tcolor: #333;\n\t}\n.leaflet-control-attribution a {\n\ttext-decoration: none;\n\t}\n.leaflet-control-attribution a:hover {\n\ttext-decoration: underline;\n\t}\n.leaflet-container .leaflet-control-attribution,\n.leaflet-container .leaflet-control-scale {\n\tfont-size: 11px;\n\t}\n.leaflet-left .leaflet-control-scale {\n\tmargin-left: 5px;\n\t}\n.leaflet-bottom .leaflet-control-scale {\n\tmargin-bottom: 5px;\n\t}\n.leaflet-control-scale-line {\n\tborder: 2px solid #777;\n\tborder-top: none;\n\tline-height: 1.1;\n\tpadding: 2px 5px 1px;\n\tfont-size: 11px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\t-moz-box-sizing: border-box;\n\t     box-sizing: border-box;\n\n\tbackground: #fff;\n\tbackground: rgba(255, 255, 255, 0.5);\n\t}\n.leaflet-control-scale-line:not(:first-child) {\n\tborder-top: 2px solid #777;\n\tborder-bottom: none;\n\tmargin-top: -2px;\n\t}\n.leaflet-control-scale-line:not(:first-child):not(:last-child) {\n\tborder-bottom: 2px solid #777;\n\t}\n\n.leaflet-touch .leaflet-control-attribution,\n.leaflet-touch .leaflet-control-layers,\n.leaflet-touch .leaflet-bar {\n\tbox-shadow: none;\n\t}\n.leaflet-touch .leaflet-control-layers,\n.leaflet-touch .leaflet-bar {\n\tborder: 2px solid rgba(0,0,0,0.2);\n\tbackground-clip: padding-box;\n\t}\n\n\n/* popup */\n\n.leaflet-popup {\n\tposition: absolute;\n\ttext-align: center;\n\tmargin-bottom: 20px;\n\t}\n.leaflet-popup-content-wrapper {\n\tpadding: 1px;\n\ttext-align: left;\n\tborder-radius: 12px;\n\t}\n.leaflet-popup-content {\n\tmargin: 13px 19px;\n\tline-height: 1.4;\n\t}\n.leaflet-popup-content p {\n\tmargin: 18px 0;\n\t}\n.leaflet-popup-tip-container {\n\twidth: 40px;\n\theight: 20px;\n\tposition: absolute;\n\tleft: 50%;\n\tmargin-left: -20px;\n\toverflow: hidden;\n\tpointer-events: none;\n\t}\n.leaflet-popup-tip {\n\twidth: 17px;\n\theight: 17px;\n\tpadding: 1px;\n\n\tmargin: -10px auto 0;\n\n\t-webkit-transform: rotate(45deg);\n\t   -moz-transform: rotate(45deg);\n\t    -ms-transform: rotate(45deg);\n\t     -o-transform: rotate(45deg);\n\t        transform: rotate(45deg);\n\t}\n.leaflet-popup-content-wrapper,\n.leaflet-popup-tip {\n\tbackground: white;\n\tcolor: #333;\n\tbox-shadow: 0 3px 14px rgba(0,0,0,0.4);\n\t}\n.leaflet-container a.leaflet-popup-close-button {\n\tposition: absolute;\n\ttop: 0;\n\tright: 0;\n\tpadding: 4px 4px 0 0;\n\tborder: none;\n\ttext-align: center;\n\twidth: 18px;\n\theight: 14px;\n\tfont: 16px/14px Tahoma, Verdana, sans-serif;\n\tcolor: #c3c3c3;\n\ttext-decoration: none;\n\tfont-weight: bold;\n\tbackground: transparent;\n\t}\n.leaflet-container a.leaflet-popup-close-button:hover {\n\tcolor: #999;\n\t}\n.leaflet-popup-scrolled {\n\toverflow: auto;\n\tborder-bottom: 1px solid #ddd;\n\tborder-top: 1px solid #ddd;\n\t}\n\n.leaflet-oldie .leaflet-popup-content-wrapper {\n\tzoom: 1;\n\t}\n.leaflet-oldie .leaflet-popup-tip {\n\twidth: 24px;\n\tmargin: 0 auto;\n\n\t-ms-filter: \"progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)\";\n\tfilter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);\n\t}\n.leaflet-oldie .leaflet-popup-tip-container {\n\tmargin-top: -1px;\n\t}\n\n.leaflet-oldie .leaflet-control-zoom,\n.leaflet-oldie .leaflet-control-layers,\n.leaflet-oldie .leaflet-popup-content-wrapper,\n.leaflet-oldie .leaflet-popup-tip {\n\tborder: 1px solid #999;\n\t}\n\n\n/* div icon */\n\n.leaflet-div-icon {\n\tbackground: #fff;\n\tborder: 1px solid #666;\n\t}\n\n\n/* Tooltip */\n/* Base styles for the element that has a tooltip */\n.leaflet-tooltip {\n\tposition: absolute;\n\tpadding: 6px;\n\tbackground-color: #fff;\n\tborder: 1px solid #fff;\n\tborder-radius: 3px;\n\tcolor: #222;\n\twhite-space: nowrap;\n\t-webkit-user-select: none;\n\t-moz-user-select: none;\n\t-ms-user-select: none;\n\tuser-select: none;\n\tpointer-events: none;\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.4);\n\t}\n.leaflet-tooltip.leaflet-clickable {\n\tcursor: pointer;\n\tpointer-events: auto;\n\t}\n.leaflet-tooltip-top:before,\n.leaflet-tooltip-bottom:before,\n.leaflet-tooltip-left:before,\n.leaflet-tooltip-right:before {\n\tposition: absolute;\n\tpointer-events: none;\n\tborder: 6px solid transparent;\n\tbackground: transparent;\n\tcontent: \"\";\n\t}\n\n/* Directions */\n\n.leaflet-tooltip-bottom {\n\tmargin-top: 6px;\n}\n.leaflet-tooltip-top {\n\tmargin-top: -6px;\n}\n.leaflet-tooltip-bottom:before,\n.leaflet-tooltip-top:before {\n\tleft: 50%;\n\tmargin-left: -6px;\n\t}\n.leaflet-tooltip-top:before {\n\tbottom: 0;\n\tmargin-bottom: -12px;\n\tborder-top-color: #fff;\n\t}\n.leaflet-tooltip-bottom:before {\n\ttop: 0;\n\tmargin-top: -12px;\n\tmargin-left: -6px;\n\tborder-bottom-color: #fff;\n\t}\n.leaflet-tooltip-left {\n\tmargin-left: -6px;\n}\n.leaflet-tooltip-right {\n\tmargin-left: 6px;\n}\n.leaflet-tooltip-left:before,\n.leaflet-tooltip-right:before {\n\ttop: 50%;\n\tmargin-top: -6px;\n\t}\n.leaflet-tooltip-left:before {\n\tright: 0;\n\tmargin-right: -12px;\n\tborder-left-color: #fff;\n\t}\n.leaflet-tooltip-right:before {\n\tleft: 0;\n\tmargin-left: -12px;\n\tborder-right-color: #fff;\n\t}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/lab/gis/leaflet/leaflet.js",
    "content": "/* @preserve\n * Leaflet 1.3.1+Detached: ba6f97fff8647e724e4dfe66d2ed7da11f908989.ba6f97f, a JS library for interactive maps. http://leafletjs.com\n * (c) 2010-2017 Vladimir Agafonkin, (c) 2010-2011 CloudMade\n */\n!function(t,i){\"object\"==typeof exports&&\"undefined\"!=typeof module?i(exports):\"function\"==typeof define&&define.amd?define([\"exports\"],i):i(t.L={})}(this,function(t){\"use strict\";function i(t){var i,e,n,o;for(e=1,n=arguments.length;e<n;e++){o=arguments[e];for(i in o)t[i]=o[i]}return t}function e(t,i){var e=Array.prototype.slice;if(t.bind)return t.bind.apply(t,e.call(arguments,1));var n=e.call(arguments,2);return function(){return t.apply(i,n.length?n.concat(e.call(arguments)):arguments)}}function n(t){return t._leaflet_id=t._leaflet_id||++ti,t._leaflet_id}function o(t,i,e){var n,o,s,r;return r=function(){n=!1,o&&(s.apply(e,o),o=!1)},s=function(){n?o=arguments:(t.apply(e,arguments),setTimeout(r,i),n=!0)}}function s(t,i,e){var n=i[1],o=i[0],s=n-o;return t===n&&e?t:((t-o)%s+s)%s+o}function r(){return!1}function a(t,i){var e=Math.pow(10,void 0===i?6:i);return Math.round(t*e)/e}function h(t){return t.trim?t.trim():t.replace(/^\\s+|\\s+$/g,\"\")}function u(t){return h(t).split(/\\s+/)}function l(t,i){t.hasOwnProperty(\"options\")||(t.options=t.options?Qt(t.options):{});for(var e in i)t.options[e]=i[e];return t.options}function c(t,i,e){var n=[];for(var o in t)n.push(encodeURIComponent(e?o.toUpperCase():o)+\"=\"+encodeURIComponent(t[o]));return(i&&-1!==i.indexOf(\"?\")?\"&\":\"?\")+n.join(\"&\")}function _(t,i){return t.replace(ii,function(t,e){var n=i[e];if(void 0===n)throw new Error(\"No value provided for variable \"+t);return\"function\"==typeof n&&(n=n(i)),n})}function d(t,i){for(var e=0;e<t.length;e++)if(t[e]===i)return e;return-1}function p(t){return window[\"webkit\"+t]||window[\"moz\"+t]||window[\"ms\"+t]}function m(t){var i=+new Date,e=Math.max(0,16-(i-oi));return oi=i+e,window.setTimeout(t,e)}function f(t,i,n){if(!n||si!==m)return si.call(window,e(t,i));t.call(i)}function g(t){t&&ri.call(window,t)}function v(){}function y(t){if(\"undefined\"!=typeof L&&L&&L.Mixin){t=ei(t)?t:[t];for(var i=0;i<t.length;i++)t[i]===L.Mixin.Events&&console.warn(\"Deprecated include of L.Mixin.Events: this property will be removed in future releases, please inherit from L.Evented instead.\",(new Error).stack)}}function x(t,i,e){this.x=e?Math.round(t):t,this.y=e?Math.round(i):i}function w(t,i,e){return t instanceof x?t:ei(t)?new x(t[0],t[1]):void 0===t||null===t?t:\"object\"==typeof t&&\"x\"in t&&\"y\"in t?new x(t.x,t.y):new x(t,i,e)}function P(t,i){if(t)for(var e=i?[t,i]:t,n=0,o=e.length;n<o;n++)this.extend(e[n])}function b(t,i){return!t||t instanceof P?t:new P(t,i)}function T(t,i){if(t)for(var e=i?[t,i]:t,n=0,o=e.length;n<o;n++)this.extend(e[n])}function z(t,i){return t instanceof T?t:new T(t,i)}function M(t,i,e){if(isNaN(t)||isNaN(i))throw new Error(\"Invalid LatLng object: (\"+t+\", \"+i+\")\");this.lat=+t,this.lng=+i,void 0!==e&&(this.alt=+e)}function C(t,i,e){return t instanceof M?t:ei(t)&&\"object\"!=typeof t[0]?3===t.length?new M(t[0],t[1],t[2]):2===t.length?new M(t[0],t[1]):null:void 0===t||null===t?t:\"object\"==typeof t&&\"lat\"in t?new M(t.lat,\"lng\"in t?t.lng:t.lon,t.alt):void 0===i?null:new M(t,i,e)}function Z(t,i,e,n){if(ei(t))return this._a=t[0],this._b=t[1],this._c=t[2],void(this._d=t[3]);this._a=t,this._b=i,this._c=e,this._d=n}function S(t,i,e,n){return new Z(t,i,e,n)}function E(t){return document.createElementNS(\"http://www.w3.org/2000/svg\",t)}function k(t,i){var e,n,o,s,r,a,h=\"\";for(e=0,o=t.length;e<o;e++){for(n=0,s=(r=t[e]).length;n<s;n++)a=r[n],h+=(n?\"L\":\"M\")+a.x+\" \"+a.y;h+=i?Xi?\"z\":\"x\":\"\"}return h||\"M0 0\"}function A(t){return navigator.userAgent.toLowerCase().indexOf(t)>=0}function I(t,i,e,n){return\"touchstart\"===i?O(t,e,n):\"touchmove\"===i?W(t,e,n):\"touchend\"===i&&H(t,e,n),this}function B(t,i,e){var n=t[\"_leaflet_\"+i+e];return\"touchstart\"===i?t.removeEventListener(Qi,n,!1):\"touchmove\"===i?t.removeEventListener(te,n,!1):\"touchend\"===i&&(t.removeEventListener(ie,n,!1),t.removeEventListener(ee,n,!1)),this}function O(t,i,n){var o=e(function(t){if(\"mouse\"!==t.pointerType&&t.MSPOINTER_TYPE_MOUSE&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(ne.indexOf(t.target.tagName)<0))return;$(t)}j(t,i)});t[\"_leaflet_touchstart\"+n]=o,t.addEventListener(Qi,o,!1),se||(document.documentElement.addEventListener(Qi,R,!0),document.documentElement.addEventListener(te,D,!0),document.documentElement.addEventListener(ie,N,!0),document.documentElement.addEventListener(ee,N,!0),se=!0)}function R(t){oe[t.pointerId]=t,re++}function D(t){oe[t.pointerId]&&(oe[t.pointerId]=t)}function N(t){delete oe[t.pointerId],re--}function j(t,i){t.touches=[];for(var e in oe)t.touches.push(oe[e]);t.changedTouches=[t],i(t)}function W(t,i,e){var n=function(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&\"mouse\"!==t.pointerType||0!==t.buttons)&&j(t,i)};t[\"_leaflet_touchmove\"+e]=n,t.addEventListener(te,n,!1)}function H(t,i,e){var n=function(t){j(t,i)};t[\"_leaflet_touchend\"+e]=n,t.addEventListener(ie,n,!1),t.addEventListener(ee,n,!1)}function F(t,i,e){function n(t){var i;if(Ui){if(!Pi||\"mouse\"===t.pointerType)return;i=re}else i=t.touches.length;if(!(i>1)){var e=Date.now(),n=e-(s||e);r=t.touches?t.touches[0]:t,a=n>0&&n<=h,s=e}}function o(t){if(a&&!r.cancelBubble){if(Ui){if(!Pi||\"mouse\"===t.pointerType)return;var e,n,o={};for(n in r)e=r[n],o[n]=e&&e.bind?e.bind(r):e;r=o}r.type=\"dblclick\",i(r),s=null}}var s,r,a=!1,h=250;return t[ue+ae+e]=n,t[ue+he+e]=o,t[ue+\"dblclick\"+e]=i,t.addEventListener(ae,n,!1),t.addEventListener(he,o,!1),t.addEventListener(\"dblclick\",i,!1),this}function U(t,i){var e=t[ue+ae+i],n=t[ue+he+i],o=t[ue+\"dblclick\"+i];return t.removeEventListener(ae,e,!1),t.removeEventListener(he,n,!1),Pi||t.removeEventListener(\"dblclick\",o,!1),this}function V(t,i,e,n){if(\"object\"==typeof i)for(var o in i)G(t,o,i[o],e);else for(var s=0,r=(i=u(i)).length;s<r;s++)G(t,i[s],e,n);return this}function q(t,i,e,n){if(\"object\"==typeof i)for(var o in i)K(t,o,i[o],e);else if(i)for(var s=0,r=(i=u(i)).length;s<r;s++)K(t,i[s],e,n);else{for(var a in t[le])K(t,a,t[le][a]);delete t[le]}return this}function G(t,i,e,o){var s=i+n(e)+(o?\"_\"+n(o):\"\");if(t[le]&&t[le][s])return this;var r=function(i){return e.call(o||t,i||window.event)},a=r;Ui&&0===i.indexOf(\"touch\")?I(t,i,r,s):!Vi||\"dblclick\"!==i||!F||Ui&&Si?\"addEventListener\"in t?\"mousewheel\"===i?t.addEventListener(\"onwheel\"in t?\"wheel\":\"mousewheel\",r,!1):\"mouseenter\"===i||\"mouseleave\"===i?(r=function(i){i=i||window.event,ot(t,i)&&a(i)},t.addEventListener(\"mouseenter\"===i?\"mouseover\":\"mouseout\",r,!1)):(\"click\"===i&&Ti&&(r=function(t){st(t,a)}),t.addEventListener(i,r,!1)):\"attachEvent\"in t&&t.attachEvent(\"on\"+i,r):F(t,r,s),t[le]=t[le]||{},t[le][s]=r}function K(t,i,e,o){var s=i+n(e)+(o?\"_\"+n(o):\"\"),r=t[le]&&t[le][s];if(!r)return this;Ui&&0===i.indexOf(\"touch\")?B(t,i,s):!Vi||\"dblclick\"!==i||!U||Ui&&Si?\"removeEventListener\"in t?\"mousewheel\"===i?t.removeEventListener(\"onwheel\"in t?\"wheel\":\"mousewheel\",r,!1):t.removeEventListener(\"mouseenter\"===i?\"mouseover\":\"mouseleave\"===i?\"mouseout\":i,r,!1):\"detachEvent\"in t&&t.detachEvent(\"on\"+i,r):U(t,s),t[le][s]=null}function Y(t){return t.stopPropagation?t.stopPropagation():t.originalEvent?t.originalEvent._stopped=!0:t.cancelBubble=!0,nt(t),this}function X(t){return G(t,\"mousewheel\",Y),this}function J(t){return V(t,\"mousedown touchstart dblclick\",Y),G(t,\"click\",et),this}function $(t){return t.preventDefault?t.preventDefault():t.returnValue=!1,this}function Q(t){return $(t),Y(t),this}function tt(t,i){if(!i)return new x(t.clientX,t.clientY);var e=i.getBoundingClientRect(),n=e.width/i.offsetWidth||1,o=e.height/i.offsetHeight||1;return new x(t.clientX/n-e.left-i.clientLeft,t.clientY/o-e.top-i.clientTop)}function it(t){return Pi?t.wheelDeltaY/2:t.deltaY&&0===t.deltaMode?-t.deltaY/ce:t.deltaY&&1===t.deltaMode?20*-t.deltaY:t.deltaY&&2===t.deltaMode?60*-t.deltaY:t.deltaX||t.deltaZ?0:t.wheelDelta?(t.wheelDeltaY||t.wheelDelta)/2:t.detail&&Math.abs(t.detail)<32765?20*-t.detail:t.detail?t.detail/-32765*60:0}function et(t){_e[t.type]=!0}function nt(t){var i=_e[t.type];return _e[t.type]=!1,i}function ot(t,i){var e=i.relatedTarget;if(!e)return!0;try{for(;e&&e!==t;)e=e.parentNode}catch(t){return!1}return e!==t}function st(t,i){var e=t.timeStamp||t.originalEvent&&t.originalEvent.timeStamp,n=pi&&e-pi;n&&n>100&&n<500||t.target._simulatedClick&&!t._simulated?Q(t):(pi=e,i(t))}function rt(t){return\"string\"==typeof t?document.getElementById(t):t}function at(t,i){var e=t.style[i]||t.currentStyle&&t.currentStyle[i];if((!e||\"auto\"===e)&&document.defaultView){var n=document.defaultView.getComputedStyle(t,null);e=n?n[i]:null}return\"auto\"===e?null:e}function ht(t,i,e){var n=document.createElement(t);return n.className=i||\"\",e&&e.appendChild(n),n}function ut(t){var i=t.parentNode;i&&i.removeChild(t)}function lt(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function ct(t){var i=t.parentNode;i.lastChild!==t&&i.appendChild(t)}function _t(t){var i=t.parentNode;i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function dt(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=gt(t);return e.length>0&&new RegExp(\"(^|\\\\s)\"+i+\"(\\\\s|$)\").test(e)}function pt(t,i){if(void 0!==t.classList)for(var e=u(i),n=0,o=e.length;n<o;n++)t.classList.add(e[n]);else if(!dt(t,i)){var s=gt(t);ft(t,(s?s+\" \":\"\")+i)}}function mt(t,i){void 0!==t.classList?t.classList.remove(i):ft(t,h((\" \"+gt(t)+\" \").replace(\" \"+i+\" \",\" \")))}function ft(t,i){void 0===t.className.baseVal?t.className=i:t.className.baseVal=i}function gt(t){return void 0===t.className.baseVal?t.className:t.className.baseVal}function vt(t,i){\"opacity\"in t.style?t.style.opacity=i:\"filter\"in t.style&&yt(t,i)}function yt(t,i){var e=!1,n=\"DXImageTransform.Microsoft.Alpha\";try{e=t.filters.item(n)}catch(t){if(1===i)return}i=Math.round(100*i),e?(e.Enabled=100!==i,e.Opacity=i):t.style.filter+=\" progid:\"+n+\"(opacity=\"+i+\")\"}function xt(t){for(var i=document.documentElement.style,e=0;e<t.length;e++)if(t[e]in i)return t[e];return!1}function wt(t,i,e){var n=i||new x(0,0);t.style[pe]=(Oi?\"translate(\"+n.x+\"px,\"+n.y+\"px)\":\"translate3d(\"+n.x+\"px,\"+n.y+\"px,0)\")+(e?\" scale(\"+e+\")\":\"\")}function Lt(t,i){t._leaflet_pos=i,Ni?wt(t,i):(t.style.left=i.x+\"px\",t.style.top=i.y+\"px\")}function Pt(t){return t._leaflet_pos||new x(0,0)}function bt(){V(window,\"dragstart\",$)}function Tt(){q(window,\"dragstart\",$)}function zt(t){for(;-1===t.tabIndex;)t=t.parentNode;t.style&&(Mt(),ve=t,ye=t.style.outline,t.style.outline=\"none\",V(window,\"keydown\",Mt))}function Mt(){ve&&(ve.style.outline=ye,ve=void 0,ye=void 0,q(window,\"keydown\",Mt))}function Ct(t,i){if(!i||!t.length)return t.slice();var e=i*i;return t=kt(t,e),t=St(t,e)}function Zt(t,i,e){return Math.sqrt(Rt(t,i,e,!0))}function St(t,i){var e=t.length,n=new(typeof Uint8Array!=void 0+\"\"?Uint8Array:Array)(e);n[0]=n[e-1]=1,Et(t,n,i,0,e-1);var o,s=[];for(o=0;o<e;o++)n[o]&&s.push(t[o]);return s}function Et(t,i,e,n,o){var s,r,a,h=0;for(r=n+1;r<=o-1;r++)(a=Rt(t[r],t[n],t[o],!0))>h&&(s=r,h=a);h>e&&(i[s]=1,Et(t,i,e,n,s),Et(t,i,e,s,o))}function kt(t,i){for(var e=[t[0]],n=1,o=0,s=t.length;n<s;n++)Ot(t[n],t[o])>i&&(e.push(t[n]),o=n);return o<s-1&&e.push(t[s-1]),e}function At(t,i,e,n,o){var s,r,a,h=n?Se:Bt(t,e),u=Bt(i,e);for(Se=u;;){if(!(h|u))return[t,i];if(h&u)return!1;a=Bt(r=It(t,i,s=h||u,e,o),e),s===h?(t=r,h=a):(i=r,u=a)}}function It(t,i,e,n,o){var s,r,a=i.x-t.x,h=i.y-t.y,u=n.min,l=n.max;return 8&e?(s=t.x+a*(l.y-t.y)/h,r=l.y):4&e?(s=t.x+a*(u.y-t.y)/h,r=u.y):2&e?(s=l.x,r=t.y+h*(l.x-t.x)/a):1&e&&(s=u.x,r=t.y+h*(u.x-t.x)/a),new x(s,r,o)}function Bt(t,i){var e=0;return t.x<i.min.x?e|=1:t.x>i.max.x&&(e|=2),t.y<i.min.y?e|=4:t.y>i.max.y&&(e|=8),e}function Ot(t,i){var e=i.x-t.x,n=i.y-t.y;return e*e+n*n}function Rt(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return u>0&&((o=((t.x-s)*a+(t.y-r)*h)/u)>1?(s=e.x,r=e.y):o>0&&(s+=a*o,r+=h*o)),a=t.x-s,h=t.y-r,n?a*a+h*h:new x(s,r)}function Dt(t){return!ei(t[0])||\"object\"!=typeof t[0][0]&&void 0!==t[0][0]}function Nt(t){return console.warn(\"Deprecated use of _flat, please use L.LineUtil.isFlat instead.\"),Dt(t)}function jt(t,i,e){var n,o,s,r,a,h,u,l,c,_=[1,4,2,8];for(o=0,u=t.length;o<u;o++)t[o]._code=Bt(t[o],i);for(r=0;r<4;r++){for(l=_[r],n=[],o=0,s=(u=t.length)-1;o<u;s=o++)a=t[o],h=t[s],a._code&l?h._code&l||((c=It(h,a,l,i,e))._code=Bt(c,i),n.push(c)):(h._code&l&&((c=It(h,a,l,i,e))._code=Bt(c,i),n.push(c)),n.push(a));t=n}return t}function Wt(t,i){var e,n,o,s,r=\"Feature\"===t.type?t.geometry:t,a=r?r.coordinates:null,h=[],u=i&&i.pointToLayer,l=i&&i.coordsToLatLng||Ht;if(!a&&!r)return null;switch(r.type){case\"Point\":return e=l(a),u?u(t,e):new Xe(e);case\"MultiPoint\":for(o=0,s=a.length;o<s;o++)e=l(a[o]),h.push(u?u(t,e):new Xe(e));return new qe(h);case\"LineString\":case\"MultiLineString\":return n=Ft(a,\"LineString\"===r.type?0:1,l),new tn(n,i);case\"Polygon\":case\"MultiPolygon\":return n=Ft(a,\"Polygon\"===r.type?1:2,l),new en(n,i);case\"GeometryCollection\":for(o=0,s=r.geometries.length;o<s;o++){var c=Wt({geometry:r.geometries[o],type:\"Feature\",properties:t.properties},i);c&&h.push(c)}return new qe(h);default:throw new Error(\"Invalid GeoJSON object.\")}}function Ht(t){return new M(t[1],t[0],t[2])}function Ft(t,i,e){for(var n,o=[],s=0,r=t.length;s<r;s++)n=i?Ft(t[s],i-1,e):(e||Ht)(t[s]),o.push(n);return o}function Ut(t,i){return i=\"number\"==typeof i?i:6,void 0!==t.alt?[a(t.lng,i),a(t.lat,i),a(t.alt,i)]:[a(t.lng,i),a(t.lat,i)]}function Vt(t,i,e,n){for(var o=[],s=0,r=t.length;s<r;s++)o.push(i?Vt(t[s],i-1,e,n):Ut(t[s],n));return!i&&e&&o.push(o[0]),o}function qt(t,e){return t.feature?i({},t.feature,{geometry:e}):Gt(e)}function Gt(t){return\"Feature\"===t.type||\"FeatureCollection\"===t.type?t:{type:\"Feature\",properties:{},geometry:t}}function Kt(t,i){return new nn(t,i)}function Yt(t,i){return new dn(t,i)}function Xt(t){return Yi?new fn(t):null}function Jt(t){return Xi||Ji?new xn(t):null}var $t=Object.freeze;Object.freeze=function(t){return t};var Qt=Object.create||function(){function t(){}return function(i){return t.prototype=i,new t}}(),ti=0,ii=/\\{ *([\\w_-]+) *\\}/g,ei=Array.isArray||function(t){return\"[object Array]\"===Object.prototype.toString.call(t)},ni=\"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=\",oi=0,si=window.requestAnimationFrame||p(\"RequestAnimationFrame\")||m,ri=window.cancelAnimationFrame||p(\"CancelAnimationFrame\")||p(\"CancelRequestAnimationFrame\")||function(t){window.clearTimeout(t)},ai=(Object.freeze||Object)({freeze:$t,extend:i,create:Qt,bind:e,lastId:ti,stamp:n,throttle:o,wrapNum:s,falseFn:r,formatNum:a,trim:h,splitWords:u,setOptions:l,getParamString:c,template:_,isArray:ei,indexOf:d,emptyImageUrl:ni,requestFn:si,cancelFn:ri,requestAnimFrame:f,cancelAnimFrame:g});v.extend=function(t){var e=function(){this.initialize&&this.initialize.apply(this,arguments),this.callInitHooks()},n=e.__super__=this.prototype,o=Qt(n);o.constructor=e,e.prototype=o;for(var s in this)this.hasOwnProperty(s)&&\"prototype\"!==s&&\"__super__\"!==s&&(e[s]=this[s]);return t.statics&&(i(e,t.statics),delete t.statics),t.includes&&(y(t.includes),i.apply(null,[o].concat(t.includes)),delete t.includes),o.options&&(t.options=i(Qt(o.options),t.options)),i(o,t),o._initHooks=[],o.callInitHooks=function(){if(!this._initHooksCalled){n.callInitHooks&&n.callInitHooks.call(this),this._initHooksCalled=!0;for(var t=0,i=o._initHooks.length;t<i;t++)o._initHooks[t].call(this)}},e},v.include=function(t){return i(this.prototype,t),this},v.mergeOptions=function(t){return i(this.prototype.options,t),this},v.addInitHook=function(t){var i=Array.prototype.slice.call(arguments,1),e=\"function\"==typeof t?t:function(){this[t].apply(this,i)};return this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(e),this};var hi={on:function(t,i,e){if(\"object\"==typeof t)for(var n in t)this._on(n,t[n],i);else for(var o=0,s=(t=u(t)).length;o<s;o++)this._on(t[o],i,e);return this},off:function(t,i,e){if(t)if(\"object\"==typeof t)for(var n in t)this._off(n,t[n],i);else for(var o=0,s=(t=u(t)).length;o<s;o++)this._off(t[o],i,e);else delete this._events;return this},_on:function(t,i,e){this._events=this._events||{};var n=this._events[t];n||(n=[],this._events[t]=n),e===this&&(e=void 0);for(var o={fn:i,ctx:e},s=n,r=0,a=s.length;r<a;r++)if(s[r].fn===i&&s[r].ctx===e)return;s.push(o)},_off:function(t,i,e){var n,o,s;if(this._events&&(n=this._events[t]))if(i){if(e===this&&(e=void 0),n)for(o=0,s=n.length;o<s;o++){var a=n[o];if(a.ctx===e&&a.fn===i)return a.fn=r,this._firingCount&&(this._events[t]=n=n.slice()),void n.splice(o,1)}}else{for(o=0,s=n.length;o<s;o++)n[o].fn=r;delete this._events[t]}},fire:function(t,e,n){if(!this.listens(t,n))return this;var o=i({},e,{type:t,target:this,sourceTarget:e&&e.sourceTarget||this});if(this._events){var s=this._events[t];if(s){this._firingCount=this._firingCount+1||1;for(var r=0,a=s.length;r<a;r++){var h=s[r];h.fn.call(h.ctx||this,o)}this._firingCount--}}return n&&this._propagateEvent(o),this},listens:function(t,i){var e=this._events&&this._events[t];if(e&&e.length)return!0;if(i)for(var n in this._eventParents)if(this._eventParents[n].listens(t,i))return!0;return!1},once:function(t,i,n){if(\"object\"==typeof t){for(var o in t)this.once(o,t[o],i);return this}var s=e(function(){this.off(t,i,n).off(t,s,n)},this);return this.on(t,i,n).on(t,s,n)},addEventParent:function(t){return this._eventParents=this._eventParents||{},this._eventParents[n(t)]=t,this},removeEventParent:function(t){return this._eventParents&&delete this._eventParents[n(t)],this},_propagateEvent:function(t){for(var e in this._eventParents)this._eventParents[e].fire(t.type,i({layer:t.target,propagatedFrom:t.target},t),!0)}};hi.addEventListener=hi.on,hi.removeEventListener=hi.clearAllEventListeners=hi.off,hi.addOneTimeEventListener=hi.once,hi.fireEvent=hi.fire,hi.hasEventListeners=hi.listens;var ui=v.extend(hi),li=Math.trunc||function(t){return t>0?Math.floor(t):Math.ceil(t)};x.prototype={clone:function(){return new x(this.x,this.y)},add:function(t){return this.clone()._add(w(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(w(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},scaleBy:function(t){return new x(this.x*t.x,this.y*t.y)},unscaleBy:function(t){return new x(this.x/t.x,this.y/t.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},trunc:function(){return this.clone()._trunc()},_trunc:function(){return this.x=li(this.x),this.y=li(this.y),this},distanceTo:function(t){var i=(t=w(t)).x-this.x,e=t.y-this.y;return Math.sqrt(i*i+e*e)},equals:function(t){return(t=w(t)).x===this.x&&t.y===this.y},contains:function(t){return t=w(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return\"Point(\"+a(this.x)+\", \"+a(this.y)+\")\"}},P.prototype={extend:function(t){return t=w(t),this.min||this.max?(this.min.x=Math.min(t.x,this.min.x),this.max.x=Math.max(t.x,this.max.x),this.min.y=Math.min(t.y,this.min.y),this.max.y=Math.max(t.y,this.max.y)):(this.min=t.clone(),this.max=t.clone()),this},getCenter:function(t){return new x((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t)},getBottomLeft:function(){return new x(this.min.x,this.max.y)},getTopRight:function(){return new x(this.max.x,this.min.y)},getTopLeft:function(){return this.min},getBottomRight:function(){return this.max},getSize:function(){return this.max.subtract(this.min)},contains:function(t){var i,e;return(t=\"number\"==typeof t[0]||t instanceof x?w(t):b(t))instanceof P?(i=t.min,e=t.max):i=e=t,i.x>=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=b(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=b(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.x<e.x,r=o.y>i.y&&n.y<e.y;return s&&r},isValid:function(){return!(!this.min||!this.max)}},T.prototype={extend:function(t){var i,e,n=this._southWest,o=this._northEast;if(t instanceof M)i=t,e=t;else{if(!(t instanceof T))return t?this.extend(C(t)||z(t)):this;if(i=t._southWest,e=t._northEast,!i||!e)return this}return n||o?(n.lat=Math.min(i.lat,n.lat),n.lng=Math.min(i.lng,n.lng),o.lat=Math.max(e.lat,o.lat),o.lng=Math.max(e.lng,o.lng)):(this._southWest=new M(i.lat,i.lng),this._northEast=new M(e.lat,e.lng)),this},pad:function(t){var i=this._southWest,e=this._northEast,n=Math.abs(i.lat-e.lat)*t,o=Math.abs(i.lng-e.lng)*t;return new T(new M(i.lat-n,i.lng-o),new M(e.lat+n,e.lng+o))},getCenter:function(){return new M((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new M(this.getNorth(),this.getWest())},getSouthEast:function(){return new M(this.getSouth(),this.getEast())},getWest:function(){return this._southWest.lng},getSouth:function(){return this._southWest.lat},getEast:function(){return this._northEast.lng},getNorth:function(){return this._northEast.lat},contains:function(t){t=\"number\"==typeof t[0]||t instanceof M||\"lat\"in t?C(t):z(t);var i,e,n=this._southWest,o=this._northEast;return t instanceof T?(i=t.getSouthWest(),e=t.getNorthEast()):i=e=t,i.lat>=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=z(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=z(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lat<e.lat,r=o.lng>i.lng&&n.lng<e.lng;return s&&r},toBBoxString:function(){return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(\",\")},equals:function(t,i){return!!t&&(t=z(t),this._southWest.equals(t.getSouthWest(),i)&&this._northEast.equals(t.getNorthEast(),i))},isValid:function(){return!(!this._southWest||!this._northEast)}},M.prototype={equals:function(t,i){return!!t&&(t=C(t),Math.max(Math.abs(this.lat-t.lat),Math.abs(this.lng-t.lng))<=(void 0===i?1e-9:i))},toString:function(t){return\"LatLng(\"+a(this.lat,t)+\", \"+a(this.lng,t)+\")\"},distanceTo:function(t){return _i.distance(this,C(t))},wrap:function(){return _i.wrapLatLng(this)},toBounds:function(t){var i=180*t/40075017,e=i/Math.cos(Math.PI/180*this.lat);return z([this.lat-i,this.lng-e],[this.lat+i,this.lng+e])},clone:function(){return new M(this.lat,this.lng,this.alt)}};var ci={latLngToPoint:function(t,i){var e=this.projection.project(t),n=this.scale(i);return this.transformation._transform(e,n)},pointToLatLng:function(t,i){var e=this.scale(i),n=this.transformation.untransform(t,e);return this.projection.unproject(n)},project:function(t){return this.projection.project(t)},unproject:function(t){return this.projection.unproject(t)},scale:function(t){return 256*Math.pow(2,t)},zoom:function(t){return Math.log(t/256)/Math.LN2},getProjectedBounds:function(t){if(this.infinite)return null;var i=this.projection.bounds,e=this.scale(t);return new P(this.transformation.transform(i.min,e),this.transformation.transform(i.max,e))},infinite:!1,wrapLatLng:function(t){var i=this.wrapLng?s(t.lng,this.wrapLng,!0):t.lng;return new M(this.wrapLat?s(t.lat,this.wrapLat,!0):t.lat,i,t.alt)},wrapLatLngBounds:function(t){var i=t.getCenter(),e=this.wrapLatLng(i),n=i.lat-e.lat,o=i.lng-e.lng;if(0===n&&0===o)return t;var s=t.getSouthWest(),r=t.getNorthEast();return new T(new M(s.lat-n,s.lng-o),new M(r.lat-n,r.lng-o))}},_i=i({},ci,{wrapLng:[-180,180],R:6371e3,distance:function(t,i){var e=Math.PI/180,n=t.lat*e,o=i.lat*e,s=Math.sin((i.lat-t.lat)*e/2),r=Math.sin((i.lng-t.lng)*e/2),a=s*s+Math.cos(n)*Math.cos(o)*r*r,h=2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));return this.R*h}}),di={R:6378137,MAX_LATITUDE:85.0511287798,project:function(t){var i=Math.PI/180,e=this.MAX_LATITUDE,n=Math.max(Math.min(e,t.lat),-e),o=Math.sin(n*i);return new x(this.R*t.lng*i,this.R*Math.log((1+o)/(1-o))/2)},unproject:function(t){var i=180/Math.PI;return new M((2*Math.atan(Math.exp(t.y/this.R))-Math.PI/2)*i,t.x*i/this.R)},bounds:function(){var t=6378137*Math.PI;return new P([-t,-t],[t,t])}()};Z.prototype={transform:function(t,i){return this._transform(t.clone(),i)},_transform:function(t,i){return i=i||1,t.x=i*(this._a*t.x+this._b),t.y=i*(this._c*t.y+this._d),t},untransform:function(t,i){return i=i||1,new x((t.x/i-this._b)/this._a,(t.y/i-this._d)/this._c)}};var pi,mi,fi,gi,vi=i({},_i,{code:\"EPSG:3857\",projection:di,transformation:function(){var t=.5/(Math.PI*di.R);return S(t,.5,-t,.5)}()}),yi=i({},vi,{code:\"EPSG:900913\"}),xi=document.documentElement.style,wi=\"ActiveXObject\"in window,Li=wi&&!document.addEventListener,Pi=\"msLaunchUri\"in navigator&&!(\"documentMode\"in document),bi=A(\"webkit\"),Ti=A(\"android\"),zi=A(\"android 2\")||A(\"android 3\"),Mi=parseInt(/WebKit\\/([0-9]+)|$/.exec(navigator.userAgent)[1],10),Ci=Ti&&A(\"Google\")&&Mi<537&&!(\"AudioNode\"in window),Zi=!!window.opera,Si=A(\"chrome\"),Ei=A(\"gecko\")&&!bi&&!Zi&&!wi,ki=!Si&&A(\"safari\"),Ai=A(\"phantom\"),Ii=\"OTransition\"in xi,Bi=0===navigator.platform.indexOf(\"Win\"),Oi=wi&&\"transition\"in xi,Ri=\"WebKitCSSMatrix\"in window&&\"m11\"in new window.WebKitCSSMatrix&&!zi,Di=\"MozPerspective\"in xi,Ni=!window.L_DISABLE_3D&&(Oi||Ri||Di)&&!Ii&&!Ai,ji=\"undefined\"!=typeof orientation||A(\"mobile\"),Wi=ji&&bi,Hi=ji&&Ri,Fi=!window.PointerEvent&&window.MSPointerEvent,Ui=!(!window.PointerEvent&&!Fi),Vi=!window.L_NO_TOUCH&&(Ui||\"ontouchstart\"in window||window.DocumentTouch&&document instanceof window.DocumentTouch),qi=ji&&Zi,Gi=ji&&Ei,Ki=(window.devicePixelRatio||window.screen.deviceXDPI/window.screen.logicalXDPI)>1,Yi=!!document.createElement(\"canvas\").getContext,Xi=!(!document.createElementNS||!E(\"svg\").createSVGRect),Ji=!Xi&&function(){try{var t=document.createElement(\"div\");t.innerHTML='<v:shape adj=\"1\"/>';var i=t.firstChild;return i.style.behavior=\"url(#default#VML)\",i&&\"object\"==typeof i.adj}catch(t){return!1}}(),$i=(Object.freeze||Object)({ie:wi,ielt9:Li,edge:Pi,webkit:bi,android:Ti,android23:zi,androidStock:Ci,opera:Zi,chrome:Si,gecko:Ei,safari:ki,phantom:Ai,opera12:Ii,win:Bi,ie3d:Oi,webkit3d:Ri,gecko3d:Di,any3d:Ni,mobile:ji,mobileWebkit:Wi,mobileWebkit3d:Hi,msPointer:Fi,pointer:Ui,touch:Vi,mobileOpera:qi,mobileGecko:Gi,retina:Ki,canvas:Yi,svg:Xi,vml:Ji}),Qi=Fi?\"MSPointerDown\":\"pointerdown\",te=Fi?\"MSPointerMove\":\"pointermove\",ie=Fi?\"MSPointerUp\":\"pointerup\",ee=Fi?\"MSPointerCancel\":\"pointercancel\",ne=[\"INPUT\",\"SELECT\",\"OPTION\"],oe={},se=!1,re=0,ae=Fi?\"MSPointerDown\":Ui?\"pointerdown\":\"touchstart\",he=Fi?\"MSPointerUp\":Ui?\"pointerup\":\"touchend\",ue=\"_leaflet_\",le=\"_leaflet_events\",ce=Bi&&Si?2*window.devicePixelRatio:Ei?window.devicePixelRatio:1,_e={},de=(Object.freeze||Object)({on:V,off:q,stopPropagation:Y,disableScrollPropagation:X,disableClickPropagation:J,preventDefault:$,stop:Q,getMousePosition:tt,getWheelDelta:it,fakeStop:et,skipped:nt,isExternalTarget:ot,addListener:V,removeListener:q}),pe=xt([\"transform\",\"WebkitTransform\",\"OTransform\",\"MozTransform\",\"msTransform\"]),me=xt([\"webkitTransition\",\"transition\",\"OTransition\",\"MozTransition\",\"msTransition\"]),fe=\"webkitTransition\"===me||\"OTransition\"===me?me+\"End\":\"transitionend\";if(\"onselectstart\"in document)mi=function(){V(window,\"selectstart\",$)},fi=function(){q(window,\"selectstart\",$)};else{var ge=xt([\"userSelect\",\"WebkitUserSelect\",\"OUserSelect\",\"MozUserSelect\",\"msUserSelect\"]);mi=function(){if(ge){var t=document.documentElement.style;gi=t[ge],t[ge]=\"none\"}},fi=function(){ge&&(document.documentElement.style[ge]=gi,gi=void 0)}}var ve,ye,xe=(Object.freeze||Object)({TRANSFORM:pe,TRANSITION:me,TRANSITION_END:fe,get:rt,getStyle:at,create:ht,remove:ut,empty:lt,toFront:ct,toBack:_t,hasClass:dt,addClass:pt,removeClass:mt,setClass:ft,getClass:gt,setOpacity:vt,testProp:xt,setTransform:wt,setPosition:Lt,getPosition:Pt,disableTextSelection:mi,enableTextSelection:fi,disableImageDrag:bt,enableImageDrag:Tt,preventOutline:zt,restoreOutline:Mt}),we=ui.extend({run:function(t,i,e,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=e||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=Pt(t),this._offset=i.subtract(this._startPos),this._startTime=+new Date,this.fire(\"start\"),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=f(this._animate,this),this._step()},_step:function(t){var i=+new Date-this._startTime,e=1e3*this._duration;i<e?this._runFrame(this._easeOut(i/e),t):(this._runFrame(1),this._complete())},_runFrame:function(t,i){var e=this._startPos.add(this._offset.multiplyBy(t));i&&e._round(),Lt(this._el,e),this.fire(\"step\")},_complete:function(){g(this._animId),this._inProgress=!1,this.fire(\"end\")},_easeOut:function(t){return 1-Math.pow(1-t,this._easeOutPower)}}),Le=ui.extend({options:{crs:vi,center:void 0,zoom:void 0,minZoom:void 0,maxZoom:void 0,layers:[],maxBounds:void 0,renderer:void 0,zoomAnimation:!0,zoomAnimationThreshold:4,fadeAnimation:!0,markerZoomAnimation:!0,transform3DLimit:8388608,zoomSnap:1,zoomDelta:1,trackResize:!0},initialize:function(t,i){i=l(this,i),this._initContainer(t),this._initLayout(),this._onResize=e(this._onResize,this),this._initEvents(),i.maxBounds&&this.setMaxBounds(i.maxBounds),void 0!==i.zoom&&(this._zoom=this._limitZoom(i.zoom)),i.center&&void 0!==i.zoom&&this.setView(C(i.center),i.zoom,{reset:!0}),this._handlers=[],this._layers={},this._zoomBoundLayers={},this._sizeChanged=!0,this.callInitHooks(),this._zoomAnimated=me&&Ni&&!qi&&this.options.zoomAnimation,this._zoomAnimated&&(this._createAnimProxy(),V(this._proxy,fe,this._catchTransitionEnd,this)),this._addLayers(this.options.layers)},setView:function(t,e,n){return e=void 0===e?this._zoom:this._limitZoom(e),t=this._limitCenter(C(t),e,this.options.maxBounds),n=n||{},this._stop(),this._loaded&&!n.reset&&!0!==n&&(void 0!==n.animate&&(n.zoom=i({animate:n.animate},n.zoom),n.pan=i({animate:n.animate,duration:n.duration},n.pan)),this._zoom!==e?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,e,n.zoom):this._tryAnimatedPan(t,n.pan))?(clearTimeout(this._sizeTimer),this):(this._resetView(t,e),this)},setZoom:function(t,i){return this._loaded?this.setView(this.getCenter(),t,{zoom:i}):(this._zoom=t,this)},zoomIn:function(t,i){return t=t||(Ni?this.options.zoomDelta:1),this.setZoom(this._zoom+t,i)},zoomOut:function(t,i){return t=t||(Ni?this.options.zoomDelta:1),this.setZoom(this._zoom-t,i)},setZoomAround:function(t,i,e){var n=this.getZoomScale(i),o=this.getSize().divideBy(2),s=(t instanceof x?t:this.latLngToContainerPoint(t)).subtract(o).multiplyBy(1-1/n),r=this.containerPointToLatLng(o.add(s));return this.setView(r,i,{zoom:e})},_getBoundsCenterZoom:function(t,i){i=i||{},t=t.getBounds?t.getBounds():z(t);var e=w(i.paddingTopLeft||i.padding||[0,0]),n=w(i.paddingBottomRight||i.padding||[0,0]),o=this.getBoundsZoom(t,!1,e.add(n));if((o=\"number\"==typeof i.maxZoom?Math.min(i.maxZoom,o):o)===1/0)return{center:t.getCenter(),zoom:o};var s=n.subtract(e).divideBy(2),r=this.project(t.getSouthWest(),o),a=this.project(t.getNorthEast(),o);return{center:this.unproject(r.add(a).divideBy(2).add(s),o),zoom:o}},fitBounds:function(t,i){if(!(t=z(t)).isValid())throw new Error(\"Bounds are not valid.\");var e=this._getBoundsCenterZoom(t,i);return this.setView(e.center,e.zoom,i)},fitWorld:function(t){return this.fitBounds([[-90,-180],[90,180]],t)},panTo:function(t,i){return this.setView(t,this._zoom,{pan:i})},panBy:function(t,i){if(t=w(t).round(),i=i||{},!t.x&&!t.y)return this.fire(\"moveend\");if(!0!==i.animate&&!this.getSize().contains(t))return this._resetView(this.unproject(this.project(this.getCenter()).add(t)),this.getZoom()),this;if(this._panAnim||(this._panAnim=new we,this._panAnim.on({step:this._onPanTransitionStep,end:this._onPanTransitionEnd},this)),i.noMoveStart||this.fire(\"movestart\"),!1!==i.animate){pt(this._mapPane,\"leaflet-pan-anim\");var e=this._getMapPanePos().subtract(t).round();this._panAnim.run(this._mapPane,e,i.duration||.25,i.easeLinearity)}else this._rawPanBy(t),this.fire(\"move\").fire(\"moveend\");return this},flyTo:function(t,i,e){function n(t){var i=(g*g-m*m+(t?-1:1)*x*x*v*v)/(2*(t?g:m)*x*v),e=Math.sqrt(i*i+1)-i;return e<1e-9?-18:Math.log(e)}function o(t){return(Math.exp(t)-Math.exp(-t))/2}function s(t){return(Math.exp(t)+Math.exp(-t))/2}function r(t){return o(t)/s(t)}function a(t){return m*(s(w)/s(w+y*t))}function h(t){return m*(s(w)*r(w+y*t)-o(w))/x}function u(t){return 1-Math.pow(1-t,1.5)}function l(){var e=(Date.now()-L)/b,n=u(e)*P;e<=1?(this._flyToFrame=f(l,this),this._move(this.unproject(c.add(_.subtract(c).multiplyBy(h(n)/v)),p),this.getScaleZoom(m/a(n),p),{flyTo:!0})):this._move(t,i)._moveEnd(!0)}if(!1===(e=e||{}).animate||!Ni)return this.setView(t,i,e);this._stop();var c=this.project(this.getCenter()),_=this.project(t),d=this.getSize(),p=this._zoom;t=C(t),i=void 0===i?p:i;var m=Math.max(d.x,d.y),g=m*this.getZoomScale(p,i),v=_.distanceTo(c)||1,y=1.42,x=y*y,w=n(0),L=Date.now(),P=(n(1)-w)/y,b=e.duration?1e3*e.duration:1e3*P*.8;return this._moveStart(!0,e.noMoveStart),l.call(this),this},flyToBounds:function(t,i){var e=this._getBoundsCenterZoom(t,i);return this.flyTo(e.center,e.zoom,i)},setMaxBounds:function(t){return(t=z(t)).isValid()?(this.options.maxBounds&&this.off(\"moveend\",this._panInsideMaxBounds),this.options.maxBounds=t,this._loaded&&this._panInsideMaxBounds(),this.on(\"moveend\",this._panInsideMaxBounds)):(this.options.maxBounds=null,this.off(\"moveend\",this._panInsideMaxBounds))},setMinZoom:function(t){var i=this.options.minZoom;return this.options.minZoom=t,this._loaded&&i!==t&&(this.fire(\"zoomlevelschange\"),this.getZoom()<this.options.minZoom)?this.setZoom(t):this},setMaxZoom:function(t){var i=this.options.maxZoom;return this.options.maxZoom=t,this._loaded&&i!==t&&(this.fire(\"zoomlevelschange\"),this.getZoom()>this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,z(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},invalidateSize:function(t){if(!this._loaded)return this;t=i({animate:!1,pan:!0},!0===t?{animate:!0}:t);var n=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var o=this.getSize(),s=n.divideBy(2).round(),r=o.divideBy(2).round(),a=s.subtract(r);return a.x||a.y?(t.animate&&t.pan?this.panBy(a):(t.pan&&this._rawPanBy(a),this.fire(\"move\"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(e(this.fire,this,\"moveend\"),200)):this.fire(\"moveend\")),this.fire(\"resize\",{oldSize:n,newSize:o})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire(\"viewreset\"),this._stop()},locate:function(t){if(t=this._locateOptions=i({timeout:1e4,watch:!1},t),!(\"geolocation\"in navigator))return this._handleGeolocationError({code:0,message:\"Geolocation not supported.\"}),this;var n=e(this._handleGeolocationResponse,this),o=e(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(n,o,t):navigator.geolocation.getCurrentPosition(n,o,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var i=t.code,e=t.message||(1===i?\"permission denied\":2===i?\"position unavailable\":\"timeout\");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire(\"locationerror\",{code:i,message:\"Geolocation error: \"+e+\".\"})},_handleGeolocationResponse:function(t){var i=new M(t.coords.latitude,t.coords.longitude),e=i.toBounds(t.coords.accuracy),n=this._locateOptions;if(n.setView){var o=this.getBoundsZoom(e);this.setView(i,n.maxZoom?Math.min(o,n.maxZoom):o)}var s={latlng:i,bounds:e,timestamp:t.timestamp};for(var r in t.coords)\"number\"==typeof t.coords[r]&&(s[r]=t.coords[r]);this.fire(\"locationfound\",s)},addHandler:function(t,i){if(!i)return this;var e=this[t]=new i(this);return this._handlers.push(e),this.options[t]&&e.enable(),this},remove:function(){if(this._initEvents(!0),this._containerId!==this._container._leaflet_id)throw new Error(\"Map container is being reused by another instance\");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),ut(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._clearHandlers(),this._loaded&&this.fire(\"unload\");var t;for(t in this._layers)this._layers[t].remove();for(t in this._panes)ut(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,i){var e=ht(\"div\",\"leaflet-pane\"+(t?\" leaflet-\"+t.replace(\"Pane\",\"\")+\"-pane\":\"\"),i||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new T(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,i,e){t=z(t),e=w(e||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),a=t.getSouthEast(),h=this.getSize().subtract(e),u=b(this.project(a,n),this.project(r,n)).getSize(),l=Ni?this.options.zoomSnap:1,c=h.x/u.x,_=h.y/u.y,d=i?Math.max(c,_):Math.min(c,_);return n=this.getScaleZoom(d,n),l&&(n=Math.round(n/(l/100))*(l/100),n=i?Math.ceil(n/l)*l:Math.floor(n/l)*l),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new x(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,i){var e=this._getTopLeftPoint(t,i);return new P(e,e.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return\"string\"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,i){var e=this.options.crs;return i=void 0===i?this._zoom:i,e.scale(t)/e.scale(i)},getScaleZoom:function(t,i){var e=this.options.crs;i=void 0===i?this._zoom:i;var n=e.zoom(t*e.scale(i));return isNaN(n)?1/0:n},project:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.latLngToPoint(C(t),i)},unproject:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.pointToLatLng(w(t),i)},layerPointToLatLng:function(t){var i=w(t).add(this.getPixelOrigin());return this.unproject(i)},latLngToLayerPoint:function(t){return this.project(C(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(C(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(z(t))},distance:function(t,i){return this.options.crs.distance(C(t),C(i))},containerPointToLayerPoint:function(t){return w(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return w(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var i=this.containerPointToLayerPoint(w(t));return this.layerPointToLatLng(i)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(C(t)))},mouseEventToContainerPoint:function(t){return tt(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var i=this._container=rt(t);if(!i)throw new Error(\"Map container not found.\");if(i._leaflet_id)throw new Error(\"Map container is already initialized.\");V(i,\"scroll\",this._onScroll,this),this._containerId=n(i)},_initLayout:function(){var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&Ni,pt(t,\"leaflet-container\"+(Vi?\" leaflet-touch\":\"\")+(Ki?\" leaflet-retina\":\"\")+(Li?\" leaflet-oldie\":\"\")+(ki?\" leaflet-safari\":\"\")+(this._fadeAnimated?\" leaflet-fade-anim\":\"\"));var i=at(t,\"position\");\"absolute\"!==i&&\"relative\"!==i&&\"fixed\"!==i&&(t.style.position=\"relative\"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane(\"mapPane\",this._container),Lt(this._mapPane,new x(0,0)),this.createPane(\"tilePane\"),this.createPane(\"shadowPane\"),this.createPane(\"overlayPane\"),this.createPane(\"markerPane\"),this.createPane(\"tooltipPane\"),this.createPane(\"popupPane\"),this.options.markerZoomAnimation||(pt(t.markerPane,\"leaflet-zoom-hide\"),pt(t.shadowPane,\"leaflet-zoom-hide\"))},_resetView:function(t,i){Lt(this._mapPane,new x(0,0));var e=!this._loaded;this._loaded=!0,i=this._limitZoom(i),this.fire(\"viewprereset\");var n=this._zoom!==i;this._moveStart(n,!1)._move(t,i)._moveEnd(n),this.fire(\"viewreset\"),e&&this.fire(\"load\")},_moveStart:function(t,i){return t&&this.fire(\"zoomstart\"),i||this.fire(\"movestart\"),this},_move:function(t,i,e){void 0===i&&(i=this._zoom);var n=this._zoom!==i;return this._zoom=i,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(n||e&&e.pinch)&&this.fire(\"zoom\",e),this.fire(\"move\",e)},_moveEnd:function(t){return t&&this.fire(\"zoomend\"),this.fire(\"moveend\")},_stop:function(){return g(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Lt(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error(\"Set map center and zoom first.\")},_initEvents:function(t){this._targets={},this._targets[n(this._container)]=this;var i=t?q:V;i(this._container,\"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress\",this._handleDOMEvent,this),this.options.trackResize&&i(window,\"resize\",this._onResize,this),Ni&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,\"moveend\",this._onMoveEnd)},_onResize:function(){g(this._resizeRequest),this._resizeRequest=f(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,o=[],s=\"mouseout\"===i||\"mouseover\"===i,r=t.target||t.srcElement,a=!1;r;){if((e=this._targets[n(r)])&&(\"click\"===i||\"preclick\"===i)&&!t._simulated&&this._draggableMoved(e)){a=!0;break}if(e&&e.listens(i,!0)){if(s&&!ot(r,t))break;if(o.push(e),s)break}if(r===this._container)break;r=r.parentNode}return o.length||a||s||!ot(r,t)||(o=[this]),o},_handleDOMEvent:function(t){if(this._loaded&&!nt(t)){var i=t.type;\"mousedown\"!==i&&\"keypress\"!==i||zt(t.target||t.srcElement),this._fireDOMEvent(t,i)}},_mouseEvents:[\"click\",\"dblclick\",\"mouseover\",\"mouseout\",\"contextmenu\"],_fireDOMEvent:function(t,e,n){if(\"click\"===t.type){var o=i({},t);o.type=\"preclick\",this._fireDOMEvent(o,o.type,n)}if(!t._stopped&&(n=(n||[]).concat(this._findEventTargets(t,e))).length){var s=n[0];\"contextmenu\"===e&&s.listens(e,!0)&&$(t);var r={originalEvent:t};if(\"keypress\"!==t.type){var a=s.getLatLng&&(!s._radius||s._radius<=10);r.containerPoint=a?this.latLngToContainerPoint(s.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=a?s.getLatLng():this.layerPointToLatLng(r.layerPoint)}for(var h=0;h<n.length;h++)if(n[h].fire(e,r,!0),r.originalEvent._stopped||!1===n[h].options.bubblingMouseEvents&&-1!==d(this._mouseEvents,e))return}},_draggableMoved:function(t){return(t=t.dragging&&t.dragging.enabled()?t:this).dragging&&t.dragging.moved()||this.boxZoom&&this.boxZoom.moved()},_clearHandlers:function(){for(var t=0,i=this._handlers.length;t<i;t++)this._handlers[t].disable()},whenReady:function(t,i){return this._loaded?t.call(i||this,{target:this}):this.on(\"load\",t,i),this},_getMapPanePos:function(){return Pt(this._mapPane)||new x(0,0)},_moved:function(){var t=this._getMapPanePos();return t&&!t.equals([0,0])},_getTopLeftPoint:function(t,i){return(t&&void 0!==i?this._getNewPixelOrigin(t,i):this.getPixelOrigin()).subtract(this._getMapPanePos())},_getNewPixelOrigin:function(t,i){var e=this.getSize()._divideBy(2);return this.project(t,i)._subtract(e)._add(this._getMapPanePos())._round()},_latLngToNewLayerPoint:function(t,i,e){var n=this._getNewPixelOrigin(e,i);return this.project(t,i)._subtract(n)},_latLngBoundsToNewLayerBounds:function(t,i,e){var n=this._getNewPixelOrigin(e,i);return b([this.project(t.getSouthWest(),i)._subtract(n),this.project(t.getNorthWest(),i)._subtract(n),this.project(t.getSouthEast(),i)._subtract(n),this.project(t.getNorthEast(),i)._subtract(n)])},_getCenterLayerPoint:function(){return this.containerPointToLayerPoint(this.getSize()._divideBy(2))},_getCenterOffset:function(t){return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint())},_limitCenter:function(t,i,e){if(!e)return t;var n=this.project(t,i),o=this.getSize().divideBy(2),s=new P(n.subtract(o),n.add(o)),r=this._getBoundsOffset(s,e,i);return r.round().equals([0,0])?t:this.unproject(n.add(r),i)},_limitOffset:function(t,i){if(!i)return t;var e=this.getPixelBounds(),n=new P(e.min.add(t),e.max.add(t));return t.add(this._getBoundsOffset(n,i))},_getBoundsOffset:function(t,i,e){var n=b(this.project(i.getNorthEast(),e),this.project(i.getSouthWest(),e)),o=n.min.subtract(t.min),s=n.max.subtract(t.max);return new x(this._rebound(o.x,-s.x),this._rebound(o.y,-s.y))},_rebound:function(t,i){return t+i>0?Math.round(t-i)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(i))},_limitZoom:function(t){var i=this.getMinZoom(),e=this.getMaxZoom(),n=Ni?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(i,Math.min(e,t))},_onPanTransitionStep:function(){this.fire(\"move\")},_onPanTransitionEnd:function(){mt(this._mapPane,\"leaflet-pan-anim\"),this.fire(\"moveend\")},_tryAnimatedPan:function(t,i){var e=this._getCenterOffset(t)._trunc();return!(!0!==(i&&i.animate)&&!this.getSize().contains(e))&&(this.panBy(e,i),!0)},_createAnimProxy:function(){var t=this._proxy=ht(\"div\",\"leaflet-proxy leaflet-zoom-animated\");this._panes.mapPane.appendChild(t),this.on(\"zoomanim\",function(t){var i=pe,e=this._proxy.style[i];wt(this._proxy,this.project(t.center,t.zoom),this.getZoomScale(t.zoom,1)),e===this._proxy.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on(\"load moveend\",function(){var t=this.getCenter(),i=this.getZoom();wt(this._proxy,this.project(t,i),this.getZoomScale(i,1))},this),this._on(\"unload\",this._destroyAnimProxy,this)},_destroyAnimProxy:function(){ut(this._proxy),delete this._proxy},_catchTransitionEnd:function(t){this._animatingZoom&&t.propertyName.indexOf(\"transform\")>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName(\"leaflet-zoom-animated\").length},_tryAnimatedZoom:function(t,i,e){if(this._animatingZoom)return!0;if(e=e||{},!this._zoomAnimated||!1===e.animate||this._nothingToAnimate()||Math.abs(i-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(f(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,n,o){this._mapPane&&(n&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,pt(this._mapPane,\"leaflet-zoom-anim\")),this.fire(\"zoomanim\",{center:t,zoom:i,noUpdate:o}),setTimeout(e(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&mt(this._mapPane,\"leaflet-zoom-anim\"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),f(function(){this._moveEnd(!0)},this))}}),Pe=v.extend({options:{position:\"topright\"},initialize:function(t){l(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return pt(i,\"leaflet-control\"),-1!==e.indexOf(\"bottom\")?n.insertBefore(i,n.firstChild):n.appendChild(i),this},remove:function(){return this._map?(ut(this._container),this.onRemove&&this.onRemove(this._map),this._map=null,this):this},_refocusOnMap:function(t){this._map&&t&&t.screenX>0&&t.screenY>0&&this._map.getContainer().focus()}}),be=function(t){return new Pe(t)};Le.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){function t(t,o){var s=e+t+\" \"+e+o;i[t+o]=ht(\"div\",s,n)}var i=this._controlCorners={},e=\"leaflet-\",n=this._controlContainer=ht(\"div\",e+\"control-container\",this._container);t(\"top\",\"left\"),t(\"top\",\"right\"),t(\"bottom\",\"left\"),t(\"bottom\",\"right\")},_clearControlPos:function(){for(var t in this._controlCorners)ut(this._controlCorners[t]);ut(this._controlContainer),delete this._controlCorners,delete this._controlContainer}});var Te=Pe.extend({options:{collapsed:!0,position:\"topright\",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,i,e,n){return e<n?-1:n<e?1:0}},initialize:function(t,i,e){l(this,e),this._layerControlInputs=[],this._layers=[],this._lastZIndex=0,this._handlingClick=!1;for(var n in t)this._addLayer(t[n],n);for(n in i)this._addLayer(i[n],n,!0)},onAdd:function(t){this._initLayout(),this._update(),this._map=t,t.on(\"zoomend\",this._checkDisabledLayers,this);for(var i=0;i<this._layers.length;i++)this._layers[i].layer.on(\"add remove\",this._onLayerChange,this);return this._container},addTo:function(t){return Pe.prototype.addTo.call(this,t),this._expandIfNotCollapsed()},onRemove:function(){this._map.off(\"zoomend\",this._checkDisabledLayers,this);for(var t=0;t<this._layers.length;t++)this._layers[t].layer.off(\"add remove\",this._onLayerChange,this)},addBaseLayer:function(t,i){return this._addLayer(t,i),this._map?this._update():this},addOverlay:function(t,i){return this._addLayer(t,i,!0),this._map?this._update():this},removeLayer:function(t){t.off(\"add remove\",this._onLayerChange,this);var i=this._getLayer(n(t));return i&&this._layers.splice(this._layers.indexOf(i),1),this._map?this._update():this},expand:function(){pt(this._container,\"leaflet-control-layers-expanded\"),this._form.style.height=null;var t=this._map.getSize().y-(this._container.offsetTop+50);return t<this._form.clientHeight?(pt(this._form,\"leaflet-control-layers-scrollbar\"),this._form.style.height=t+\"px\"):mt(this._form,\"leaflet-control-layers-scrollbar\"),this._checkDisabledLayers(),this},collapse:function(){return mt(this._container,\"leaflet-control-layers-expanded\"),this},_initLayout:function(){var t=\"leaflet-control-layers\",i=this._container=ht(\"div\",t),e=this.options.collapsed;i.setAttribute(\"aria-haspopup\",!0),J(i),X(i);var n=this._form=ht(\"form\",t+\"-list\");e&&(this._map.on(\"click\",this.collapse,this),Ti||V(i,{mouseenter:this.expand,mouseleave:this.collapse},this));var o=this._layersLink=ht(\"a\",t+\"-toggle\",i);o.href=\"#\",o.title=\"Layers\",Vi?(V(o,\"click\",Q),V(o,\"click\",this.expand,this)):V(o,\"focus\",this.expand,this),e||this.expand(),this._baseLayersList=ht(\"div\",t+\"-base\",n),this._separator=ht(\"div\",t+\"-separator\",n),this._overlaysList=ht(\"div\",t+\"-overlays\",n),i.appendChild(n)},_getLayer:function(t){for(var i=0;i<this._layers.length;i++)if(this._layers[i]&&n(this._layers[i].layer)===t)return this._layers[i]},_addLayer:function(t,i,n){this._map&&t.on(\"add remove\",this._onLayerChange,this),this._layers.push({layer:t,name:i,overlay:n}),this.options.sortLayers&&this._layers.sort(e(function(t,i){return this.options.sortFunction(t.layer,i.layer,t.name,i.name)},this)),this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex)),this._expandIfNotCollapsed()},_update:function(){if(!this._container)return this;lt(this._baseLayersList),lt(this._overlaysList),this._layerControlInputs=[];var t,i,e,n,o=0;for(e=0;e<this._layers.length;e++)n=this._layers[e],this._addItem(n),i=i||n.overlay,t=t||!n.overlay,o+=n.overlay?0:1;return this.options.hideSingleBase&&(t=t&&o>1,this._baseLayersList.style.display=t?\"\":\"none\"),this._separator.style.display=i&&t?\"\":\"none\",this},_onLayerChange:function(t){this._handlingClick||this._update();var i=this._getLayer(n(t.target)),e=i.overlay?\"add\"===t.type?\"overlayadd\":\"overlayremove\":\"add\"===t.type?\"baselayerchange\":null;e&&this._map.fire(e,i)},_createRadioElement:function(t,i){var e='<input type=\"radio\" class=\"leaflet-control-layers-selector\" name=\"'+t+'\"'+(i?' checked=\"checked\"':\"\")+\"/>\",n=document.createElement(\"div\");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement(\"label\"),o=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement(\"input\")).type=\"checkbox\",i.className=\"leaflet-control-layers-selector\",i.defaultChecked=o):i=this._createRadioElement(\"leaflet-base-layers\",o),this._layerControlInputs.push(i),i.layerId=n(t.layer),V(i,\"click\",this._onInputClick,this);var s=document.createElement(\"span\");s.innerHTML=\" \"+t.name;var r=document.createElement(\"div\");return e.appendChild(r),r.appendChild(i),r.appendChild(s),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;s>=0;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;s<o.length;s++)this._map.hasLayer(o[s])&&this._map.removeLayer(o[s]);for(s=0;s<n.length;s++)this._map.hasLayer(n[s])||this._map.addLayer(n[s]);this._handlingClick=!1,this._refocusOnMap()},_checkDisabledLayers:function(){for(var t,i,e=this._layerControlInputs,n=this._map.getZoom(),o=e.length-1;o>=0;o--)t=e[o],i=this._getLayer(t.layerId).layer,t.disabled=void 0!==i.options.minZoom&&n<i.options.minZoom||void 0!==i.options.maxZoom&&n>i.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),ze=Pe.extend({options:{position:\"topleft\",zoomInText:\"+\",zoomInTitle:\"Zoom in\",zoomOutText:\"&#x2212;\",zoomOutTitle:\"Zoom out\"},onAdd:function(t){var i=\"leaflet-control-zoom\",e=ht(\"div\",i+\" leaflet-bar\"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+\"-in\",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+\"-out\",e,this._zoomOut),this._updateDisabled(),t.on(\"zoomend zoomlevelschange\",this._updateDisabled,this),e},onRemove:function(t){t.off(\"zoomend zoomlevelschange\",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoom<this._map.getMaxZoom()&&this._map.zoomIn(this._map.options.zoomDelta*(t.shiftKey?3:1))},_zoomOut:function(t){!this._disabled&&this._map._zoom>this._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=ht(\"a\",e,n);return s.innerHTML=t,s.href=\"#\",s.title=i,s.setAttribute(\"role\",\"button\"),s.setAttribute(\"aria-label\",i),J(s),V(s,\"click\",Q),V(s,\"click\",o,this),V(s,\"click\",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i=\"leaflet-disabled\";mt(this._zoomInButton,i),mt(this._zoomOutButton,i),(this._disabled||t._zoom===t.getMinZoom())&&pt(this._zoomOutButton,i),(this._disabled||t._zoom===t.getMaxZoom())&&pt(this._zoomInButton,i)}});Le.mergeOptions({zoomControl:!0}),Le.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new ze,this.addControl(this.zoomControl))});var Me=Pe.extend({options:{position:\"bottomleft\",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i=ht(\"div\",\"leaflet-control-scale\"),e=this.options;return this._addScales(e,\"leaflet-control-scale-line\",i),t.on(e.updateWhenIdle?\"moveend\":\"move\",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?\"moveend\":\"move\",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=ht(\"div\",i,e)),t.imperial&&(this._iScale=ht(\"div\",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+\" m\":i/1e3+\" km\";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;o>5280?(i=o/5280,e=this._getRoundNum(i),this._updateScale(this._iScale,e+\" mi\",e/i)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+\" ft\",n/o))},_updateScale:function(t,i,e){t.style.width=Math.round(this.options.maxWidth*e)+\"px\",t.innerHTML=i},_getRoundNum:function(t){var i=Math.pow(10,(Math.floor(t)+\"\").length-1),e=t/i;return e=e>=10?10:e>=5?5:e>=3?3:e>=2?2:1,i*e}}),Ce=Pe.extend({options:{position:\"bottomright\",prefix:'<a href=\"http://leafletjs.com\" title=\"A JS library for interactive maps\">Leaflet</a>'},initialize:function(t){l(this,t),this._attributions={}},onAdd:function(t){t.attributionControl=this,this._container=ht(\"div\",\"leaflet-control-attribution\"),J(this._container);for(var i in t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):this},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(\", \")),this._container.innerHTML=e.join(\" | \")}}});Le.mergeOptions({attributionControl:!0}),Le.addInitHook(function(){this.options.attributionControl&&(new Ce).addTo(this)});Pe.Layers=Te,Pe.Zoom=ze,Pe.Scale=Me,Pe.Attribution=Ce,be.layers=function(t,i,e){return new Te(t,i,e)},be.zoom=function(t){return new ze(t)},be.scale=function(t){return new Me(t)},be.attribution=function(t){return new Ce(t)};var Ze=v.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled?this:(this._enabled=!0,this.addHooks(),this)},disable:function(){return this._enabled?(this._enabled=!1,this.removeHooks(),this):this},enabled:function(){return!!this._enabled}});Ze.addTo=function(t,i){return t.addHandler(i,this),this};var Se,Ee={Events:hi},ke=Vi?\"touchstart mousedown\":\"mousedown\",Ae={mousedown:\"mouseup\",touchstart:\"touchend\",pointerdown:\"touchend\",MSPointerDown:\"touchend\"},Ie={mousedown:\"mousemove\",touchstart:\"touchmove\",pointerdown:\"touchmove\",MSPointerDown:\"touchmove\"},Be=ui.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){l(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(V(this._dragStartTarget,ke,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Be._dragging===this&&this.finishDrag(),q(this._dragStartTarget,ke,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){if(!t._simulated&&this._enabled&&(this._moved=!1,!dt(this._element,\"leaflet-zoom-anim\")&&!(Be._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||(Be._dragging=this,this._preventOutline&&zt(this._element),bt(),mi(),this._moving)))){this.fire(\"down\");var i=t.touches?t.touches[0]:t;this._startPoint=new x(i.clientX,i.clientY),V(document,Ie[t.type],this._onMove,this),V(document,Ae[t.type],this._onUp,this)}},_onMove:function(t){if(!t._simulated&&this._enabled)if(t.touches&&t.touches.length>1)this._moved=!0;else{var i=t.touches&&1===t.touches.length?t.touches[0]:t,e=new x(i.clientX,i.clientY).subtract(this._startPoint);(e.x||e.y)&&(Math.abs(e.x)+Math.abs(e.y)<this.options.clickTolerance||($(t),this._moved||(this.fire(\"dragstart\"),this._moved=!0,this._startPos=Pt(this._element).subtract(e),pt(document.body,\"leaflet-dragging\"),this._lastTarget=t.target||t.srcElement,window.SVGElementInstance&&this._lastTarget instanceof SVGElementInstance&&(this._lastTarget=this._lastTarget.correspondingUseElement),pt(this._lastTarget,\"leaflet-drag-target\")),this._newPos=this._startPos.add(e),this._moving=!0,g(this._animRequest),this._lastEvent=t,this._animRequest=f(this._updatePosition,this,!0)))}},_updatePosition:function(){var t={originalEvent:this._lastEvent};this.fire(\"predrag\",t),Lt(this._element,this._newPos),this.fire(\"drag\",t)},_onUp:function(t){!t._simulated&&this._enabled&&this.finishDrag()},finishDrag:function(){mt(document.body,\"leaflet-dragging\"),this._lastTarget&&(mt(this._lastTarget,\"leaflet-drag-target\"),this._lastTarget=null);for(var t in Ie)q(document,Ie[t],this._onMove,this),q(document,Ae[t],this._onUp,this);Tt(),fi(),this._moved&&this._moving&&(g(this._animRequest),this.fire(\"dragend\",{distance:this._newPos.distanceTo(this._startPos)})),this._moving=!1,Be._dragging=!1}}),Oe=(Object.freeze||Object)({simplify:Ct,pointToSegmentDistance:Zt,closestPointOnSegment:function(t,i,e){return Rt(t,i,e)},clipSegment:At,_getEdgeIntersection:It,_getBitCode:Bt,_sqClosestPointOnSegment:Rt,isFlat:Dt,_flat:Nt}),Re=(Object.freeze||Object)({clipPolygon:jt}),De={project:function(t){return new x(t.lng,t.lat)},unproject:function(t){return new M(t.y,t.x)},bounds:new P([-180,-90],[180,90])},Ne={R:6378137,R_MINOR:6356752.314245179,bounds:new P([-20037508.34279,-15496570.73972],[20037508.34279,18764656.23138]),project:function(t){var i=Math.PI/180,e=this.R,n=t.lat*i,o=this.R_MINOR/e,s=Math.sqrt(1-o*o),r=s*Math.sin(n),a=Math.tan(Math.PI/4-n/2)/Math.pow((1-r)/(1+r),s/2);return n=-e*Math.log(Math.max(a,1e-10)),new x(t.lng*i*e,n)},unproject:function(t){for(var i,e=180/Math.PI,n=this.R,o=this.R_MINOR/n,s=Math.sqrt(1-o*o),r=Math.exp(-t.y/n),a=Math.PI/2-2*Math.atan(r),h=0,u=.1;h<15&&Math.abs(u)>1e-7;h++)i=s*Math.sin(a),i=Math.pow((1-i)/(1+i),s/2),a+=u=Math.PI/2-2*Math.atan(r*i)-a;return new M(a*e,t.x*e/n)}},je=(Object.freeze||Object)({LonLat:De,Mercator:Ne,SphericalMercator:di}),We=i({},_i,{code:\"EPSG:3395\",projection:Ne,transformation:function(){var t=.5/(Math.PI*Ne.R);return S(t,.5,-t,.5)}()}),He=i({},_i,{code:\"EPSG:4326\",projection:De,transformation:S(1/180,1,-1/180,.5)}),Fe=i({},ci,{projection:De,transformation:S(1,0,-1,0),scale:function(t){return Math.pow(2,t)},zoom:function(t){return Math.log(t)/Math.LN2},distance:function(t,i){var e=i.lng-t.lng,n=i.lat-t.lat;return Math.sqrt(e*e+n*n)},infinite:!0});ci.Earth=_i,ci.EPSG3395=We,ci.EPSG3857=vi,ci.EPSG900913=yi,ci.EPSG4326=He,ci.Simple=Fe;var Ue=ui.extend({options:{pane:\"overlayPane\",attribution:null,bubblingMouseEvents:!0},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[n(t)]=this,this},removeInteractiveTarget:function(t){return delete this._map._targets[n(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var i=t.target;if(i.hasLayer(this)){if(this._map=i,this._zoomAnimated=i._zoomAnimated,this.getEvents){var e=this.getEvents();i.on(e,this),this.once(\"remove\",function(){i.off(e,this)},this)}this.onAdd(i),this.getAttribution&&i.attributionControl&&i.attributionControl.addAttribution(this.getAttribution()),this.fire(\"add\"),i.fire(\"layeradd\",{layer:this})}}});Le.include({addLayer:function(t){if(!t._layerAdd)throw new Error(\"The provided object is not a Layer.\");var i=n(t);return this._layers[i]?this:(this._layers[i]=t,t._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t),this)},removeLayer:function(t){var i=n(t);return this._layers[i]?(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[i],this._loaded&&(this.fire(\"layerremove\",{layer:t}),t.fire(\"remove\")),t._map=t._mapToAdd=null,this):this},hasLayer:function(t){return!!t&&n(t)in this._layers},eachLayer:function(t,i){for(var e in this._layers)t.call(i,this._layers[e]);return this},_addLayers:function(t){for(var i=0,e=(t=t?ei(t)?t:[t]:[]).length;i<e;i++)this.addLayer(t[i])},_addZoomLimit:function(t){!isNaN(t.options.maxZoom)&&isNaN(t.options.minZoom)||(this._zoomBoundLayers[n(t)]=t,this._updateZoomLevels())},_removeZoomLimit:function(t){var i=n(t);this._zoomBoundLayers[i]&&(delete this._zoomBoundLayers[i],this._updateZoomLevels())},_updateZoomLevels:function(){var t=1/0,i=-1/0,e=this._getZoomSpan();for(var n in this._zoomBoundLayers){var o=this._zoomBoundLayers[n].options;t=void 0===o.minZoom?t:Math.min(t,o.minZoom),i=void 0===o.maxZoom?i:Math.max(i,o.maxZoom)}this._layersMaxZoom=i===-1/0?void 0:i,this._layersMinZoom=t===1/0?void 0:t,e!==this._getZoomSpan()&&this.fire(\"zoomlevelschange\"),void 0===this.options.maxZoom&&this._layersMaxZoom&&this.getZoom()>this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()<this._layersMinZoom&&this.setZoom(this._layersMinZoom)}});var Ve=Ue.extend({initialize:function(t,i){l(this,i),this._layers={};var e,n;if(t)for(e=0,n=t.length;e<n;e++)this.addLayer(t[e])},addLayer:function(t){var i=this.getLayerId(t);return this._layers[i]=t,this._map&&this._map.addLayer(t),this},removeLayer:function(t){var i=t in this._layers?t:this.getLayerId(t);return this._map&&this._layers[i]&&this._map.removeLayer(this._layers[i]),delete this._layers[i],this},hasLayer:function(t){return!!t&&(t in this._layers||this.getLayerId(t)in this._layers)},clearLayers:function(){return this.eachLayer(this.removeLayer,this)},invoke:function(t){var i,e,n=Array.prototype.slice.call(arguments,1);for(i in this._layers)(e=this._layers[i])[t]&&e[t].apply(e,n);return this},onAdd:function(t){this.eachLayer(t.addLayer,t)},onRemove:function(t){this.eachLayer(t.removeLayer,t)},eachLayer:function(t,i){for(var e in this._layers)t.call(i,this._layers[e]);return this},getLayer:function(t){return this._layers[t]},getLayers:function(){var t=[];return this.eachLayer(t.push,t),t},setZIndex:function(t){return this.invoke(\"setZIndex\",t)},getLayerId:function(t){return n(t)}}),qe=Ve.extend({addLayer:function(t){return this.hasLayer(t)?this:(t.addEventParent(this),Ve.prototype.addLayer.call(this,t),this.fire(\"layeradd\",{layer:t}))},removeLayer:function(t){return this.hasLayer(t)?(t in this._layers&&(t=this._layers[t]),t.removeEventParent(this),Ve.prototype.removeLayer.call(this,t),this.fire(\"layerremove\",{layer:t})):this},setStyle:function(t){return this.invoke(\"setStyle\",t)},bringToFront:function(){return this.invoke(\"bringToFront\")},bringToBack:function(){return this.invoke(\"bringToBack\")},getBounds:function(){var t=new T;for(var i in this._layers){var e=this._layers[i];t.extend(e.getBounds?e.getBounds():e.getLatLng())}return t}}),Ge=v.extend({options:{popupAnchor:[0,0],tooltipAnchor:[0,0]},initialize:function(t){l(this,t)},createIcon:function(t){return this._createIcon(\"icon\",t)},createShadow:function(t){return this._createIcon(\"shadow\",t)},_createIcon:function(t,i){var e=this._getIconUrl(t);if(!e){if(\"icon\"===t)throw new Error(\"iconUrl not set in Icon options (see the docs).\");return null}var n=this._createImg(e,i&&\"IMG\"===i.tagName?i:null);return this._setIconStyles(n,t),n},_setIconStyles:function(t,i){var e=this.options,n=e[i+\"Size\"];\"number\"==typeof n&&(n=[n,n]);var o=w(n),s=w(\"shadow\"===i&&e.shadowAnchor||e.iconAnchor||o&&o.divideBy(2,!0));t.className=\"leaflet-marker-\"+i+\" \"+(e.className||\"\"),s&&(t.style.marginLeft=-s.x+\"px\",t.style.marginTop=-s.y+\"px\"),o&&(t.style.width=o.x+\"px\",t.style.height=o.y+\"px\")},_createImg:function(t,i){return i=i||document.createElement(\"img\"),i.src=t,i},_getIconUrl:function(t){return Ki&&this.options[t+\"RetinaUrl\"]||this.options[t+\"Url\"]}}),Ke=Ge.extend({options:{iconUrl:\"marker-icon.png\",iconRetinaUrl:\"marker-icon-2x.png\",shadowUrl:\"marker-shadow.png\",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],tooltipAnchor:[16,-28],shadowSize:[41,41]},_getIconUrl:function(t){return Ke.imagePath||(Ke.imagePath=this._detectIconPath()),(this.options.imagePath||Ke.imagePath)+Ge.prototype._getIconUrl.call(this,t)},_detectIconPath:function(){var t=ht(\"div\",\"leaflet-default-icon-path\",document.body),i=at(t,\"background-image\")||at(t,\"backgroundImage\");return document.body.removeChild(t),i=null===i||0!==i.indexOf(\"url\")?\"\":i.replace(/^url\\([\"']?/,\"\").replace(/marker-icon\\.png[\"']?\\)$/,\"\")}}),Ye=Ze.extend({initialize:function(t){this._marker=t},addHooks:function(){var t=this._marker._icon;this._draggable||(this._draggable=new Be(t,t,!0)),this._draggable.on({dragstart:this._onDragStart,predrag:this._onPreDrag,drag:this._onDrag,dragend:this._onDragEnd},this).enable(),pt(t,\"leaflet-marker-draggable\")},removeHooks:function(){this._draggable.off({dragstart:this._onDragStart,predrag:this._onPreDrag,drag:this._onDrag,dragend:this._onDragEnd},this).disable(),this._marker._icon&&mt(this._marker._icon,\"leaflet-marker-draggable\")},moved:function(){return this._draggable&&this._draggable._moved},_adjustPan:function(t){var i=this._marker,e=i._map,n=this._marker.options.autoPanSpeed,o=this._marker.options.autoPanPadding,s=L.DomUtil.getPosition(i._icon),r=e.getPixelBounds(),a=e.getPixelOrigin(),h=b(r.min._subtract(a).add(o),r.max._subtract(a).subtract(o));if(!h.contains(s)){var u=w((Math.max(h.max.x,s.x)-h.max.x)/(r.max.x-h.max.x)-(Math.min(h.min.x,s.x)-h.min.x)/(r.min.x-h.min.x),(Math.max(h.max.y,s.y)-h.max.y)/(r.max.y-h.max.y)-(Math.min(h.min.y,s.y)-h.min.y)/(r.min.y-h.min.y)).multiplyBy(n);e.panBy(u,{animate:!1}),this._draggable._newPos._add(u),this._draggable._startPos._add(u),L.DomUtil.setPosition(i._icon,this._draggable._newPos),this._onDrag(t),this._panRequest=f(this._adjustPan.bind(this,t))}},_onDragStart:function(){this._oldLatLng=this._marker.getLatLng(),this._marker.closePopup().fire(\"movestart\").fire(\"dragstart\")},_onPreDrag:function(t){this._marker.options.autoPan&&(g(this._panRequest),this._panRequest=f(this._adjustPan.bind(this,t)))},_onDrag:function(t){var i=this._marker,e=i._shadow,n=Pt(i._icon),o=i._map.layerPointToLatLng(n);e&&Lt(e,n),i._latlng=o,t.latlng=o,t.oldLatLng=this._oldLatLng,i.fire(\"move\",t).fire(\"drag\",t)},_onDragEnd:function(t){g(this._panRequest),delete this._oldLatLng,this._marker.fire(\"moveend\").fire(\"dragend\",t)}}),Xe=Ue.extend({options:{icon:new Ke,interactive:!0,draggable:!1,autoPan:!1,autoPanPadding:[50,50],autoPanSpeed:10,keyboard:!0,title:\"\",alt:\"\",zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250,pane:\"markerPane\",bubblingMouseEvents:!1},initialize:function(t,i){l(this,i),this._latlng=C(t)},onAdd:function(t){this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._zoomAnimated&&t.on(\"zoomanim\",this._animateZoom,this),this._initIcon(),this.update()},onRemove:function(t){this.dragging&&this.dragging.enabled()&&(this.options.draggable=!0,this.dragging.removeHooks()),delete this.dragging,this._zoomAnimated&&t.off(\"zoomanim\",this._animateZoom,this),this._removeIcon(),this._removeShadow()},getEvents:function(){return{zoom:this.update,viewreset:this.update}},getLatLng:function(){return this._latlng},setLatLng:function(t){var i=this._latlng;return this._latlng=C(t),this.update(),this.fire(\"move\",{oldLatLng:i,latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update()},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup,this._popup.options),this},getElement:function(){return this._icon},update:function(){if(this._icon&&this._map){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,i=\"leaflet-zoom-\"+(this._zoomAnimated?\"animated\":\"hide\"),e=t.icon.createIcon(this._icon),n=!1;e!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(e.title=t.title),\"IMG\"===e.tagName&&(e.alt=t.alt||\"\")),pt(e,i),t.keyboard&&(e.tabIndex=\"0\"),this._icon=e,t.riseOnHover&&this.on({mouseover:this._bringToFront,mouseout:this._resetZIndex});var o=t.icon.createShadow(this._shadow),s=!1;o!==this._shadow&&(this._removeShadow(),s=!0),o&&(pt(o,i),o.alt=\"\"),this._shadow=o,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),this._initInteraction(),o&&s&&this.getPane(\"shadowPane\").appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&this.off({mouseover:this._bringToFront,mouseout:this._resetZIndex}),ut(this._icon),this.removeInteractiveTarget(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&ut(this._shadow),this._shadow=null},_setPos:function(t){Lt(this._icon,t),this._shadow&&Lt(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(i)},_initInteraction:function(){if(this.options.interactive&&(pt(this._icon,\"leaflet-interactive\"),this.addInteractiveTarget(this._icon),Ye)){var t=this.options.draggable;this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new Ye(this),t&&this.dragging.enable()}},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){var t=this.options.opacity;vt(this._icon,t),this._shadow&&vt(this._shadow,t)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)},_getPopupAnchor:function(){return this.options.icon.options.popupAnchor},_getTooltipAnchor:function(){return this.options.icon.options.tooltipAnchor}}),Je=Ue.extend({options:{stroke:!0,color:\"#3388ff\",weight:3,opacity:1,lineCap:\"round\",lineJoin:\"round\",dashArray:null,dashOffset:null,fill:!1,fillColor:null,fillOpacity:.2,fillRule:\"evenodd\",interactive:!0,bubblingMouseEvents:!0},beforeAdd:function(t){this._renderer=t.getRenderer(this)},onAdd:function(){this._renderer._initPath(this),this._reset(),this._renderer._addPath(this)},onRemove:function(){this._renderer._removePath(this)},redraw:function(){return this._map&&this._renderer._updatePath(this),this},setStyle:function(t){return l(this,t),this._renderer&&this._renderer._updateStyle(this),this},bringToFront:function(){return this._renderer&&this._renderer._bringToFront(this),this},bringToBack:function(){return this._renderer&&this._renderer._bringToBack(this),this},getElement:function(){return this._path},_reset:function(){this._project(),this._update()},_clickTolerance:function(){return(this.options.stroke?this.options.weight/2:0)+this._renderer.options.tolerance}}),$e=Je.extend({options:{fill:!0,radius:10},initialize:function(t,i){l(this,i),this._latlng=C(t),this._radius=this.options.radius},setLatLng:function(t){return this._latlng=C(t),this.redraw(),this.fire(\"move\",{latlng:this._latlng})},getLatLng:function(){return this._latlng},setRadius:function(t){return this.options.radius=this._radius=t,this.redraw()},getRadius:function(){return this._radius},setStyle:function(t){var i=t&&t.radius||this._radius;return Je.prototype.setStyle.call(this,t),this.setRadius(i),this},_project:function(){this._point=this._map.latLngToLayerPoint(this._latlng),this._updateBounds()},_updateBounds:function(){var t=this._radius,i=this._radiusY||t,e=this._clickTolerance(),n=[t+e,i+e];this._pxBounds=new P(this._point.subtract(n),this._point.add(n))},_update:function(){this._map&&this._updatePath()},_updatePath:function(){this._renderer._updateCircle(this)},_empty:function(){return this._radius&&!this._renderer._bounds.intersects(this._pxBounds)},_containsPoint:function(t){return t.distanceTo(this._point)<=this._radius+this._clickTolerance()}}),Qe=$e.extend({initialize:function(t,e,n){if(\"number\"==typeof e&&(e=i({},n,{radius:e})),l(this,e),this._latlng=C(t),isNaN(this.options.radius))throw new Error(\"Circle radius cannot be NaN\");this._mRadius=this.options.radius},setRadius:function(t){return this._mRadius=t,this.redraw()},getRadius:function(){return this._mRadius},getBounds:function(){var t=[this._radius,this._radiusY||this._radius];return new T(this._map.layerPointToLatLng(this._point.subtract(t)),this._map.layerPointToLatLng(this._point.add(t)))},setStyle:Je.prototype.setStyle,_project:function(){var t=this._latlng.lng,i=this._latlng.lat,e=this._map,n=e.options.crs;if(n.distance===_i.distance){var o=Math.PI/180,s=this._mRadius/_i.R/o,r=e.project([i+s,t]),a=e.project([i-s,t]),h=r.add(a).divideBy(2),u=e.unproject(h).lat,l=Math.acos((Math.cos(s*o)-Math.sin(i*o)*Math.sin(u*o))/(Math.cos(i*o)*Math.cos(u*o)))/o;(isNaN(l)||0===l)&&(l=s/Math.cos(Math.PI/180*i)),this._point=h.subtract(e.getPixelOrigin()),this._radius=isNaN(l)?0:h.x-e.project([u,t-l]).x,this._radiusY=h.y-r.y}else{var c=n.unproject(n.project(this._latlng).subtract([this._mRadius,0]));this._point=e.latLngToLayerPoint(this._latlng),this._radius=this._point.x-e.latLngToLayerPoint(c).x}this._updateBounds()}}),tn=Je.extend({options:{smoothFactor:1,noClip:!1},initialize:function(t,i){l(this,i),this._setLatLngs(t)},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._setLatLngs(t),this.redraw()},isEmpty:function(){return!this._latlngs.length},closestLayerPoint:function(t){for(var i,e,n=1/0,o=null,s=Rt,r=0,a=this._parts.length;r<a;r++)for(var h=this._parts[r],u=1,l=h.length;u<l;u++){var c=s(t,i=h[u-1],e=h[u],!0);c<n&&(n=c,o=s(t,i,e))}return o&&(o.distance=Math.sqrt(n)),o},getCenter:function(){if(!this._map)throw new Error(\"Must add layer to map before using getCenter()\");var t,i,e,n,o,s,r,a=this._rings[0],h=a.length;if(!h)return null;for(t=0,i=0;t<h-1;t++)i+=a[t].distanceTo(a[t+1])/2;if(0===i)return this._map.layerPointToLatLng(a[0]);for(t=0,n=0;t<h-1;t++)if(o=a[t],s=a[t+1],e=o.distanceTo(s),(n+=e)>i)return r=(n-i)/e,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,i){return i=i||this._defaultShape(),t=C(t),i.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new T,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return Dt(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var i=[],e=Dt(t),n=0,o=t.length;n<o;n++)e?(i[n]=C(t[n]),this._bounds.extend(i[n])):i[n]=this._convertLatLngs(t[n]);return i},_project:function(){var t=new P;this._rings=[],this._projectLatlngs(this._latlngs,this._rings,t);var i=this._clickTolerance(),e=new x(i,i);this._bounds.isValid()&&t.isValid()&&(t.min._subtract(e),t.max._add(e),this._pxBounds=t)},_projectLatlngs:function(t,i,e){var n,o,s=t[0]instanceof M,r=t.length;if(s){for(o=[],n=0;n<r;n++)o[n]=this._map.latLngToLayerPoint(t[n]),e.extend(o[n]);i.push(o)}else for(n=0;n<r;n++)this._projectLatlngs(t[n],i,e)},_clipPoints:function(){var t=this._renderer._bounds;if(this._parts=[],this._pxBounds&&this._pxBounds.intersects(t))if(this.options.noClip)this._parts=this._rings;else{var i,e,n,o,s,r,a,h=this._parts;for(i=0,n=0,o=this._rings.length;i<o;i++)for(e=0,s=(a=this._rings[i]).length;e<s-1;e++)(r=At(a[e],a[e+1],t,e,!0))&&(h[n]=h[n]||[],h[n].push(r[0]),r[1]===a[e+1]&&e!==s-2||(h[n].push(r[1]),n++))}},_simplifyPoints:function(){for(var t=this._parts,i=this.options.smoothFactor,e=0,n=t.length;e<n;e++)t[e]=Ct(t[e],i)},_update:function(){this._map&&(this._clipPoints(),this._simplifyPoints(),this._updatePath())},_updatePath:function(){this._renderer._updatePoly(this)},_containsPoint:function(t,i){var e,n,o,s,r,a,h=this._clickTolerance();if(!this._pxBounds||!this._pxBounds.contains(t))return!1;for(e=0,s=this._parts.length;e<s;e++)for(n=0,o=(r=(a=this._parts[e]).length)-1;n<r;o=n++)if((i||0!==n)&&Zt(t,a[o],a[n])<=h)return!0;return!1}});tn._flat=Nt;var en=tn.extend({options:{fill:!0},isEmpty:function(){return!this._latlngs.length||!this._latlngs[0].length},getCenter:function(){if(!this._map)throw new Error(\"Must add layer to map before using getCenter()\");var t,i,e,n,o,s,r,a,h,u=this._rings[0],l=u.length;if(!l)return null;for(s=r=a=0,t=0,i=l-1;t<l;i=t++)e=u[t],n=u[i],o=e.y*n.x-n.y*e.x,r+=(e.x+n.x)*o,a+=(e.y+n.y)*o,s+=3*o;return h=0===s?u[0]:[r/s,a/s],this._map.layerPointToLatLng(h)},_convertLatLngs:function(t){var i=tn.prototype._convertLatLngs.call(this,t),e=i.length;return e>=2&&i[0]instanceof M&&i[0].equals(i[e-1])&&i.pop(),i},_setLatLngs:function(t){tn.prototype._setLatLngs.call(this,t),Dt(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return Dt(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,i=this.options.weight,e=new x(i,i);if(t=new P(t.min.subtract(e),t.max.add(e)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t))if(this.options.noClip)this._parts=this._rings;else for(var n,o=0,s=this._rings.length;o<s;o++)(n=jt(this._rings[o],t,!0)).length&&this._parts.push(n)},_updatePath:function(){this._renderer._updatePoly(this,!0)},_containsPoint:function(t){var i,e,n,o,s,r,a,h,u=!1;if(!this._pxBounds.contains(t))return!1;for(o=0,a=this._parts.length;o<a;o++)for(s=0,r=(h=(i=this._parts[o]).length)-1;s<h;r=s++)e=i[s],n=i[r],e.y>t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||tn.prototype._containsPoint.call(this,t,!0)}}),nn=qe.extend({initialize:function(t,i){l(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=ei(t)?t:t.features;if(o){for(i=0,e=o.length;i<e;i++)((n=o[i]).geometries||n.geometry||n.features||n.coordinates)&&this.addData(n);return this}var s=this.options;if(s.filter&&!s.filter(t))return this;var r=Wt(t,s);return r?(r.feature=Gt(t),r.defaultOptions=r.options,this.resetStyle(r),s.onEachFeature&&s.onEachFeature(t,r),this.addLayer(r)):this},resetStyle:function(t){return t.options=i({},t.defaultOptions),this._setLayerStyle(t,this.options.style),this},setStyle:function(t){return this.eachLayer(function(i){this._setLayerStyle(i,t)},this)},_setLayerStyle:function(t,i){\"function\"==typeof i&&(i=i(t.feature)),t.setStyle&&t.setStyle(i)}}),on={toGeoJSON:function(t){return qt(this,{type:\"Point\",coordinates:Ut(this.getLatLng(),t)})}};Xe.include(on),Qe.include(on),$e.include(on),tn.include({toGeoJSON:function(t){var i=!Dt(this._latlngs),e=Vt(this._latlngs,i?1:0,!1,t);return qt(this,{type:(i?\"Multi\":\"\")+\"LineString\",coordinates:e})}}),en.include({toGeoJSON:function(t){var i=!Dt(this._latlngs),e=i&&!Dt(this._latlngs[0]),n=Vt(this._latlngs,e?2:i?1:0,!0,t);return i||(n=[n]),qt(this,{type:(e?\"Multi\":\"\")+\"Polygon\",coordinates:n})}}),Ve.include({toMultiPoint:function(t){var i=[];return this.eachLayer(function(e){i.push(e.toGeoJSON(t).geometry.coordinates)}),qt(this,{type:\"MultiPoint\",coordinates:i})},toGeoJSON:function(t){var i=this.feature&&this.feature.geometry&&this.feature.geometry.type;if(\"MultiPoint\"===i)return this.toMultiPoint(t);var e=\"GeometryCollection\"===i,n=[];return this.eachLayer(function(i){if(i.toGeoJSON){var o=i.toGeoJSON(t);if(e)n.push(o.geometry);else{var s=Gt(o);\"FeatureCollection\"===s.type?n.push.apply(n,s.features):n.push(s)}}}),e?qt(this,{geometries:n,type:\"GeometryCollection\"}):{type:\"FeatureCollection\",features:n}}});var sn=Kt,rn=Ue.extend({options:{opacity:1,alt:\"\",interactive:!1,crossOrigin:!1,errorOverlayUrl:\"\",zIndex:1,className:\"\"},initialize:function(t,i,e){this._url=t,this._bounds=z(i),l(this,e)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(pt(this._image,\"leaflet-interactive\"),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){ut(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(t){return this.options.opacity=t,this._image&&this._updateOpacity(),this},setStyle:function(t){return t.opacity&&this.setOpacity(t.opacity),this},bringToFront:function(){return this._map&&ct(this._image),this},bringToBack:function(){return this._map&&_t(this._image),this},setUrl:function(t){return this._url=t,this._image&&(this._image.src=t),this},setBounds:function(t){return this._bounds=z(t),this._map&&this._reset(),this},getEvents:function(){var t={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var t=\"IMG\"===this._url.tagName,i=this._image=t?this._url:ht(\"img\");pt(i,\"leaflet-image-layer\"),this._zoomAnimated&&pt(i,\"leaflet-zoom-animated\"),this.options.className&&pt(i,this.options.className),i.onselectstart=r,i.onmousemove=r,i.onload=e(this.fire,this,\"load\"),i.onerror=e(this._overlayOnError,this,\"error\"),this.options.crossOrigin&&(i.crossOrigin=\"\"),this.options.zIndex&&this._updateZIndex(),t?this._url=i.src:(i.src=this._url,i.alt=this.options.alt)},_animateZoom:function(t){var i=this._map.getZoomScale(t.zoom),e=this._map._latLngBoundsToNewLayerBounds(this._bounds,t.zoom,t.center).min;wt(this._image,e,i)},_reset:function(){var t=this._image,i=new P(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),e=i.getSize();Lt(t,i.min),t.style.width=e.x+\"px\",t.style.height=e.y+\"px\"},_updateOpacity:function(){vt(this._image,this.options.opacity)},_updateZIndex:function(){this._image&&void 0!==this.options.zIndex&&null!==this.options.zIndex&&(this._image.style.zIndex=this.options.zIndex)},_overlayOnError:function(){this.fire(\"error\");var t=this.options.errorOverlayUrl;t&&this._url!==t&&(this._url=t,this._image.src=t)}}),an=rn.extend({options:{autoplay:!0,loop:!0},_initImage:function(){var t=\"VIDEO\"===this._url.tagName,i=this._image=t?this._url:ht(\"video\");if(pt(i,\"leaflet-image-layer\"),this._zoomAnimated&&pt(i,\"leaflet-zoom-animated\"),i.onselectstart=r,i.onmousemove=r,i.onloadeddata=e(this.fire,this,\"load\"),t){for(var n=i.getElementsByTagName(\"source\"),o=[],s=0;s<n.length;s++)o.push(n[s].src);this._url=n.length>0?o:[i.src]}else{ei(this._url)||(this._url=[this._url]),i.autoplay=!!this.options.autoplay,i.loop=!!this.options.loop;for(var a=0;a<this._url.length;a++){var h=ht(\"source\");h.src=this._url[a],i.appendChild(h)}}}}),hn=Ue.extend({options:{offset:[0,7],className:\"\",pane:\"popupPane\"},initialize:function(t,i){l(this,t),this._source=i},onAdd:function(t){this._zoomAnimated=t._zoomAnimated,this._container||this._initLayout(),t._fadeAnimated&&vt(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&vt(this._container,1),this.bringToFront()},onRemove:function(t){t._fadeAnimated?(vt(this._container,0),this._removeTimeout=setTimeout(e(ut,void 0,this._container),200)):ut(this._container)},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=C(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},getElement:function(){return this._container},update:function(){this._map&&(this._container.style.visibility=\"hidden\",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility=\"\",this._adjustPan())},getEvents:function(){var t={zoom:this._updatePosition,viewreset:this._updatePosition};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},isOpen:function(){return!!this._map&&this._map.hasLayer(this)},bringToFront:function(){return this._map&&ct(this._container),this},bringToBack:function(){return this._map&&_t(this._container),this},_updateContent:function(){if(this._content){var t=this._contentNode,i=\"function\"==typeof this._content?this._content(this._source||this):this._content;if(\"string\"==typeof i)t.innerHTML=i;else{for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(i)}this.fire(\"contentupdate\")}},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),i=w(this.options.offset),e=this._getAnchor();this._zoomAnimated?Lt(this._container,t.add(e)):i=i.add(t).add(e);var n=this._containerBottom=-i.y,o=this._containerLeft=-Math.round(this._containerWidth/2)+i.x;this._container.style.bottom=n+\"px\",this._container.style.left=o+\"px\"}},_getAnchor:function(){return[0,0]}}),un=hn.extend({options:{maxWidth:300,minWidth:50,maxHeight:null,autoPan:!0,autoPanPaddingTopLeft:null,autoPanPaddingBottomRight:null,autoPanPadding:[5,5],keepInView:!1,closeButton:!0,autoClose:!0,closeOnEscapeKey:!0,className:\"\"},openOn:function(t){return t.openPopup(this),this},onAdd:function(t){hn.prototype.onAdd.call(this,t),t.fire(\"popupopen\",{popup:this}),this._source&&(this._source.fire(\"popupopen\",{popup:this},!0),this._source instanceof Je||this._source.on(\"preclick\",Y))},onRemove:function(t){hn.prototype.onRemove.call(this,t),t.fire(\"popupclose\",{popup:this}),this._source&&(this._source.fire(\"popupclose\",{popup:this},!0),this._source instanceof Je||this._source.off(\"preclick\",Y))},getEvents:function(){var t=hn.prototype.getEvents.call(this);return(void 0!==this.options.closeOnClick?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t=\"leaflet-popup\",i=this._container=ht(\"div\",t+\" \"+(this.options.className||\"\")+\" leaflet-zoom-animated\"),e=this._wrapper=ht(\"div\",t+\"-content-wrapper\",i);if(this._contentNode=ht(\"div\",t+\"-content\",e),J(e),X(this._contentNode),V(e,\"contextmenu\",Y),this._tipContainer=ht(\"div\",t+\"-tip-container\",i),this._tip=ht(\"div\",t+\"-tip\",this._tipContainer),this.options.closeButton){var n=this._closeButton=ht(\"a\",t+\"-close-button\",i);n.href=\"#close\",n.innerHTML=\"&#215;\",V(n,\"click\",this._onCloseButtonClick,this)}},_updateLayout:function(){var t=this._contentNode,i=t.style;i.width=\"\",i.whiteSpace=\"nowrap\";var e=t.offsetWidth;e=Math.min(e,this.options.maxWidth),e=Math.max(e,this.options.minWidth),i.width=e+1+\"px\",i.whiteSpace=\"\",i.height=\"\";var n=t.offsetHeight,o=this.options.maxHeight;o&&n>o?(i.height=o+\"px\",pt(t,\"leaflet-popup-scrolled\")):mt(t,\"leaflet-popup-scrolled\"),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),e=this._getAnchor();Lt(this._container,i.add(e))},_adjustPan:function(){if(!(!this.options.autoPan||this._map._panAnim&&this._map._panAnim._inProgress)){var t=this._map,i=parseInt(at(this._container,\"marginBottom\"),10)||0,e=this._container.offsetHeight+i,n=this._containerWidth,o=new x(this._containerLeft,-e-this._containerBottom);o._add(Pt(this._container));var s=t.layerPointToContainerPoint(o),r=w(this.options.autoPanPadding),a=w(this.options.autoPanPaddingTopLeft||r),h=w(this.options.autoPanPaddingBottomRight||r),u=t.getSize(),l=0,c=0;s.x+n+h.x>u.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire(\"autopanstart\").panBy([l,c])}},_onCloseButtonClick:function(t){this._close(),Q(t)},_getAnchor:function(){return w(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});Le.mergeOptions({closePopupOnClick:!0}),Le.include({openPopup:function(t,i,e){return t instanceof un||(t=new un(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Ue.include({bindPopup:function(t,i){return t instanceof un?(l(t,i),this._popup=t,t._source=this):(this._popup&&!i||(this._popup=new un(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){if(t instanceof Ue||(i=t,t=this),t instanceof qe)for(var e in this._layers){t=this._layers[e];break}return i||(i=t.getCenter?t.getCenter():t.getLatLng()),this._popup&&this._map&&(this._popup._source=t,this._popup.update(),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Q(t),i instanceof Je?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var ln=hn.extend({options:{pane:\"tooltipPane\",offset:[0,0],direction:\"auto\",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){hn.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire(\"tooltipopen\",{tooltip:this}),this._source&&this._source.fire(\"tooltipopen\",{tooltip:this},!0)},onRemove:function(t){hn.prototype.onRemove.call(this,t),t.fire(\"tooltipclose\",{tooltip:this}),this._source&&this._source.fire(\"tooltipclose\",{tooltip:this},!0)},getEvents:function(){var t=hn.prototype.getEvents.call(this);return Vi&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t=\"leaflet-tooltip \"+(this.options.className||\"\")+\" leaflet-zoom-\"+(this._zoomAnimated?\"animated\":\"hide\");this._contentNode=this._container=ht(\"div\",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i=this._map,e=this._container,n=i.latLngToContainerPoint(i.getCenter()),o=i.layerPointToContainerPoint(t),s=this.options.direction,r=e.offsetWidth,a=e.offsetHeight,h=w(this.options.offset),u=this._getAnchor();\"top\"===s?t=t.add(w(-r/2+h.x,-a+h.y+u.y,!0)):\"bottom\"===s?t=t.subtract(w(r/2-h.x,-h.y,!0)):\"center\"===s?t=t.subtract(w(r/2+h.x,a/2-u.y+h.y,!0)):\"right\"===s||\"auto\"===s&&o.x<n.x?(s=\"right\",t=t.add(w(h.x+u.x,u.y-a/2+h.y,!0))):(s=\"left\",t=t.subtract(w(r+u.x-h.x,a/2-u.y-h.y,!0))),mt(e,\"leaflet-tooltip-right\"),mt(e,\"leaflet-tooltip-left\"),mt(e,\"leaflet-tooltip-top\"),mt(e,\"leaflet-tooltip-bottom\"),pt(e,\"leaflet-tooltip-\"+s),Lt(e,t)},_updatePosition:function(){var t=this._map.latLngToLayerPoint(this._latlng);this._setPosition(t)},setOpacity:function(t){this.options.opacity=t,this._container&&vt(this._container,t)},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPosition(i)},_getAnchor:function(){return w(this._source&&this._source._getTooltipAnchor&&!this.options.sticky?this._source._getTooltipAnchor():[0,0])}});Le.include({openTooltip:function(t,i,e){return t instanceof ln||(t=new ln(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:this.addLayer(t)},closeTooltip:function(t){return t&&this.removeLayer(t),this}}),Ue.include({bindTooltip:function(t,i){return t instanceof ln?(l(t,i),this._tooltip=t,t._source=this):(this._tooltip&&!i||(this._tooltip=new ln(i,this)),this._tooltip.setContent(t)),this._initTooltipInteractions(),this._tooltip.options.permanent&&this._map&&this._map.hasLayer(this)&&this.openTooltip(),this},unbindTooltip:function(){return this._tooltip&&(this._initTooltipInteractions(!0),this.closeTooltip(),this._tooltip=null),this},_initTooltipInteractions:function(t){if(t||!this._tooltipHandlersAdded){var i=t?\"off\":\"on\",e={remove:this.closeTooltip,move:this._moveTooltip};this._tooltip.options.permanent?e.add=this._openTooltip:(e.mouseover=this._openTooltip,e.mouseout=this.closeTooltip,this._tooltip.options.sticky&&(e.mousemove=this._moveTooltip),Vi&&(e.click=this._openTooltip)),this[i](e),this._tooltipHandlersAdded=!t}},openTooltip:function(t,i){if(t instanceof Ue||(i=t,t=this),t instanceof qe)for(var e in this._layers){t=this._layers[e];break}return i||(i=t.getCenter?t.getCenter():t.getLatLng()),this._tooltip&&this._map&&(this._tooltip._source=t,this._tooltip.update(),this._map.openTooltip(this._tooltip,i),this._tooltip.options.interactive&&this._tooltip._container&&(pt(this._tooltip._container,\"leaflet-clickable\"),this.addInteractiveTarget(this._tooltip._container))),this},closeTooltip:function(){return this._tooltip&&(this._tooltip._close(),this._tooltip.options.interactive&&this._tooltip._container&&(mt(this._tooltip._container,\"leaflet-clickable\"),this.removeInteractiveTarget(this._tooltip._container))),this},toggleTooltip:function(t){return this._tooltip&&(this._tooltip._map?this.closeTooltip():this.openTooltip(t)),this},isTooltipOpen:function(){return this._tooltip.isOpen()},setTooltipContent:function(t){return this._tooltip&&this._tooltip.setContent(t),this},getTooltip:function(){return this._tooltip},_openTooltip:function(t){var i=t.layer||t.target;this._tooltip&&this._map&&this.openTooltip(i,this._tooltip.options.sticky?t.latlng:void 0)},_moveTooltip:function(t){var i,e,n=t.latlng;this._tooltip.options.sticky&&t.originalEvent&&(i=this._map.mouseEventToContainerPoint(t.originalEvent),e=this._map.containerPointToLayerPoint(i),n=this._map.layerPointToLatLng(e)),this._tooltip.setLatLng(n)}});var cn=Ge.extend({options:{iconSize:[12,12],html:!1,bgPos:null,className:\"leaflet-div-icon\"},createIcon:function(t){var i=t&&\"DIV\"===t.tagName?t:document.createElement(\"div\"),e=this.options;if(i.innerHTML=!1!==e.html?e.html:\"\",e.bgPos){var n=w(e.bgPos);i.style.backgroundPosition=-n.x+\"px \"+-n.y+\"px\"}return this._setIconStyles(i,\"icon\"),i},createShadow:function(){return null}});Ge.Default=Ke;var _n=Ue.extend({options:{tileSize:256,opacity:1,updateWhenIdle:ji,updateWhenZooming:!0,updateInterval:200,zIndex:1,bounds:null,minZoom:0,maxZoom:void 0,maxNativeZoom:void 0,minNativeZoom:void 0,noWrap:!1,pane:\"tilePane\",className:\"\",keepBuffer:2},initialize:function(t){l(this,t)},onAdd:function(){this._initContainer(),this._levels={},this._tiles={},this._resetView(),this._update()},beforeAdd:function(t){t._addZoomLimit(this)},onRemove:function(t){this._removeAllTiles(),ut(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=void 0},bringToFront:function(){return this._map&&(ct(this._container),this._setAutoZIndex(Math.max)),this},bringToBack:function(){return this._map&&(_t(this._container),this._setAutoZIndex(Math.min)),this},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},isLoading:function(){return this._loading},redraw:function(){return this._map&&(this._removeAllTiles(),this._update()),this},getEvents:function(){var t={viewprereset:this._invalidateAll,viewreset:this._resetView,zoom:this._resetView,moveend:this._onMoveEnd};return this.options.updateWhenIdle||(this._onMove||(this._onMove=o(this._onMoveEnd,this.options.updateInterval,this)),t.move=this._onMove),this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},createTile:function(){return document.createElement(\"div\")},getTileSize:function(){var t=this.options.tileSize;return t instanceof x?t:new x(t,t)},_updateZIndex:function(){this._container&&void 0!==this.options.zIndex&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t){for(var i,e=this.getPane().children,n=-t(-1/0,1/0),o=0,s=e.length;o<s;o++)i=e[o].style.zIndex,e[o]!==this._container&&i&&(n=t(n,+i));isFinite(n)&&(this.options.zIndex=n+t(-1,1),this._updateZIndex())},_updateOpacity:function(){if(this._map&&!Li){vt(this._container,this.options.opacity);var t=+new Date,i=!1,e=!1;for(var n in this._tiles){var o=this._tiles[n];if(o.current&&o.loaded){var s=Math.min(1,(t-o.loaded)/200);vt(o.el,s),s<1?i=!0:(o.active?e=!0:this._onOpaqueTile(o),o.active=!0)}}e&&!this._noPrune&&this._pruneTiles(),i&&(g(this._fadeFrame),this._fadeFrame=f(this._updateOpacity,this))}},_onOpaqueTile:r,_initContainer:function(){this._container||(this._container=ht(\"div\",\"leaflet-layer \"+(this.options.className||\"\")),this._updateZIndex(),this.options.opacity<1&&this._updateOpacity(),this.getPane().appendChild(this._container))},_updateLevels:function(){var t=this._tileZoom,i=this.options.maxZoom;if(void 0!==t){for(var e in this._levels)this._levels[e].el.children.length||e===t?(this._levels[e].el.style.zIndex=i-Math.abs(t-e),this._onUpdateLevel(e)):(ut(this._levels[e].el),this._removeTilesAtZoom(e),this._onRemoveLevel(e),delete this._levels[e]);var n=this._levels[t],o=this._map;return n||((n=this._levels[t]={}).el=ht(\"div\",\"leaflet-tile-container leaflet-zoom-animated\",this._container),n.el.style.zIndex=i,n.origin=o.project(o.unproject(o.getPixelOrigin()),t).round(),n.zoom=t,this._setZoomTransform(n,o.getCenter(),o.getZoom()),n.el.offsetWidth,this._onCreateLevel(n)),this._level=n,n}},_onUpdateLevel:r,_onRemoveLevel:r,_onCreateLevel:r,_pruneTiles:function(){if(this._map){var t,i,e=this._map.getZoom();if(e>this.options.maxZoom||e<this.options.minZoom)this._removeAllTiles();else{for(t in this._tiles)(i=this._tiles[t]).retain=i.current;for(t in this._tiles)if((i=this._tiles[t]).current&&!i.active){var n=i.coords;this._retainParent(n.x,n.y,n.z,n.z-5)||this._retainChildren(n.x,n.y,n.z,n.z+2)}for(t in this._tiles)this._tiles[t].retain||this._removeTile(t)}}},_removeTilesAtZoom:function(t){for(var i in this._tiles)this._tiles[i].coords.z===t&&this._removeTile(i)},_removeAllTiles:function(){for(var t in this._tiles)this._removeTile(t)},_invalidateAll:function(){for(var t in this._levels)ut(this._levels[t].el),this._onRemoveLevel(t),delete this._levels[t];this._removeAllTiles(),this._tileZoom=void 0},_retainParent:function(t,i,e,n){var o=Math.floor(t/2),s=Math.floor(i/2),r=e-1,a=new x(+o,+s);a.z=+r;var h=this._tileCoordsToKey(a),u=this._tiles[h];return u&&u.active?(u.retain=!0,!0):(u&&u.loaded&&(u.retain=!0),r>n&&this._retainParent(o,s,r,n))},_retainChildren:function(t,i,e,n){for(var o=2*t;o<2*t+2;o++)for(var s=2*i;s<2*i+2;s++){var r=new x(o,s);r.z=e+1;var a=this._tileCoordsToKey(r),h=this._tiles[a];h&&h.active?h.retain=!0:(h&&h.loaded&&(h.retain=!0),e+1<n&&this._retainChildren(o,s,e+1,n))}},_resetView:function(t){var i=t&&(t.pinch||t.flyTo);this._setView(this._map.getCenter(),this._map.getZoom(),i,i)},_animateZoom:function(t){this._setView(t.center,t.zoom,!0,t.noUpdate)},_clampZoom:function(t){var i=this.options;return void 0!==i.minNativeZoom&&t<i.minNativeZoom?i.minNativeZoom:void 0!==i.maxNativeZoom&&i.maxNativeZoom<t?i.maxNativeZoom:t},_setView:function(t,i,e,n){var o=this._clampZoom(Math.round(i));(void 0!==this.options.maxZoom&&o>this.options.maxZoom||void 0!==this.options.minZoom&&o<this.options.minZoom)&&(o=void 0);var s=this.options.updateWhenZooming&&o!==this._tileZoom;n&&!s||(this._tileZoom=o,this._abortLoading&&this._abortLoading(),this._updateLevels(),this._resetGrid(),void 0!==o&&this._update(t),e||this._pruneTiles(),this._noPrune=!!e),this._setZoomTransforms(t,i)},_setZoomTransforms:function(t,i){for(var e in this._levels)this._setZoomTransform(this._levels[e],t,i)},_setZoomTransform:function(t,i,e){var n=this._map.getZoomScale(e,t.zoom),o=t.origin.multiplyBy(n).subtract(this._map._getNewPixelOrigin(i,e)).round();Ni?wt(t.el,o,n):Lt(t.el,o)},_resetGrid:function(){var t=this._map,i=t.options.crs,e=this._tileSize=this.getTileSize(),n=this._tileZoom,o=this._map.getPixelWorldBounds(this._tileZoom);o&&(this._globalTileRange=this._pxBoundsToTileRange(o)),this._wrapX=i.wrapLng&&!this.options.noWrap&&[Math.floor(t.project([0,i.wrapLng[0]],n).x/e.x),Math.ceil(t.project([0,i.wrapLng[1]],n).x/e.y)],this._wrapY=i.wrapLat&&!this.options.noWrap&&[Math.floor(t.project([i.wrapLat[0],0],n).y/e.x),Math.ceil(t.project([i.wrapLat[1],0],n).y/e.y)]},_onMoveEnd:function(){this._map&&!this._map._animatingZoom&&this._update()},_getTiledPixelBounds:function(t){var i=this._map,e=i._animatingZoom?Math.max(i._animateToZoom,i.getZoom()):i.getZoom(),n=i.getZoomScale(e,this._tileZoom),o=i.project(t,this._tileZoom).floor(),s=i.getSize().divideBy(2*n);return new P(o.subtract(s),o.add(s))},_update:function(t){var i=this._map;if(i){var e=this._clampZoom(i.getZoom());if(void 0===t&&(t=i.getCenter()),void 0!==this._tileZoom){var n=this._getTiledPixelBounds(t),o=this._pxBoundsToTileRange(n),s=o.getCenter(),r=[],a=this.options.keepBuffer,h=new P(o.getBottomLeft().subtract([a,-a]),o.getTopRight().add([a,-a]));if(!(isFinite(o.min.x)&&isFinite(o.min.y)&&isFinite(o.max.x)&&isFinite(o.max.y)))throw new Error(\"Attempted to load an infinite number of tiles\");for(var u in this._tiles){var l=this._tiles[u].coords;l.z===this._tileZoom&&h.contains(new x(l.x,l.y))||(this._tiles[u].current=!1)}if(Math.abs(e-this._tileZoom)>1)this._setView(t,e);else{for(var c=o.min.y;c<=o.max.y;c++)for(var _=o.min.x;_<=o.max.x;_++){var d=new x(_,c);if(d.z=this._tileZoom,this._isValidTile(d)){var p=this._tiles[this._tileCoordsToKey(d)];p?p.current=!0:r.push(d)}}if(r.sort(function(t,i){return t.distanceTo(s)-i.distanceTo(s)}),0!==r.length){this._loading||(this._loading=!0,this.fire(\"loading\"));var m=document.createDocumentFragment();for(_=0;_<r.length;_++)this._addTile(r[_],m);this._level.el.appendChild(m)}}}}},_isValidTile:function(t){var i=this._map.options.crs;if(!i.infinite){var e=this._globalTileRange;if(!i.wrapLng&&(t.x<e.min.x||t.x>e.max.x)||!i.wrapLat&&(t.y<e.min.y||t.y>e.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return z(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new T(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+\":\"+t.y+\":\"+t.z},_keyToTileCoords:function(t){var i=t.split(\":\"),e=new x(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(Ci||i.el.setAttribute(\"src\",ni),ut(i.el),delete this._tiles[t],this.fire(\"tileunload\",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){pt(t,\"leaflet-tile\");var i=this.getTileSize();t.style.width=i.x+\"px\",t.style.height=i.y+\"px\",t.onselectstart=r,t.onmousemove=r,Li&&this.options.opacity<1&&vt(t,this.options.opacity),Ti&&!zi&&(t.style.WebkitBackfaceVisibility=\"hidden\")},_addTile:function(t,i){var n=this._getTilePos(t),o=this._tileCoordsToKey(t),s=this.createTile(this._wrapCoords(t),e(this._tileReady,this,t));this._initTile(s),this.createTile.length<2&&f(e(this._tileReady,this,t,null,s)),Lt(s,n),this._tiles[o]={el:s,coords:t,current:!0},i.appendChild(s),this.fire(\"tileloadstart\",{tile:s,coords:t})},_tileReady:function(t,i,n){if(this._map){i&&this.fire(\"tileerror\",{error:i,tile:n,coords:t});var o=this._tileCoordsToKey(t);(n=this._tiles[o])&&(n.loaded=+new Date,this._map._fadeAnimated?(vt(n.el,0),g(this._fadeFrame),this._fadeFrame=f(this._updateOpacity,this)):(n.active=!0,this._pruneTiles()),i||(pt(n.el,\"leaflet-tile-loaded\"),this.fire(\"tileload\",{tile:n.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire(\"load\"),Li||!this._map._fadeAnimated?f(this._pruneTiles,this):setTimeout(e(this._pruneTiles,this),250)))}},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new x(this._wrapX?s(t.x,this._wrapX):t.x,this._wrapY?s(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new P(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}}),dn=_n.extend({options:{minZoom:0,maxZoom:18,subdomains:\"abc\",errorTileUrl:\"\",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=l(this,i)).detectRetina&&Ki&&i.maxZoom>0&&(i.tileSize=Math.floor(i.tileSize/2),i.zoomReverse?(i.zoomOffset--,i.minZoom++):(i.zoomOffset++,i.maxZoom--),i.minZoom=Math.max(0,i.minZoom)),\"string\"==typeof i.subdomains&&(i.subdomains=i.subdomains.split(\"\")),Ti||this.on(\"tileunload\",this._onTileRemove)},setUrl:function(t,i){return this._url=t,i||this.redraw(),this},createTile:function(t,i){var n=document.createElement(\"img\");return V(n,\"load\",e(this._tileOnLoad,this,i,n)),V(n,\"error\",e(this._tileOnError,this,i,n)),this.options.crossOrigin&&(n.crossOrigin=\"\"),n.alt=\"\",n.setAttribute(\"role\",\"presentation\"),n.src=this.getTileUrl(t),n},getTileUrl:function(t){var e={r:Ki?\"@2x\":\"\",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var n=this._globalTileRange.max.y-t.y;this.options.tms&&(e.y=n),e[\"-y\"]=n}return _(this._url,i(e,this.options))},_tileOnLoad:function(t,i){Li?setTimeout(e(t,this,null,i),0):t(null,i)},_tileOnError:function(t,i,e){var n=this.options.errorTileUrl;n&&i.getAttribute(\"src\")!==n&&(i.src=n),t(e,i)},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,i=this.options.maxZoom,e=this.options.zoomReverse,n=this.options.zoomOffset;return e&&(t=i-t),t+n},_getSubdomain:function(t){var i=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[i]},_abortLoading:function(){var t,i;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&((i=this._tiles[t].el).onload=r,i.onerror=r,i.complete||(i.src=ni,ut(i),delete this._tiles[t]))}}),pn=dn.extend({defaultWmsParams:{service:\"WMS\",request:\"GetMap\",layers:\"\",styles:\"\",format:\"image/jpeg\",transparent:!1,version:\"1.1.1\"},options:{crs:null,uppercase:!1},initialize:function(t,e){this._url=t;var n=i({},this.defaultWmsParams);for(var o in e)o in this.options||(n[o]=e[o]);var s=(e=l(this,e)).detectRetina&&Ki?2:1,r=this.getTileSize();n.width=r.x*s,n.height=r.y*s,this.wmsParams=n},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var i=this._wmsVersion>=1.3?\"crs\":\"srs\";this.wmsParams[i]=this._crs.code,dn.prototype.onAdd.call(this,t)},getTileUrl:function(t){var i=this._tileCoordsToNwSe(t),e=this._crs,n=b(e.project(i[0]),e.project(i[1])),o=n.min,s=n.max,r=(this._wmsVersion>=1.3&&this._crs===He?[o.y,o.x,s.y,s.x]:[o.x,o.y,s.x,s.y]).join(\",\"),a=L.TileLayer.prototype.getTileUrl.call(this,t);return a+c(this.wmsParams,a,this.options.uppercase)+(this.options.uppercase?\"&BBOX=\":\"&bbox=\")+r},setParams:function(t,e){return i(this.wmsParams,t),e||this.redraw(),this}});dn.WMS=pn,Yt.wms=function(t,i){return new pn(t,i)};var mn=Ue.extend({options:{padding:.1,tolerance:0},initialize:function(t){l(this,t),n(this),this._layers=this._layers||{}},onAdd:function(){this._container||(this._initContainer(),this._zoomAnimated&&pt(this._container,\"leaflet-zoom-animated\")),this.getPane().appendChild(this._container),this._update(),this.on(\"update\",this._updatePaths,this)},onRemove:function(){this.off(\"update\",this._updatePaths,this),this._destroyContainer()},getEvents:function(){var t={viewreset:this._reset,zoom:this._onZoom,moveend:this._update,zoomend:this._onZoomEnd};return this._zoomAnimated&&(t.zoomanim=this._onAnimZoom),t},_onAnimZoom:function(t){this._updateTransform(t.center,t.zoom)},_onZoom:function(){this._updateTransform(this._map.getCenter(),this._map.getZoom())},_updateTransform:function(t,i){var e=this._map.getZoomScale(i,this._zoom),n=Pt(this._container),o=this._map.getSize().multiplyBy(.5+this.options.padding),s=this._map.project(this._center,i),r=this._map.project(t,i).subtract(s),a=o.multiplyBy(-e).add(n).add(o).subtract(r);Ni?wt(this._container,a,e):Lt(this._container,a)},_reset:function(){this._update(),this._updateTransform(this._center,this._zoom);for(var t in this._layers)this._layers[t]._reset()},_onZoomEnd:function(){for(var t in this._layers)this._layers[t]._project()},_updatePaths:function(){for(var t in this._layers)this._layers[t]._update()},_update:function(){var t=this.options.padding,i=this._map.getSize(),e=this._map.containerPointToLayerPoint(i.multiplyBy(-t)).round();this._bounds=new P(e,e.add(i.multiplyBy(1+2*t)).round()),this._center=this._map.getCenter(),this._zoom=this._map.getZoom()}}),fn=mn.extend({getEvents:function(){var t=mn.prototype.getEvents.call(this);return t.viewprereset=this._onViewPreReset,t},_onViewPreReset:function(){this._postponeUpdatePaths=!0},onAdd:function(){mn.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=document.createElement(\"canvas\");V(t,\"mousemove\",o(this._onMouseMove,32,this),this),V(t,\"click dblclick mousedown mouseup contextmenu\",this._onClick,this),V(t,\"mouseout\",this._handleMouseOut,this),this._ctx=t.getContext(\"2d\")},_destroyContainer:function(){delete this._ctx,ut(this._container),q(this._container),delete this._container},_updatePaths:function(){if(!this._postponeUpdatePaths){this._redrawBounds=null;for(var t in this._layers)this._layers[t]._update();this._redraw()}},_update:function(){if(!this._map._animatingZoom||!this._bounds){this._drawnLayers={},mn.prototype._update.call(this);var t=this._bounds,i=this._container,e=t.getSize(),n=Ki?2:1;Lt(i,t.min),i.width=n*e.x,i.height=n*e.y,i.style.width=e.x+\"px\",i.style.height=e.y+\"px\",Ki&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire(\"update\")}},_reset:function(){mn.prototype._reset.call(this),this._postponeUpdatePaths&&(this._postponeUpdatePaths=!1,this._updatePaths())},_initPath:function(t){this._updateDashArray(t),this._layers[n(t)]=t;var i=t._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=i),this._drawLast=i,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var i=t._order,e=i.next,n=i.prev;e?e.prev=n:this._drawLast=n,n?n.next=e:this._drawFirst=e,delete t._order,delete this._layers[L.stamp(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if(t.options.dashArray){var i,e=t.options.dashArray.split(\",\"),n=[];for(i=0;i<e.length;i++)n.push(Number(e[i]));t.options._dashArray=n}},_requestRedraw:function(t){this._map&&(this._extendRedrawBounds(t),this._redrawRequest=this._redrawRequest||f(this._redraw,this))},_extendRedrawBounds:function(t){if(t._pxBounds){var i=(t.options.weight||0)+1;this._redrawBounds=this._redrawBounds||new P,this._redrawBounds.extend(t._pxBounds.min.subtract([i,i])),this._redrawBounds.extend(t._pxBounds.max.add([i,i]))}},_redraw:function(){this._redrawRequest=null,this._redrawBounds&&(this._redrawBounds.min._floor(),this._redrawBounds.max._ceil()),this._clear(),this._draw(),this._redrawBounds=null},_clear:function(){var t=this._redrawBounds;if(t){var i=t.getSize();this._ctx.clearRect(t.min.x,t.min.y,i.x,i.y)}else this._ctx.clearRect(0,0,this._container.width,this._container.height)},_draw:function(){var t,i=this._redrawBounds;if(this._ctx.save(),i){var e=i.getSize();this._ctx.beginPath(),this._ctx.rect(i.min.x,i.min.y,e.x,e.y),this._ctx.clip()}this._drawing=!0;for(var n=this._drawFirst;n;n=n.next)t=n.layer,(!i||t._pxBounds&&t._pxBounds.intersects(i))&&t._updatePath();this._drawing=!1,this._ctx.restore()},_updatePoly:function(t,i){if(this._drawing){var e,n,o,s,r=t._parts,a=r.length,h=this._ctx;if(a){for(this._drawnLayers[t._leaflet_id]=t,h.beginPath(),e=0;e<a;e++){for(n=0,o=r[e].length;n<o;n++)s=r[e][n],h[n?\"lineTo\":\"moveTo\"](s.x,s.y);i&&h.closePath()}this._fillStroke(h,t)}}},_updateCircle:function(t){if(this._drawing&&!t._empty()){var i=t._point,e=this._ctx,n=Math.max(Math.round(t._radius),1),o=(Math.max(Math.round(t._radiusY),1)||n)/n;this._drawnLayers[t._leaflet_id]=t,1!==o&&(e.save(),e.scale(1,o)),e.beginPath(),e.arc(i.x,i.y/o,n,0,2*Math.PI,!1),1!==o&&e.restore(),this._fillStroke(e,t)}},_fillStroke:function(t,i){var e=i.options;e.fill&&(t.globalAlpha=e.fillOpacity,t.fillStyle=e.fillColor||e.color,t.fill(e.fillRule||\"evenodd\")),e.stroke&&0!==e.weight&&(t.setLineDash&&t.setLineDash(i.options&&i.options._dashArray||[]),t.globalAlpha=e.opacity,t.lineWidth=e.weight,t.strokeStyle=e.color,t.lineCap=e.lineCap,t.lineJoin=e.lineJoin,t.stroke())},_onClick:function(t){for(var i,e,n=this._map.mouseEventToLayerPoint(t),o=this._drawFirst;o;o=o.next)(i=o.layer).options.interactive&&i._containsPoint(n)&&!this._map._draggableMoved(i)&&(e=i);e&&(et(t),this._fireEvent([e],t))},_onMouseMove:function(t){if(this._map&&!this._map.dragging.moving()&&!this._map._animatingZoom){var i=this._map.mouseEventToLayerPoint(t);this._handleMouseHover(t,i)}},_handleMouseOut:function(t){var i=this._hoveredLayer;i&&(mt(this._container,\"leaflet-interactive\"),this._fireEvent([i],t,\"mouseout\"),this._hoveredLayer=null)},_handleMouseHover:function(t,i){for(var e,n,o=this._drawFirst;o;o=o.next)(e=o.layer).options.interactive&&e._containsPoint(i)&&(n=e);n!==this._hoveredLayer&&(this._handleMouseOut(t),n&&(pt(this._container,\"leaflet-interactive\"),this._fireEvent([n],t,\"mouseover\"),this._hoveredLayer=n)),this._hoveredLayer&&this._fireEvent([this._hoveredLayer],t)},_fireEvent:function(t,i,e){this._map._fireDOMEvent(i,e||i.type,t)},_bringToFront:function(t){var i=t._order,e=i.next,n=i.prev;e&&(e.prev=n,n?n.next=e:e&&(this._drawFirst=e),i.prev=this._drawLast,this._drawLast.next=i,i.next=null,this._drawLast=i,this._requestRedraw(t))},_bringToBack:function(t){var i=t._order,e=i.next,n=i.prev;n&&(n.next=e,e?e.prev=n:n&&(this._drawLast=n),i.prev=null,i.next=this._drawFirst,this._drawFirst.prev=i,this._drawFirst=i,this._requestRedraw(t))}}),gn=function(){try{return document.namespaces.add(\"lvml\",\"urn:schemas-microsoft-com:vml\"),function(t){return document.createElement(\"<lvml:\"+t+' class=\"lvml\">')}}catch(t){return function(t){return document.createElement(\"<\"+t+' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"lvml\">')}}}(),vn={_initContainer:function(){this._container=ht(\"div\",\"leaflet-vml-container\")},_update:function(){this._map._animatingZoom||(mn.prototype._update.call(this),this.fire(\"update\"))},_initPath:function(t){var i=t._container=gn(\"shape\");pt(i,\"leaflet-vml-shape \"+(this.options.className||\"\")),i.coordsize=\"1 1\",t._path=gn(\"path\"),i.appendChild(t._path),this._updateStyle(t),this._layers[n(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;ut(i),t.removeInteractiveTarget(i),delete this._layers[n(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i||(i=t._stroke=gn(\"stroke\")),o.appendChild(i),i.weight=n.weight+\"px\",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=ei(n.dashArray)?n.dashArray.join(\" \"):n.dashArray.replace(/( *, *)/g,\" \"):i.dashStyle=\"\",i.endcap=n.lineCap.replace(\"butt\",\"flat\"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e||(e=t._fill=gn(\"fill\")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?\"M0 0\":\"AL \"+i.x+\",\"+i.y+\" \"+e+\",\"+n+\" 0,23592600\")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){ct(t._container)},_bringToBack:function(t){_t(t._container)}},yn=Ji?gn:E,xn=mn.extend({getEvents:function(){var t=mn.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=yn(\"svg\"),this._container.setAttribute(\"pointer-events\",\"none\"),this._rootGroup=yn(\"g\"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){ut(this._container),q(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){if(!this._map._animatingZoom||!this._bounds){mn.prototype._update.call(this);var t=this._bounds,i=t.getSize(),e=this._container;this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute(\"width\",i.x),e.setAttribute(\"height\",i.y)),Lt(e,t.min),e.setAttribute(\"viewBox\",[t.min.x,t.min.y,i.x,i.y].join(\" \")),this.fire(\"update\")}},_initPath:function(t){var i=t._path=yn(\"path\");t.options.className&&pt(i,t.options.className),t.options.interactive&&pt(i,\"leaflet-interactive\"),this._updateStyle(t),this._layers[n(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){ut(t._path),t.removeInteractiveTarget(t._path),delete this._layers[n(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute(\"stroke\",e.color),i.setAttribute(\"stroke-opacity\",e.opacity),i.setAttribute(\"stroke-width\",e.weight),i.setAttribute(\"stroke-linecap\",e.lineCap),i.setAttribute(\"stroke-linejoin\",e.lineJoin),e.dashArray?i.setAttribute(\"stroke-dasharray\",e.dashArray):i.removeAttribute(\"stroke-dasharray\"),e.dashOffset?i.setAttribute(\"stroke-dashoffset\",e.dashOffset):i.removeAttribute(\"stroke-dashoffset\")):i.setAttribute(\"stroke\",\"none\"),e.fill?(i.setAttribute(\"fill\",e.fillColor||e.color),i.setAttribute(\"fill-opacity\",e.fillOpacity),i.setAttribute(\"fill-rule\",e.fillRule||\"evenodd\")):i.setAttribute(\"fill\",\"none\"))},_updatePoly:function(t,i){this._setPath(t,k(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n=\"a\"+e+\",\"+(Math.max(Math.round(t._radiusY),1)||e)+\" 0 1,0 \",o=t._empty()?\"M0 0\":\"M\"+(i.x-e)+\",\"+i.y+n+2*e+\",0 \"+n+2*-e+\",0 \";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute(\"d\",i)},_bringToFront:function(t){ct(t._path)},_bringToBack:function(t){_t(t._path)}});Ji&&xn.include(vn),Le.include({getRenderer:function(t){var i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer;return i||(i=this._renderer=this.options.preferCanvas&&Xt()||Jt()),this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if(\"overlayPane\"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=xn&&Jt({pane:t})||fn&&Xt({pane:t}),this._paneRenderers[t]=i),i}});var wn=en.extend({initialize:function(t,i){en.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return t=z(t),[t.getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});xn.create=yn,xn.pointsToPath=k,nn.geometryToLayer=Wt,nn.coordsToLatLng=Ht,nn.coordsToLatLngs=Ft,nn.latLngToCoords=Ut,nn.latLngsToCoords=Vt,nn.getFeature=qt,nn.asFeature=Gt,Le.mergeOptions({boxZoom:!0});var Ln=Ze.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on(\"unload\",this._destroy,this)},addHooks:function(){V(this._container,\"mousedown\",this._onMouseDown,this)},removeHooks:function(){q(this._container,\"mousedown\",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){ut(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),mi(),bt(),this._startPoint=this._map.mouseEventToContainerPoint(t),V(document,{contextmenu:Q,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=ht(\"div\",\"leaflet-zoom-box\",this._container),pt(this._container,\"leaflet-crosshair\"),this._map.fire(\"boxzoomstart\")),this._point=this._map.mouseEventToContainerPoint(t);var i=new P(this._point,this._startPoint),e=i.getSize();Lt(this._box,i.min),this._box.style.width=e.x+\"px\",this._box.style.height=e.y+\"px\"},_finish:function(){this._moved&&(ut(this._box),mt(this._container,\"leaflet-crosshair\")),fi(),Tt(),q(document,{contextmenu:Q,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(e(this._resetState,this),0);var i=new T(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(i).fire(\"boxzoomend\",{boxZoomBounds:i})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});Le.addInitHook(\"addHandler\",\"boxZoom\",Ln),Le.mergeOptions({doubleClickZoom:!0});var Pn=Ze.extend({addHooks:function(){this._map.on(\"dblclick\",this._onDoubleClick,this)},removeHooks:function(){this._map.off(\"dblclick\",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;\"center\"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});Le.addInitHook(\"addHandler\",\"doubleClickZoom\",Pn),Le.mergeOptions({dragging:!0,inertia:!zi,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var bn=Ze.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new Be(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on(\"predrag\",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on(\"predrag\",this._onPreDragWrap,this),t.on(\"zoomend\",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))}pt(this._map._container,\"leaflet-grab leaflet-touch-drag\"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){mt(this._map._container,\"leaflet-grab\"),mt(this._map._container,\"leaflet-touch-drag\"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t=this._map;if(t._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity){var i=z(this._map.options.maxBounds);this._offsetLimit=b(this._map.latLngToContainerPoint(i.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(i.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))}else this._offsetLimit=null;t.fire(\"movestart\").fire(\"dragstart\"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){if(this._map.options.inertia){var i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(e),this._times.push(i),this._prunePositions(i)}this._map.fire(\"move\",t).fire(\"drag\",t)},_prunePositions:function(t){for(;this._positions.length>1&&t-this._times[0]>50;)this._positions.shift(),this._times.shift()},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),i=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=i.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,i){return t-(t-i)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),i=this._offsetLimit;t.x<i.min.x&&(t.x=this._viscousLimit(t.x,i.min.x)),t.y<i.min.y&&(t.y=this._viscousLimit(t.y,i.min.y)),t.x>i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)<Math.abs(s+e)?o:s;this._draggable._absPos=this._draggable._newPos.clone(),this._draggable._newPos.x=r},_onDragEnd:function(t){var i=this._map,e=i.options,n=!e.inertia||this._times.length<2;if(i.fire(\"dragend\",t),n)i.fire(\"moveend\");else{this._prunePositions(+new Date);var o=this._lastPos.subtract(this._positions[0]),s=(this._lastTime-this._times[0])/1e3,r=e.easeLinearity,a=o.multiplyBy(r/s),h=a.distanceTo([0,0]),u=Math.min(e.inertiaMaxSpeed,h),l=a.multiplyBy(u/h),c=u/(e.inertiaDeceleration*r),_=l.multiplyBy(-c/2).round();_.x||_.y?(_=i._limitOffset(_,i.options.maxBounds),f(function(){i.panBy(_,{duration:c,easeLinearity:r,noMoveStart:!0,animate:!0})})):i.fire(\"moveend\")}}});Le.addInitHook(\"addHandler\",\"dragging\",bn),Le.mergeOptions({keyboard:!0,keyboardPanDelta:80});var Tn=Ze.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,54,173]},initialize:function(t){this._map=t,this._setPanDelta(t.options.keyboardPanDelta),this._setZoomDelta(t.options.zoomDelta)},addHooks:function(){var t=this._map._container;t.tabIndex<=0&&(t.tabIndex=\"0\"),V(t,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.on({focus:this._addHooks,blur:this._removeHooks},this)},removeHooks:function(){this._removeHooks(),q(this._map._container,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.off({focus:this._addHooks,blur:this._removeHooks},this)},_onMouseDown:function(){if(!this._focused){var t=document.body,i=document.documentElement,e=t.scrollTop||i.scrollTop,n=t.scrollLeft||i.scrollLeft;this._map._container.focus(),window.scrollTo(n,e)}},_onFocus:function(){this._focused=!0,this._map.fire(\"focus\")},_onBlur:function(){this._focused=!1,this._map.fire(\"blur\")},_setPanDelta:function(t){var i,e,n=this._panKeys={},o=this.keyCodes;for(i=0,e=o.left.length;i<e;i++)n[o.left[i]]=[-1*t,0];for(i=0,e=o.right.length;i<e;i++)n[o.right[i]]=[t,0];for(i=0,e=o.down.length;i<e;i++)n[o.down[i]]=[0,t];for(i=0,e=o.up.length;i<e;i++)n[o.up[i]]=[0,-1*t]},_setZoomDelta:function(t){var i,e,n=this._zoomKeys={},o=this.keyCodes;for(i=0,e=o.zoomIn.length;i<e;i++)n[o.zoomIn[i]]=t;for(i=0,e=o.zoomOut.length;i<e;i++)n[o.zoomOut[i]]=-t},_addHooks:function(){V(document,\"keydown\",this._onKeyDown,this)},_removeHooks:function(){q(document,\"keydown\",this._onKeyDown,this)},_onKeyDown:function(t){if(!(t.altKey||t.ctrlKey||t.metaKey)){var i,e=t.keyCode,n=this._map;if(e in this._panKeys){if(n._panAnim&&n._panAnim._inProgress)return;i=this._panKeys[e],t.shiftKey&&(i=w(i).multiplyBy(3)),n.panBy(i),n.options.maxBounds&&n.panInsideBounds(n.options.maxBounds)}else if(e in this._zoomKeys)n.setZoom(n.getZoom()+(t.shiftKey?3:1)*this._zoomKeys[e]);else{if(27!==e||!n._popup||!n._popup.options.closeOnEscapeKey)return;n.closePopup()}Q(t)}}});Le.addInitHook(\"addHandler\",\"keyboard\",Tn),Le.mergeOptions({scrollWheelZoom:!0,wheelDebounceTime:40,wheelPxPerZoomLevel:60});var zn=Ze.extend({addHooks:function(){V(this._map._container,\"mousewheel\",this._onWheelScroll,this),this._delta=0},removeHooks:function(){q(this._map._container,\"mousewheel\",this._onWheelScroll,this)},_onWheelScroll:function(t){var i=it(t),n=this._map.options.wheelDebounceTime;this._delta+=i,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date);var o=Math.max(n-(+new Date-this._startTime),0);clearTimeout(this._timer),this._timer=setTimeout(e(this._performZoom,this),o),Q(t)},_performZoom:function(){var t=this._map,i=t.getZoom(),e=this._map.options.zoomSnap||0;t._stop();var n=this._delta/(4*this._map.options.wheelPxPerZoomLevel),o=4*Math.log(2/(1+Math.exp(-Math.abs(n))))/Math.LN2,s=e?Math.ceil(o/e)*e:o,r=t._limitZoom(i+(this._delta>0?s:-s))-i;this._delta=0,this._startTime=null,r&&(\"center\"===t.options.scrollWheelZoom?t.setZoom(i+r):t.setZoomAround(this._lastMousePos,i+r))}});Le.addInitHook(\"addHandler\",\"scrollWheelZoom\",zn),Le.mergeOptions({tap:!0,tapTolerance:15});var Mn=Ze.extend({addHooks:function(){V(this._map._container,\"touchstart\",this._onDown,this)},removeHooks:function(){q(this._map._container,\"touchstart\",this._onDown,this)},_onDown:function(t){if(t.touches){if($(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new x(i.clientX,i.clientY),n.tagName&&\"a\"===n.tagName.toLowerCase()&&pt(n,\"leaflet-active\"),this._holdTimeout=setTimeout(e(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent(\"contextmenu\",i))},this),1e3),this._simulateEvent(\"mousedown\",i),V(document,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),q(document,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],e=i.target;e&&e.tagName&&\"a\"===e.tagName.toLowerCase()&&mt(e,\"leaflet-active\"),this._simulateEvent(\"mouseup\",i),this._isTapValid()&&this._simulateEvent(\"click\",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var i=t.touches[0];this._newPos=new x(i.clientX,i.clientY),this._simulateEvent(\"mousemove\",i)},_simulateEvent:function(t,i){var e=document.createEvent(\"MouseEvents\");e._simulated=!0,i.target._simulatedClick=!0,e.initMouseEvent(t,!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),i.target.dispatchEvent(e)}});Vi&&!Ui&&Le.addInitHook(\"addHandler\",\"tap\",Mn),Le.mergeOptions({touchZoom:Vi&&!zi,bounceAtZoomLimits:!0});var Cn=Ze.extend({addHooks:function(){pt(this._map._container,\"leaflet-touch-zoom\"),V(this._map._container,\"touchstart\",this._onTouchStart,this)},removeHooks:function(){mt(this._map._container,\"leaflet-touch-zoom\"),q(this._map._container,\"touchstart\",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),\"center\"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(e.add(n)._divideBy(2))),this._startDist=e.distanceTo(n),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),V(document,\"touchmove\",this._onTouchMove,this),V(document,\"touchend\",this._onTouchEnd,this),$(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var i=this._map,n=i.mouseEventToContainerPoint(t.touches[0]),o=i.mouseEventToContainerPoint(t.touches[1]),s=n.distanceTo(o)/this._startDist;if(this._zoom=i.getScaleZoom(s,this._startZoom),!i.options.bounceAtZoomLimits&&(this._zoom<i.getMinZoom()&&s<1||this._zoom>i.getMaxZoom()&&s>1)&&(this._zoom=i._limitZoom(this._zoom)),\"center\"===i.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=n._add(o)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=i.unproject(i.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(i._moveStart(!0,!1),this._moved=!0),g(this._animRequest);var a=e(i._move,i,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=f(a,this,!0),$(t)}},_onTouchEnd:function(){this._moved&&this._zooming?(this._zooming=!1,g(this._animRequest),q(document,\"touchmove\",this._onTouchMove),q(document,\"touchend\",this._onTouchEnd),this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom))):this._zooming=!1}});Le.addInitHook(\"addHandler\",\"touchZoom\",Cn),Le.BoxZoom=Ln,Le.DoubleClickZoom=Pn,Le.Drag=bn,Le.Keyboard=Tn,Le.ScrollWheelZoom=zn,Le.Tap=Mn,Le.TouchZoom=Cn;var Zn=window.L;window.L=t,Object.freeze=$t,t.version=\"1.3.1+HEAD.ba6f97f\",t.noConflict=function(){return window.L=Zn,this},t.Control=Pe,t.control=be,t.Browser=$i,t.Evented=ui,t.Mixin=Ee,t.Util=ai,t.Class=v,t.Handler=Ze,t.extend=i,t.bind=e,t.stamp=n,t.setOptions=l,t.DomEvent=de,t.DomUtil=xe,t.PosAnimation=we,t.Draggable=Be,t.LineUtil=Oe,t.PolyUtil=Re,t.Point=x,t.point=w,t.Bounds=P,t.bounds=b,t.Transformation=Z,t.transformation=S,t.Projection=je,t.LatLng=M,t.latLng=C,t.LatLngBounds=T,t.latLngBounds=z,t.CRS=ci,t.GeoJSON=nn,t.geoJSON=Kt,t.geoJson=sn,t.Layer=Ue,t.LayerGroup=Ve,t.layerGroup=function(t,i){return new Ve(t,i)},t.FeatureGroup=qe,t.featureGroup=function(t){return new qe(t)},t.ImageOverlay=rn,t.imageOverlay=function(t,i,e){return new rn(t,i,e)},t.VideoOverlay=an,t.videoOverlay=function(t,i,e){return new an(t,i,e)},t.DivOverlay=hn,t.Popup=un,t.popup=function(t,i){return new un(t,i)},t.Tooltip=ln,t.tooltip=function(t,i){return new ln(t,i)},t.Icon=Ge,t.icon=function(t){return new Ge(t)},t.DivIcon=cn,t.divIcon=function(t){return new cn(t)},t.Marker=Xe,t.marker=function(t,i){return new Xe(t,i)},t.TileLayer=dn,t.tileLayer=Yt,t.GridLayer=_n,t.gridLayer=function(t){return new _n(t)},t.SVG=xn,t.svg=Jt,t.Renderer=mn,t.Canvas=fn,t.canvas=Xt,t.Path=Je,t.CircleMarker=$e,t.circleMarker=function(t,i){return new $e(t,i)},t.Circle=Qe,t.circle=function(t,i,e){return new Qe(t,i,e)},t.Polyline=tn,t.polyline=function(t,i){return new tn(t,i)},t.Polygon=en,t.polygon=function(t,i){return new en(t,i)},t.Rectangle=wn,t.rectangle=function(t,i){return new wn(t,i)},t.Map=Le,t.map=function(t,i){return new Le(t,i)}});"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/app.less",
    "content": "/*\n * Load Main Bootstrap LESS files\n */\n\n@import 'vendors/bower_components/bootstrap/less/bootstrap';\n\n/*\n * LESS Plugins\n */\n@import 'inc/less-plugins/for';\n\n\n/*\n * Variable and Mixin\n */ \n\n@import 'inc/variables';\n@import 'inc/mixin';\n\n/* \n * Load Font\n */   \n@import 'inc/font'; \n \n/*\n * Vendors\n */\n@import 'vendors/weather-icons/weather-icons'; \n@import 'vendors/fileinput/fileinput';\n@import 'vendors/bower_components/material-shadows/material-shadows';  \n@import 'vendors/bower_components/Waves/src/less/waves';\n\n/* \n * Load Website related LESS files \n */  \n@import 'inc/generics';\n@import 'inc/bootstrap-overrides';\n@import 'inc/base';\n@import 'inc/list';\n@import 'inc/header'; \n@import 'inc/sidebar'; \n@import 'inc/dropdown'; \n@import 'inc/listview';\n@import 'inc/progress-bar'; \n@import 'inc/chat';\n@import 'inc/tabs';\n@import 'inc/card';\n@import 'inc/chart'; \n@import 'inc/widgets';\n@import 'inc/table';\n@import 'inc/todo';\n@import 'inc/button';\n@import 'inc/form';\n@import 'inc/pagination';\n@import 'inc/popover';\n@import 'inc/wizard';\n@import 'inc/alert'; \n@import 'inc/media';\n@import 'inc/modal';  \n@import 'inc/panel';\n@import 'inc/tooltip';\n@import 'inc/breadcrumb';\n@import 'inc/messages';\n@import 'inc/404';\n@import 'inc/login';\n@import 'inc/profile';\n@import 'inc/photos';\n@import 'inc/contacts'; \n@import 'inc/shadow'; \n@import 'inc/misc';\n@import 'inc/ie-warning';\n@import 'inc/footer';\n@import 'inc/pricing-table';\n@import 'inc/invoice';\n@import 'inc/wall';\n@import 'inc/skin';\n@import 'inc/preloader';\n\n@import 'inc/print'; \n\n/*\n * Vendor Overrides\n */\n@import 'inc/vendor-overrides/mediaelement';\n@import 'inc/vendor-overrides/fullcalendar';\n@import 'inc/vendor-overrides/bootgrid';\n@import 'inc/vendor-overrides/bootstrap-select';\n@import 'inc/vendor-overrides/chosen';\n@import 'inc/vendor-overrides/noUiSlider'; \n@import 'inc/vendor-overrides/farbtastic';\n@import 'inc/vendor-overrides/summernote';\n@import 'inc/vendor-overrides/bootstrap-datetimepicker';\n@import 'inc/vendor-overrides/fileinput';\n@import 'inc/vendor-overrides/light-gallery';\n@import 'inc/vendor-overrides/waves';\n@import 'inc/vendor-overrides/sweetalert';\n@import 'inc/vendor-overrides/typeahead';\n@import 'inc/vendor-overrides/malihu-custom-scrollbar';\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/404.less",
    "content": ".four-zero-content {\n\tbackground: #fff;\n\tpadding: 20px;\n\t\n\t&:before {\n\t\theight: 50%;\n\t\twidth: 100%;\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\tbackground: #EDECEC;\n\t\tcontent: \"\";\n\t}\n}\n\n.four-zero {\n\tbackground: @m-cyan;\n\tbox-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);\n\tborder-radius: 2px;\n\tposition: absolute;\n\ttop: 50%;\n\tmargin-top: -150px;\n\tcolor: #fff;\n\ttext-align: center;\n\tpadding: 15px;\n\theight: 300px;\n\twidth: 500px;\n\tleft: 50%;\n\tmargin-left: -250px;\n\t\n\th2 {\n\t\tfont-size: 130px;\n\t}\n\n\t\n\t@media (max-width: @screen-xs-max) {\n\t\twidth: ~\"calc(100% - 40px)\";\n\t\tleft: 20px;\n\t\tmargin-left: 0;\n\t\theight: 260px;\n\t\tmargin-top: -130px;\n\t\t\n\t\th2 {\n\t\t\tfont-size: 90px;\n\t\t}\n        }\n\t\n\th2 {\n\t\tline-height: 100%;\n\t\tcolor: #fff;\n\t\tfont-weight: 100;\n\t}\n\t\n\tsmall {\n\t\tdisplay: block;\n\t\tfont-size: 26px;\n\t\tmargin-top: -10px\n\t}\n\t\n\t\n\tfooter {\n\t\tbackground: rgba(0,0,0,0.13);\n\t\tposition: absolute;\n\t\tleft: 0;\n\t\tbottom: 0;\n\t\twidth: 100%;\n\t\tpadding: 10px;\n\t\t\n\t\t& > a {\n\t\t\tfont-size: 21px;\n\t\t\tdisplay: inline-block;\n\t\t\tcolor: #FFF;\n\t\t\tmargin: 0 1px;\n\t\t\tline-height: 40px;\n\t\t\twidth: 40px;\n\t\t\theight: 40px;\n\t\t\tbackground: rgba(0, 0, 0, 0.09);\n\t\t\tborder-radius: 50%;\n\t\t\ttext-align: center;\n\t\t\t.transition(all);\n\t\t\t.transition-duration(300ms);\n\t\t\t\n\t\t\t&:hover {\n\t\t\t\tbackground: rgba(0, 0, 0, 0.2);\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/alert.less",
    "content": ".alert {\n    padding-left: 30px;\n    font-size: 13px;\n    \n    span {\n        cursor: pointer;\n    }\n\n    &:not(.alert-dismissible) {\n        padding-right: 30px;\n    }\n\n    &.alert-dismissable {\n        padding-right: 44px;\n    } \n}\n\n.alert-inverse {\n    .alert-variant(@alert-inverse-bg; @alert-inverse-border; @alert-inverse-text);\n}\n\n.growl-animated {\n    &.alert-inverse {\n        box-shadow: 0 0 5px fade(@alert-inverse-bg, 50%);\n    }\n    \n    &.alert-info {\n        box-shadow: 0 0 5px fade(@alert-info-bg, 50%);\n    }\n\n    &.alert-success {\n        box-shadow: 0 0 5px fade(@alert-success-bg, 50%);\n    }\n\n    &.alert-warning {\n        box-shadow: 0 0 5px fade(@alert-warning-bg, 50%);\n    }\n\n    &.alert-danger {\n        box-shadow: 0 0 5px fade(@alert-danger-bg, 50%);\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/base.less",
    "content": "*, button, input, i, a {\n    -webkit-font-smoothing: antialiased;\n}\n\n*,\n*:active,\n*:hover {\n    outline: none !important;\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n}\n\nhtml {\n    overflow-x: ~\"hidden\\0/\";\n    -ms-overflow-style: none;\n}\n\nhtml, body {\n    min-height: 100vh; \n} \n\nbody {\n    font-weight: 400;\n    position: relative;\n}\n\naudio, video {  \n      outline: none;\n}\n\np {\n    margin-bottom: 20px;\n}\n\nsmall {\n    font-size: 11px;\n}\n\nh1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 {\n    small {\n        font-size: 12px;\n    }\n}\n\n#main {\n    position: relative;\n    padding-bottom: @footer-height;\n    padding-top: @header-height + 30;\n}\n\n.container {\n    &.c-alt {\n        max-width: 1170px;\n    }\n}\n\n @media (min-width: @screen-sm-min) and (max-width: @screen-md-max) {\n    #content {\n        padding-left: 15px;\n        padding-right: 15px;\n    }\n}\n\nbody {\n    &.sw-toggled {\n        #content {\n            @media (min-width: @screen-lg-min) {\n                padding-left: @sidebar-left-width;\n            }\n\n            & > .container {\n                @media (min-width: @screen-lg-min) {\n                    width: ~\"calc(100% - 30px)\";\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/alerts.less",
    "content": "//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n  padding: @alert-padding;\n  margin-bottom: @line-height-computed;\n  border: 1px solid transparent;\n  border-radius: @alert-border-radius;\n\n  // Headings for larger alerts\n  h4 {\n    margin-top: 0;\n    // Specified for the h4 to prevent conflicts of changing @headings-color\n    color: inherit;\n  }\n\n  // Provide class for links that match alerts\n  .alert-link {\n    font-weight: @alert-link-font-weight;\n  }\n\n  // Improve alignment and spacing of inner content\n  > p,\n  > ul {\n    margin-bottom: 0;\n  }\n\n  > p + p {\n    margin-top: 5px;\n  }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n  padding-right: (@alert-padding + 20);\n\n  // Adjust close link position\n  .close {\n    position: relative;\n    top: -2px;\n    right: -21px;\n    color: inherit;\n  }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n  .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n  .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n  .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n  .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/badges.less",
    "content": "//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: @font-size-small;\n  font-weight: @badge-font-weight;\n  color: @badge-color;\n  line-height: @badge-line-height;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: @badge-bg;\n  border-radius: @badge-border-radius;\n\n  // Empty badges collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for badges in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n\n  .btn-xs &,\n  .btn-group-xs > .btn & {\n    top: 0;\n    padding: 1px 5px;\n  }\n\n  // Hover state, but only for links\n  a& {\n    &:hover,\n    &:focus {\n      color: @badge-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Account for badges in navs\n  .list-group-item.active > &,\n  .nav-pills > .active > a > & {\n    color: @badge-active-color;\n    background-color: @badge-active-bg;\n  }\n\n  .list-group-item > & {\n    float: right;\n  }\n\n  .list-group-item > & + & {\n    margin-right: 5px;\n  }\n\n  .nav-pills > li > a > & {\n    margin-left: 3px;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/bootstrap.less",
    "content": "// Core variables and mixins\n@import \"variables.less\";\n@import \"mixins.less\";\n\n// Reset and dependencies\n@import \"normalize.less\";\n@import \"print.less\";\n@import \"glyphicons.less\";\n\n// Core CSS\n@import \"scaffolding.less\";\n@import \"type.less\";\n@import \"code.less\";\n@import \"grid.less\";\n@import \"tables.less\";\n@import \"forms.less\";\n@import \"buttons.less\";\n\n// Components\n@import \"component-animations.less\";\n@import \"dropdowns.less\";\n@import \"button-groups.less\";\n@import \"input-groups.less\";\n@import \"navs.less\";\n@import \"navbar.less\";\n@import \"breadcrumbs.less\";\n@import \"pagination.less\";\n@import \"pager.less\";\n@import \"labels.less\";\n@import \"badges.less\";\n@import \"jumbotron.less\";\n@import \"thumbnails.less\";\n@import \"alerts.less\";\n@import \"progress-bars.less\";\n@import \"media.less\";\n@import \"list-group.less\";\n@import \"panels.less\";\n@import \"responsive-embed.less\";\n@import \"wells.less\";\n@import \"close.less\";\n\n// Components w/ JavaScript\n@import \"modals.less\";\n@import \"tooltip.less\";\n@import \"popovers.less\";\n@import \"carousel.less\";\n\n// Utility classes\n@import \"utilities.less\";\n@import \"responsive-utilities.less\";\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/breadcrumbs.less",
    "content": "//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n  padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n  margin-bottom: @line-height-computed;\n  list-style: none;\n  background-color: @breadcrumb-bg;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline-block;\n\n    + li:before {\n      content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n      padding: 0 5px;\n      color: @breadcrumb-color;\n    }\n  }\n\n  > .active {\n    color: @breadcrumb-active-color;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/button-groups.less",
    "content": "//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle; // match .btn alignment given font-size hack above\n  > .btn {\n    position: relative;\n    float: left;\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active,\n    &.active {\n      z-index: 2;\n    }\n  }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n  .btn + .btn,\n  .btn + .btn-group,\n  .btn-group + .btn,\n  .btn-group + .btn-group {\n    margin-left: -1px;\n  }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n  margin-left: -5px; // Offset the first child's margin\n  &:extend(.clearfix all);\n\n  .btn-group,\n  .input-group {\n    float: left;\n  }\n  > .btn,\n  > .btn-group,\n  > .input-group {\n    margin-left: 5px;\n  }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n  margin-left: 0;\n  &:not(:last-child):not(.dropdown-toggle) {\n    .border-right-radius(0);\n  }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n  .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\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) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-right-radius(0);\n  }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n  padding-left: 8px;\n  padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n  .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n  // Show no shadow for `.btn-link` since it has no other button styles.\n  &.btn-link {\n    .box-shadow(none);\n  }\n}\n\n\n// Reposition the caret\n.btn .caret {\n  margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n  border-width: @caret-width-large @caret-width-large 0;\n  border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n  border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n  > .btn,\n  > .btn-group,\n  > .btn-group > .btn {\n    display: block;\n    float: none;\n    width: 100%;\n    max-width: 100%;\n  }\n\n  // Clear floats so dropdown menus can be properly placed\n  > .btn-group {\n    &:extend(.clearfix all);\n    > .btn {\n      float: none;\n    }\n  }\n\n  > .btn + .btn,\n  > .btn + .btn-group,\n  > .btn-group + .btn,\n  > .btn-group + .btn-group {\n    margin-top: -1px;\n    margin-left: 0;\n  }\n}\n\n.btn-group-vertical > .btn {\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n  &:first-child:not(:last-child) {\n    border-top-right-radius: @border-radius-base;\n    .border-bottom-radius(0);\n  }\n  &:last-child:not(:first-child) {\n    border-bottom-left-radius: @border-radius-base;\n    .border-top-radius(0);\n  }\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) {\n  > .btn:last-child,\n  > .dropdown-toggle {\n    .border-bottom-radius(0);\n  }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n  .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n  > .btn,\n  > .btn-group {\n    float: none;\n    display: table-cell;\n    width: 1%;\n  }\n  > .btn-group .btn {\n    width: 100%;\n  }\n\n  > .btn-group .dropdown-menu {\n    left: auto;\n  }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n  > .btn,\n  > .btn-group > .btn {\n    input[type=\"radio\"],\n    input[type=\"checkbox\"] {\n      position: absolute;\n      clip: rect(0,0,0,0);\n      pointer-events: none;\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/buttons.less",
    "content": "//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n  display: inline-block;\n  margin-bottom: 0; // For input.btn\n  font-weight: @btn-font-weight;\n  text-align: center;\n  vertical-align: middle;\n  touch-action: manipulation;\n  cursor: pointer;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  white-space: nowrap;\n  .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @border-radius-base);\n  .user-select(none);\n\n  &,\n  &:active,\n  &.active {\n    &:focus,\n    &.focus {\n      .tab-focus();\n    }\n  }\n\n  &:hover,\n  &:focus,\n  &.focus {\n    color: @btn-default-color;\n    text-decoration: none;\n  }\n\n  &:active,\n  &.active {\n    outline: 0;\n    background-image: none;\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n    .opacity(.65);\n    .box-shadow(none);\n  }\n\n  a& {\n    &.disabled,\n    fieldset[disabled] & {\n      pointer-events: none; // Future-proof disabling of clicks on `<a>` elements\n    }\n  }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n  .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n  .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n  .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n  .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n  .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n  .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n  color: @link-color;\n  font-weight: normal;\n  border-radius: 0;\n\n  &,\n  &:active,\n  &.active,\n  &[disabled],\n  fieldset[disabled] & {\n    background-color: transparent;\n    .box-shadow(none);\n  }\n  &,\n  &:hover,\n  &:focus,\n  &:active {\n    border-color: transparent;\n  }\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: @link-hover-decoration;\n    background-color: transparent;\n  }\n  &[disabled],\n  fieldset[disabled] & {\n    &:hover,\n    &:focus {\n      color: @btn-link-disabled-color;\n      text-decoration: none;\n    }\n  }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n  // line-height: ensure even-numbered height of button next to large input\n  .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n.btn-sm {\n  // line-height: ensure proper height of button next to small input\n  .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n.btn-xs {\n  .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n  display: block;\n  width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n  margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n  &.btn-block {\n    width: 100%;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/carousel.less",
    "content": "//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n  position: relative;\n}\n\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n\n  > .item {\n    display: none;\n    position: relative;\n    .transition(.6s ease-in-out left);\n\n    // Account for jankitude on images\n    > img,\n    > a > img {\n      &:extend(.img-responsive);\n      line-height: 1;\n    }\n\n    // WebKit CSS3 transforms for supported devices\n    @media all and (transform-3d), (-webkit-transform-3d) {\n      .transition-transform(~'0.6s ease-in-out');\n      .backface-visibility(~'hidden');\n      .perspective(1000);\n\n      &.next,\n      &.active.right {\n        .translate3d(100%, 0, 0);\n        left: 0;\n      }\n      &.prev,\n      &.active.left {\n        .translate3d(-100%, 0, 0);\n        left: 0;\n      }\n      &.next.left,\n      &.prev.right,\n      &.active {\n        .translate3d(0, 0, 0);\n        left: 0;\n      }\n    }\n  }\n\n  > .active,\n  > .next,\n  > .prev {\n    display: block;\n  }\n\n  > .active {\n    left: 0;\n  }\n\n  > .next,\n  > .prev {\n    position: absolute;\n    top: 0;\n    width: 100%;\n  }\n\n  > .next {\n    left: 100%;\n  }\n  > .prev {\n    left: -100%;\n  }\n  > .next.left,\n  > .prev.right {\n    left: 0;\n  }\n\n  > .active.left {\n    left: -100%;\n  }\n  > .active.right {\n    left: 100%;\n  }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n  position: absolute;\n  top: 0;\n  left: 0;\n  bottom: 0;\n  width: @carousel-control-width;\n  .opacity(@carousel-control-opacity);\n  font-size: @carousel-control-font-size;\n  color: @carousel-control-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  // We can't have this transition here because WebKit cancels the carousel\n  // animation if you trip this while in the middle of another animation.\n\n  // Set gradients for backgrounds\n  &.left {\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n  }\n  &.right {\n    left: auto;\n    right: 0;\n    #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n  }\n\n  // Hover/focus state\n  &:hover,\n  &:focus {\n    outline: 0;\n    color: @carousel-control-color;\n    text-decoration: none;\n    .opacity(.9);\n  }\n\n  // Toggles\n  .icon-prev,\n  .icon-next,\n  .glyphicon-chevron-left,\n  .glyphicon-chevron-right {\n    position: absolute;\n    top: 50%;\n    z-index: 5;\n    display: inline-block;\n  }\n  .icon-prev,\n  .glyphicon-chevron-left {\n    left: 50%;\n    margin-left: -10px;\n  }\n  .icon-next,\n  .glyphicon-chevron-right {\n    right: 50%;\n    margin-right: -10px;\n  }\n  .icon-prev,\n  .icon-next {\n    width:  20px;\n    height: 20px;\n    margin-top: -10px;\n    line-height: 1;\n    font-family: serif;\n  }\n\n\n  .icon-prev {\n    &:before {\n      content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n    }\n  }\n  .icon-next {\n    &:before {\n      content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n    }\n  }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n  position: absolute;\n  bottom: 10px;\n  left: 50%;\n  z-index: 15;\n  width: 60%;\n  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n\n  li {\n    display: inline-block;\n    width:  10px;\n    height: 10px;\n    margin: 1px;\n    text-indent: -999px;\n    border: 1px solid @carousel-indicator-border-color;\n    border-radius: 10px;\n    cursor: pointer;\n\n    // IE8-9 hack for event handling\n    //\n    // Internet Explorer 8-9 does not support clicks on elements without a set\n    // `background-color`. We cannot use `filter` since that's not viewed as a\n    // background color by the browser. Thus, a hack is needed.\n    // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer\n    //\n    // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n    // set alpha transparency for the best results possible.\n    background-color: #000 \\9; // IE8\n    background-color: rgba(0,0,0,0); // IE9\n  }\n  .active {\n    margin: 0;\n    width:  12px;\n    height: 12px;\n    background-color: @carousel-indicator-active-bg;\n  }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: @carousel-caption-color;\n  text-align: center;\n  text-shadow: @carousel-text-shadow;\n  & .btn {\n    text-shadow: none; // No shadow for button elements in carousel-caption\n  }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n  // Scale up the controls a smidge\n  .carousel-control {\n    .glyphicon-chevron-left,\n    .glyphicon-chevron-right,\n    .icon-prev,\n    .icon-next {\n      width: 30px;\n      height: 30px;\n      margin-top: -15px;\n      font-size: 30px;\n    }\n    .glyphicon-chevron-left,\n    .icon-prev {\n      margin-left: -15px;\n    }\n    .glyphicon-chevron-right,\n    .icon-next {\n      margin-right: -15px;\n    }\n  }\n\n  // Show and left align the captions\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n\n  // Move up the indicators\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/close.less",
    "content": "//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n  float: right;\n  font-size: (@font-size-base * 1.5);\n  font-weight: @close-font-weight;\n  line-height: 1;\n  color: @close-color;\n  text-shadow: @close-text-shadow;\n  .opacity(.2);\n\n  &:hover,\n  &:focus {\n    color: @close-color;\n    text-decoration: none;\n    cursor: pointer;\n    .opacity(.5);\n  }\n\n  // Additional properties for button version\n  // iOS requires the button element instead of an anchor tag.\n  // If you want the anchor version, it requires `href=\"#\"`.\n  // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n  button& {\n    padding: 0;\n    cursor: pointer;\n    background: transparent;\n    border: 0;\n    -webkit-appearance: none;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/code.less",
    "content": "//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n  font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @code-color;\n  background-color: @code-bg;\n  border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: @kbd-color;\n  background-color: @kbd-bg;\n  border-radius: @border-radius-small;\n  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n  kbd {\n    padding: 0;\n    font-size: 100%;\n    font-weight: bold;\n    box-shadow: none;\n  }\n}\n\n// Blocks of code\npre {\n  display: block;\n  padding: ((@line-height-computed - 1) / 2);\n  margin: 0 0 (@line-height-computed / 2);\n  font-size: (@font-size-base - 1); // 14px to 13px\n  line-height: @line-height-base;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: @pre-color;\n  background-color: @pre-bg;\n  border: 1px solid @pre-border-color;\n  border-radius: @border-radius-base;\n\n  // Account for some code outputs that place code tags in pre tags\n  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}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n  max-height: @pre-scrollable-max-height;\n  overflow-y: scroll;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/component-animations.less",
    "content": "//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n  opacity: 0;\n  .transition(opacity .15s linear);\n  &.in {\n    opacity: 1;\n  }\n}\n\n.collapse {\n  display: none;\n\n  &.in      { display: block; }\n  tr&.in    { display: table-row; }\n  tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  .transition-property(~\"height, visibility\");\n  .transition-duration(.35s);\n  .transition-timing-function(ease);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/dropdowns.less",
    "content": "//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top:   @caret-width-base dashed;\n  border-right: @caret-width-base solid transparent;\n  border-left:  @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n  position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n  outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n  position: absolute;\n  top: 100%;\n  left: 0;\n  z-index: @zindex-dropdown;\n  display: none; // none by default, but block on \"open\" of the menu\n  float: left;\n  min-width: 160px;\n  padding: 5px 0;\n  margin: 2px 0 0; // override default ul\n  list-style: none;\n  font-size: @font-size-base;\n  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n  background-color: @dropdown-bg;\n  border: 1px solid @dropdown-fallback-border; // IE8 fallback\n  border: 1px solid @dropdown-border;\n  border-radius: @border-radius-base;\n  .box-shadow(0 6px 12px rgba(0,0,0,.175));\n  background-clip: padding-box;\n\n  // Aligns the dropdown menu to right\n  //\n  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n  &.pull-right {\n    right: 0;\n    left: auto;\n  }\n\n  // Dividers (basically an hr) within the dropdown\n  .divider {\n    .nav-divider(@dropdown-divider-bg);\n  }\n\n  // Links within the dropdown menu\n  > li > a {\n    display: block;\n    padding: 3px 20px;\n    clear: both;\n    font-weight: normal;\n    line-height: @line-height-base;\n    color: @dropdown-link-color;\n    white-space: nowrap; // prevent links from randomly breaking onto new lines\n  }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @dropdown-link-hover-color;\n    background-color: @dropdown-link-hover-bg;\n  }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-active-color;\n    text-decoration: none;\n    outline: 0;\n    background-color: @dropdown-link-active-bg;\n  }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n  &,\n  &:hover,\n  &:focus {\n    color: @dropdown-link-disabled-color;\n  }\n\n  // Nuke hover/focus effects\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    background-color: transparent;\n    background-image: none; // Remove CSS gradient\n    .reset-filter();\n    cursor: @cursor-disabled;\n  }\n}\n\n// Open state for the dropdown\n.open {\n  // Show the menu\n  > .dropdown-menu {\n    display: block;\n  }\n\n  // Remove the outline when :focus is triggered\n  > a {\n    outline: 0;\n  }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n  left: auto; // Reset the default from `.dropdown-menu`\n  right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n  left: 0;\n  right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: @font-size-small;\n  line-height: @line-height-base;\n  color: @dropdown-header-color;\n  white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n  // Reverse the caret\n  .caret {\n    border-top: 0;\n    border-bottom: @caret-width-base solid;\n    content: \"\";\n  }\n  // Different positioning for bottom up menu\n  .dropdown-menu {\n    top: auto;\n    bottom: 100%;\n    margin-bottom: 2px;\n  }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-right {\n    .dropdown-menu {\n      .dropdown-menu-right();\n    }\n    // Necessary for overrides of the default right aligned menu.\n    // Will remove come v4 in all likelihood.\n    .dropdown-menu-left {\n      .dropdown-menu-left();\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/forms.less",
    "content": "//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n  // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n  // so we reset that to ensure it behaves more like a standard block element.\n  // See https://github.com/twbs/bootstrap/issues/12359.\n  min-width: 0;\n}\n\nlegend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: @line-height-computed;\n  font-size: (@font-size-base * 1.5);\n  line-height: inherit;\n  color: @legend-color;\n  border: 0;\n  border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n  display: inline-block;\n  max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n  .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9; // IE8-9\n  line-height: normal;\n}\n\n// Set the height of file controls to match text inputs\ninput[type=\"file\"] {\n  display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n  display: block;\n  width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n  height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n  .tab-focus();\n}\n\n// Adjust output element\noutput {\n  display: block;\n  padding-top: (@padding-base-vertical + 1);\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n  display: block;\n  width: 100%;\n  height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @input-color;\n  background-color: @input-bg;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid @input-border;\n  border-radius: @input-border-radius; // Note: This has no effect on <select>s in some browsers, due to the limited stylability of <select>s in CSS.\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n  .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n  // Customize the `:focus` state to imitate native WebKit styles.\n  .form-control-focus();\n\n  // Placeholder\n  .placeholder();\n\n  // Disabled and read-only inputs\n  //\n  // HTML5 says that controls under a fieldset > legend:first-child won't be\n  // disabled if the fieldset is disabled. Due to implementation difficulty, we\n  // don't honor that edge case; we style them as disabled anyway.\n  &[disabled],\n  &[readonly],\n  fieldset[disabled] & {\n    background-color: @input-bg-disabled;\n    opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655\n  }\n\n  &[disabled],\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n\n  // Reset height for `textarea`s\n  textarea& {\n    height: auto;\n  }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n  -webkit-appearance: none;\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned. As a workaround, we\n// set a pixel line-height that matches the given height of the input, but only\n// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n  input[type=\"date\"],\n  input[type=\"time\"],\n  input[type=\"datetime-local\"],\n  input[type=\"month\"] {\n    line-height: @input-height-base;\n\n    &.input-sm,\n    .input-group-sm & {\n      line-height: @input-height-small;\n    }\n\n    &.input-lg,\n    .input-group-lg & {\n      line-height: @input-height-large;\n    }\n  }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n  margin-bottom: @form-group-margin-bottom;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n  position: relative;\n  display: block;\n  margin-top: 10px;\n  margin-bottom: 10px;\n\n  label {\n    min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n    padding-left: 20px;\n    margin-bottom: 0;\n    font-weight: normal;\n    cursor: pointer;\n  }\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-left: -20px;\n  margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n  margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n  position: relative;\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n// Some special care is needed because <label>s don't inherit their parent's `cursor`.\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n  &[disabled],\n  &.disabled,\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n}\n// These classes are used directly on <label>s\n.radio-inline,\n.checkbox-inline {\n  &.disabled,\n  fieldset[disabled] & {\n    cursor: @cursor-disabled;\n  }\n}\n// These classes are used on elements with <label> descendants\n.radio,\n.checkbox {\n  &.disabled,\n  fieldset[disabled] & {\n    label {\n      cursor: @cursor-disabled;\n    }\n  }\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n  // Size it appropriately next to real form controls\n  padding-top: (@padding-base-vertical + 1);\n  padding-bottom: (@padding-base-vertical + 1);\n  // Remove default margin from `p`\n  margin-bottom: 0;\n  min-height: (@line-height-computed + @font-size-base);\n\n  &.input-lg,\n  &.input-sm {\n    padding-left: 0;\n    padding-right: 0;\n  }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n//\n// The `.form-group-* form-control` variations are sadly duplicated to avoid the\n// issue documented in https://github.com/twbs/bootstrap/issues/15074.\n\n.input-sm {\n  .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n}\n.form-group-sm {\n  .form-control {\n    .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n  }\n  .form-control-static {\n    height: @input-height-small;\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    line-height: @line-height-small;\n    min-height: (@line-height-computed + @font-size-small);\n  }\n}\n\n.input-lg {\n  .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n}\n.form-group-lg {\n  .form-control {\n    .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n  }\n  .form-control-static {\n    height: @input-height-large;\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    line-height: @line-height-large;\n    min-height: (@line-height-computed + @font-size-large);\n  }\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n  // Enable absolute positioning\n  position: relative;\n\n  // Ensure icons don't overlap text\n  .form-control {\n    padding-right: (@input-height-base * 1.25);\n  }\n}\n// Feedback icon (requires .glyphicon classes)\n.form-control-feedback {\n  position: absolute;\n  top: 0;\n  right: 0;\n  z-index: 2; // Ensure icon is above input groups\n  display: block;\n  width: @input-height-base;\n  height: @input-height-base;\n  line-height: @input-height-base;\n  text-align: center;\n  pointer-events: none;\n}\n.input-lg + .form-control-feedback {\n  width: @input-height-large;\n  height: @input-height-large;\n  line-height: @input-height-large;\n}\n.input-sm + .form-control-feedback {\n  width: @input-height-small;\n  height: @input-height-small;\n  line-height: @input-height-small;\n}\n\n// Feedback states\n.has-success {\n  .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n  .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n  .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n// Reposition feedback icon if input has visible label above\n.has-feedback label {\n\n  & ~ .form-control-feedback {\n     top: (@line-height-computed + 5); // Height of the `label` and its margin\n  }\n  &.sr-only ~ .form-control-feedback {\n     top: 0;\n  }\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n  display: block; // account for any element using help-block\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n  // Kick in the inline\n  @media (min-width: @screen-sm-min) {\n    // Inline-block all the things for \"inline\"\n    .form-group {\n      display: inline-block;\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // In navbar-form, allow folks to *not* use `.form-group`\n    .form-control {\n      display: inline-block;\n      width: auto; // Prevent labels from stacking above inputs in `.form-group`\n      vertical-align: middle;\n    }\n\n    // Make static controls behave like regular ones\n    .form-control-static {\n      display: inline-block;\n    }\n\n    .input-group {\n      display: inline-table;\n      vertical-align: middle;\n\n      .input-group-addon,\n      .input-group-btn,\n      .form-control {\n        width: auto;\n      }\n    }\n\n    // Input groups need that 100% width though\n    .input-group > .form-control {\n      width: 100%;\n    }\n\n    .control-label {\n      margin-bottom: 0;\n      vertical-align: middle;\n    }\n\n    // Remove default margin on radios/checkboxes that were used for stacking, and\n    // then undo the floating of radios and checkboxes to match.\n    .radio,\n    .checkbox {\n      display: inline-block;\n      margin-top: 0;\n      margin-bottom: 0;\n      vertical-align: middle;\n\n      label {\n        padding-left: 0;\n      }\n    }\n    .radio input[type=\"radio\"],\n    .checkbox input[type=\"checkbox\"] {\n      position: relative;\n      margin-left: 0;\n    }\n\n    // Re-override the feedback icon.\n    .has-feedback .form-control-feedback {\n      top: 0;\n    }\n  }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n  // Consistent vertical alignment of radios and checkboxes\n  //\n  // Labels also get some reset styles, but that is scoped to a media query below.\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline {\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n  }\n  // Account for padding we're adding to ensure the alignment and of help text\n  // and other content below items\n  .radio,\n  .checkbox {\n    min-height: (@line-height-computed + (@padding-base-vertical + 1));\n  }\n\n  // Make form groups behave like rows\n  .form-group {\n    .make-row();\n  }\n\n  // Reset spacing and right align labels, but scope to media queries so that\n  // labels on narrow viewports stack the same as a default form example.\n  @media (min-width: @screen-sm-min) {\n    .control-label {\n      text-align: right;\n      margin-bottom: 0;\n      padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n    }\n  }\n\n  // Validation states\n  //\n  // Reposition the icon because it's now within a grid column and columns have\n  // `position: relative;` on them. Also accounts for the grid gutter padding.\n  .has-feedback .form-control-feedback {\n    right: (@grid-gutter-width / 2);\n  }\n\n  // Form group sizes\n  //\n  // Quick utility class for applying `.input-lg` and `.input-sm` styles to the\n  // inputs and labels within a `.form-group`.\n  .form-group-lg {\n    @media (min-width: @screen-sm-min) {\n      .control-label {\n        padding-top: ((@padding-large-vertical * @line-height-large) + 1);\n      }\n    }\n  }\n  .form-group-sm {\n    @media (min-width: @screen-sm-min) {\n      .control-label {\n        padding-top: (@padding-small-vertical + 1);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/glyphicons.less",
    "content": "//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n  font-family: 'Glyphicons Halflings';\n  src: url('@{icon-font-path}@{icon-font-name}.eot');\n  src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n       url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),\n       url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n       url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n       url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\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  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk               { &:before { content: \"\\2a\"; } }\n.glyphicon-plus                   { &:before { content: \"\\2b\"; } }\n.glyphicon-euro,\n.glyphicon-eur                    { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus                  { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud                  { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope               { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil                 { &:before { content: \"\\270f\"; } }\n.glyphicon-glass                  { &:before { content: \"\\e001\"; } }\n.glyphicon-music                  { &:before { content: \"\\e002\"; } }\n.glyphicon-search                 { &:before { content: \"\\e003\"; } }\n.glyphicon-heart                  { &:before { content: \"\\e005\"; } }\n.glyphicon-star                   { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty             { &:before { content: \"\\e007\"; } }\n.glyphicon-user                   { &:before { content: \"\\e008\"; } }\n.glyphicon-film                   { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large               { &:before { content: \"\\e010\"; } }\n.glyphicon-th                     { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list                { &:before { content: \"\\e012\"; } }\n.glyphicon-ok                     { &:before { content: \"\\e013\"; } }\n.glyphicon-remove                 { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in                { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out               { &:before { content: \"\\e016\"; } }\n.glyphicon-off                    { &:before { content: \"\\e017\"; } }\n.glyphicon-signal                 { &:before { content: \"\\e018\"; } }\n.glyphicon-cog                    { &:before { content: \"\\e019\"; } }\n.glyphicon-trash                  { &:before { content: \"\\e020\"; } }\n.glyphicon-home                   { &:before { content: \"\\e021\"; } }\n.glyphicon-file                   { &:before { content: \"\\e022\"; } }\n.glyphicon-time                   { &:before { content: \"\\e023\"; } }\n.glyphicon-road                   { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt           { &:before { content: \"\\e025\"; } }\n.glyphicon-download               { &:before { content: \"\\e026\"; } }\n.glyphicon-upload                 { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox                  { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle            { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat                 { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh                { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt               { &:before { content: \"\\e032\"; } }\n.glyphicon-lock                   { &:before { content: \"\\e033\"; } }\n.glyphicon-flag                   { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones             { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off             { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down            { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up              { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode                 { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode                { &:before { content: \"\\e040\"; } }\n.glyphicon-tag                    { &:before { content: \"\\e041\"; } }\n.glyphicon-tags                   { &:before { content: \"\\e042\"; } }\n.glyphicon-book                   { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark               { &:before { content: \"\\e044\"; } }\n.glyphicon-print                  { &:before { content: \"\\e045\"; } }\n.glyphicon-camera                 { &:before { content: \"\\e046\"; } }\n.glyphicon-font                   { &:before { content: \"\\e047\"; } }\n.glyphicon-bold                   { &:before { content: \"\\e048\"; } }\n.glyphicon-italic                 { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height            { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width             { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left             { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center           { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right            { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify          { &:before { content: \"\\e055\"; } }\n.glyphicon-list                   { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left            { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right           { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video         { &:before { content: \"\\e059\"; } }\n.glyphicon-picture                { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker             { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust                 { &:before { content: \"\\e063\"; } }\n.glyphicon-tint                   { &:before { content: \"\\e064\"; } }\n.glyphicon-edit                   { &:before { content: \"\\e065\"; } }\n.glyphicon-share                  { &:before { content: \"\\e066\"; } }\n.glyphicon-check                  { &:before { content: \"\\e067\"; } }\n.glyphicon-move                   { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward          { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward          { &:before { content: \"\\e070\"; } }\n.glyphicon-backward               { &:before { content: \"\\e071\"; } }\n.glyphicon-play                   { &:before { content: \"\\e072\"; } }\n.glyphicon-pause                  { &:before { content: \"\\e073\"; } }\n.glyphicon-stop                   { &:before { content: \"\\e074\"; } }\n.glyphicon-forward                { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward           { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward           { &:before { content: \"\\e077\"; } }\n.glyphicon-eject                  { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left           { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right          { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign              { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign             { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign            { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign                { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign          { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign              { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot             { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle          { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle              { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle             { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left             { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right            { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up               { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down             { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt              { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full            { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small           { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign       { &:before { content: \"\\e101\"; } }\n.glyphicon-gift                   { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf                   { &:before { content: \"\\e103\"; } }\n.glyphicon-fire                   { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open               { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close              { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign           { &:before { content: \"\\e107\"; } }\n.glyphicon-plane                  { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar               { &:before { content: \"\\e109\"; } }\n.glyphicon-random                 { &:before { content: \"\\e110\"; } }\n.glyphicon-comment                { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet                 { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up             { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down           { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet                { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart          { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close           { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open            { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical        { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal      { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd                    { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn               { &:before { content: \"\\e122\"; } }\n.glyphicon-bell                   { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate            { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up              { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down            { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right             { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left              { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up                { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down              { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right     { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left      { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up        { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down      { &:before { content: \"\\e134\"; } }\n.glyphicon-globe                  { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench                 { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks                  { &:before { content: \"\\e137\"; } }\n.glyphicon-filter                 { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase              { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen             { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard              { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip              { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty            { &:before { content: \"\\e143\"; } }\n.glyphicon-link                   { &:before { content: \"\\e144\"; } }\n.glyphicon-phone                  { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin                { &:before { content: \"\\e146\"; } }\n.glyphicon-usd                    { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp                    { &:before { content: \"\\e149\"; } }\n.glyphicon-sort                   { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet       { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt   { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order          { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt      { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes     { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked              { &:before { content: \"\\e157\"; } }\n.glyphicon-expand                 { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down          { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up            { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in                 { &:before { content: \"\\e161\"; } }\n.glyphicon-flash                  { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out                { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window             { &:before { content: \"\\e164\"; } }\n.glyphicon-record                 { &:before { content: \"\\e165\"; } }\n.glyphicon-save                   { &:before { content: \"\\e166\"; } }\n.glyphicon-open                   { &:before { content: \"\\e167\"; } }\n.glyphicon-saved                  { &:before { content: \"\\e168\"; } }\n.glyphicon-import                 { &:before { content: \"\\e169\"; } }\n.glyphicon-export                 { &:before { content: \"\\e170\"; } }\n.glyphicon-send                   { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk            { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved           { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove          { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save            { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open            { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card            { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer               { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery                { &:before { content: \"\\e179\"; } }\n.glyphicon-header                 { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed             { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone               { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt              { &:before { content: \"\\e183\"; } }\n.glyphicon-tower                  { &:before { content: \"\\e184\"; } }\n.glyphicon-stats                  { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video               { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video               { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles              { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo           { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby            { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1              { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1              { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1              { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark         { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark      { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download         { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload           { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer           { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous         { &:before { content: \"\\e200\"; } }\n.glyphicon-cd                     { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file              { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file              { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up               { &:before { content: \"\\e204\"; } }\n.glyphicon-copy                   { &:before { content: \"\\e205\"; } }\n.glyphicon-paste                  { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door                   { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key                    { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert                  { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer              { &:before { content: \"\\e210\"; } }\n.glyphicon-king                   { &:before { content: \"\\e211\"; } }\n.glyphicon-queen                  { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn                   { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop                 { &:before { content: \"\\e214\"; } }\n.glyphicon-knight                 { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula           { &:before { content: \"\\e216\"; } }\n.glyphicon-tent                   { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard             { &:before { content: \"\\e218\"; } }\n.glyphicon-bed                    { &:before { content: \"\\e219\"; } }\n.glyphicon-apple                  { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase                  { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass              { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp                   { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate              { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank             { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors               { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin                { &:before { content: \"\\e227\"; } }\n.glyphicon-btc                    { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt                    { &:before { content: \"\\e227\"; } }\n.glyphicon-yen                    { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy                    { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble                  { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub                    { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale                  { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly              { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted       { &:before { content: \"\\e232\"; } }\n.glyphicon-education              { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal      { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical        { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger         { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window           { &:before { content: \"\\e237\"; } }\n.glyphicon-oil                    { &:before { content: \"\\e238\"; } }\n.glyphicon-grain                  { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses             { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size              { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color             { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background        { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top       { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom    { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left      { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical  { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right     { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right         { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left          { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom        { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top           { &:before { content: \"\\e253\"; } }\n.glyphicon-console                { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript            { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript              { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left              { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right             { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down              { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up                { &:before { content: \"\\e260\"; } }\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/grid.less",
    "content": "//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n  .container-fixed();\n\n  @media (min-width: @screen-sm-min) {\n    width: @container-sm;\n  }\n  @media (min-width: @screen-md-min) {\n    width: @container-md;\n  }\n  @media (min-width: @screen-lg-min) {\n    width: @container-lg;\n  }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n  .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n  .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n  .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n  .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n  .make-grid(lg);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/input-groups.less",
    "content": "//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n  position: relative; // For dropdowns\n  display: table;\n  border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n  // Undo padding and float of grid classes\n  &[class*=\"col-\"] {\n    float: none;\n    padding-left: 0;\n    padding-right: 0;\n  }\n\n  .form-control {\n    // Ensure that the input is always above the *appended* addon button for\n    // proper border colors.\n    position: relative;\n    z-index: 2;\n\n    // IE9 fubars the placeholder attribute in text inputs and the arrows on\n    // select elements in input groups. To fix it, we float the input. Details:\n    // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n    float: left;\n\n    width: 100%;\n    margin-bottom: 0;\n  }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n  .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n  .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n  display: table-cell;\n\n  &:not(:first-child):not(:last-child) {\n    border-radius: 0;\n  }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n  padding: @padding-base-vertical @padding-base-horizontal;\n  font-size: @font-size-base;\n  font-weight: normal;\n  line-height: 1;\n  color: @input-color;\n  text-align: center;\n  background-color: @input-group-addon-bg;\n  border: 1px solid @input-group-addon-border-color;\n  border-radius: @border-radius-base;\n\n  // Sizing\n  &.input-sm {\n    padding: @padding-small-vertical @padding-small-horizontal;\n    font-size: @font-size-small;\n    border-radius: @border-radius-small;\n  }\n  &.input-lg {\n    padding: @padding-large-vertical @padding-large-horizontal;\n    font-size: @font-size-large;\n    border-radius: @border-radius-large;\n  }\n\n  // Nuke default margins from checkboxes and radios to vertically center within.\n  input[type=\"radio\"],\n  input[type=\"checkbox\"] {\n    margin-top: 0;\n  }\n}\n\n// Reset rounded corners\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-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-left-radius(0);\n}\n.input-group-addon:last-child {\n  border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n  position: relative;\n  // Jankily prevent input button groups from wrapping with `white-space` and\n  // `font-size` in combination with `inline-block` on buttons.\n  font-size: 0;\n  white-space: nowrap;\n\n  // Negative margin for spacing, position for bringing hovered/focused/actived\n  // element above the siblings.\n  > .btn {\n    position: relative;\n    + .btn {\n      margin-left: -1px;\n    }\n    // Bring the \"active\" button to the front\n    &:hover,\n    &:focus,\n    &:active {\n      z-index: 2;\n    }\n  }\n\n  // Negative margin to only have a 1px border between the two\n  &:first-child {\n    > .btn,\n    > .btn-group {\n      margin-right: -1px;\n    }\n  }\n  &:last-child {\n    > .btn,\n    > .btn-group {\n      margin-left: -1px;\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/jumbotron.less",
    "content": "//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n  padding: @jumbotron-padding (@jumbotron-padding / 2);\n  margin-bottom: @jumbotron-padding;\n  color: @jumbotron-color;\n  background-color: @jumbotron-bg;\n\n  h1,\n  .h1 {\n    color: @jumbotron-heading-color;\n  }\n\n  p {\n    margin-bottom: (@jumbotron-padding / 2);\n    font-size: @jumbotron-font-size;\n    font-weight: 200;\n  }\n\n  > hr {\n    border-top-color: darken(@jumbotron-bg, 10%);\n  }\n\n  .container &,\n  .container-fluid & {\n    border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n  }\n\n  .container {\n    max-width: 100%;\n  }\n\n  @media screen and (min-width: @screen-sm-min) {\n    padding: (@jumbotron-padding * 1.6) 0;\n\n    .container &,\n    .container-fluid & {\n      padding-left:  (@jumbotron-padding * 2);\n      padding-right: (@jumbotron-padding * 2);\n    }\n\n    h1,\n    .h1 {\n      font-size: @jumbotron-heading-font-size;\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/labels.less",
    "content": "//\n// Labels\n// --------------------------------------------------\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: @label-color;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n\n  // Add hover effects, but only for links\n  a& {\n    &:hover,\n    &:focus {\n      color: @label-link-hover-color;\n      text-decoration: none;\n      cursor: pointer;\n    }\n  }\n\n  // Empty labels collapse automatically (not available in IE8)\n  &:empty {\n    display: none;\n  }\n\n  // Quick fix for labels in buttons\n  .btn & {\n    position: relative;\n    top: -1px;\n  }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n  .label-variant(@label-default-bg);\n}\n\n.label-primary {\n  .label-variant(@label-primary-bg);\n}\n\n.label-success {\n  .label-variant(@label-success-bg);\n}\n\n.label-info {\n  .label-variant(@label-info-bg);\n}\n\n.label-warning {\n  .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n  .label-variant(@label-danger-bg);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/list-group.less",
    "content": "//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n  // No need to set list-style: none; since .list-group-item is block level\n  margin-bottom: 20px;\n  padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  // Place the border on the list items and negative margin up for better styling\n  margin-bottom: -1px;\n  background-color: @list-group-bg;\n  border: 1px solid @list-group-border;\n\n  // Round the first and last items\n  &:first-child {\n    .border-top-radius(@list-group-border-radius);\n  }\n  &:last-child {\n    margin-bottom: 0;\n    .border-bottom-radius(@list-group-border-radius);\n  }\n}\n\n\n// Linked list items\n//\n// Use anchor elements instead of `li`s or `div`s to create linked list items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item {\n  color: @list-group-link-color;\n\n  .list-group-item-heading {\n    color: @list-group-link-heading-color;\n  }\n\n  // Hover state\n  &:hover,\n  &:focus {\n    text-decoration: none;\n    color: @list-group-link-hover-color;\n    background-color: @list-group-hover-bg;\n  }\n}\n\n.list-group-item {\n  // Disabled state\n  &.disabled,\n  &.disabled:hover,\n  &.disabled:focus {\n    background-color: @list-group-disabled-bg;\n    color: @list-group-disabled-color;\n    cursor: @cursor-disabled;\n\n    // Force color to inherit for custom content\n    .list-group-item-heading {\n      color: inherit;\n    }\n    .list-group-item-text {\n      color: @list-group-disabled-text-color;\n    }\n  }\n\n  // Active class on item itself, not parent\n  &.active,\n  &.active:hover,\n  &.active:focus {\n    z-index: 2; // Place active items above their siblings for proper border styling\n    color: @list-group-active-color;\n    background-color: @list-group-active-bg;\n    border-color: @list-group-active-border;\n\n    // Force color to inherit for custom content\n    .list-group-item-heading,\n    .list-group-item-heading > small,\n    .list-group-item-heading > .small {\n      color: inherit;\n    }\n    .list-group-item-text {\n      color: @list-group-active-text-color;\n    }\n  }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\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"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/media.less",
    "content": ".media {\n  // Proper spacing between instances of .media\n  margin-top: 15px;\n\n  &:first-child {\n    margin-top: 0;\n  }\n}\n\n.media,\n.media-body {\n  zoom: 1;\n  overflow: hidden;\n}\n\n.media-body {\n  width: 10000px;\n}\n\n.media-object {\n  display: block;\n}\n\n.media-right,\n.media > .pull-right {\n  padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n  padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n  display: table-cell;\n  vertical-align: top;\n}\n\n.media-middle {\n  vertical-align: middle;\n}\n\n.media-bottom {\n  vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n  padding-left: 0;\n  list-style: none;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/alerts.less",
    "content": "// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n  background-color: @background;\n  border-color: @border;\n  color: @text-color;\n\n  hr {\n    border-top-color: darken(@border, 5%);\n  }\n  .alert-link {\n    color: darken(@text-color, 10%);\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/background-variant.less",
    "content": "// Contextual backgrounds\n\n.bg-variant(@color) {\n  background-color: @color;\n  a&:hover,\n  a&:focus {\n    background-color: darken(@color, 10%);\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/border-radius.less",
    "content": "// Single side border-radius\n\n.border-top-radius(@radius) {\n  border-top-right-radius: @radius;\n   border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n  border-bottom-right-radius: @radius;\n     border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n  border-bottom-right-radius: @radius;\n   border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n  border-bottom-left-radius: @radius;\n     border-top-left-radius: @radius;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/buttons.less",
    "content": "// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n  color: @color;\n  background-color: @background;\n  border-color: @border;\n\n  &:focus,\n  &.focus {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 25%);\n  }\n  &:hover {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 12%);\n  }\n  &:active,\n  &.active,\n  .open > .dropdown-toggle& {\n    color: @color;\n    background-color: darken(@background, 10%);\n        border-color: darken(@border, 12%);\n\n    &:hover,\n    &:focus,\n    &.focus {\n      color: @color;\n      background-color: darken(@background, 17%);\n          border-color: darken(@border, 25%);\n    }\n  }\n  &:active,\n  &.active,\n  .open > .dropdown-toggle& {\n    background-image: none;\n  }\n  &.disabled,\n  &[disabled],\n  fieldset[disabled] & {\n    &,\n    &:hover,\n    &:focus,\n    &.focus,\n    &:active,\n    &.active {\n      background-color: @background;\n          border-color: @border;\n    }\n  }\n\n  .badge {\n    color: @background;\n    background-color: @color;\n  }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/center-block.less",
    "content": "// Center-align a block level element\n\n.center-block() {\n  display: block;\n  margin-left: auto;\n  margin-right: auto;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/clearfix.less",
    "content": "// Clearfix\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n//    contenteditable attribute is included anywhere else in the document.\n//    Otherwise it causes space to appear at the top and bottom of elements\n//    that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n//    `:before` to contain the top-margins of child elements.\n//\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n\n.clearfix() {\n  &:before,\n  &:after {\n    content: \" \"; // 1\n    display: table; // 2\n  }\n  &:after {\n    clear: both;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/forms.less",
    "content": "// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n  // Color the label and help text\n  .help-block,\n  .control-label,\n  .radio,\n  .checkbox,\n  .radio-inline,\n  .checkbox-inline,\n  &.radio label,\n  &.checkbox label,\n  &.radio-inline label,\n  &.checkbox-inline label  {\n    color: @text-color;\n  }\n  // Set the border and box shadow on specific inputs to match\n  .form-control {\n    border-color: @border-color;\n    .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n    &:focus {\n      border-color: darken(@border-color, 10%);\n      @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n      .box-shadow(@shadow);\n    }\n  }\n  // Set validation states also for addons\n  .input-group-addon {\n    color: @text-color;\n    border-color: @border-color;\n    background-color: @background-color;\n  }\n  // Optional feedback icon\n  .form-control-feedback {\n    color: @text-color;\n  }\n}\n\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-border-focus` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n.form-control-focus(@color: @input-border-focus) {\n  @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n  &:focus {\n    border-color: @color;\n    outline: 0;\n    .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n  }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n  height: @input-height;\n  padding: @padding-vertical @padding-horizontal;\n  font-size: @font-size;\n  line-height: @line-height;\n  border-radius: @border-radius;\n\n  select& {\n    height: @input-height;\n    line-height: @input-height;\n  }\n\n  textarea&,\n  select[multiple]& {\n    height: auto;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/gradients.less",
    "content": "// Gradients\n\n#gradient {\n\n  // Horizontal gradient, from left to right\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n    background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  // Vertical gradient, from top to bottom\n  //\n  // Creates two color stops, start and end, by specifying a color and position for each color stop.\n  // Color stops are not available in IE9 and below.\n  .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n    background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent);  // Opera 12\n    background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n    background-repeat: repeat-x;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n  }\n\n  .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n    background-repeat: repeat-x;\n    background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n    background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n    background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n  }\n  .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n    background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n    background-repeat: no-repeat;\n    filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n  }\n  .radial(@inner-color: #555; @outer-color: #333) {\n    background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n    background-image: radial-gradient(circle, @inner-color, @outer-color);\n    background-repeat: no-repeat;\n  }\n  .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n    background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n    background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/grid-framework.less",
    "content": "// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n  // Common styles for all sizes of grid columns, widths 1-12\n  .col(@index) { // initial\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n    @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      position: relative;\n      // Prevent columns from collapsing when empty\n      min-height: 1px;\n      // Inner gutter via padding\n      padding-left:  (@grid-gutter-width / 2);\n      padding-right: (@grid-gutter-width / 2);\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n  .col(@index) { // initial\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), @item);\n  }\n  .col(@index, @list) when (@index =< @grid-columns) { // general\n    @item: ~\".col-@{class}-@{index}\";\n    .col((@index + 1), ~\"@{list}, @{item}\");\n  }\n  .col(@index, @list) when (@index > @grid-columns) { // terminal\n    @{list} {\n      float: left;\n    }\n  }\n  .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n  .col-@{class}-@{index} {\n    width: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n  .col-@{class}-push-@{index} {\n    left: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n  .col-@{class}-push-0 {\n    left: auto;\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n  .col-@{class}-pull-@{index} {\n    right: percentage((@index / @grid-columns));\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n  .col-@{class}-pull-0 {\n    right: auto;\n  }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n  .col-@{class}-offset-@{index} {\n    margin-left: percentage((@index / @grid-columns));\n  }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n  .calc-grid-column(@index, @class, @type);\n  // next iteration\n  .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n  .float-grid-columns(@class);\n  .loop-grid-columns(@grid-columns, @class, width);\n  .loop-grid-columns(@grid-columns, @class, pull);\n  .loop-grid-columns(@grid-columns, @class, push);\n  .loop-grid-columns(@grid-columns, @class, offset);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/grid.less",
    "content": "// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n  &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n  margin-left:  (@gutter / -2);\n  margin-right: (@gutter / -2);\n  &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  float: left;\n  width: percentage((@columns / @grid-columns));\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n  margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n  left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n  right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-sm-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-offset(@columns) {\n  @media (min-width: @screen-sm-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-push(@columns) {\n  @media (min-width: @screen-sm-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-sm-column-pull(@columns) {\n  @media (min-width: @screen-sm-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-md-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-offset(@columns) {\n  @media (min-width: @screen-md-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-push(@columns) {\n  @media (min-width: @screen-md-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-md-column-pull(@columns) {\n  @media (min-width: @screen-md-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n  position: relative;\n  min-height: 1px;\n  padding-left:  (@gutter / 2);\n  padding-right: (@gutter / 2);\n\n  @media (min-width: @screen-lg-min) {\n    float: left;\n    width: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-offset(@columns) {\n  @media (min-width: @screen-lg-min) {\n    margin-left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-push(@columns) {\n  @media (min-width: @screen-lg-min) {\n    left: percentage((@columns / @grid-columns));\n  }\n}\n.make-lg-column-pull(@columns) {\n  @media (min-width: @screen-lg-min) {\n    right: percentage((@columns / @grid-columns));\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/hide-text.less",
    "content": "// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n  font: ~\"0/0\" a;\n  color: transparent;\n  text-shadow: none;\n  background-color: transparent;\n  border: 0;\n}\n\n// New mixin to use as of v3.0.1\n.text-hide() {\n  .hide-text();\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/image.less",
    "content": "// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n  display: @display;\n  max-width: 100%; // Part 1: Set a maximum relative to the parent\n  height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n  background-image: url(\"@{file-1x}\");\n\n  @media\n  only screen and (-webkit-min-device-pixel-ratio: 2),\n  only screen and (   min--moz-device-pixel-ratio: 2),\n  only screen and (     -o-min-device-pixel-ratio: 2/1),\n  only screen and (        min-device-pixel-ratio: 2),\n  only screen and (                min-resolution: 192dpi),\n  only screen and (                min-resolution: 2dppx) {\n    background-image: url(\"@{file-2x}\");\n    background-size: @width-1x @height-1x;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/labels.less",
    "content": "// Labels\n\n.label-variant(@color) {\n  background-color: @color;\n\n  &[href] {\n    &:hover,\n    &:focus {\n      background-color: darken(@color, 10%);\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/list-group.less",
    "content": "// List Groups\n\n.list-group-item-variant(@state; @background; @color) {\n  .list-group-item-@{state} {\n    color: @color;\n    background-color: @background;\n\n    a& {\n      color: @color;\n\n      .list-group-item-heading {\n        color: inherit;\n      }\n\n      &:hover,\n      &:focus {\n        color: @color;\n        background-color: darken(@background, 5%);\n      }\n      &.active,\n      &.active:hover,\n      &.active:focus {\n        color: #fff;\n        background-color: @color;\n        border-color: @color;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/nav-divider.less",
    "content": "// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n  height: 1px;\n  margin: ((@line-height-computed / 2) - 1) 0;\n  overflow: hidden;\n  background-color: @color;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/nav-vertical-align.less",
    "content": "// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n  margin-top: ((@navbar-height - @element-height) / 2);\n  margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/opacity.less",
    "content": "// Opacity\n\n.opacity(@opacity) {\n  opacity: @opacity;\n  // IE8 filter\n  @opacity-ie: (@opacity * 100);\n  filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/pagination.less",
    "content": "// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n  > li {\n    > a,\n    > span {\n      padding: @padding-vertical @padding-horizontal;\n      font-size: @font-size;\n    }\n    &:first-child {\n      > a,\n      > span {\n        .border-left-radius(@border-radius);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/panels.less",
    "content": "// Panels\n\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n  border-color: @border;\n\n  & > .panel-heading {\n    color: @heading-text-color;\n    background-color: @heading-bg-color;\n    border-color: @heading-border;\n\n    + .panel-collapse > .panel-body {\n      border-top-color: @border;\n    }\n    .badge {\n      color: @heading-bg-color;\n      background-color: @heading-text-color;\n    }\n  }\n  & > .panel-footer {\n    + .panel-collapse > .panel-body {\n      border-bottom-color: @border;\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/progress-bar.less",
    "content": "// Progress bars\n\n.progress-bar-variant(@color) {\n  background-color: @color;\n\n  // Deprecated parent class requirement as of v3.2.0\n  .progress-striped & {\n    #gradient > .striped();\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/reset-filter.less",
    "content": "// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n  filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/resize.less",
    "content": "// Resize anything\n\n.resizable(@direction) {\n  resize: @direction; // Options: horizontal, vertical, both\n  overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible`\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/responsive-visibility.less",
    "content": "// Responsive utilities\n\n//\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n  display: block !important;\n  table&  { display: table; }\n  tr&     { display: table-row !important; }\n  th&,\n  td&     { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n  display: none !important;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/size.less",
    "content": "// Sizing shortcuts\n\n.size(@width; @height) {\n  width: @width;\n  height: @height;\n}\n\n.square(@size) {\n  .size(@size; @size);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/tab-focus.less",
    "content": "// WebKit-style focus\n\n.tab-focus() {\n  // Default\n  outline: thin dotted;\n  // WebKit\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/table-row.less",
    "content": "// Tables\n\n.table-row-variant(@state; @background) {\n  // Exact selectors below required to override `.table-striped` and prevent\n  // inheritance to nested tables.\n  .table > thead > tr,\n  .table > tbody > tr,\n  .table > tfoot > tr {\n    > td.@{state},\n    > th.@{state},\n    &.@{state} > td,\n    &.@{state} > th {\n      background-color: @background;\n    }\n  }\n\n  // Hover states for `.table-hover`\n  // Note: this is not available for cells or rows within `thead` or `tfoot`.\n  .table-hover > tbody > tr {\n    > td.@{state}:hover,\n    > th.@{state}:hover,\n    &.@{state}:hover > td,\n    &:hover > .@{state},\n    &.@{state}:hover > th {\n      background-color: darken(@background, 5%);\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/text-emphasis.less",
    "content": "// Typography\n\n.text-emphasis-variant(@color) {\n  color: @color;\n  a&:hover,\n  a&:focus {\n    color: darken(@color, 10%);\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/text-overflow.less",
    "content": "// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n  overflow: hidden;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins/vendor-prefixes.less",
    "content": "// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n  -webkit-animation: @animation;\n       -o-animation: @animation;\n          animation: @animation;\n}\n.animation-name(@name) {\n  -webkit-animation-name: @name;\n          animation-name: @name;\n}\n.animation-duration(@duration) {\n  -webkit-animation-duration: @duration;\n          animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n  -webkit-animation-timing-function: @timing-function;\n          animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n  -webkit-animation-delay: @delay;\n          animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n  -webkit-animation-iteration-count: @iteration-count;\n          animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n  -webkit-animation-direction: @direction;\n          animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n  -webkit-animation-fill-mode: @fill-mode;\n          animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n  -webkit-backface-visibility: @visibility;\n     -moz-backface-visibility: @visibility;\n          backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n  -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n          box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n  -webkit-box-sizing: @boxmodel;\n     -moz-box-sizing: @boxmodel;\n          box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n  -webkit-column-count: @column-count;\n     -moz-column-count: @column-count;\n          column-count: @column-count;\n  -webkit-column-gap: @column-gap;\n     -moz-column-gap: @column-gap;\n          column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n  word-wrap: break-word;\n  -webkit-hyphens: @mode;\n     -moz-hyphens: @mode;\n      -ms-hyphens: @mode; // IE10+\n       -o-hyphens: @mode;\n          hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n  // Firefox\n  &::-moz-placeholder {\n    color: @color;\n    opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n  }\n  &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n  &::-webkit-input-placeholder  { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n  -webkit-transform: scale(@ratio);\n      -ms-transform: scale(@ratio); // IE9 only\n       -o-transform: scale(@ratio);\n          transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n  -webkit-transform: scale(@ratioX, @ratioY);\n      -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n       -o-transform: scale(@ratioX, @ratioY);\n          transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n  -webkit-transform: scaleX(@ratio);\n      -ms-transform: scaleX(@ratio); // IE9 only\n       -o-transform: scaleX(@ratio);\n          transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n  -webkit-transform: scaleY(@ratio);\n      -ms-transform: scaleY(@ratio); // IE9 only\n       -o-transform: scaleY(@ratio);\n          transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n  -webkit-transform: skewX(@x) skewY(@y);\n      -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n       -o-transform: skewX(@x) skewY(@y);\n          transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n  -webkit-transform: translate(@x, @y);\n      -ms-transform: translate(@x, @y); // IE9 only\n       -o-transform: translate(@x, @y);\n          transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n  -webkit-transform: translate3d(@x, @y, @z);\n          transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n  -webkit-transform: rotate(@degrees);\n      -ms-transform: rotate(@degrees); // IE9 only\n       -o-transform: rotate(@degrees);\n          transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n  -webkit-transform: rotateX(@degrees);\n      -ms-transform: rotateX(@degrees); // IE9 only\n       -o-transform: rotateX(@degrees);\n          transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n  -webkit-transform: rotateY(@degrees);\n      -ms-transform: rotateY(@degrees); // IE9 only\n       -o-transform: rotateY(@degrees);\n          transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n  -webkit-perspective: @perspective;\n     -moz-perspective: @perspective;\n          perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n  -webkit-perspective-origin: @perspective;\n     -moz-perspective-origin: @perspective;\n          perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n  -webkit-transform-origin: @origin;\n     -moz-transform-origin: @origin;\n      -ms-transform-origin: @origin; // IE9 only\n          transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n  -webkit-transition: @transition;\n       -o-transition: @transition;\n          transition: @transition;\n}\n.transition-property(@transition-property) {\n  -webkit-transition-property: @transition-property;\n          transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n  -webkit-transition-delay: @transition-delay;\n          transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n  -webkit-transition-duration: @transition-duration;\n          transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n  -webkit-transition-timing-function: @timing-function;\n          transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n  -webkit-transition: -webkit-transform @transition;\n     -moz-transition: -moz-transform @transition;\n       -o-transition: -o-transform @transition;\n          transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n  -webkit-user-select: @select;\n     -moz-user-select: @select;\n      -ms-user-select: @select; // IE10+\n          user-select: @select;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/mixins.less",
    "content": "// Mixins\n// --------------------------------------------------\n\n// Utilities\n@import \"mixins/hide-text.less\";\n@import \"mixins/opacity.less\";\n@import \"mixins/image.less\";\n@import \"mixins/labels.less\";\n@import \"mixins/reset-filter.less\";\n@import \"mixins/resize.less\";\n@import \"mixins/responsive-visibility.less\";\n@import \"mixins/size.less\";\n@import \"mixins/tab-focus.less\";\n@import \"mixins/text-emphasis.less\";\n@import \"mixins/text-overflow.less\";\n@import \"mixins/vendor-prefixes.less\";\n\n// Components\n@import \"mixins/alerts.less\";\n@import \"mixins/buttons.less\";\n@import \"mixins/panels.less\";\n@import \"mixins/pagination.less\";\n@import \"mixins/list-group.less\";\n@import \"mixins/nav-divider.less\";\n@import \"mixins/forms.less\";\n@import \"mixins/progress-bar.less\";\n@import \"mixins/table-row.less\";\n\n// Skins\n@import \"mixins/background-variant.less\";\n@import \"mixins/border-radius.less\";\n@import \"mixins/gradients.less\";\n\n// Layout\n@import \"mixins/clearfix.less\";\n@import \"mixins/center-block.less\";\n@import \"mixins/nav-vertical-align.less\";\n@import \"mixins/grid-framework.less\";\n@import \"mixins/grid.less\";\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/modals.less",
    "content": "//\n// Modals\n// --------------------------------------------------\n\n// .modal-open      - body class for killing the scroll\n// .modal           - container to scroll within\n// .modal-dialog    - positioning shell for the actual modal\n// .modal-content   - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n  overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n  display: none;\n  overflow: hidden;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-modal;\n  -webkit-overflow-scrolling: touch;\n\n  // Prevent Chrome on Windows from adding a focus outline. For details, see\n  // https://github.com/twbs/bootstrap/pull/10951.\n  outline: 0;\n\n  // When fading in the modal, animate it to slide down\n  &.fade .modal-dialog {\n    .translate(0, -25%);\n    .transition-transform(~\"0.3s ease-out\");\n  }\n  &.in .modal-dialog { .translate(0, 0) }\n}\n.modal-open .modal {\n  overflow-x: hidden;\n  overflow-y: auto;\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n  position: relative;\n  width: auto;\n  margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n  position: relative;\n  background-color: @modal-content-bg;\n  border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n  border: 1px solid @modal-content-border-color;\n  border-radius: @border-radius-large;\n  .box-shadow(0 3px 9px rgba(0,0,0,.5));\n  background-clip: padding-box;\n  // Remove focus outline from opened modal\n  outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: @zindex-modal-background;\n  background-color: @modal-backdrop-bg;\n  // Fade for backdrop\n  &.fade { .opacity(0); }\n  &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n  padding: @modal-title-padding;\n  border-bottom: 1px solid @modal-header-border-color;\n  min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n  margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n  margin: 0;\n  line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n  position: relative;\n  padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n  padding: @modal-inner-padding;\n  text-align: right; // right align buttons\n  border-top: 1px solid @modal-footer-border-color;\n  &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n  // Properly space out buttons\n  .btn + .btn {\n    margin-left: 5px;\n    margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n  }\n  // but override that for button groups\n  .btn-group .btn + .btn {\n    margin-left: -1px;\n  }\n  // and override it for block buttons as well\n  .btn-block + .btn-block {\n    margin-left: 0;\n  }\n}\n\n// Measure scrollbar width for padding body during modal show/hide\n.modal-scrollbar-measure {\n  position: absolute;\n  top: -9999px;\n  width: 50px;\n  height: 50px;\n  overflow: scroll;\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n  // Automatically set modal's width for larger viewports\n  .modal-dialog {\n    width: @modal-md;\n    margin: 30px auto;\n  }\n  .modal-content {\n    .box-shadow(0 5px 15px rgba(0,0,0,.5));\n  }\n\n  // Modal sizes\n  .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n  .modal-lg { width: @modal-lg; }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/navbar.less",
    "content": "//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n  position: relative;\n  min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n  margin-bottom: @navbar-margin-bottom;\n  border: 1px solid transparent;\n\n  // Prevent floats from breaking the navbar\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: @navbar-border-radius;\n  }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n  &:extend(.clearfix all);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n  }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n  overflow-x: visible;\n  padding-right: @navbar-padding-horizontal;\n  padding-left:  @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n  &:extend(.clearfix all);\n  -webkit-overflow-scrolling: touch;\n\n  &.in {\n    overflow-y: auto;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n\n    &.collapse {\n      display: block !important;\n      height: auto !important;\n      padding-bottom: 0; // Override default setting\n      overflow: visible !important;\n    }\n\n    &.in {\n      overflow-y: visible;\n    }\n\n    // Undo the collapse side padding for navbars with containers to ensure\n    // alignment of right-aligned contents.\n    .navbar-fixed-top &,\n    .navbar-static-top &,\n    .navbar-fixed-bottom & {\n      padding-left: 0;\n      padding-right: 0;\n    }\n  }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  .navbar-collapse {\n    max-height: @navbar-collapse-max-height;\n\n    @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n      max-height: 200px;\n    }\n  }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n  > .navbar-header,\n  > .navbar-collapse {\n    margin-right: -@navbar-padding-horizontal;\n    margin-left:  -@navbar-padding-horizontal;\n\n    @media (min-width: @grid-float-breakpoint) {\n      margin-right: 0;\n      margin-left:  0;\n    }\n  }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n  z-index: @zindex-navbar;\n  border-width: 0 0 1px;\n\n  @media (min-width: @grid-float-breakpoint) {\n    border-radius: 0;\n  }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  z-index: @zindex-navbar-fixed;\n\n  // Undo the rounded corners\n  @media (min-width: @grid-float-breakpoint) {\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; // override .navbar defaults\n  border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n  float: left;\n  padding: @navbar-padding-vertical @navbar-padding-horizontal;\n  font-size: @font-size-large;\n  line-height: @line-height-computed;\n  height: @navbar-height;\n\n  &:hover,\n  &:focus {\n    text-decoration: none;\n  }\n\n  > img {\n    display: block;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    .navbar > .container &,\n    .navbar > .container-fluid & {\n      margin-left: -@navbar-padding-horizontal;\n    }\n  }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: @navbar-padding-horizontal;\n  padding: 9px 10px;\n  .navbar-vertical-align(34px);\n  background-color: transparent;\n  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n  border: 1px solid transparent;\n  border-radius: @border-radius-base;\n\n  // We remove the `outline` here, but later compensate by attaching `:hover`\n  // styles to `:focus`.\n  &:focus {\n    outline: 0;\n  }\n\n  // Bars\n  .icon-bar {\n    display: block;\n    width: 22px;\n    height: 2px;\n    border-radius: 1px;\n  }\n  .icon-bar + .icon-bar {\n    margin-top: 4px;\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    display: none;\n  }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n  margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n  > li > a {\n    padding-top:    10px;\n    padding-bottom: 10px;\n    line-height: @line-height-computed;\n  }\n\n  @media (max-width: @grid-float-breakpoint-max) {\n    // Dropdowns get custom display when collapsed\n    .open .dropdown-menu {\n      position: static;\n      float: none;\n      width: auto;\n      margin-top: 0;\n      background-color: transparent;\n      border: 0;\n      box-shadow: none;\n      > li > a,\n      .dropdown-header {\n        padding: 5px 15px 5px 25px;\n      }\n      > li > a {\n        line-height: @line-height-computed;\n        &:hover,\n        &:focus {\n          background-image: none;\n        }\n      }\n    }\n  }\n\n  // Uncollapse the nav\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin: 0;\n\n    > li {\n      float: left;\n      > a {\n        padding-top:    @navbar-padding-vertical;\n        padding-bottom: @navbar-padding-vertical;\n      }\n    }\n  }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n  margin-left: -@navbar-padding-horizontal;\n  margin-right: -@navbar-padding-horizontal;\n  padding: 10px @navbar-padding-horizontal;\n  border-top: 1px solid transparent;\n  border-bottom: 1px solid transparent;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n\n  // Mixin behavior for optimum display\n  .form-inline();\n\n  .form-group {\n    @media (max-width: @grid-float-breakpoint-max) {\n      margin-bottom: 5px;\n\n      &:last-child {\n        margin-bottom: 0;\n      }\n    }\n  }\n\n  // Vertically center in expanded, horizontal navbar\n  .navbar-vertical-align(@input-height-base);\n\n  // Undo 100% width for pull classes\n  @media (min-width: @grid-float-breakpoint) {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    .box-shadow(none);\n  }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  margin-bottom: 0;\n  .border-top-radius(@navbar-border-radius);\n  .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n  .navbar-vertical-align(@input-height-base);\n\n  &.btn-sm {\n    .navbar-vertical-align(@input-height-small);\n  }\n  &.btn-xs {\n    .navbar-vertical-align(22);\n  }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n  .navbar-vertical-align(@line-height-computed);\n\n  @media (min-width: @grid-float-breakpoint) {\n    float: left;\n    margin-left: @navbar-padding-horizontal;\n    margin-right: @navbar-padding-horizontal;\n  }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n  .navbar-left  { .pull-left(); }\n  .navbar-right {\n    .pull-right();\n    margin-right: -@navbar-padding-horizontal;\n\n    ~ .navbar-right {\n      margin-right: 0;\n    }\n  }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  background-color: @navbar-default-bg;\n  border-color: @navbar-default-border;\n\n  .navbar-brand {\n    color: @navbar-default-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-brand-hover-color;\n      background-color: @navbar-default-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-default-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-default-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-hover-color;\n        background-color: @navbar-default-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-active-color;\n        background-color: @navbar-default-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n        background-color: @navbar-default-link-disabled-bg;\n      }\n    }\n  }\n\n  .navbar-toggle {\n    border-color: @navbar-default-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-default-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-default-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: @navbar-default-border;\n  }\n\n  // Dropdown menu items\n  .navbar-nav {\n    // Remove background color from open dropdown\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-default-link-active-bg;\n        color: @navbar-default-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display when collapsed\n      .open .dropdown-menu {\n        > li > a {\n          color: @navbar-default-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-hover-color;\n            background-color: @navbar-default-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-active-color;\n            background-color: @navbar-default-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-default-link-disabled-color;\n            background-color: @navbar-default-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n\n  // Links in navbars\n  //\n  // Add a class to ensure links outside the navbar nav are colored correctly.\n\n  .navbar-link {\n    color: @navbar-default-link-color;\n    &:hover {\n      color: @navbar-default-link-hover-color;\n    }\n  }\n\n  .btn-link {\n    color: @navbar-default-link-color;\n    &:hover,\n    &:focus {\n      color: @navbar-default-link-hover-color;\n    }\n    &[disabled],\n    fieldset[disabled] & {\n      &:hover,\n      &:focus {\n        color: @navbar-default-link-disabled-color;\n      }\n    }\n  }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n  background-color: @navbar-inverse-bg;\n  border-color: @navbar-inverse-border;\n\n  .navbar-brand {\n    color: @navbar-inverse-brand-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-brand-hover-color;\n      background-color: @navbar-inverse-brand-hover-bg;\n    }\n  }\n\n  .navbar-text {\n    color: @navbar-inverse-color;\n  }\n\n  .navbar-nav {\n    > li > a {\n      color: @navbar-inverse-link-color;\n\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-hover-color;\n        background-color: @navbar-inverse-link-hover-bg;\n      }\n    }\n    > .active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-active-color;\n        background-color: @navbar-inverse-link-active-bg;\n      }\n    }\n    > .disabled > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n        background-color: @navbar-inverse-link-disabled-bg;\n      }\n    }\n  }\n\n  // Darken the responsive nav toggle\n  .navbar-toggle {\n    border-color: @navbar-inverse-toggle-border-color;\n    &:hover,\n    &:focus {\n      background-color: @navbar-inverse-toggle-hover-bg;\n    }\n    .icon-bar {\n      background-color: @navbar-inverse-toggle-icon-bar-bg;\n    }\n  }\n\n  .navbar-collapse,\n  .navbar-form {\n    border-color: darken(@navbar-inverse-bg, 7%);\n  }\n\n  // Dropdowns\n  .navbar-nav {\n    > .open > a {\n      &,\n      &:hover,\n      &:focus {\n        background-color: @navbar-inverse-link-active-bg;\n        color: @navbar-inverse-link-active-color;\n      }\n    }\n\n    @media (max-width: @grid-float-breakpoint-max) {\n      // Dropdowns get custom display\n      .open .dropdown-menu {\n        > .dropdown-header {\n          border-color: @navbar-inverse-border;\n        }\n        .divider {\n          background-color: @navbar-inverse-border;\n        }\n        > li > a {\n          color: @navbar-inverse-link-color;\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-hover-color;\n            background-color: @navbar-inverse-link-hover-bg;\n          }\n        }\n        > .active > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-active-color;\n            background-color: @navbar-inverse-link-active-bg;\n          }\n        }\n        > .disabled > a {\n          &,\n          &:hover,\n          &:focus {\n            color: @navbar-inverse-link-disabled-color;\n            background-color: @navbar-inverse-link-disabled-bg;\n          }\n        }\n      }\n    }\n  }\n\n  .navbar-link {\n    color: @navbar-inverse-link-color;\n    &:hover {\n      color: @navbar-inverse-link-hover-color;\n    }\n  }\n\n  .btn-link {\n    color: @navbar-inverse-link-color;\n    &:hover,\n    &:focus {\n      color: @navbar-inverse-link-hover-color;\n    }\n    &[disabled],\n    fieldset[disabled] & {\n      &:hover,\n      &:focus {\n        color: @navbar-inverse-link-disabled-color;\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/navs.less",
    "content": "//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n  margin-bottom: 0;\n  padding-left: 0; // Override default ul/ol\n  list-style: none;\n  &:extend(.clearfix all);\n\n  > li {\n    position: relative;\n    display: block;\n\n    > a {\n      position: relative;\n      display: block;\n      padding: @nav-link-padding;\n      &:hover,\n      &:focus {\n        text-decoration: none;\n        background-color: @nav-link-hover-bg;\n      }\n    }\n\n    // Disabled state sets text to gray and nukes hover/tab effects\n    &.disabled > a {\n      color: @nav-disabled-link-color;\n\n      &:hover,\n      &:focus {\n        color: @nav-disabled-link-hover-color;\n        text-decoration: none;\n        background-color: transparent;\n        cursor: @cursor-disabled;\n      }\n    }\n  }\n\n  // Open dropdowns\n  .open > a {\n    &,\n    &:hover,\n    &:focus {\n      background-color: @nav-link-hover-bg;\n      border-color: @link-color;\n    }\n  }\n\n  // Nav dividers (deprecated with v3.0.1)\n  //\n  // This should have been removed in v3 with the dropping of `.nav-list`, but\n  // we missed it. We don't currently support this anywhere, but in the interest\n  // of maintaining backward compatibility in case you use it, it's deprecated.\n  .nav-divider {\n    .nav-divider();\n  }\n\n  // Prevent IE8 from misplacing imgs\n  //\n  // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n  > li > a > img {\n    max-width: none;\n  }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n  border-bottom: 1px solid @nav-tabs-border-color;\n  > li {\n    float: left;\n    // Make the list-items overlay the bottom border\n    margin-bottom: -1px;\n\n    // Actual tabs (as links)\n    > a {\n      margin-right: 2px;\n      line-height: @line-height-base;\n      border: 1px solid transparent;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n      &:hover {\n        border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n      }\n    }\n\n    // Active state, and its :hover to override normal :hover\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-tabs-active-link-hover-color;\n        background-color: @nav-tabs-active-link-hover-bg;\n        border: 1px solid @nav-tabs-active-link-hover-border-color;\n        border-bottom-color: transparent;\n        cursor: default;\n      }\n    }\n  }\n  // pulling this in mainly for less shorthand\n  &.nav-justified {\n    .nav-justified();\n    .nav-tabs-justified();\n  }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n  > li {\n    float: left;\n\n    // Links rendered as pills\n    > a {\n      border-radius: @nav-pills-border-radius;\n    }\n    + li {\n      margin-left: 2px;\n    }\n\n    // Active state\n    &.active > a {\n      &,\n      &:hover,\n      &:focus {\n        color: @nav-pills-active-link-hover-color;\n        background-color: @nav-pills-active-link-hover-bg;\n      }\n    }\n  }\n}\n\n\n// Stacked pills\n.nav-stacked {\n  > li {\n    float: none;\n    + li {\n      margin-top: 2px;\n      margin-left: 0; // no need for this gap between nav items\n    }\n  }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n  width: 100%;\n\n  > li {\n    float: none;\n    > a {\n      text-align: center;\n      margin-bottom: 5px;\n    }\n  }\n\n  > .dropdown .dropdown-menu {\n    top: auto;\n    left: auto;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li {\n      display: table-cell;\n      width: 1%;\n      > a {\n        margin-bottom: 0;\n      }\n    }\n  }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n  border-bottom: 0;\n\n  > li > a {\n    // Override margin from .nav-tabs\n    margin-right: 0;\n    border-radius: @border-radius-base;\n  }\n\n  > .active > a,\n  > .active > a:hover,\n  > .active > a:focus {\n    border: 1px solid @nav-tabs-justified-link-border-color;\n  }\n\n  @media (min-width: @screen-sm-min) {\n    > li > a {\n      border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n      border-radius: @border-radius-base @border-radius-base 0 0;\n    }\n    > .active > a,\n    > .active > a:hover,\n    > .active > a:focus {\n      border-bottom-color: @nav-tabs-justified-active-link-border-color;\n    }\n  }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n  > .tab-pane {\n    display: none;\n  }\n  > .active {\n    display: block;\n  }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n  // make dropdown border overlap tab border\n  margin-top: -1px;\n  // Remove the top rounded corners here since there is a hard edge above the menu\n  .border-top-radius(0);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/normalize.less",
    "content": "/*! normalize.css v3.0.2 | MIT License | git.io/normalize */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS text size adjust after orientation change, without disabling\n//    user zoom.\n//\n\nhtml {\n  font-family: sans-serif; // 1\n  -ms-text-size-adjust: 100%; // 2\n  -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n  margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n  display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n  display: inline-block; // 1\n  vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n  display: none;\n  height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n  display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n  background-color: transparent;\n}\n\n//\n// Improve readability when focused and also mouse hovered in all browsers.\n//\n\na:active,\na:hover {\n  outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n  border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n  font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n  font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n  background: #ff0;\n  color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n  font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n\nsup {\n  top: -0.5em;\n}\n\nsub {\n  bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n  border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n  overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n  margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n  overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n  font-family: monospace, monospace;\n  font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n//    Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n  color: inherit; // 1\n  font: inherit; // 2\n  margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n  overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n  text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n//    and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n//    `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n  -webkit-appearance: button; // 2\n  cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n  cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n  line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n  box-sizing: border-box; // 1\n  padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n  height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome\n//    (include `-moz` to future-proof).\n//\n\ninput[type=\"search\"] {\n  -webkit-appearance: textfield; // 1\n  -moz-box-sizing: content-box;\n  -webkit-box-sizing: content-box; // 2\n  box-sizing: content-box;\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n  border: 0; // 1\n  padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n  overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n  font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n\ntd,\nth {\n  padding: 0;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/pager.less",
    "content": "//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  list-style: none;\n  text-align: center;\n  &:extend(.clearfix all);\n  li {\n    display: inline;\n    > a,\n    > span {\n      display: inline-block;\n      padding: 5px 14px;\n      background-color: @pager-bg;\n      border: 1px solid @pager-border;\n      border-radius: @pager-border-radius;\n    }\n\n    > a:hover,\n    > a:focus {\n      text-decoration: none;\n      background-color: @pager-hover-bg;\n    }\n  }\n\n  .next {\n    > a,\n    > span {\n      float: right;\n    }\n  }\n\n  .previous {\n    > a,\n    > span {\n      float: left;\n    }\n  }\n\n  .disabled {\n    > a,\n    > a:hover,\n    > a:focus,\n    > span {\n      color: @pager-disabled-color;\n      background-color: @pager-bg;\n      cursor: @cursor-disabled;\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/pagination.less",
    "content": "//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: @line-height-computed 0;\n  border-radius: @border-radius-base;\n\n  > li {\n    display: inline; // Remove list-style and block-level defaults\n    > a,\n    > span {\n      position: relative;\n      float: left; // Collapse white-space\n      padding: @padding-base-vertical @padding-base-horizontal;\n      line-height: @line-height-base;\n      text-decoration: none;\n      color: @pagination-color;\n      background-color: @pagination-bg;\n      border: 1px solid @pagination-border;\n      margin-left: -1px;\n    }\n    &:first-child {\n      > a,\n      > span {\n        margin-left: 0;\n        .border-left-radius(@border-radius-base);\n      }\n    }\n    &:last-child {\n      > a,\n      > span {\n        .border-right-radius(@border-radius-base);\n      }\n    }\n  }\n\n  > li > a,\n  > li > span {\n    &:hover,\n    &:focus {\n      color: @pagination-hover-color;\n      background-color: @pagination-hover-bg;\n      border-color: @pagination-hover-border;\n    }\n  }\n\n  > .active > a,\n  > .active > span {\n    &,\n    &:hover,\n    &:focus {\n      z-index: 2;\n      color: @pagination-active-color;\n      background-color: @pagination-active-bg;\n      border-color: @pagination-active-border;\n      cursor: default;\n    }\n  }\n\n  > .disabled {\n    > span,\n    > span:hover,\n    > span:focus,\n    > a,\n    > a:hover,\n    > a:focus {\n      color: @pagination-disabled-color;\n      background-color: @pagination-disabled-bg;\n      border-color: @pagination-disabled-border;\n      cursor: @cursor-disabled;\n    }\n  }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n  .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n  .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @border-radius-small);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/panels.less",
    "content": "//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n  margin-bottom: @line-height-computed;\n  background-color: @panel-bg;\n  border: 1px solid transparent;\n  border-radius: @panel-border-radius;\n  .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n  padding: @panel-body-padding;\n  &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n  padding: @panel-heading-padding;\n  border-bottom: 1px solid transparent;\n  .border-top-radius((@panel-border-radius - 1));\n\n  > .dropdown .dropdown-toggle {\n    color: inherit;\n  }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: ceil((@font-size-base * 1.125));\n  color: inherit;\n\n  > a,\n  > small,\n  > .small,\n  > small > a,\n  > .small > a {\n    color: inherit;\n  }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n  padding: @panel-footer-padding;\n  background-color: @panel-footer-bg;\n  border-top: 1px solid @panel-inner-border;\n  .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n  > .list-group,\n  > .panel-collapse > .list-group {\n    margin-bottom: 0;\n\n    .list-group-item {\n      border-width: 1px 0;\n      border-radius: 0;\n    }\n\n    // Add border top radius for first one\n    &:first-child {\n      .list-group-item:first-child {\n        border-top: 0;\n        .border-top-radius((@panel-border-radius - 1));\n      }\n    }\n    // Add border bottom radius for last one\n    &:last-child {\n      .list-group-item:last-child {\n        border-bottom: 0;\n        .border-bottom-radius((@panel-border-radius - 1));\n      }\n    }\n  }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n  .list-group-item:first-child {\n    border-top-width: 0;\n  }\n}\n.list-group + .panel-footer {\n  border-top-width: 0;\n}\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n  > .table,\n  > .table-responsive > .table,\n  > .panel-collapse > .table {\n    margin-bottom: 0;\n\n    caption {\n      padding-left: @panel-body-padding;\n      padding-right: @panel-body-padding;\n    }\n  }\n  // Add border top radius for first one\n  > .table:first-child,\n  > .table-responsive:first-child > .table:first-child {\n    .border-top-radius((@panel-border-radius - 1));\n\n    > thead:first-child,\n    > tbody:first-child {\n      > tr:first-child {\n        border-top-left-radius: (@panel-border-radius - 1);\n        border-top-right-radius: (@panel-border-radius - 1);\n\n        td:first-child,\n        th:first-child {\n          border-top-left-radius: (@panel-border-radius - 1);\n        }\n        td:last-child,\n        th:last-child {\n          border-top-right-radius: (@panel-border-radius - 1);\n        }\n      }\n    }\n  }\n  // Add border bottom radius for last one\n  > .table:last-child,\n  > .table-responsive:last-child > .table:last-child {\n    .border-bottom-radius((@panel-border-radius - 1));\n\n    > tbody:last-child,\n    > tfoot:last-child {\n      > tr:last-child {\n        border-bottom-left-radius: (@panel-border-radius - 1);\n        border-bottom-right-radius: (@panel-border-radius - 1);\n\n        td:first-child,\n        th:first-child {\n          border-bottom-left-radius: (@panel-border-radius - 1);\n        }\n        td:last-child,\n        th:last-child {\n          border-bottom-right-radius: (@panel-border-radius - 1);\n        }\n      }\n    }\n  }\n  > .panel-body + .table,\n  > .panel-body + .table-responsive,\n  > .table + .panel-body,\n  > .table-responsive + .panel-body {\n    border-top: 1px solid @table-border-color;\n  }\n  > .table > tbody:first-child > tr:first-child th,\n  > .table > tbody:first-child > tr:first-child td {\n    border-top: 0;\n  }\n  > .table-bordered,\n  > .table-responsive > .table-bordered {\n    border: 0;\n    > thead,\n    > tbody,\n    > tfoot {\n      > tr {\n        > th:first-child,\n        > td:first-child {\n          border-left: 0;\n        }\n        > th:last-child,\n        > td:last-child {\n          border-right: 0;\n        }\n      }\n    }\n    > thead,\n    > tbody {\n      > tr:first-child {\n        > td,\n        > th {\n          border-bottom: 0;\n        }\n      }\n    }\n    > tbody,\n    > tfoot {\n      > tr:last-child {\n        > td,\n        > th {\n          border-bottom: 0;\n        }\n      }\n    }\n  }\n  > .table-responsive {\n    border: 0;\n    margin-bottom: 0;\n  }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n  margin-bottom: @line-height-computed;\n\n  // Tighten up margin so it's only between panels\n  .panel {\n    margin-bottom: 0;\n    border-radius: @panel-border-radius;\n\n    + .panel {\n      margin-top: 5px;\n    }\n  }\n\n  .panel-heading {\n    border-bottom: 0;\n\n    + .panel-collapse > .panel-body,\n    + .panel-collapse > .list-group {\n      border-top: 1px solid @panel-inner-border;\n    }\n  }\n\n  .panel-footer {\n    border-top: 0;\n    + .panel-collapse .panel-body {\n      border-bottom: 1px solid @panel-inner-border;\n    }\n  }\n}\n\n\n// Contextual variations\n.panel-default {\n  .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n  .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n  .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n  .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n  .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n  .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/popovers.less",
    "content": "//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: @zindex-popover;\n  display: none;\n  max-width: @popover-max-width;\n  padding: 1px;\n  // Reset font and text properties given new insertion method\n  font-family: @font-family-base;\n  font-size: @font-size-base;\n  font-weight: normal;\n  line-height: @line-height-base;\n  text-align: left;\n  background-color: @popover-bg;\n  background-clip: padding-box;\n  border: 1px solid @popover-fallback-border-color;\n  border: 1px solid @popover-border-color;\n  border-radius: @border-radius-large;\n  .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n  // Overrides for proper insertion\n  white-space: normal;\n\n  // Offset the popover to account for the popover arrow\n  &.top     { margin-top: -@popover-arrow-width; }\n  &.right   { margin-left: @popover-arrow-width; }\n  &.bottom  { margin-top: @popover-arrow-width; }\n  &.left    { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n  margin: 0; // reset heading margin\n  padding: 8px 14px;\n  font-size: @font-size-base;\n  background-color: @popover-title-bg;\n  border-bottom: 1px solid darken(@popover-title-bg, 5%);\n  border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;\n}\n\n.popover-content {\n  padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n  &,\n  &:after {\n    position: absolute;\n    display: block;\n    width: 0;\n    height: 0;\n    border-color: transparent;\n    border-style: solid;\n  }\n}\n.popover > .arrow {\n  border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n  border-width: @popover-arrow-width;\n  content: \"\";\n}\n\n.popover {\n  &.top > .arrow {\n    left: 50%;\n    margin-left: -@popover-arrow-outer-width;\n    border-bottom-width: 0;\n    border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-top-color: @popover-arrow-outer-color;\n    bottom: -@popover-arrow-outer-width;\n    &:after {\n      content: \" \";\n      bottom: 1px;\n      margin-left: -@popover-arrow-width;\n      border-bottom-width: 0;\n      border-top-color: @popover-arrow-color;\n    }\n  }\n  &.right > .arrow {\n    top: 50%;\n    left: -@popover-arrow-outer-width;\n    margin-top: -@popover-arrow-outer-width;\n    border-left-width: 0;\n    border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-right-color: @popover-arrow-outer-color;\n    &:after {\n      content: \" \";\n      left: 1px;\n      bottom: -@popover-arrow-width;\n      border-left-width: 0;\n      border-right-color: @popover-arrow-color;\n    }\n  }\n  &.bottom > .arrow {\n    left: 50%;\n    margin-left: -@popover-arrow-outer-width;\n    border-top-width: 0;\n    border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-bottom-color: @popover-arrow-outer-color;\n    top: -@popover-arrow-outer-width;\n    &:after {\n      content: \" \";\n      top: 1px;\n      margin-left: -@popover-arrow-width;\n      border-top-width: 0;\n      border-bottom-color: @popover-arrow-color;\n    }\n  }\n\n  &.left > .arrow {\n    top: 50%;\n    right: -@popover-arrow-outer-width;\n    margin-top: -@popover-arrow-outer-width;\n    border-right-width: 0;\n    border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n    border-left-color: @popover-arrow-outer-color;\n    &:after {\n      content: \" \";\n      right: 1px;\n      border-right-width: 0;\n      border-left-color: @popover-arrow-color;\n      bottom: -@popover-arrow-width;\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/print.less",
    "content": "/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n    *,\n    *:before,\n    *:after {\n        background: transparent !important;\n        color: #000 !important; // Black prints faster: h5bp.com/s\n        box-shadow: none !important;\n        text-shadow: none !important;\n    }\n\n    a,\n    a:visited {\n        text-decoration: underline;\n    }\n\n    a[href]:after {\n        content: \" (\" attr(href) \")\";\n    }\n\n    abbr[title]:after {\n        content: \" (\" attr(title) \")\";\n    }\n\n    // Don't show links that are fragment identifiers,\n    // or use the `javascript:` pseudo protocol\n    a[href^=\"#\"]:after,\n    a[href^=\"javascript:\"]:after {\n        content: \"\";\n    }\n\n    pre,\n    blockquote {\n        border: 1px solid #999;\n        page-break-inside: avoid;\n    }\n\n    thead {\n        display: table-header-group; // h5bp.com/t\n    }\n\n    tr,\n    img {\n        page-break-inside: avoid;\n    }\n\n    img {\n        max-width: 100% !important;\n    }\n\n    p,\n    h2,\n    h3 {\n        orphans: 3;\n        widows: 3;\n    }\n\n    h2,\n    h3 {\n        page-break-after: avoid;\n    }\n\n    // Bootstrap specific changes start\n    //\n    // Chrome (OSX) fix for https://github.com/twbs/bootstrap/issues/11245\n    // Once fixed, we can just straight up remove this.\n    select {\n        background: #fff !important;\n    }\n\n    // Bootstrap components\n    .navbar {\n        display: none;\n    }\n    .btn,\n    .dropup > .btn {\n        > .caret {\n            border-top-color: #000 !important;\n        }\n    }\n    .label {\n        border: 1px solid #000;\n    }\n\n    .table {\n        border-collapse: collapse !important;\n\n        td,\n        th {\n            background-color: #fff !important;\n        }\n    }\n    .table-bordered {\n        th,\n        td {\n            border: 1px solid #ddd !important;\n        }\n    }\n\n    // Bootstrap specific changes end\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/progress-bars.less",
    "content": "//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n  from  { background-position: 40px 0; }\n  to    { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n  overflow: hidden;\n  height: @line-height-computed;\n  margin-bottom: @line-height-computed;\n  background-color: @progress-bg;\n  border-radius: @progress-border-radius;\n  .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: @font-size-small;\n  line-height: @line-height-computed;\n  color: @progress-bar-color;\n  text-align: center;\n  background-color: @progress-bar-bg;\n  .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n  .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n  #gradient > .striped();\n  background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n  .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n  .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n  .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n  .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n  .progress-bar-variant(@progress-bar-danger-bg);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/responsive-embed.less",
    "content": "// Embeds responsive\n//\n// Credit: Nicolas Gallagher and SUIT CSS.\n\n.embed-responsive {\n  position: relative;\n  display: block;\n  height: 0;\n  padding: 0;\n  overflow: hidden;\n\n  .embed-responsive-item,\n  iframe,\n  embed,\n  object,\n  video {\n    position: absolute;\n    top: 0;\n    left: 0;\n    bottom: 0;\n    height: 100%;\n    width: 100%;\n    border: 0;\n  }\n}\n\n// Modifier class for 16:9 aspect ratio\n.embed-responsive-16by9 {\n  padding-bottom: 56.25%;\n}\n\n// Modifier class for 4:3 aspect ratio\n.embed-responsive-4by3 {\n  padding-bottom: 75%;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/responsive-utilities.less",
    "content": "//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#support-ie10-width\n// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n  width: device-width;\n}\n\n\n// Visibility utilities\n// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n  .responsive-invisibility();\n}\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\n.visible-xs {\n  @media (max-width: @screen-xs-max) {\n    .responsive-visibility();\n  }\n}\n.visible-xs-block {\n  @media (max-width: @screen-xs-max) {\n    display: block !important;\n  }\n}\n.visible-xs-inline {\n  @media (max-width: @screen-xs-max) {\n    display: inline !important;\n  }\n}\n.visible-xs-inline-block {\n  @media (max-width: @screen-xs-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-sm {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    .responsive-visibility();\n  }\n}\n.visible-sm-block {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: block !important;\n  }\n}\n.visible-sm-inline {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: inline !important;\n  }\n}\n.visible-sm-inline-block {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-md {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    .responsive-visibility();\n  }\n}\n.visible-md-block {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: block !important;\n  }\n}\n.visible-md-inline {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: inline !important;\n  }\n}\n.visible-md-inline-block {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    display: inline-block !important;\n  }\n}\n\n.visible-lg {\n  @media (min-width: @screen-lg-min) {\n    .responsive-visibility();\n  }\n}\n.visible-lg-block {\n  @media (min-width: @screen-lg-min) {\n    display: block !important;\n  }\n}\n.visible-lg-inline {\n  @media (min-width: @screen-lg-min) {\n    display: inline !important;\n  }\n}\n.visible-lg-inline-block {\n  @media (min-width: @screen-lg-min) {\n    display: inline-block !important;\n  }\n}\n\n.hidden-xs {\n  @media (max-width: @screen-xs-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-sm {\n  @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-md {\n  @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n    .responsive-invisibility();\n  }\n}\n.hidden-lg {\n  @media (min-width: @screen-lg-min) {\n    .responsive-invisibility();\n  }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n// Note: Deprecated .visible-print as of v3.2.0\n.visible-print {\n  .responsive-invisibility();\n\n  @media print {\n    .responsive-visibility();\n  }\n}\n.visible-print-block {\n  display: none !important;\n\n  @media print {\n    display: block !important;\n  }\n}\n.visible-print-inline {\n  display: none !important;\n\n  @media print {\n    display: inline !important;\n  }\n}\n.visible-print-inline-block {\n  display: none !important;\n\n  @media print {\n    display: inline-block !important;\n  }\n}\n\n.hidden-print {\n  @media print {\n    .responsive-invisibility();\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/scaffolding.less",
    "content": "//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n  .box-sizing(border-box);\n}\n*:before,\n*:after {\n  .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n  font-size: 10px;\n  -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n  font-family: @font-family-base;\n  font-size: @font-size-base;\n  line-height: @line-height-base;\n  color: @text-color;\n  background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n\n\n// Links\n\na {\n  color: @link-color;\n  text-decoration: none;\n\n  &:hover,\n  &:focus {\n    color: @link-hover-color;\n    text-decoration: @link-hover-decoration;\n  }\n\n  &:focus {\n    .tab-focus();\n  }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n  margin: 0;\n}\n\n\n// Images\n\nimg {\n  vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n  .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n  border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n  padding: @thumbnail-padding;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(all .2s ease-in-out);\n\n  // Keep them at most 100% wide\n  .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n  border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n  margin-top:    @line-height-computed;\n  margin-bottom: @line-height-computed;\n  border: 0;\n  border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0,0,0,0);\n  border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n  &:active,\n  &:focus {\n    position: static;\n    width: auto;\n    height: auto;\n    margin: 0;\n    overflow: visible;\n    clip: auto;\n  }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n// Upstream patch for normalize.css submitted: https://github.com/necolas/normalize.css/pull/379 - remove this fix once that is merged\n\n[role=\"button\"] {\n  cursor: pointer;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/tables.less",
    "content": "//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n  background-color: @table-bg;\n}\ncaption {\n  padding-top: @table-cell-padding;\n  padding-bottom: @table-cell-padding;\n  color: @text-muted;\n  text-align: left;\n}\nth {\n  text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n  width: 100%;\n  max-width: 100%;\n  margin-bottom: @line-height-computed;\n  // Cells\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-cell-padding;\n        line-height: @line-height-base;\n        vertical-align: top;\n        border-top: 1px solid @table-border-color;\n      }\n    }\n  }\n  // Bottom align for column headings\n  > thead > tr > th {\n    vertical-align: bottom;\n    border-bottom: 2px solid @table-border-color;\n  }\n  // Remove top border from thead by default\n  > caption + thead,\n  > colgroup + thead,\n  > thead:first-child {\n    > tr:first-child {\n      > th,\n      > td {\n        border-top: 0;\n      }\n    }\n  }\n  // Account for multiple tbody instances\n  > tbody + tbody {\n    border-top: 2px solid @table-border-color;\n  }\n\n  // Nesting\n  .table {\n    background-color: @body-bg;\n  }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        padding: @table-condensed-cell-padding;\n      }\n    }\n  }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n  border: 1px solid @table-border-color;\n  > thead,\n  > tbody,\n  > tfoot {\n    > tr {\n      > th,\n      > td {\n        border: 1px solid @table-border-color;\n      }\n    }\n  }\n  > thead > tr {\n    > th,\n    > td {\n      border-bottom-width: 2px;\n    }\n  }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n  > tbody > tr:nth-of-type(odd) {\n    background-color: @table-bg-accent;\n  }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n  > tbody > tr:hover {\n    background-color: @table-bg-hover;\n  }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n  position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n  float: none;\n  display: table-column;\n}\ntable {\n  td,\n  th {\n    &[class*=\"col-\"] {\n      position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n      float: none;\n      display: table-cell;\n    }\n  }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n  overflow-x: auto;\n  min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n  @media screen and (max-width: @screen-xs-max) {\n    width: 100%;\n    margin-bottom: (@line-height-computed * 0.75);\n    overflow-y: hidden;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid @table-border-color;\n\n    // Tighten up spacing\n    > .table {\n      margin-bottom: 0;\n\n      // Ensure the content doesn't wrap\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th,\n          > td {\n            white-space: nowrap;\n          }\n        }\n      }\n    }\n\n    // Special overrides for the bordered tables\n    > .table-bordered {\n      border: 0;\n\n      // Nuke the appropriate borders so that the parent can handle them\n      > thead,\n      > tbody,\n      > tfoot {\n        > tr {\n          > th:first-child,\n          > td:first-child {\n            border-left: 0;\n          }\n          > th:last-child,\n          > td:last-child {\n            border-right: 0;\n          }\n        }\n      }\n\n      // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n      // chances are there will be only one `tr` in a `thead` and that would\n      // remove the border altogether.\n      > tbody,\n      > tfoot {\n        > tr:last-child {\n          > th,\n          > td {\n            border-bottom: 0;\n          }\n        }\n      }\n\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/theme.less",
    "content": "\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\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  @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n  .box-shadow(@shadow);\n\n  // Reset the shadow\n  &:active,\n  &.active {\n    .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n  }\n\n  .badge {\n    text-shadow: none;\n  }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n  #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n  .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n  background-repeat: repeat-x;\n  border-color: darken(@btn-color, 14%);\n\n  &:hover,\n  &:focus  {\n    background-color: darken(@btn-color, 12%);\n    background-position: 0 -15px;\n  }\n\n  &:active,\n  &.active {\n    background-color: darken(@btn-color, 12%);\n    border-color: darken(@btn-color, 14%);\n  }\n\n  &.disabled,\n  &:disabled,\n  &[disabled] {\n    background-color: darken(@btn-color, 12%);\n    background-image: none;\n  }\n}\n\n// Common styles\n.btn {\n  // Remove the gradient for the pressed/active state\n  &:active,\n  &.active {\n    background-image: none;\n  }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info    { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger  { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n  .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n  #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n  background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n  #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n  background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n  #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n  .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n  border-radius: @navbar-border-radius;\n  @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n  .box-shadow(@shadow);\n\n  .navbar-nav > .open > a,\n  .navbar-nav > .active > a {\n    #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n    .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n  }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n  text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n  #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n  .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n\n  .navbar-nav > .open > a,\n  .navbar-nav > .active > a {\n    #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n    .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n  }\n\n  .navbar-brand,\n  .navbar-nav > li > a {\n    text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n  }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n  border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n  .navbar .navbar-nav .open .dropdown-menu > .active > a {\n    &,\n    &:hover,\n    &:focus {\n      color: #fff;\n      #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n    }\n  }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n  text-shadow: 0 1px 0 rgba(255,255,255,.2);\n  @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n  .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n  border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success    { .alert-styles(@alert-success-bg); }\n.alert-info       { .alert-styles(@alert-info-bg); }\n.alert-warning    { .alert-styles(@alert-warning-bg); }\n.alert-danger     { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n  #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar            { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success    { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info       { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning    { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger     { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n  #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n  border-radius: @border-radius-base;\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 darken(@list-group-active-bg, 10%);\n  #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n  border-color: darken(@list-group-active-border, 7.5%);\n\n  .badge {\n    text-shadow: none;\n  }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n  .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n  #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading   { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading   { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading   { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading      { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading   { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading    { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n  #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n  border-color: darken(@well-bg, 10%);\n  @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n  .box-shadow(@shadow);\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/thumbnails.less",
    "content": "//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n  display: block;\n  padding: @thumbnail-padding;\n  margin-bottom: @line-height-computed;\n  line-height: @line-height-base;\n  background-color: @thumbnail-bg;\n  border: 1px solid @thumbnail-border;\n  border-radius: @thumbnail-border-radius;\n  .transition(border .2s ease-in-out);\n\n  > img,\n  a > img {\n    &:extend(.img-responsive);\n    margin-left: auto;\n    margin-right: auto;\n  }\n\n  // Add a hover state for linked versions only\n  a&:hover,\n  a&:focus,\n  a&.active {\n    border-color: @link-color;\n  }\n\n  // Image captions\n  .caption {\n    padding: @thumbnail-caption-padding;\n    color: @thumbnail-caption-color;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/tooltip.less",
    "content": "//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n  position: absolute;\n  z-index: @zindex-tooltip;\n  display: block;\n  // Reset font and text properties given new insertion method\n  font-family: @font-family-base;\n  font-size: @font-size-small;\n  font-weight: normal;\n  line-height: 1.4;\n  .opacity(0);\n\n  &.in     { .opacity(@tooltip-opacity); }\n  &.top    { margin-top:  -3px; padding: @tooltip-arrow-width 0; }\n  &.right  { margin-left:  3px; padding: 0 @tooltip-arrow-width; }\n  &.bottom { margin-top:   3px; padding: @tooltip-arrow-width 0; }\n  &.left   { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n  max-width: @tooltip-max-width;\n  padding: 3px 8px;\n  color: @tooltip-color;\n  text-align: center;\n  text-decoration: none;\n  background-color: @tooltip-bg;\n  border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n  position: absolute;\n  width: 0;\n  height: 0;\n  border-color: transparent;\n  border-style: solid;\n}\n// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1\n.tooltip {\n  &.top .tooltip-arrow {\n    bottom: 0;\n    left: 50%;\n    margin-left: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.top-left .tooltip-arrow {\n    bottom: 0;\n    right: @tooltip-arrow-width;\n    margin-bottom: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.top-right .tooltip-arrow {\n    bottom: 0;\n    left: @tooltip-arrow-width;\n    margin-bottom: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-top-color: @tooltip-arrow-color;\n  }\n  &.right .tooltip-arrow {\n    top: 50%;\n    left: 0;\n    margin-top: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n    border-right-color: @tooltip-arrow-color;\n  }\n  &.left .tooltip-arrow {\n    top: 50%;\n    right: 0;\n    margin-top: -@tooltip-arrow-width;\n    border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-left-color: @tooltip-arrow-color;\n  }\n  &.bottom .tooltip-arrow {\n    top: 0;\n    left: 50%;\n    margin-left: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n  &.bottom-left .tooltip-arrow {\n    top: 0;\n    right: @tooltip-arrow-width;\n    margin-top: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n  &.bottom-right .tooltip-arrow {\n    top: 0;\n    left: @tooltip-arrow-width;\n    margin-top: -@tooltip-arrow-width;\n    border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n    border-bottom-color: @tooltip-arrow-color;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/type.less",
    "content": "//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n  font-family: @headings-font-family;\n  font-weight: @headings-font-weight;\n  line-height: @headings-line-height;\n  color: @headings-color;\n\n  small,\n  .small {\n    font-weight: normal;\n    line-height: 1;\n    color: @headings-small-color;\n  }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n  margin-top: @line-height-computed;\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 65%;\n  }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n  margin-top: (@line-height-computed / 2);\n  margin-bottom: (@line-height-computed / 2);\n\n  small,\n  .small {\n    font-size: 75%;\n  }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n  margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n  margin-bottom: @line-height-computed;\n  font-size: floor((@font-size-base * 1.15));\n  font-weight: 300;\n  line-height: 1.4;\n\n  @media (min-width: @screen-sm-min) {\n    font-size: (@font-size-base * 1.5);\n  }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n  font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n  background-color: @state-warning-bg;\n  padding: .2em;\n}\n\n// Alignment\n.text-left           { text-align: left; }\n.text-right          { text-align: right; }\n.text-center         { text-align: center; }\n.text-justify        { text-align: justify; }\n.text-nowrap         { white-space: nowrap; }\n\n// Transformation\n.text-lowercase      { text-transform: lowercase; }\n.text-uppercase      { text-transform: uppercase; }\n.text-capitalize     { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n  color: @text-muted;\n}\n.text-primary {\n  .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n  .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n  .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n  .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n  .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n  // Given the contrast here, this is the only class to have its color inverted\n  // automatically.\n  color: #fff;\n  .bg-variant(@brand-primary);\n}\n.bg-success {\n  .bg-variant(@state-success-bg);\n}\n.bg-info {\n  .bg-variant(@state-info-bg);\n}\n.bg-warning {\n  .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n  .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n  padding-bottom: ((@line-height-computed / 2) - 1);\n  margin: (@line-height-computed * 2) 0 @line-height-computed;\n  border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n  margin-top: 0;\n  margin-bottom: (@line-height-computed / 2);\n  ul,\n  ol {\n    margin-bottom: 0;\n  }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n  .list-unstyled();\n  margin-left: -5px;\n\n  > li {\n    display: inline-block;\n    padding-left: 5px;\n    padding-right: 5px;\n  }\n}\n\n// Description Lists\ndl {\n  margin-top: 0; // Remove browser default\n  margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n  line-height: @line-height-base;\n}\ndt {\n  font-weight: bold;\n}\ndd {\n  margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n  dd {\n    &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n  }\n\n  @media (min-width: @grid-float-breakpoint) {\n    dt {\n      float: left;\n      width: (@dl-horizontal-offset - 20);\n      clear: left;\n      text-align: right;\n      .text-overflow();\n    }\n    dd {\n      margin-left: @dl-horizontal-offset;\n    }\n  }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n  font-size: 90%;\n  .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n  padding: (@line-height-computed / 2) @line-height-computed;\n  margin: 0 0 @line-height-computed;\n  font-size: @blockquote-font-size;\n  border-left: 5px solid @blockquote-border-color;\n\n  p,\n  ul,\n  ol {\n    &:last-child {\n      margin-bottom: 0;\n    }\n  }\n\n  // Note: Deprecated small and .small as of v3.1.0\n  // Context: https://github.com/twbs/bootstrap/issues/11660\n  footer,\n  small,\n  .small {\n    display: block;\n    font-size: 80%; // back to default font-size\n    line-height: @line-height-base;\n    color: @blockquote-small-color;\n\n    &:before {\n      content: '\\2014 \\00A0'; // em dash, nbsp\n    }\n  }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid @blockquote-border-color;\n  border-left: 0;\n  text-align: right;\n\n  // Account for citation\n  footer,\n  small,\n  .small {\n    &:before { content: ''; }\n    &:after {\n      content: '\\00A0 \\2014'; // nbsp, em dash\n    }\n  }\n}\n\n// Addresses\naddress {\n  margin-bottom: @line-height-computed;\n  font-style: normal;\n  line-height: @line-height-base;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/utilities.less",
    "content": "//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n  .clearfix();\n}\n.center-block {\n  .center-block();\n}\n.pull-right {\n  float: right !important;\n}\n.pull-left {\n  float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n  display: none !important;\n}\n.show {\n  display: block !important;\n}\n.invisible {\n  visibility: hidden;\n}\n.text-hide {\n  .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n  display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n  position: fixed;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/variables.less",
    "content": "//\n// Variables\n// --------------------------------------------------\n\n\n//== Colors\n//\n//## Gray and brand colors for use across Bootstrap.\n\n@gray-base:              #000;\n@gray-darker:            lighten(@gray-base, 13.5%); // #222\n@gray-dark:              lighten(@gray-base, 20%);   // #333\n@gray:                   lighten(@gray-base, 33.5%); // #555\n@gray-light:             lighten(@gray-base, 46.7%); // #777\n@gray-lighter:           lighten(@gray-base, 93.5%); // #eee\n\n@brand-primary:         darken(#428bca, 6.5%); // #337ab7\n@brand-success:         #5cb85c;\n@brand-info:            #5bc0de;\n@brand-warning:         #f0ad4e;\n@brand-danger:          #d9534f;\n\n\n//== Scaffolding\n//\n//## Settings for some of the most global styles.\n\n//** Background color for `<body>`.\n@body-bg:               #fff;\n//** Global text color on `<body>`.\n@text-color:            @gray-dark;\n\n//** Global textual link color.\n@link-color:            @brand-primary;\n//** Link hover color set via `darken()` function.\n@link-hover-color:      darken(@link-color, 15%);\n//** Link hover decoration.\n@link-hover-decoration: underline;\n\n\n//== Typography\n//\n//## Font, line-height, and color for body text, headings, and more.\n\n@font-family-sans-serif:  \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n@font-family-serif:       Georgia, \"Times New Roman\", Times, serif;\n//** Default monospace fonts for `<code>`, `<kbd>`, and `<pre>`.\n@font-family-monospace:   Menlo, Monaco, Consolas, \"Courier New\", monospace;\n@font-family-base:        @font-family-sans-serif;\n\n@font-size-base:          14px;\n@font-size-large:         ceil((@font-size-base * 1.25)); // ~18px\n@font-size-small:         ceil((@font-size-base * 0.85)); // ~12px\n\n@font-size-h1:            floor((@font-size-base * 2.6)); // ~36px\n@font-size-h2:            floor((@font-size-base * 2.15)); // ~30px\n@font-size-h3:            ceil((@font-size-base * 1.7)); // ~24px\n@font-size-h4:            ceil((@font-size-base * 1.25)); // ~18px\n@font-size-h5:            @font-size-base;\n@font-size-h6:            ceil((@font-size-base * 0.85)); // ~12px\n\n//** Unit-less `line-height` for use in components like buttons.\n@line-height-base:        1.428571429; // 20/14\n//** Computed \"line-height\" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.\n@line-height-computed:    floor((@font-size-base * @line-height-base)); // ~20px\n\n//** By default, this inherits from the `<body>`.\n@headings-font-family:    inherit;\n@headings-font-weight:    500;\n@headings-line-height:    1.1;\n@headings-color:          inherit;\n\n\n//== Iconography\n//\n//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.\n\n//** Load fonts from this directory.\n@icon-font-path:          \"../fonts/\";\n//** File name for all font files.\n@icon-font-name:          \"glyphicons-halflings-regular\";\n//** Element ID within SVG icon file.\n@icon-font-svg-id:        \"glyphicons_halflingsregular\";\n\n\n//== Components\n//\n//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).\n\n@padding-base-vertical:     6px;\n@padding-base-horizontal:   12px;\n\n@padding-large-vertical:    10px;\n@padding-large-horizontal:  16px;\n\n@padding-small-vertical:    5px;\n@padding-small-horizontal:  10px;\n\n@padding-xs-vertical:       1px;\n@padding-xs-horizontal:     5px;\n\n@line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome\n@line-height-small:         1.5;\n\n@border-radius-base:        4px;\n@border-radius-large:       6px;\n@border-radius-small:       3px;\n\n//** Global color for active items (e.g., navs or dropdowns).\n@component-active-color:    #fff;\n//** Global background color for active items (e.g., navs or dropdowns).\n@component-active-bg:       @brand-primary;\n\n//** Width of the `border` for generating carets that indicator dropdowns.\n@caret-width-base:          4px;\n//** Carets increase slightly in size for larger components.\n@caret-width-large:         5px;\n\n\n//== Tables\n//\n//## Customizes the `.table` component with basic values, each used across all table variations.\n\n//** Padding for `<th>`s and `<td>`s.\n@table-cell-padding:            8px;\n//** Padding for cells in `.table-condensed`.\n@table-condensed-cell-padding:  5px;\n\n//** Default background color used for all tables.\n@table-bg:                      transparent;\n//** Background color used for `.table-striped`.\n@table-bg-accent:               #f9f9f9;\n//** Background color used for `.table-hover`.\n@table-bg-hover:                #f5f5f5;\n@table-bg-active:               @table-bg-hover;\n\n//** Border color for table and cell borders.\n@table-border-color:            #ddd;\n\n\n//== Buttons\n//\n//## For each of Bootstrap's buttons, define text, background and border color.\n\n@btn-font-weight:                normal;\n\n@btn-default-color:              #333;\n@btn-default-bg:                 #fff;\n@btn-default-border:             #ccc;\n\n@btn-primary-color:              #fff;\n@btn-primary-bg:                 @brand-primary;\n@btn-primary-border:             darken(@btn-primary-bg, 5%);\n\n@btn-success-color:              #fff;\n@btn-success-bg:                 @brand-success;\n@btn-success-border:             darken(@btn-success-bg, 5%);\n\n@btn-info-color:                 #fff;\n@btn-info-bg:                    @brand-info;\n@btn-info-border:                darken(@btn-info-bg, 5%);\n\n@btn-warning-color:              #fff;\n@btn-warning-bg:                 @brand-warning;\n@btn-warning-border:             darken(@btn-warning-bg, 5%);\n\n@btn-danger-color:               #fff;\n@btn-danger-bg:                  @brand-danger;\n@btn-danger-border:              darken(@btn-danger-bg, 5%);\n\n@btn-link-disabled-color:        @gray-light;\n\n\n//== Forms\n//\n//##\n\n//** `<input>` background color\n@input-bg:                       #fff;\n//** `<input disabled>` background color\n@input-bg-disabled:              @gray-lighter;\n\n//** Text color for `<input>`s\n@input-color:                    @gray;\n//** `<input>` border color\n@input-border:                   #ccc;\n\n// TODO: Rename `@input-border-radius` to `@input-border-radius-base` in v4\n//** Default `.form-control` border radius\n// This has no effect on `<select>`s in some browsers, due to the limited stylability of `<select>`s in CSS.\n@input-border-radius:            @border-radius-base;\n//** Large `.form-control` border radius\n@input-border-radius-large:      @border-radius-large;\n//** Small `.form-control` border radius\n@input-border-radius-small:      @border-radius-small;\n\n//** Border color for inputs on focus\n@input-border-focus:             #66afe9;\n\n//** Placeholder text color\n@input-color-placeholder:        #999;\n\n//** Default `.form-control` height\n@input-height-base:              (@line-height-computed + (@padding-base-vertical * 2) + 2);\n//** Large `.form-control` height\n@input-height-large:             (ceil(@font-size-large * @line-height-large) + (@padding-large-vertical * 2) + 2);\n//** Small `.form-control` height\n@input-height-small:             (floor(@font-size-small * @line-height-small) + (@padding-small-vertical * 2) + 2);\n\n//** `.form-group` margin\n@form-group-margin-bottom:       15px;\n\n@legend-color:                   @gray-dark;\n@legend-border-color:            #e5e5e5;\n\n//** Background color for textual input addons\n@input-group-addon-bg:           @gray-lighter;\n//** Border color for textual input addons\n@input-group-addon-border-color: @input-border;\n\n//** Disabled cursor for form controls and buttons.\n@cursor-disabled:                not-allowed;\n\n\n//== Dropdowns\n//\n//## Dropdown menu container and contents.\n\n//** Background for the dropdown menu.\n@dropdown-bg:                    #fff;\n//** Dropdown menu `border-color`.\n@dropdown-border:                rgba(0,0,0,.15);\n//** Dropdown menu `border-color` **for IE8**.\n@dropdown-fallback-border:       #ccc;\n//** Divider color for between dropdown items.\n@dropdown-divider-bg:            #e5e5e5;\n\n//** Dropdown link text color.\n@dropdown-link-color:            @gray-dark;\n//** Hover color for dropdown links.\n@dropdown-link-hover-color:      darken(@gray-dark, 5%);\n//** Hover background for dropdown links.\n@dropdown-link-hover-bg:         #f5f5f5;\n\n//** Active dropdown menu item text color.\n@dropdown-link-active-color:     @component-active-color;\n//** Active dropdown menu item background color.\n@dropdown-link-active-bg:        @component-active-bg;\n\n//** Disabled dropdown menu item background color.\n@dropdown-link-disabled-color:   @gray-light;\n\n//** Text color for headers within dropdown menus.\n@dropdown-header-color:          @gray-light;\n\n//** Deprecated `@dropdown-caret-color` as of v3.1.0\n@dropdown-caret-color:           #000;\n\n\n//-- Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n//\n// Note: These variables are not generated into the Customizer.\n\n@zindex-navbar:            1000;\n@zindex-dropdown:          1000;\n@zindex-popover:           1060;\n@zindex-tooltip:           1070;\n@zindex-navbar-fixed:      1030;\n@zindex-modal-background:  1040;\n@zindex-modal:             1050;\n\n\n//== Media queries breakpoints\n//\n//## Define the breakpoints at which your layout will change, adapting to different screen sizes.\n\n// Extra small screen / phone\n//** Deprecated `@screen-xs` as of v3.0.1\n@screen-xs:                  480px;\n//** Deprecated `@screen-xs-min` as of v3.2.0\n@screen-xs-min:              @screen-xs;\n//** Deprecated `@screen-phone` as of v3.0.1\n@screen-phone:               @screen-xs-min;\n\n// Small screen / tablet\n//** Deprecated `@screen-sm` as of v3.0.1\n@screen-sm:                  768px;\n@screen-sm-min:              @screen-sm;\n//** Deprecated `@screen-tablet` as of v3.0.1\n@screen-tablet:              @screen-sm-min;\n\n// Medium screen / desktop\n//** Deprecated `@screen-md` as of v3.0.1\n@screen-md:                  992px;\n@screen-md-min:              @screen-md;\n//** Deprecated `@screen-desktop` as of v3.0.1\n@screen-desktop:             @screen-md-min;\n\n// Large screen / wide desktop\n//** Deprecated `@screen-lg` as of v3.0.1\n@screen-lg:                  1200px;\n@screen-lg-min:              @screen-lg;\n//** Deprecated `@screen-lg-desktop` as of v3.0.1\n@screen-lg-desktop:          @screen-lg-min;\n\n// So media queries don't overlap when required, provide a maximum\n@screen-xs-max:              (@screen-sm-min - 1);\n@screen-sm-max:              (@screen-md-min - 1);\n@screen-md-max:              (@screen-lg-min - 1);\n\n\n//== Grid system\n//\n//## Define your custom responsive grid.\n\n//** Number of columns in the grid.\n@grid-columns:              12;\n//** Padding between columns. Gets divided in half for the left and right.\n@grid-gutter-width:         24px;\n// Navbar collapse\n//** Point at which the navbar becomes uncollapsed.\n@grid-float-breakpoint:     @screen-sm-min;\n//** Point at which the navbar begins collapsing.\n@grid-float-breakpoint-max: (@grid-float-breakpoint - 1);\n\n\n//== Container sizes\n//\n//## Define the maximum width of `.container` for different screen sizes.\n\n// Small screen / tablet\n@container-tablet:             (720px + @grid-gutter-width);\n//** For `@screen-sm-min` and up.\n@container-sm:                 @container-tablet;\n\n// Medium screen / desktop\n@container-desktop:            (940px + @grid-gutter-width);\n//** For `@screen-md-min` and up.\n@container-md:                 @container-desktop;\n\n// Large screen / wide desktop\n@container-large-desktop:      (1140px + @grid-gutter-width);\n//** For `@screen-lg-min` and up.\n@container-lg:                 @container-large-desktop;\n\n\n//== Navbar\n//\n//##\n\n// Basics of a navbar\n@navbar-height:                    50px;\n@navbar-margin-bottom:             @line-height-computed;\n@navbar-border-radius:             @border-radius-base;\n@navbar-padding-horizontal:        floor((@grid-gutter-width / 2));\n@navbar-padding-vertical:          ((@navbar-height - @line-height-computed) / 2);\n@navbar-collapse-max-height:       340px;\n\n@navbar-default-color:             #777;\n@navbar-default-bg:                #f8f8f8;\n@navbar-default-border:            darken(@navbar-default-bg, 6.5%);\n\n// Navbar links\n@navbar-default-link-color:                #777;\n@navbar-default-link-hover-color:          #333;\n@navbar-default-link-hover-bg:             transparent;\n@navbar-default-link-active-color:         #555;\n@navbar-default-link-active-bg:            darken(@navbar-default-bg, 6.5%);\n@navbar-default-link-disabled-color:       #ccc;\n@navbar-default-link-disabled-bg:          transparent;\n\n// Navbar brand label\n@navbar-default-brand-color:               @navbar-default-link-color;\n@navbar-default-brand-hover-color:         darken(@navbar-default-brand-color, 10%);\n@navbar-default-brand-hover-bg:            transparent;\n\n// Navbar toggle\n@navbar-default-toggle-hover-bg:           #ddd;\n@navbar-default-toggle-icon-bar-bg:        #888;\n@navbar-default-toggle-border-color:       #ddd;\n\n\n// Inverted navbar\n// Reset inverted navbar basics\n@navbar-inverse-color:                      lighten(@gray-light, 15%);\n@navbar-inverse-bg:                         #222;\n@navbar-inverse-border:                     darken(@navbar-inverse-bg, 10%);\n\n// Inverted navbar links\n@navbar-inverse-link-color:                 lighten(@gray-light, 15%);\n@navbar-inverse-link-hover-color:           #fff;\n@navbar-inverse-link-hover-bg:              transparent;\n@navbar-inverse-link-active-color:          @navbar-inverse-link-hover-color;\n@navbar-inverse-link-active-bg:             darken(@navbar-inverse-bg, 10%);\n@navbar-inverse-link-disabled-color:        #444;\n@navbar-inverse-link-disabled-bg:           transparent;\n\n// Inverted navbar brand label\n@navbar-inverse-brand-color:                @navbar-inverse-link-color;\n@navbar-inverse-brand-hover-color:          #fff;\n@navbar-inverse-brand-hover-bg:             transparent;\n\n// Inverted navbar toggle\n@navbar-inverse-toggle-hover-bg:            #333;\n@navbar-inverse-toggle-icon-bar-bg:         #fff;\n@navbar-inverse-toggle-border-color:        #333;\n\n\n//== Navs\n//\n//##\n\n//=== Shared nav styles\n@nav-link-padding:                          10px 15px;\n@nav-link-hover-bg:                         @gray-lighter;\n\n@nav-disabled-link-color:                   @gray-light;\n@nav-disabled-link-hover-color:             @gray-light;\n\n//== Tabs\n@nav-tabs-border-color:                     #ddd;\n\n@nav-tabs-link-hover-border-color:          @gray-lighter;\n\n@nav-tabs-active-link-hover-bg:             @body-bg;\n@nav-tabs-active-link-hover-color:          @gray;\n@nav-tabs-active-link-hover-border-color:   #ddd;\n\n@nav-tabs-justified-link-border-color:            #ddd;\n@nav-tabs-justified-active-link-border-color:     @body-bg;\n\n//== Pills\n@nav-pills-border-radius:                   @border-radius-base;\n@nav-pills-active-link-hover-bg:            @component-active-bg;\n@nav-pills-active-link-hover-color:         @component-active-color;\n\n\n//== Pagination\n//\n//##\n\n@pagination-color:                     @link-color;\n@pagination-bg:                        #fff;\n@pagination-border:                    #ddd;\n\n@pagination-hover-color:               @link-hover-color;\n@pagination-hover-bg:                  @gray-lighter;\n@pagination-hover-border:              #ddd;\n\n@pagination-active-color:              #fff;\n@pagination-active-bg:                 @brand-primary;\n@pagination-active-border:             @brand-primary;\n\n@pagination-disabled-color:            @gray-light;\n@pagination-disabled-bg:               #fff;\n@pagination-disabled-border:           #ddd;\n\n\n//== Pager\n//\n//##\n\n@pager-bg:                             @pagination-bg;\n@pager-border:                         @pagination-border;\n@pager-border-radius:                  15px;\n\n@pager-hover-bg:                       @pagination-hover-bg;\n\n@pager-active-bg:                      @pagination-active-bg;\n@pager-active-color:                   @pagination-active-color;\n\n@pager-disabled-color:                 @pagination-disabled-color;\n\n\n//== Jumbotron\n//\n//##\n\n@jumbotron-padding:              30px;\n@jumbotron-color:                inherit;\n@jumbotron-bg:                   @gray-lighter;\n@jumbotron-heading-color:        inherit;\n@jumbotron-font-size:            ceil((@font-size-base * 1.5));\n@jumbotron-heading-font-size:    ceil((@font-size-base * 4.5));\n\n\n//== Form states and alerts\n//\n//## Define colors for form feedback states and, by default, alerts.\n\n@state-success-text:             #3c763d;\n@state-success-bg:               #dff0d8;\n@state-success-border:           darken(spin(@state-success-bg, -10), 5%);\n\n@state-info-text:                #31708f;\n@state-info-bg:                  #d9edf7;\n@state-info-border:              darken(spin(@state-info-bg, -10), 7%);\n\n@state-warning-text:             #8a6d3b;\n@state-warning-bg:               #fcf8e3;\n@state-warning-border:           darken(spin(@state-warning-bg, -10), 5%);\n\n@state-danger-text:              #a94442;\n@state-danger-bg:                #f2dede;\n@state-danger-border:            darken(spin(@state-danger-bg, -10), 5%);\n\n\n//== Tooltips\n//\n//##\n\n//** Tooltip max width\n@tooltip-max-width:           200px;\n//** Tooltip text color\n@tooltip-color:               #fff;\n//** Tooltip background color\n@tooltip-bg:                  #000;\n@tooltip-opacity:             .9;\n\n//** Tooltip arrow width\n@tooltip-arrow-width:         5px;\n//** Tooltip arrow color\n@tooltip-arrow-color:         @tooltip-bg;\n\n\n//== Popovers\n//\n//##\n\n//** Popover body background color\n@popover-bg:                          #fff;\n//** Popover maximum width\n@popover-max-width:                   276px;\n//** Popover border color\n@popover-border-color:                rgba(0,0,0,.2);\n//** Popover fallback border color\n@popover-fallback-border-color:       #ccc;\n\n//** Popover title background color\n@popover-title-bg:                    darken(@popover-bg, 3%);\n\n//** Popover arrow width\n@popover-arrow-width:                 10px;\n//** Popover arrow color\n@popover-arrow-color:                 @popover-bg;\n\n//** Popover outer arrow width\n@popover-arrow-outer-width:           (@popover-arrow-width + 1);\n//** Popover outer arrow color\n@popover-arrow-outer-color:           fadein(@popover-border-color, 5%);\n//** Popover outer arrow fallback color\n@popover-arrow-outer-fallback-color:  darken(@popover-fallback-border-color, 20%);\n\n\n//== Labels\n//\n//##\n\n//** Default label background color\n@label-default-bg:            @gray-light;\n//** Primary label background color\n@label-primary-bg:            @brand-primary;\n//** Success label background color\n@label-success-bg:            @brand-success;\n//** Info label background color\n@label-info-bg:               @brand-info;\n//** Warning label background color\n@label-warning-bg:            @brand-warning;\n//** Danger label background color\n@label-danger-bg:             @brand-danger;\n\n//** Default label text color\n@label-color:                 #fff;\n//** Default text color of a linked label\n@label-link-hover-color:      #fff;\n\n\n//== Modals\n//\n//##\n\n//** Padding applied to the modal body\n@modal-inner-padding:         15px;\n\n//** Padding applied to the modal title\n@modal-title-padding:         15px;\n//** Modal title line-height\n@modal-title-line-height:     @line-height-base;\n\n//** Background color of modal content area\n@modal-content-bg:                             #fff;\n//** Modal content border color\n@modal-content-border-color:                   rgba(0,0,0,.2);\n//** Modal content border color **for IE8**\n@modal-content-fallback-border-color:          #999;\n\n//** Modal backdrop background color\n@modal-backdrop-bg:           #000;\n//** Modal backdrop opacity\n@modal-backdrop-opacity:      .5;\n//** Modal header border color\n@modal-header-border-color:   #e5e5e5;\n//** Modal footer border color\n@modal-footer-border-color:   @modal-header-border-color;\n\n@modal-lg:                    900px;\n@modal-md:                    600px;\n@modal-sm:                    300px;\n\n\n//== Alerts\n//\n//## Define alert colors, border radius, and padding.\n\n@alert-padding:               15px;\n@alert-border-radius:         @border-radius-base;\n@alert-link-font-weight:      bold;\n\n@alert-success-bg:            @state-success-bg;\n@alert-success-text:          @state-success-text;\n@alert-success-border:        @state-success-border;\n\n@alert-info-bg:               @state-info-bg;\n@alert-info-text:             @state-info-text;\n@alert-info-border:           @state-info-border;\n\n@alert-warning-bg:            @state-warning-bg;\n@alert-warning-text:          @state-warning-text;\n@alert-warning-border:        @state-warning-border;\n\n@alert-danger-bg:             @state-danger-bg;\n@alert-danger-text:           @state-danger-text;\n@alert-danger-border:         @state-danger-border;\n\n\n//== Progress bars\n//\n//##\n\n//** Background color of the whole progress component\n@progress-bg:                 #f5f5f5;\n//** Progress bar text color\n@progress-bar-color:          #fff;\n//** Variable for setting rounded corners on progress bar.\n@progress-border-radius:      @border-radius-base;\n\n//** Default progress bar color\n@progress-bar-bg:             @brand-primary;\n//** Success progress bar color\n@progress-bar-success-bg:     @brand-success;\n//** Warning progress bar color\n@progress-bar-warning-bg:     @brand-warning;\n//** Danger progress bar color\n@progress-bar-danger-bg:      @brand-danger;\n//** Info progress bar color\n@progress-bar-info-bg:        @brand-info;\n\n\n//== List group\n//\n//##\n\n//** Background color on `.list-group-item`\n@list-group-bg:                 #fff;\n//** `.list-group-item` border color\n@list-group-border:             #ddd;\n//** List group border radius\n@list-group-border-radius:      @border-radius-base;\n\n//** Background color of single list items on hover\n@list-group-hover-bg:           #f5f5f5;\n//** Text color of active list items\n@list-group-active-color:       @component-active-color;\n//** Background color of active list items\n@list-group-active-bg:          @component-active-bg;\n//** Border color of active list elements\n@list-group-active-border:      @list-group-active-bg;\n//** Text color for content within active list items\n@list-group-active-text-color:  lighten(@list-group-active-bg, 40%);\n\n//** Text color of disabled list items\n@list-group-disabled-color:      @gray-light;\n//** Background color of disabled list items\n@list-group-disabled-bg:         @gray-lighter;\n//** Text color for content within disabled list items\n@list-group-disabled-text-color: @list-group-disabled-color;\n\n@list-group-link-color:         #555;\n@list-group-link-hover-color:   @list-group-link-color;\n@list-group-link-heading-color: #333;\n\n\n//== Panels\n//\n//##\n\n@panel-bg:                    #fff;\n@panel-body-padding:          15px;\n@panel-heading-padding:       10px 15px;\n@panel-footer-padding:        @panel-heading-padding;\n@panel-border-radius:         @border-radius-base;\n\n//** Border color for elements within panels\n@panel-inner-border:          #ddd;\n@panel-footer-bg:             #f5f5f5;\n\n@panel-default-text:          @gray-dark;\n@panel-default-border:        #ddd;\n@panel-default-heading-bg:    #f5f5f5;\n\n@panel-primary-text:          #fff;\n@panel-primary-border:        @brand-primary;\n@panel-primary-heading-bg:    @brand-primary;\n\n@panel-success-text:          @state-success-text;\n@panel-success-border:        @state-success-border;\n@panel-success-heading-bg:    @state-success-bg;\n\n@panel-info-text:             @state-info-text;\n@panel-info-border:           @state-info-border;\n@panel-info-heading-bg:       @state-info-bg;\n\n@panel-warning-text:          @state-warning-text;\n@panel-warning-border:        @state-warning-border;\n@panel-warning-heading-bg:    @state-warning-bg;\n\n@panel-danger-text:           @state-danger-text;\n@panel-danger-border:         @state-danger-border;\n@panel-danger-heading-bg:     @state-danger-bg;\n\n\n//== Thumbnails\n//\n//##\n\n//** Padding around the thumbnail image\n@thumbnail-padding:           4px;\n//** Thumbnail background color\n@thumbnail-bg:                @body-bg;\n//** Thumbnail border color\n@thumbnail-border:            #ddd;\n//** Thumbnail border radius\n@thumbnail-border-radius:     @border-radius-base;\n\n//** Custom text color for thumbnail captions\n@thumbnail-caption-color:     @text-color;\n//** Padding around the thumbnail caption\n@thumbnail-caption-padding:   9px;\n\n\n//== Wells\n//\n//##\n\n@well-bg:                     #f5f5f5;\n@well-border:                 darken(@well-bg, 7%);\n\n\n//== Badges\n//\n//##\n\n@badge-color:                 #fff;\n//** Linked badge text color on hover\n@badge-link-hover-color:      #fff;\n@badge-bg:                    @gray-light;\n\n//** Badge text color in active nav link\n@badge-active-color:          @link-color;\n//** Badge background color in active nav link\n@badge-active-bg:             #fff;\n\n@badge-font-weight:           bold;\n@badge-line-height:           1;\n@badge-border-radius:         10px;\n\n\n//== Breadcrumbs\n//\n//##\n\n@breadcrumb-padding-vertical:   8px;\n@breadcrumb-padding-horizontal: 15px;\n//** Breadcrumb background color\n@breadcrumb-bg:                 #f5f5f5;\n//** Breadcrumb text color\n@breadcrumb-color:              #ccc;\n//** Text color of current page in the breadcrumb\n@breadcrumb-active-color:       @gray-light;\n//** Textual separator for between breadcrumb elements\n@breadcrumb-separator:          \"/\";\n\n\n//== Carousel\n//\n//##\n\n@carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);\n\n@carousel-control-color:                      #fff;\n@carousel-control-width:                      15%;\n@carousel-control-opacity:                    .5;\n@carousel-control-font-size:                  20px;\n\n@carousel-indicator-active-bg:                #fff;\n@carousel-indicator-border-color:             #fff;\n\n@carousel-caption-color:                      #fff;\n\n\n//== Close\n//\n//##\n\n@close-font-weight:           bold;\n@close-color:                 #000;\n@close-text-shadow:           0 1px 0 #fff;\n\n\n//== Code\n//\n//##\n\n@code-color:                  #c7254e;\n@code-bg:                     #f9f2f4;\n\n@kbd-color:                   #fff;\n@kbd-bg:                      #333;\n\n@pre-bg:                      #f5f5f5;\n@pre-color:                   @gray-dark;\n@pre-border-color:            #ccc;\n@pre-scrollable-max-height:   340px;\n\n\n//== Type\n//\n//##\n\n//** Horizontal offset for forms and lists.\n@component-offset-horizontal: 180px;\n//** Text muted color\n@text-muted:                  @gray-light;\n//** Abbreviations and acronyms border color\n@abbr-border-color:           @gray-light;\n//** Headings small color\n@headings-small-color:        @gray-light;\n//** Blockquote small color\n@blockquote-small-color:      @gray-light;\n//** Blockquote font size\n@blockquote-font-size:        (@font-size-base * 1.25);\n//** Blockquote border color\n@blockquote-border-color:     @gray-lighter;\n//** Page header border color\n@page-header-border-color:    @gray-lighter;\n//** Width of horizontal description list titles\n@dl-horizontal-offset:        @component-offset-horizontal;\n//** Horizontal line color.\n@hr-border:                   @gray-lighter;\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-master/wells.less",
    "content": "//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n  min-height: 20px;\n  padding: 19px;\n  margin-bottom: 20px;\n  background-color: @well-bg;\n  border: 1px solid @well-border;\n  border-radius: @border-radius-base;\n  .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n  blockquote {\n    border-color: #ddd;\n    border-color: rgba(0,0,0,.15);\n  }\n}\n\n// Sizes\n.well-lg {\n  padding: 24px;\n  border-radius: @border-radius-large;\n}\n.well-sm {\n  padding: 9px;\n  border-radius: @border-radius-small;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/bootstrap-overrides.less",
    "content": "/*\n * Media - Overriding the Media object to 3.2 version in order to prevent issues like text overflow.\n */\n.media {\n    .clearfix();\n    \n    & > .pull-left {\n        padding-right: 15px;\n    }\n    \n    & > .pull-right {\n        padding-left: 15px;\n    }\n    \n    overflow: visible;\n}\n\n.media-heading {\n    font-size: 14px;\n    margin-bottom: 10px;\n}\n\n.media-body {\n    zoom: 1;\n    display: block;\n    width: auto;\n} \n\n.media-object {\n    border-radius: 2px;\n}\n\n.close { \n    .opacity(0.5);\n    font-weight: normal;\n    text-shadow: none;\n\n    &:hover {\n        color: inherit;\n        .opacity(1);\n    }\n}\n\n.dl-horizontal dt {\n    text-align: left;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/breadcrumb.less",
    "content": ".breadcrumb {\n    border-bottom: 1px solid #E5E5E5;\n    border-radius: 0;\n\n    \n    \n    & > li {\n        \n        & > a {\n            color: #A9A9A9;\n            \n            &:hover {\n                color: @breadcrumb-active-color;\n            }\n        }\n    }\n}\n\nbody {\n    &:not(.sw-toggled) {\n        .breadcrumb {\n            @media (min-width: @screen-sm-min) {\n                padding: 10px 33px 11px;\n            }\n        }\n    }\n    \n    &.sw-toggled {\n        .breadcrumb {\n            @media (min-width: 1199px) {\n                padding: 10px 33px 11px 280px;\n            }\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/button.less",
    "content": ".btn {\n    border: 0;\n    text-transform: uppercase;\n\n\n    &[class*=\"bgm-\"]:not(.bgm-white) {\n        color: #fff;\n    }\n\n    .caret {\n        margin-top: -3px;\n    }\n     \n    &:not(.btn-link) {\n        .z-depth(1);\n    }\n}\n\n.btn-group, .btn-group-vertical {\n    &:not(.bootstrap-select) {\n        box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.3);\n    }\n\n    .btn,\n    .btn:active,\n    .btn:focus,\n    .btn-group {\n        box-shadow: none !important;\n    }\n    \n    .btn {\n        margin: 0;\n    }\n}\n\n.btn-xs {\n  .button-size(2px; @padding-xs-horizontal; 11px; @line-height-small; @border-radius-small);\n}\n\n.btn-link {\n    color: #797979;\n    text-decoration: none;\n    border-radius: 2px;\n\n    &:hover {\n        color: #0a0a0a;\n    }\n\n    &:hover,\n    &:active,\n    &:focus  {\n        text-decoration: none;\n    }\n}\n\n.btn-inverse {\n    .button-variant(#fff, #454545, transparent);\n}\n\n.btn-icon {\n    border-radius: 50%;\n    width: 40px;\n    line-height: 42px;\n    height: 40px;\n    padding: 0;\n    text-align: center;\n    \n    .zmdi {\n        font-size: 17px;\n    }\n}\n\n.btn-icon-text {\n    & > .zmdi {\n        font-size: 15px;\n        vertical-align: top;\n        display: inline-block;\n        margin-top: 2px;\n        line-height: 100%;\n        margin-right: 5px;\n    }\n}\n\n.btn-float { \n    width: 50px;\n    height: 50px;\n    border-radius: 50%;\n    line-height: 45px !important;\n    \n    &:not(.m-btn) {\n        position: absolute !important;\n    }\n\n    i {\n        font-size: 23px;\n        .transition(all);\n        .transition-duration(500ms);\n    }\n    \n    &:hover {\n        i {\n            .rotate(360deg);\n        }\n    }\n    \n    &:not(.bgm-white):not(.bgm-gray) {\n        & > i {\n            color: #fff;\n        }\n    }\n\n    &:not(.bgm-white):not(.bgm-gray) {\n        & > i {\n            color: #fff;\n        }\n    }\n    \n    &.bgm-white,\n    &.bgm-gray {\n        & > i {\n            color: #333;\n        }\n    }\n}\n\n\n.open .btn {\n    outline: none !important;\n    -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n    \n    &:focus, &:active {\n        outline: none !important;\n        -webkit-tap-highlight-color: rgba(0, 0, 0, 0) !important;\n    }\n}\n\n/*\n * Material Design Add button\n */\n.m-btn {\n    z-index: 1;\n    bottom: 40px;\n    right: 40px;\n    position: fixed !important;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/card.less",
    "content": ".card {\n    position: relative;\n    background: #fff;\n    box-shadow: @card-shadow;\n    margin-bottom: @grid-gutter-width;\n\n    .card-header {\n        position: relative; \n        \n        &:not(.ch-alt) {\n            @media screen and (min-width: @screen-sm-min) {\n                padding: 23px 25px;\n            }\n            \n            @media screen and (max-width: @screen-sm-max) {\n                padding: 18px; \n            }\n        }\n\n        h2 {\n            margin: 0;\n            line-height: 100%;\n            font-size: 17px;\n            font-weight: 400;\n            \n            small {\n                display: block;\n                margin-top: 8px;\n                color: #AEAEAE;\n                line-height: 160%;\n            }\n        } \n\n        &.ch-alt {\n            @media screen and (min-width: @screen-sm-min) {\n                padding: 23px 26px;\n            } \n            \n            @media screen and (max-width: @screen-sm-max) {\n                padding: 18px 18px 28px;\n            }\n                        \n            &:not([class*=\"bgm-\"]) {\n                background-color: #f7f7f7;\n            }\n        }\n\n        &[class*=\"bgm-\"] {\n            h2, h2 small { \n                color: #fff;\n            }\n        }\n        \n        .actions {\n            position: absolute; \n            right: 10px;\n            z-index: 2; \n            top: 15px;\n        }\n        \n        .btn-float {\n            right: 25px;\n            bottom: -23px;\n            z-index: 1;\n        }\n    }\n    \n    .card-body { \n        &.card-padding {\n            @media screen and (min-width: @screen-sm-min) {\n                padding: 23px 26px;\n            }\n            \n            @media screen and (max-width: @screen-sm-max) {\n                padding: 18px;\n            }\n        }\n        \n        &.card-padding-sm {\n            padding: 15px;\n        }\n    }\n}\n\n.card-header:not(.ch-alt):not([class*=\"bgm-\"]) + .card-padding {\n    padding-top: 0;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/chart.less",
    "content": ".chart-edge {\n    margin: 20px -8px 0 -10px;\n    overflow: hidden;\n    \n    .flot-chart {\n        bottom: -14px;\n    }\n}\n\n.charts-row {\n    margin-top: 50px;\n    margin-bottom: 20px;\n}\n\n.mini-charts-item {\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n    position: relative;\n    margin-bottom: 30px;\n    \n    .chart {\n        padding: 15px;\n        float: left;\n        \n        &.chart-pie {\n            margin: 0 20px;\n        }\n    } \n    \n    .count {\n        overflow: hidden;\n        color: rgba(255, 255, 255, 0.9);\n        padding: 16px 12px;\n        \n        & > h2 {\n            margin: 0;\n            line-height: 100%;\n            font-size: 22px;\n            font-weight: 300;\n            color: #fff;   \n        }\n        \n        & > small {\n            margin-bottom: 2px;\n            display: block;\n        }\n        \n        & > h2,\n        & > small {\n            .text-overflow();\n        }\n    }\n    \n    \n    \n    & > .clearfix {\n        position: relative;\n        z-index: 1;\n    }\n    \n    &:before {\n        .transition(width);\n        .transition-duration(500ms);\n        .backface-visibility(hidden);\n        content: \"\";\n        width: 113px;\n        height: 100%;\n        background: rgba(0,0,0,0.1);\n        position: absolute;\n        left: 0;\n        top: 0;\n    }\n    \n    &:hover {\n        .count {\n            color: #fff !important;\n        }\n        \n        &:before {\n            width: 100%;\n        }\n    }\n}\n\n/*\n * Sparkline Tooltip\n */\n#jqstooltip {\n    min-width: 21px;\n    min-height: 23px;\n    text-align: center;\n    border: 0;\n    background: #fff;\n    box-shadow: 2px 2px 5px rgba(0,0,0,0.3);\n    background-color: #fff;\n\n    .jqsfield {\n        font-size: 12px;\n        font-weight: 700;\n        font-family: inherit;\n        text-align: center;\n        color: #333;\n\n        & > span {\n            display: none;\n        }\n    }\n}\n\n/*\n * Easy Pie Charts\n */\n\n.epc-item {\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n    position: relative;\n    margin-bottom: 30px;\n    padding: 30px 20px;\n    text-align: center;\n}\n\n.easy-pie {\n    display: inline-block;\n    position: relative;\n    padding: 0 5px 10px;\n    \n    .percent {\n       position: absolute;\n       font-weight: 300;\n       width: 100%;\n       line-height: 100%;\n       left: 0;\n       \n        &:after {\n            content: \"%\";\n        } \n    }\n    \n    &.main-pie {\n        .percent {\n            margin-top: 49px;\n            font-size: 50px;\n            text-align: center;\n            \n            &:not([class*=\"c-\"]) {\n                color: rgba(255,255,255,0.7);\n            }\n            \n            &:after {\n                font-size: 30px;\n            } \n        }\n        \n        .pie-title {\n            color: #fff;\n        }\n    }\n    \n    &:not(.main-pie) {\n        .percent {\n            font-size: 26px;\n            margin-top: 37px;\n            \n            &:after {\n                font-size: 20px;\n            }\n        }\n    }\n    \n    .pie-title {\n        position: absolute;\n        width: 100%;\n        text-align: center;\n        bottom: -3px;\n        left: 0;\n    }\n    \n}\n\n/*\n * Recet Items Table Chart\n */\n#recent-items-chart {\n    width: ~\"calc(100% + 19px)\";\n    height: 150px;\n    margin: -20px -10px 0;\n    bottom: -10px;\n\n}\n\n/*\n * Flot Chart\n */\n[class*=\"flot-chart\"] {\n    width: 100%;\n    display: block;\n}\n\n.flot-chart {\n    height: 200px;\n}\n\n.flot-chart-pie {\n    height: 300px;\n    \n    @media (min-width: @screen-sm-min) {\n        margin-bottom: 20px;\n    }\n}\n\n.flot-tooltip, #flotTip {\n    position: absolute;\n    color: #333;\n    display: none;\n    font-size: 12px;\n    box-shadow: 2px 2px 5px rgba(0,0,0,0.1);\n    padding: 3px 10px;\n    background-color: #fff;\n    z-index: 99999;\n}\n\n[class*=\"flc-\"] {\n    text-align: center;\n    margin: 10px 0 5px;\n    \n    table {\n        display: inline-block;\n    }\n    \n    .legendColorBox {\n        & > div {\n            border: #fff !important;\n            \n            & > div {\n                border-radius: 50%;\n            }\n        }\n    }\n    \n    .legendLabel {\n        padding: 0 8px 0 3px;\n    }\n}\n\n\n\n    "
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/chat.less",
    "content": "#chat {\n    padding: 20px 0;\n    width: @sidebar-right-width;\n    right: -(@sidebar-right-width + 20);\n\n    &.toggled {\n        right: 0;\n    }\n    \n    .chat-search {\n        padding: 20px 20px 15px 20px;\n        \n        .form-control {\n            .img-retina('../img/icons/search-2.png', '../img/icons/search-2@2x.png', 24px, 24px);\n            background-repeat: no-repeat;\n            background-position: left center;\n            padding-left: 30px;\n            .transition(all); \n            .transition-duration(300ms);\n            \n            &:focus {\n                background-position: right center;\n                padding: 0 30px 0 0;\n            }\n        }\n    }\n}\n\n/*\n * Chat Status Icons\n */\n[class*=\"chat-status\"] {\n    position: absolute;\n    width: 10px;\n    height: 10px;\n    border-radius: 50%;\n    top: -3px;\n    right: 12px;\n    border: 2px solid #FFF;\n }\n \n/* Simple Mixin */\n.chat-status(@color) {\n   box-shadow: 0 0 0 1px @color;\n   background: @color;\n}\n\n.chat-status-online {\n    .chat-status(#1EC01E);\n}\n\n.chat-status-offline {\n    .chat-status(#E73F3F);\n}\n\n.chat-status-busy {\n    .chat-status(#FFA500);\n}\n\n/*\n * For Stupid IE9\n */\n.ie9 {\n    #chat {\n        right: 0;\n        \n        &:not(.toggled) {\n            display: none;\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/contacts.less",
    "content": ".contacts {\n    &:not(.c-profile) {\n        padding: 0 8px;\n    }\n    \n    & > [class*=\"col-\"] {\n        padding: 0 10px;\n    }\n    \n    .c-item {\n        border: 1px solid #e2e2e2;\n        border-radius: 2px;\n        margin-bottom: 24px;\n        \n        .ci-avatar {\n            display: block;\n            \n            img {\n                width: 100%;\n                border-radius: 2px 2px 0 0;\n            }\n        } \n    }\n    \n    .ci-avatar {\n        margin: -1px -1px 0;\n    }\n    \n    .c-info {\n        text-align: center;\n        margin-top: 15px;\n        padding: 0 5px;\n         \n        strong {\n            color: #000;\n            font-size: 14px;\n            font-weight: 500;\n        }\n        \n        small {\n            color: #999;\n            margin-top: 3px;\n        }\n        \n        strong,\n        small {\n            .text-overflow();\n            display: block;\n        }\n    }\n    \n    .c-footer {\n        border-top: 1px solid #e2e2e2;\n        margin-top: 18px;\n        \n        & > button {\n            padding: 4px 10px 3px;\n            color: #333;\n            display: block;\n            width: 100%;\n            text-align: center;\n            color: #333;\n            font-weight: 500;\n            border-radius: 2px;\n            background: #fff;\n            border: 0;\n            \n            & > i {\n                font-size: 16px;\n                vertical-align: middle;\n                margin-top: -3px;   \n            }\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/dropdown.less",
    "content": ".dropdown-menu {\n    box-shadow: @dropdown-shadow;\n    .transition(all);\n    .transition-duration(250ms); \n    \n    & > li > a { \n        padding: 8px 17px;\n        .transition(background-color);\n        .transition-duration(300ms);\n    }\n\n    &.dropdown-menu-lg {\n        width: 300px;\n    }\n    \n    &.dropdown-menu-sm {\n        width: 150px;\n    }\n    \n    &.dropdown-menu-right {\n        right: 0;\n        left: auto;\n        \n        & > li > a {\n            text-align: right;\n        }\n    }\n\n    &.dm-icon {\n        & > li > a > .zmdi {\n            line-height: 100%;\n            vertical-align: top;\n            font-size: 18px;\n            width: 28px;\n        }\n    }\n    \n    &:not([class*=\"bgm-\"]) {\n        & > li > a {\n            color: #4C4C4C;\n            \n            &:hover {\n                color: #000;\n            }\n        }\n    }\n    \n    &[class*=\"bgm-\"] {\n        & > li > a {\n            font-weight: 300;\n            color: #fff;\n        }\n    }\n}\n\n.dropdown, .btn-group {\n    &:not([data-animation]) {\n        .dropdown-menu {\n            .scale(0);\n            .opacity(0);\n            display: block\n        }\n    }\n}\n\n.dropdown, .bootstrap-select, .btn-group {\n    .dropdown-menu {\n        &:not([data-animation]) {\n            &.pull-right, &.dropdown-menu-right {\n                .transform-origin(top right);\n            }\n            \n            &:not(.pull-right):not(.dropdown-menu-right) {\n                .transform-origin(top left);\n            }\n        }\n    }\n}\n\n\n.dropup {\n    .dropdown-menu {\n        &:not([data-animation]) {\n            &.pull-right, &.dropdown-menu-right {\n                .transform-origin(bottom right);\n            }\n            \n            &:not(.pull-right):not(.dropdown-menu-right) {\n                .transform-origin(bottom left);\n            }\n        }\n    }\n}\n\n.dropdown, .dropup, .bootstrap-select, .btn-group {\n    &.open {\n        .dropdown-menu {\n            &:not([data-animation]) {\n                .scale(1);\n                .opacity(1);\n            }\n        }\n    }\n}\n\n.dropdown-header {\n    padding: 3px 17px;\n    margin-top: 10px;\n    color: #b1b1b1;\n    text-transform: uppercase;\n    font-weight: normal;\n}\n\n.btn-group.open .dropdown-toggle {\n    box-shadow: none;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/font.less",
    "content": "/*\n * Roboto Light\n */ \n.font-face(roboto, 'Roboto-Light-webfont', 300, normal);\n\n/*\n * Roboto Regular\n */ \n.font-face(roboto, 'Roboto-Regular-webfont', 400, normal);\n\n/*\n * Roboto Medium\n */\n.font-face(roboto, 'Roboto-Medium-webfont', 500, normal);\n\n/*\n * Roboto Bold\n */\n.font-face(roboto, 'Roboto-Bold-webfont', 700, normal);\n\n/*\n * Shadow Light\n */\n.font-face(shadowsintolight, 'shadowsintolight-webfont', 400, normal); \n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/footer.less",
    "content": "#footer {\n    position: absolute;\n    bottom: 0;\n    text-align: center;\n    width: 100%;\n    height: @footer-height;\n    color: #a2a2a2;\n    padding-top: 35px;\n    padding-bottom: 15px;\n    \n    .f-menu {\n        display: block;\n        width: 100%;\n        .list-inline();\n        margin-top: 8px;\n        \n        & > li > a {\n            color: #a2a2a2;\n            \n            &:hover {\n                color: #777;\n            }\n        } \n    }\n}\n\n@media (min-width: @screen-md-max) {\n    body.sw-toggled {\n        #footer {\n            padding-left: @sidebar-left-width; \n        }\n    } \n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/form.less",
    "content": "label {\n    font-weight: 500;\n}\n\n/*\n * Reset Focus and Active shadows\n */\ninput:active,\ninput:focus {\n    outline: 0;\n    box-shadow: none !important;\n}\n\n.form-control {\n    box-shadow: none !important;\n    resize: none;\n    \n    &:active,\n    &:focus {\n        box-shadow: none;\n    }\n    \n    &:not(.fc-alt) {\n        border-left: 0;\n        border-right: 0;\n        border-top: 0;\n        -webkit-appearance: none;\n        -moz-appearance: none;\n        appearance: none;\n        padding: 0;\n        \n        &.auto-size {\n            padding-top: 6px;\n        }\n    }\n} \n\n/*\n * Checkbox and Radio\n */\n.checkbox, .radio {\n    label {\n        padding-left: 30px; \n        position: relative;\n    }\n  \n    input {\n        top: 0;\n        left: 0;\n        margin-left: 0 !important;  \n        z-index: 1;\n        cursor: pointer;\n        .opacity(0);\n        margin-top: 0;\n    }\n  \n    .input-helper {\n        &:before, &:after {\n            .transition(all);\n            .transition-duration(250ms);\n            .backface-visibility(hidden); \n            position: absolute;\n            content: \"\";\n        }\n    \n        &:before {\n            left: 0;\n            border: 1px solid #ccc;\n        }\n    }\n    \n    &.disabled {\n        .opacity(0.6);\n    }\n}\n\n.checkbox {\n    input {\n        width: 17px;\n        height: 17px;\n        \n        &:checked + .input-helper {\n            &:before { \n                .scale(0);\n            }\n      \n            &:after {\n                .scale-rotate(1, -50deg);\n                .opacity(1);\n            }\n        }\n    }\n    \n    .input-helper {\n        &:before {\n            top: 0;\n            width: 17px;\n            height: 17px;\n        }\n        \n        &:after {\n            .opacity(0);\n            .scale-rotate(0, 80deg);\n            width: 22px;\n            height: 9px;\n            border-bottom: 2px solid @m-teal;\n            border-left: 2px solid @m-teal;\n            border-bottom-left-radius: 2px;\n            left: -1px;\n            top: 1px;\n        }\n    }\n}\n\n.radio {\n    input {\n        width: 19px;\n        height: 19px;\n        \n        &:checked + .input-helper {\n            &:after {\n                .scale(1);\n            }\n        }\n    }\n    \n    .input-helper {\n        &:before {\n            top: -1px;\n            width: 19px;\n            height: 19px;\n            border-radius: 50%;\n        }\n        \n        &:after {\n            width: 11px;\n            height: 11px;\n            background: @m-teal;\n            border-radius: 50%;\n            top: 3px;\n            left: 4px;\n            .scale(0);\n        }\n    }\n}\n\n.checkbox-inline,\n.radio-inline {\n    vertical-align: top;\n    margin-top: 0;\n    padding-left: 25px;\n}\n\n/*\n * Select\n */\nhtml:not(.ie9) {\n    .select {\n        position: relative;\n        \n        &:before {\n            position: absolute;\n            top: -1px;\n            content: \"\";\n            height: ~\"calc(100% - 1px)\";\n            width: 30px;\n            background-color: #FFF;\n            background-position: right ~\"calc(100% - 7px)\";\n            background-repeat: no-repeat;\n            .img-retina('../img/select.png', '../img/select@2x.png', 12px, 12px);\n            pointer-events: none;\n            z-index: 5;\n        }\n        \n        &:not(.fg-line):before {\n            right: 0;\n        }\n        \n        &.fg-line:before {\n            right: 10px;\n        }\n    }\n}\n\n    \n/*\n * Input Group Addon\n */\n.input-group {\n    &:not(.input-group-lg):not(.input-group-sm) .input-group-addon {\n        font-size: 15px;\n    }\n}\n\n.input-group-addon {\n    border-width: 0px 0px 1px 0px;\n    min-width: 42px;\n    \n    & > .zmdi {\n        position: relative;\n        top: 3px;\n    }\n}\n\n/*\n * Input Feilds\n */\n.fg-line {\n    position: relative;\n    vertical-align: top;\n    \n    &:not(.form-group) {\n        display: inline-block;\n        width: 100%;\n    }\n    \n    .form-control {        \n        &:disabled {\n            color: #9d9d9d; \n            background: transparent;\n        }\n    }\n\n    &:not(.disabled):after,\n    &:not(.readonly):after {\n        position: absolute;\n        z-index: 3;\n        bottom: 0;\n        left: 0;\n        height: 2px;\n        width: 0;\n        content: \"\"; \n        .transition(all);\n        .transition-duration(300ms);\n    }\n    \n    &:not([class*=has-]):after { \n        background: @m-blue;\n    }\n    \n    &.readonly .form-control {\n        color: #9d9d9d;\n        background: transparent;\n    }\n    \n    &.fg-toggled {\n        &:after {\n            width: 100%;\n        }\n    }\n}\n\n.fg-float  {\n    margin-top: 2px;\n    position: relative;\n  \n    .form-control {\n        .placeholder(#fff);\n        position: relative;\n        background: transparent;\n        z-index: 1;\n    }\n  \n    .fg-label {\n        .transition(all);\n        .transition-duration(200ms);\n        position: absolute;\n        top: 5px;\n        font-weight: 400;\n        color: #959595;\n        pointer-events: none;\n        z-index: 0;\n        left: 0;\n        white-space: nowrap;\n    }\n    \n    .fg-toggled .fg-label {\n        top: -20px;\n        font-size: 11px;\n    }\n}\n\n.control-label {\n    font-weight: normal;\n}\n\n/*\n * Toggle Switch\n */\n.ts-color(@color){\n    input {\n        &:not(:disabled) {\n            &:checked {\n                & + .ts-helper {\n                    background: fade(@color, 50%);\n                    \n                    &:before {\n                        background: @color;\n                    }\n                    \n                    &:active {\n                        &:before {\n                            box-shadow: 0 2px 8px rgba(0,0,0,0.28), 0 0 0 20px fade(@color, 20%);\n                        }\n                    }\n                }\n            }   \n        }\n    }\n}\n\n.toggle-switch {\n    display: inline-block;\n    vertical-align: top;\n    .user-select(none);\n    \n    .ts-label {\n        display: inline-block;\n        margin: 0 20px 0 0;\n        vertical-align: top;\n        -webkit-transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1);\n        transition: color 0.56s cubic-bezier(0.4, 0, 0.2, 1);\n    }\n    \n    .ts-helper {\n        display: inline-block;\n        position: relative;\n        width: 40px;\n        height: 16px;\n        border-radius: 8px;\n        background: rgba(0,0,0,0.26);\n        -webkit-transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n        transition: background 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n        vertical-align: middle;\n        cursor: pointer;\n        \n        &:before {\n            content: '';\n            position: absolute;\n            top: -4px;\n            left: -4px;\n            width: 24px;\n            height: 24px;\n            background: #fafafa;\n            box-shadow: 0 2px 8px rgba(0,0,0,0.28);\n            border-radius: 50%;\n            webkit-transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n            transition: left 0.28s cubic-bezier(0.4, 0, 0.2, 1), background 0.28s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1);\n        }\n    }\n    \n    &:not(.disabled) {\n        .ts-helper {\n            &:active {\n                &:before {\n                    box-shadow: 0 2px 8px rgba(0,0,0,0.28), 0 0 0 20px rgba(128,128,128,0.1);\n                }\n            }\n        }\n    }\n    \n    input {\n        position: absolute;\n        z-index: 1;\n        width: 46px;\n        margin: 0 0 0 -4px;\n        height: 24px;\n        .opacity(0);\n        cursor: pointer;\n\n        &:checked {\n            & + .ts-helper {\n                &:before {\n                    left: 20px;\n                }\n            }\n        }\n    }\n      \n    &:not([data-ts-color]){\n        .ts-color(@m-teal);\n    }\n    \n    &.disabled {\n        .opacity(0.6);\n    }\n    \n    &[data-ts-color=\"red\"] {\n        .ts-color(@m-red);\n    }\n    \n    &[data-ts-color=\"blue\"] {\n        .ts-color(@m-blue);\n    }\n    \n    &[data-ts-color=\"amber\"] {\n        .ts-color(@m-amber);\n    }\n    \n    &[data-ts-color=\"purple\"] {\n        .ts-color(@m-purple);\n    }\n    \n    &[data-ts-color=\"pink\"] {\n        .ts-color(@m-pink);\n    }\n    \n    &[data-ts-color=\"lime\"] {\n        .ts-color(@m-lime);\n    }\n     \n    &[data-ts-color=\"cyan\"] {\n        .ts-color(@m-cyan);\n    }\n    \n    &[data-ts-color=\"green\"] {\n        .ts-color(@m-green);\n    }\n    \n}\n\n/*\n * IE 9 Placeholder\n */\n.ie9-placeholder {\n    color: #888 !important;\n    font-weight: normal;\n}\n\n/*\n * Validation\n */\n.checkbox-fgline-validation(@color) {\n    .checkbox .input-helper {\n        &:before {\n            border-color: lighten(@color, 20%);\n        }\n        \n        &:after {\n            border-bottom-color: lighten(@color, 10%);;\n            border-left-color: lighten(@color, 10%);\n        }\n    }\n    \n    .fg-line:after {\n        background: @color;\n    }\n    \n}\n.has-error {\n    .checkbox-fgline-validation(@m-red);\n}\n\n.has-success {\n    .checkbox-fgline-validation(@m-green);\n}\n\n.has-warning {\n    .checkbox-fgline-validation(@m-orange);\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/generics.less",
    "content": "/*\n * Generate Margin Class\n * margin, margin-top, margin-bottom, margin-left, margin-right\n */\n\n.margin (@label, @size: 1, @key:1) when (@size =< 30){\n    .m-@{key} {\n        margin: @size !important;\n    }\n    \n    .m-t-@{key} {\n        margin-top: @size !important;\n    }\n    \n    .m-b-@{key} {\n        margin-bottom: @size !important;\n    }\n    \n    .m-l-@{key} {\n        margin-left: @size !important;\n    }\n    \n    .m-r-@{key} {\n        margin-right: @size !important;\n    }\n    \n    .margin(@label - 5; @size + 5; @key + 5);\n}\n\n.margin(25, 0px, 0);\n\n/*\n * Generate Padding Class\n * padding, padding-top, padding-bottom, padding-left, padding-right\n */\n\n.padding (@label, @size: 1, @key:1) when (@size =< 30){\n    .p-@{key} {\n        padding: @size !important;\n    }\n    \n    .p-t-@{key} {\n        padding-top: @size !important;\n    }\n    \n    .p-b-@{key} {\n        padding-bottom: @size !important;\n    }\n    \n    .p-l-@{key} {\n        padding-left: @size !important;\n    }\n    \n    .p-r-@{key} {\n        padding-right: @size !important; \n    }\n    \n    .padding(@label - 5; @size + 5; @key + 5);\n} \n\n.padding(25, 0px, 0);\n\n/*\n * Generate Font-Size Classes (8px - 20px)\n */\n.font-size (@label, @size: 8, @key:10) when (@size =< 20){\n    .f-@{key} {\n        font-size: @size !important;\n    }\n    \n    .font-size(@label - 1; @size + 1; @key + 1);\n} \n\n.font-size(20, 8px, 8);\n\n/*\n * Font Weight\n */\n.f-300 { font-weight: 300 !important; }\n.f-400 { font-weight: 400 !important; }\n.f-500 { font-weight: 500 !important; }\n.f-700 { font-weight: 700 !important; }\n\n/*\n * Position Classes\n */\n.p-relative { position: relative !important; }\n.p-absolute { position: absolute !important; }\n.p-fixed { position: fixed !important; }\n.p-static { position: static !important; }\n\n/*\n * Overflow\n */\n.o-hidden { overflow: hidden !important; }\n.o-visible { overflow: visible !important; }\n.o-auto { overflow: auto !important; }\n\n/*\n * Display\n */\n.d-block { display: block !important; }\n.di-block { display: inline-block !important; } \n\n/* \n * Material Background Colors\n */\n@array: c-white bgm-white @m-white, c-black bgm-black @m-black, c-brown bgm-brown @m-brown, c-pink bgm-pink @m-pink, c-red bgm-red @m-red, c-blue bgm-blue @m-blue, c-purple bgm-purple @m-purple, c-deeppurple bgm-deeppurple @m-deeppurple, c-lightblue bgm-lightblue @m-lightblue, c-cyan bgm-cyan @m-cyan, c-teal bgm-teal @m-teal, c-green bgm-green @m-green, c-lightgreen bgm-lightgreen @m-lightgreen, c-lime bgm-lime @m-lime, c-yellow bgm-yellow @m-yellow, c-amber bgm-amber @m-amber, c-orange bgm-orange @m-orange, c-deeporange bgm-deeporange @m-deeporange, c-gray bgm-gray @m-gray, c-bluegray bgm-bluegray @m-bluegray, c-indigo bgm-indigo @m-indigo;\n\n.for(@array); .-each(@value) {\n    @name:  extract(@value, 1);\n    @name2:  extract(@value, 2);\n    @color: extract(@value, 3); \n    &.@{name2} {\n        background-color: @color !important;\n    }\n    \n    &.@{name} {\n        color: @color !important;\n    }\n} \n\n/*\n * Background Colors\n */\n.bg-black-trp { background-color: rgba(0,0,0,0.1) !important; }\n\n/*\n * Border\n */\n.b-0 { border: 0 !important; }\n\n/*\n * width\n */\n.w-100 { width: 100% !important; }\n\n/*\n * Border Radius \n */ \n.brd-2 { border-radius: 2px; }\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/header.less",
    "content": "/*\n * Common header classes & IDs\n * Do not remove this\n */ \n.header-inner {\n    list-style: none; \n    padding: 17px 0;\n    margin-bottom: 0;\n    position: relative;\n    \n    & > li {\n        &:not(.pull-right) {\n            float: left; \n        }\n        \n        &:not(:last-child) {\n            margin-right: -2px;\n        }\n    }\n}\n\n.logo {\n    a {\n        color: #fff;\n        text-transform: uppercase;\n        display: block;\n        font-size: 16px;\n    }\n}\n\n#menu-trigger  {\n    width: 65px;\n    height: 35px;\n    cursor: pointer;\n\n    .line-wrap .line {\n        background-color: #fff;\n    }\n\n    &:before {\n        content: \"\";\n        position: absolute;\n        top: 13px;\n        left: 7px;\n        width: 45px;\n        height: 45px;\n        border-radius: 50%;\n        background: rgba(255, 255, 255, 0.22);\n        .transition(all);\n        .transition-duration(300ms);\n        .scale(0);\n        z-index: 0;\n    }\n    \n    &.open {\n        &:before {\n            .scale(1);\n        }\n    }\n}\n\n.top-menu {\n    list-style: none;\n    padding: 0;\n    \n    & > li { \n        display: inline-block;\n        margin: 0 1px;\n        vertical-align: top;\n        min-width: 50px;\n        \n        @media (max-width: @screen-xs-max) {\n            position: static !important;\n        }\n        \n        .dropdown-menu-lg {\n            padding: 0;\n            \n            .lv-body {\n                min-height: 295px;\n                overflow-x: hidden;\n            }\n        }\n        \n        &:not(#toggle-width) {\n            .hover-pop(rgba(0,0,0,0.12), 2px, 250ms, 0);\n        }\n        \n        & > a {\n            color: #fff;\n            display: block;\n            text-align: center;\n            z-index: 1;\n            position: relative;\n            \n            & > .tm-icon {\n                font-size: 24px;\n                line-height: 36px;\n            }\n            \n            & > .tm-label {\n                line-height: 35px;\n                white-space: nowrap;\n                padding: 0 10px;\n                font-size: @font-size-base + 1;\n                text-transform: uppercase; \n            } \n            \n            & > .tmn-counts {\n                position: absolute;\n                font-style: normal;\n                background: @m-red;\n                padding: 1px 5px;\n                border-radius: 2px;\n                right: 7px;\n                top: -3px;\n                font-size: 10px; \n                line-height: 15px;\n            }\n\n\n        }\n    }\n    \n    @media (max-width: @screen-xs-max) {\n        .dropdown-menu-lg {\n            width: ~\"calc(100% - 28px)\" !important;\n        }\n        \n        .dropdown-menu {\n            right: 14px; \n            top: 55px;\n        }  \n    }\n}\n\n#notifications {\n    position: relative;\n    \n    .lv-body {\n        overflow-x: hidden;\n    }\n    \n    &:before {\n        content: \"\";\n        position: absolute;\n        width: 100%;\n        height: ~\"calc(100% - 70px)\";\n        background: url(../img/notifications.png) no-repeat center;\n        .transition(all);\n        .transition-duration(400ms);\n        .scale-rotate(0, -180deg);\n        .opacity(0);\n        top: 42px;\n    }\n    \n    &.empty:before {\n        .scale-rotate(1, 0deg);\n        .opacity(1);\n    }\n    \n}\n\n/* Full Screen */\n:-webkit-full-screen [data-action=\"fullscreen\"] { display: none; }\n:-moz-full-screen [data-action=\"fullscreen\"] { display: none; }\n:-ms-fullscreen [data-action=\"fullscreen\"] { display: none; }\n:full-screen [data-action=\"fullscreen\"] { display: none; }\n:fullscreen [data-action=\"fullscreen\"] { display: none; }\n\n/* ----------------------------- End common header classes and IDs------------------------------------- */\n\n\n\n/*\n * For header type 1 only\n * You may remove these if you opt header 2\n */\n#header {\n    box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);\n    min-height: @header-height;\n    .user-select(none);\n\n    &:not(.sidebar-toggled) {\n        &.header-up {\n            .translate3d(0, -70px, 0);\n        }\n    }\n    \n    position: fixed;\n    z-index: 11;\n    width: 100%;\n    left: 0;\n    top: 0;\n    padding: 0 11px;\n    \n    .logo a {\n        padding: 7px 10px;\n    }\n}\n\n#top-search-wrap {\n    position: absolute;\n    top: -65px;\n    left: 0;\n    width: 100%;\n    height: @header-height;\n    background: #fff;\n    .transition(all);\n    .transition-duration(300ms);\n    .opacity(0);\n    z-index: 10;\n    \n    input[type=\"text\"] {\n        border: 0;\n        height: 40px;\n        padding: 0 10px 0 55px;\n        font-size: 18px;\n        width: 500px;\n        border-radius: 2px;\n        background-color: darken(@ace, 3%);\n        width: 100%;\n    }\n    \n    #top-search-close {\n        position: absolute;\n        top: 15px;\n        font-size: 23px;\n        font-style: normal;\n        width: 45px;\n        text-align: center;\n        border-radius: 2px 0px 0px 2px;\n        cursor: pointer;\n        left: 15px;\n        height: 40px;\n        padding-top: 9px;\n        \n        &:hover {\n            background-color: darken(@ace, 8%);\n        }\n        \n        @media (max-width: @screen-xs-max) {\n            right: 7px;\n        }\n    }\n}\n\n.tsw-inner {\n    position: relative;\n    padding: 15px;\n    max-width: 700px;\n    display: block;\n    margin: 0 auto;\n}\n\n&.search-toggled {\n    #top-search-wrap {\n        top: 0;\n        .opacity(1);\n    }\n}\n\n/* Full Width Layout */\n#toggle-width {\n    @media(min-width: @screen-lg-min) {\n        .toggle-switch {\n            margin: 9px 30px 0 0;\n            \n            .ts-helper {\n                height: 11px;\n                width: 33px;\n                \n                &:before {\n                    width: 20px;\n                    height: 20px;\n                    top: -5px;\n                }\n            }\n            \n            input:checked + .ts-helper {\n                background: rgba(0, 0, 0, 0.26);\n                &:before {\n                    left: 18px;\n                    background: #fff;\n                }\n                \n            }\n        }\n    }\n    \n    @media(max-width: @screen-lg-min) {\n        display: none;\n    }\n}\n\n.sw-toggled {\n    @media (min-width: @screen-lg-min) {\n        #header {\n            padding-left: 15px;\n        }\n        \n        #menu-trigger {\n            display: none;\n        }\n    }\n}\n\n/* For Stupid IE9 */\n.ie9 {\n    #header:not(.sidebar-toggled) {\n        &.header-up {\n            display: none;\n        }\n    }\n}\n\n/* ----------------------------- End header type 1 ------------------------------------- */\n\n\n\n/*\n * For Header type 2 only\n * You may remove these if you opt header 1\n */ \n\n#header-2 {\n    box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.3);\n    position: relative;\n    margin-bottom: -@header-height;\n    z-index: 10;\n    \n    @media (min-width: @screen-sm-min) {\n        padding: 15px 30px 0;\n        \n        &:before {\n            content: \"\";\n            position: absolute;\n            bottom: 0;\n            left: 0;\n            background: rgba(0,0,0,0.04);\n            width: 100%;\n            height: 49px;\n        }\n    }\n     \n    .search {\n        margin-bottom: 25px;\n        \n        @media (max-width: @screen-xs-max) {\n            padding: 0 20px\n        }\n        \n        input[type=\"text\"] {\n            width: 100%;\n            background: transparent;\n            border: 0;\n            border-bottom: 1px solid rgba(255, 255, 255, 0.24);\n            color: #fff;\n            font-size: 15px;\n            font-weight: 300;\n            padding: 6px 0 6px 30px;\n            \n            .placeholder(#fff); \n        }\n        \n        \n        \n        &:after {\n            background: @m-yellow;\n        }\n        \n        .fg-line {\n            max-width: 500px;\n            position: relative;\n            \n            &:after {\n                background: @m-yellow;\n            }\n            \n            &:before {\n                content: '\\f1c3';\n                font-family: @font-icon-md;\n                position: absolute;\n                left: 0;\n                bottom: 1px;\n                color: #fff;\n                font-size: 22px;\n            }\n        }\n    }\n}\n\n.ha-menu {\n    & > ul {\n        list-style: none;\n        padding: 0;\n        margin: 0;\n        \n        & > li {\n            display: inline-block;\n            vertical-align: top;\n            \n            @media (max-width: @screen-xs-max) {\n                display: block;\n            }\n            \n            &:not(.active) > *:not(ul) {\n                color: rgba(255,255,255,0.6);\n            }\n            \n            &.active > *:not(ul) {\n                color: #fff;\n                box-shadow: inset 0px -3px 0 0px @m-yellow;\n                \n                @media (max-width: @screen-xs-max) {\n                    display: block;\n                }\n            }\n            \n            & > *:not(ul) {\n                text-transform: uppercase;\n                padding: 15px 12px;\n                display: block;\n            }\n            \n            &.open > *:not(ul),\n            & > *:not(ul):hover {\n                color: #fff; \n            }\n            \n            .dropdown-menu {\n                margin-top: -5px;\n                min-width: 100%;\n            }\n        }\n    }\n    \n    @media (max-width: @screen-xs-max) {\n        width: 200px;\n        position: absolute;\n        top: 65px;\n        left: 8px;\n        box-shadow: 0 0 10px;\n        z-index: 10;\n        padding: 0 10px;\n        \n        &:not(.toggled) {\n            display: none;\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/ie-warning.less",
    "content": ".ie-warning {\n\tposition: fixed;\n\ttop: 0;\n\tleft: 0;\n\tz-index: 9999;\n\tbackground: @m-black;\n\twidth: 100%;\n\theight: 100%;\n\ttext-align: center;\n\tcolor: #fff;\n\tfont-family: \"Courier New\", Courier, monospace;\n\tpadding: 50px 0;\n\n\tp {\n\t\tfont-size: 17px;\n\t}\n    \n    .iew-container {\n        min-width: 1024px;\n        width: 100%;\n        height: 200px;\n        background: #fff;\n        margin: 50px 0;\n    }\n\n\t.iew-download {\n\t\tlist-style: none;\n\t\tpadding: 30px 0;\n\t\tmargin: 0 auto;\n        width: 720px;\n\n\t\t& > li {\n\t\t\tfloat: left;\n\t\t\tvertical-align: top;\n\n\t\t\t& > a {\n\t\t\t\tdisplay: block;\n\t\t\t\tcolor: #000;\n\t\t\t\twidth: 140px;\n\t\t\t\tfont-size: 15px;\n\t\t\t\tpadding: 15px 0;\n\n\t\t\t\t& > div {\n\t\t\t\t\tmargin-top: 10px;\n\t\t\t\t}\n\n\t\t\t\t&:hover {\n\t\t\t\t\tbackground-color: #eee;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/invoice.less",
    "content": ".invoice {\n    min-width: 1100px;\n    max-width: 1170px;\n}\n\n.i-logo {\n        width: 150px;\n}\n\n.i-table {\n    .highlight { \n        background-color: #eee; \n        border-bottom: 1px solid darken(#eee, 3%); \n    }\n    \n    td.highlight {\n        font-size: 14px;\n        font-weight: 500;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/less-plugins/for.less",
    "content": "\n.for(@i, @n) {.-each(@i)}\n.for(@n)     when (isnumber(@n)) {.for(1, @n)}\n.for(@i, @n) when not (@i = @n)  {\n    .for((@i + (@n - @i) / abs(@n - @i)), @n);\n}\n\n.for(@array)   when (default()) {.for-impl_(length(@array))}\n.for-impl_(@i) when (@i > 1)    {.for-impl_((@i - 1))}\n.for-impl_(@i) when (@i > 0)    {.-each(extract(@array, @i))}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/list.less",
    "content": ".clist {\n  list-style: none;\n\n  & > li {\n    &:before {\n      font-family: @font-icon-md;\n      margin: 0 10px 0 -20px;\n      vertical-align: middle;\n    }\n  }\n\n  &.clist-angle > li:before {\n    content: \"\\f2fb\";\n  }\n\n  &.clist-check > li:before {\n    content: \"\\f26b\";\n  }\n\n  &.clist-star > li:before {\n    content: \"\\f27d\";\n  }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/listview.less",
    "content": ".listview {\n    position: relative;\n    \n    &:not(.lv-lg):not(.lv-message) {\n        .lv-item {\n            padding: 10px 20px;\n        }\n    }\n    \n    &.lv-lg {\n        .lv-item {\n            @media (min-width: @screen-xs-min) {\n                padding: 17px 35px 17px 25px;\n            }\n            \n            @media (max-width: @screen-xs-max) {\n                padding: 17px 35px 17px 20px;\n            }\n            \n            &:hover {\n                background-color: #FFFFDB;\n            }\n        }\n    }\n    \n    .lv-item {\n        position: relative;\n        display: block;\n        .transition(background-color);\n        .transition-duration(300ms);\n\n        .lv-small {\n            font-size: 12px;\n            color: #A9A9A9;\n            .text-overflow();\n            display: block;\n            width: 100%;\n        }\n        \n        .checkbox,\n        &.media {\n            margin: 0;\n        }\n        \n        .lv-actions {\n            position: absolute;\n            right: 15px;\n            top: 10px;\n            \n            @media (max-width: @screen-xs-min) {\n                right: 7px;\n            }\n        }\n    } \n    \n    .lv-title {\n        .text-overflow();\n        display: block;\n    }\n    \n    a.lv-item:hover {\n        background: #ECF9FF;\n    }\n    \n    [class*=\"lv-img\"] { \n        border-radius: 50%;\n    }\n    \n    .lv-img {\n        width: 48px;\n        height: 48px; \n    }\n    \n    .lv-img-sm {\n        width: 35px; \n        height: 35px;\n    }\n    \n    &.lv-bordered {\n        .lv-item {\n            &:not(:last-child) {\n                border-bottom: 1px solid #f0f0f0;\n            }\n        }\n    }\n    \n    .lv-attrs {\n        list-style: none;\n        padding: 0;\n        margin: 5px 0 0 0;\n        \n        .listview-attrs(@b-color: lighten(@text-color, 50%), @bg: #fff, @color: @text-color) {\n            border: 1px solid @b-color;\n            background: @bg;\n            color: @color;\n        }\n        \n        & > li {\n            display: inline-block;\n            padding: 2px 10px 3px;\n            font-size: 12px;\n            margin-top: 5px;\n            margin-right: 2px;\n            \n            &:not(.info):not(.primary):not(.warning):not(.danger) {\n                .listview-attrs();\n            }\n            \n            &.info { .listview-attrs(@m-cyan, @m-cyan, #fff); }\n            &.primary { .listview-attrs(@m-blue, @m-blue, #fff); }\n            &.warning { .listview-attrs(@m-orange, @m-orange, #fff); }\n            &.danger { .listview-attrs(@m-red, @m-red, #fff); }\n            \n            & > a {\n                display: block;\n            }\n        }\n    }\n    \n    &:not(.lv-message) {\n        .lv-title {\n            color: #000;\n        }\n    }\n}\n\n[class*=\"lv-img\"] { \n    border-radius: 50%;\n}\n\n.lv-img {\n    width: 48px;\n    height: 48px; \n}\n\n.lv-img-sm {\n    width: 35px; \n    height: 35px;\n}\n\n.lv-header {\n    text-align: center;\n    padding: 15px 10px 13px;\n    line-height: 100%;\n    text-transform: uppercase;\n    border-bottom: 1px solid #F0F0F0;\n    font-weight: 500;\n    color: #4C4C4C; \n    margin-bottom: 10px;\n\n    .actions {\n        position: absolute;\n        top: 6px;\n        right: 8px;\n        z-index: 10;\n    }\n}\n\n.lvh-search {\n    position: absolute;\n    top: 0;\n    left: 0;\n    height: 100%;\n    width: 100%;\n    z-index: 4;\n    background: #fff;\n    display: none;\n    \n    &:before {\n        content: \"\\f1c3\";\n        font-family: 'Material-Design-Iconic-Font';\n        position: absolute;\n        left: 24px;\n        top: 17px;\n        font-size: 22px;\n    }\n}\n\n.lvhs-input {\n    border: 0;\n    padding: 0 26px 0 55px;\n    height: 63px;\n    font-size: 18px;\n    width: 100%;\n    font-weight: 100;\n    background: #fff;\n    border-bottom: 1px solid #EEE;\n}\n\n.lvh-search-close {\n    font-style: normal;\n    position: absolute;\n    top: 23px;\n    right: 22px;\n    font-size: 17px;\n    width: 18px;\n    height: 18px;\n    background-color: #ADADAD;\n    line-height: 100%;\n    color: #fff;\n    text-align: center;\n    cursor: pointer;\n    border-radius: 50%;\n    \n    &:hover {\n        background: #333;\n    }\n}\n\n.lv-header-alt {\n    position: relative;\n    background: #f8f8f8;\n    padding: 15px;\n\n    .lv-actions {\n        z-index: 3;\n        float: right;\n        margin-top: 3px;\n        position: relative;\n\n        & > li > a {\n            margin: 0 3px;\n        }\n    }\n}\n\n.lvh-label {\n    color: #818181;\n    display: inline-block;\n    margin: 0;\n    font-size: 14px;\n    font-weight: normal;\n    padding: 0 6px;\n    line-height: 33px;\n    vertical-align: middle;\n    float: left;\n}\n\n\n\n.lv-footer {\n    display: block;\n    text-align: center;\n    padding: 7px 10px 8px;\n    border-top: 1px solid #F0F0F0;\n    line-height: 100%;\n    font-size: 11px;\n    margin-top: 20px;\n    color: #828282;\n}\n\na.lv-footer:hover {\n    color: darken(#919191, 55%);\n}\n  \n\n/*\n * Inside Card will have more padding\n */\n.card-body {\n    .lv-item {\n        padding: 12px 20px;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/login.less",
    "content": ".login-content {\n    overflow: hidden;\n    height: 100%;\n}\n\n.lc-block {\n    background: #fff;\n    box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);\n    border-radius: 2px;\n    width: 500px;\n    display: inline-block;\n    margin-top: 42px;\n    vertical-align: middle;\n    position: relative;\n    \n    &:not(.toggled) {\n        display: none;\n    }\n    \n    &.toggled {\n        .animated(fadeInUp, 300ms);\n        z-index: 10;\n    } \n    \n    &:not(.lcb-alt) {\n        padding: 35px 55px 35px;\n    }\n\n    @media (max-width: @screen-xs-max) {\n        padding: 15px 35px 25px 20px;\n        width: ~\"calc(100% - 60px)\";\n    }\n\n    .checkbox {\n        margin: 5px 0 0 42px;\n        text-align: left; \n    }\n\n    &:not(.lcb-alt) {\n        .btn-login {\n            top: 50%;\n            margin-top: -25px; \n            right: -25px; \n        }\n    }\n}\n\n.login-navigation {     \n    list-style: none;\n    padding: 0;\n    margin: 0;\n    position: absolute;\n    width: 100%;\n    text-align: center;\n    left: 0%;\n    bottom: -45px;\n\n    & > li {\n        display: inline-block;\n        margin: 0 2px;\n        .transition(all);\n        .transition-duration(150ms);\n        cursor: pointer;\n        vertical-align: top;\n        color: #fff;\n        line-height: 16px;\n        min-width: 16px;\n        min-height: 16px;\n        text-transform: uppercase;\n        .backface-visibility(hidden);\n\n        & > span {\n            .opacity(0);\n        }\n\n        &:not(:hover) {\n            font-size: 0px;\n            border-radius: 100%;\n        }\n\n        &:hover {\n            border-radius: 10px;\n            padding: 0 5px;\n            font-size: 8px; \n\n            & > span {\n                .opacity(1);\n            } \n        }\n\n    }\n}\n \n.lcb-alt {\n    padding: 70px 55px 60px;\n    \n    .btn-login {\n        bottom: -25px;\n        left: 50%;\n        margin-left: -25px;\n    }\n    \n    .login-navigation {\n        bottom: -75px;\n    }\n}\n\n.lcb-user {\n    width: 100px;\n    height: 100px;\n    border-radius: 50%;\n    border: 5px solid #fff;\n    position: absolute;\n    top: -50px;\n    left: 50%;\n    margin-left: -50px;\n    box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.18);\n}\n\nbody.login-content {\n    text-align: center;\n    \n    &:after {\n        content: \"\";\n        vertical-align: middle; \n        display: inline-block;\n        width: 1px;\n        height: 100%;\n    }\n    \n    &:before {\n        height: 50%;\n        width: 100%;\n        position: absolute;\n        top: 0;\n        left: 0;\n        background: @m-cyan;\n        content: \"\";\n        z-index: 0;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/media.less",
    "content": ".thumbnail {\n\ta&:hover,\n\ta&:focus,\n\ta&.active {\n\t    border-color: darken(@thumbnail-border, 5%);\n\t    box-shadow: 0 0 6px #EAEAEA;\n\t}\n} \n\n/*\n * Lightbox  \n */\n\n.lightbox {\t \n\t.lightbox-item {\n\t\t\n\t\t& > img {\n\t\t\twidth: 100%;\n\t\t\tborder-radius: 2px;\n\t\t}\n\n\t\t.hover-pop(rgba(0,0,0,0.1));\n\n\t\t&:hover {\n\t\t\tcursor: pointer;\n\t\t}\n\t}\n\t\n\t[data-src] {\n\t\t.clearfix();\n\t}\n\t\n\t.lightbox-item:not(.p-item) {\n\t\tposition: relative;\n\t}\n}\n\n/*\n * Carousel\n */\n.carousel {\n\t.carousel-control {\n\t\t.transition(all);\n\t\t.transition-duration(250ms);\n\t\t.opacity(0);\n\t\t\n\t\t.zmdi {\n\t\t\tposition: absolute;\n\t\t\ttop: 50%;\n\t\t\tleft: 50%;\n\t\t\tline-height: 100%;\n\t\t\t\n\t\t\t@media screen and (min-width: @screen-sm-min) {\n\t\t\t\tfont-size: 60px;\n\t\t\t\twidth: 60px;\n\t\t\t\theight: 60px;\n\t\t\t\tmargin-top: -30px;\n\t\t\t\tmargin-left: -30px;\n\t\t\t}\n\t\t\t\n\t\t\t@media screen and (max-width: @screen-sm-max) {\n\t\t\t\twidth: 24px;\n\t\t\t\theight: 24px;\n\t\t\t\tmargin-top: -12px;\n\t\t\t\tmargin-left: -12px;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t&:hover {\n\t\t.carousel-control {\n\t\t\t.opacity(1);\n\t\t}\n\t}\n\t\n\t.carousel-caption {\n\t\tbackground: rgba(0,0,0,0.6);\n\t\tleft: 0;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\twidth: 100%;\n\t\tpadding-bottom: 50px;\n\t\t\n\t\t& > h3 {\n\t\t\tcolor: #fff;\n\t\t\tmargin: 0 0 5px;\n\t\t\tfont-weight: 300;\n\t\t}\n\t\t\n\t\t& > p {\n\t\t\tmargin: 0;\n\t\t}\n\t\t\n\t\t@media screen and (max-width: @screen-sm-max) {\n\t\t\tdisplay: none;\n\t\t}\n\t}\n\t\n\t.carousel-indicators {\n\t\tbottom: 10px;\n\t\tmargin: 0;\n\t\tleft: 0;\n\t\tbottom: 0;\n\t\twidth: 100%;\n\t\tpadding: 0 0 6px;\n\t\tbackground: rgba(0,0,0,0.6);\n\t\t\n\t\tli {\n\t\t\tborder-radius: 0;\n\t\t\twidth: 15px;\n\t\t\tborder: 0;\n\t\t\tbackground: #fff;\n\t\t\theight: 3px;\n\t\t\tmargin: 0;\n\t\t\t.transition(all);\n\t\t\t.transition-duration(250ms);\n\t\t\t\n\t\t\t&.active {\n\t\t\t\twidth: 25px;\n\t\t\t\theight: 3px;\n\t\t\t\tbackground: @m-orange;\n\t\t\t}\n\t\t}\n\t}\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/messages.less",
    "content": "#messages-main {\n    position: relative;\n    .clearfix();\n    \n    .ms-block {\n        padding: 23px 20px 0;\n    }\n\n    .ms-menu {\n        position: absolute;\n        left: 0;\n        top: 0;\n        background: #F8F8F8;\n        border-right: 1px solid #EEE;\n        padding-bottom: 50px;\n        height: 100%;\n        width: 240px;\n        .transition(all);\n        .transition-duration(250ms);\n\n        @media (max-width: @screen-xs-max) {\n            height: ~\"calc(100% - 58px)\";\n            .translate3d(-240px, 58px, 0);\n            .opacity(0);\n            z-index: 1;\n\n            &.toggled {\n                .translate3d(0, 58px, 0);\n                .opacity(1);\n            }\n        }\n        \n        .lv-item {\n            padding-left: 20px;\n            padding-right: 20px;\n            \n            &.active {\n                background: #fff;\n            }\n            \n            &:not(.active):hover {\n                background: #F2F2F2;\n                cursor: pointer;\n            }\n        }\n    }\n    \n    .ms-body {\n        @media (min-width: @screen-sm-min) {\n            padding-left: 240px;\n        }\n\n        @media (max-width: @screen-xs-max) {\n            overflow: hidden;\n        }\n    }\n    \n    .ms-user {        \n        .clearfix();\n        \n        & > img {\n            border-radius: 50%;\n            width: 40px;\n            float: left;\n        }\n        \n        & > div {\n            overflow: hidden;\n            padding: 7px 5px 7px 15px;\n            font-size: 11px;\n        }\n    }\n}\n\n#ms-menu-trigger {\n    .user-select(none);\n    float: left;\n    margin: 1px 0 0 -7px;\n\n    @media (min-width: @screen-sm-min) {\n        display: none;\n    }\n\n    .line-wrap .line {\n        background-color: #717171;\n    }\n}\n\n/*\n * For Message\n */\n.lv-message {\n    .lv-item {\n        padding: 20px;\n        \n        &.right {\n            text-align: right;\n            \n            .lv-avatar {\n                margin-right: 0;\n                margin-left: 15px;\n            }\n        }\n        \n        &:not(.right) {\n            .ms-item {\n                background: @m-amber;\n                color: #fff;\n            }\n        }\n        \n        &.right .ms-item {\n            background: #eee;\n        }\n    }\n}\n\n.lv-avatar {\n    width: 35px;\n    height: 35px;\n    border-radius: 50%;\n    color: #FFF;\n    text-align: center;\n    line-height: 34px;\n    font-size: 15px;\n    margin-right: 15px;\n    padding: 0 !important;\n    text-transform: uppercase;\n    \n    & > img {\n        width: 35px;\n        height: 35px;\n        border-radius: 50%;\n        vertical-align: top;\n    }\n}\n\n.ms-item {\n    padding: 13px 19px 15px;\n    border-radius: 2px;\n    display: inline-block;\n    \n    @media (min-width: @screen-sm-min) {\n        max-width: 70%;\n    }\n}\n\n.ms-date {\n    display: block;\n    color: #B3B3B3;\n    margin-top: 7px;\n    \n    & > i {\n        font-size: 14px;\n        vertical-align: bottom;\n        line-height: 100%;\n    }\n}\n\n.ms-reply {\n    box-shadow: 0 -20px 20px -5px #FFF;\n    position: relative;\n    margin: 0 !important;\n  \n    textarea {\n        width: 100%;\n        font-size: 13px;\n        border: 0;\n        padding: 10px 8px;\n        resize: none;\n        height: 60px;\n    }\n    \n    button {\n        position: absolute;\n        top: 0;\n        right: 0;\n        border: 0;\n        height: 100%;\n        width: 60px;\n        font-size: 25px;\n        background: #F5F5F5;\n        color: @m-blue;\n        \n        &:hover {\n            background: #f2f2f2;\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/misc.less",
    "content": "/*\n * Block Header\n * Used for Heading outside the Cards.\n */\n.block-header {\n    @media screen and (min-width: @screen-sm-min) {\n        padding: 0 22px;\n    }\n\n    @media screen and (max-width: @screen-sm-max) {\n        padding: 0 18px;\n    }\n\n    margin-bottom: 25px;\n    position: relative;\n\n    & > h2 {\n        font-size: 15px;\n        color: #777;\n        margin: 0;\n        font-weight: 400;\n        text-transform: uppercase;\n\n        & > small {\n            display: block;\n            text-transform: none;\n            margin-top: 8px;\n            margin-bottom: 20px;\n            color: #9E9E9E;\n            line-height: 140%;\n        }\n    }\n\n    .actions {\n        position: absolute;\n        right: 10px;\n        top: -5px;\n        z-index: 4;\n    }\n}\n\n/*\n * Header Actions\n */\n.actions {\n    list-style: none;\n    padding: 0;\n    z-index: 3;\n    margin: 0;\n\n    & > li {\n        display: inline-block;\n        vertical-align: baseline;\n    }\n\n    & > li > a,\n    & > a {\n        width: 30px;\n        height: 30px;\n        display: inline-block;\n        text-align: center;\n        padding-top: 5px;\n\n        & > i {\n            color: #adadad;\n            font-size: 20px;\n        }\n\n        &:hover {\n            & > i {\n                color: #000;\n            }\n        }\n\n        .hover-pop(rgba(0,0,0,0.1), 50%, 250ms, 0);\n    }\n\n    & > li.open,\n    &.open {\n        & > a {\n            & > i {\n                color: #000;\n            }\n\n            &:before {\n                .scale(1);\n                .opacity(1);\n            }\n        }\n    }\n\n    &.actions-alt {\n        & > li {\n            & > a > i {\n                color: #fff;\n\n                &:hover {\n                    color: #fff;\n                }\n            }\n\n            &.open {\n                & > a {\n                    & > i {\n                        color: #fff;\n                    }\n                }\n            }\n        }\n    }\n\n    &.open {\n        z-index: 3;\n    }\n}\n\n/*\n * Collapse Menu Icons\n */\n.line-wrap {\n    width: 18px;\n    height: 12px;\n    .transition(all);\n    .transition-duration(300ms);\n    margin: 12px 20px;\n\n    .line{\n        width: 18px;\n        height: 2px;\n        .transition(all);\n        .transition-duration(300ms);\n\n        &.center {\n            margin: 3px 0;\n        }\n    }\n}\n\n&.open {\n    .line-wrap {\n        .rotate(180deg);\n\n        .line {\n            &.top {\n                width: 12px;\n                transform: translateX(8px) translateY(1px) rotate(45deg);\n                -webkit-transform: translateX(8px) translateY(1px) rotate(45deg);\n            }\n\n            &.bottom {\n                width: 12px;\n                transform: translateX(8px) translateY(-1px) rotate(-45deg);\n                -webkit-transform: translateX(8px) translateY(-1px) rotate(-45deg);\n            }\n        }\n    }\n}\n\n/*\n * Load More\n */\n.load-more {\n    text-align: center;\n    margin-top: 30px;\n\n    a {\n        padding: 5px 10px 3px;\n        display: inline-block;\n        background-color: @m-red;\n        color: #FFF;\n        border-radius: 2px;\n        white-space: nowrap;\n\n        i {\n            font-size: 20px;\n            vertical-align: middle;\n            position: relative;\n            margin-top: -2px;\n        }\n\n        &:hover {\n            background-color: darken(@m-red, 10%);\n        }\n    }\n}\n\n/*\n * Page Loader\n */\n\nhtml {\n    &:not(.ismobile) {\n        .page-loader {\n            background: #fff;\n            position: fixed;\n            width: 100%;\n            height: 100%;\n            top: 0;\n            left: 0;\n            z-index: 1000;\n\n            .preloader {\n                width: 50px;\n                position: absolute;\n                left: 50%;\n                margin-left: -25px;\n                top: 50%;\n                margin-top: -55px;\n                .animated(fadeIn, 3000ms);\n\n                p {\n                    white-space: nowrap;\n                    position: relative;\n                    left: -9px;\n                    top: 22px;\n                    color: #CCC;\n                }\n            }\n        }\n    }\n    \n    &.ismobile .page-loader {\n        display: none;\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/mixin.less",
    "content": "/*\n * Font Face\n */\n.font-face(@family, @name, @weight: 300, @style){\n    @font-face{\n        font-family: @family;\n        src:url('../fonts/@{family}/@{name}.eot');\n        src:url('../fonts/@{family}/@{name}.eot?#iefix') format('embedded-opentype'),\n            url('../fonts/@{family}/@{name}.woff') format('woff'),\n            url('../fonts/@{family}/@{name}.ttf') format('truetype'),\n            url('../fonts/@{family}/@{name}.svg#icon') format('svg');\n        font-weight: @weight;\n        font-style: @style;\n    }\n}\n\n/*\n * Background Repeat + Position\n */\n\n.bg-option(@repeat: no-repeat, @position: center) {\n    background-repeat: @repeat;\n    background-position: @position;\n}\n\n/*\n * CSS Animations based on animate.css\n */\n\n.animated(@name, @duration) {\n    -webkit-animation-name: @name;\n    animation-name: @name;\n    -webkit-animation-duration: @duration;\n    animation-duration: @duration;\n    -webkit-animation-fill-mode: both;\n    animation-fill-mode: both;\n}\n\n/*\n * CSS Transform - Scale and Rotate\n */\n.scale-rotate(@scale, @rotate) {\n    -webkit-transform: scale(@scale) rotate(@rotate);\n    -ms-transform: scale(@scale) rotate(@rotate);\n    -o-transform: scale(@scale) rotate(@rotate);\n    transform: scale(@scale) rotate(@rotate);\n}\n\n/*\n * User Select\n */\n.user-select (@val) {\n    -webkit-touch-callout:  @val;\n    -webkit-user-select:    @val;\n    -khtml-user-select:     @val;\n    -moz-user-select:       @val;\n    -ms-user-select:        @val;\n    user-select:            @val;\n}\n\n/*\n * Background Image Cover\n */\n.bg-cover(@image) {\n    background-image: url(@image);\n    background-repeat: no-repeat;\n    -webkit-background-size: cover;\n    -moz-background-size: cover;\n    -o-background-size: cover;\n    background-size: cover;\n    background-position: center;\n}\n\n.bg-cover-inline() {\n    background-repeat: no-repeat;\n    -webkit-background-size: cover;\n    -moz-background-size: cover;\n    -o-background-size: cover;\n    background-size: cover;\n    background-position: center;\n}\n\n/*\n * Tab Focus\n */\n.tab-focus() {\n    outline: none !important;\n}\n\n/*\n * Pop-in Hover effects\n */\n.hover-pop(@background: ~\"rgba(0,0,0,0.5)\", @radius: 0, @duration: 250ms, @zindex: 0) {\n    @media (min-width: @screen-sm-min) {\n        position: relative;\n        \n        &:before {\n            left: 0;\n            top: 0;\n            content: \"\";\n            position: absolute;\n            width: 100%;\n            height: 100%;\n            .scale3d(0,0,0);\n            .transition(all);\n            .transition-duration(@duration);\n            .backface-visibility(hidden);\n            background-color: @background; \n            z-index: @zindex;\n            border-radius: @radius;\n            .opacity(0);\n        }\n        \n        &:hover:before,\n        &.open:before {\n            .scale3d(1,1,1);\n            .opacity(1);\n        }\n    }\n}\n\n/*\n *  Override Bootstrap Button Mixin\n */\n.button-variant(@color; @background; @border) {\n    color: @color;\n    background-color: @background;\n    border-color: @border;\n\n    &:hover,\n    &:focus,\n    &.focus,\n    &:active,\n    .open > .dropdown-toggle& {\n        color: @color;\n        background-color: @background;\n        border-color: transparent;\n        \n        &:hover,\n        &:focus,\n        &.focus {\n          color: @color;\n          background-color: @background;\n              border-color: transparent\n        }\n    }\n    &:active,\n    &.active,\n    .open > .dropdown-toggle& {\n        background-image: none;\n    }\n    &.disabled,\n    &[disabled],\n    fieldset[disabled] & {\n    &,\n    &:hover,\n    &:focus,\n    &.focus,\n    &:active {\n        background-color: @background;\n            border-color: @border;\n        }\n    }\n\n    .badge {\n        color: @background;\n        background-color: @color;\n    }\n}\n\n/*\n * Scale 3d\n */ \n.scale3d(...) {\n  @process: ~`(function(e){return e=e||\"1, 1, 1\"})((function(){var e=\"@{arguments}\";return e=e.replace(/^\\[|\\]$/g,\"\")})())`;\n  -webkit-transform: scale3d(@process);\n  -moz-transform: scale3d(@process);\n  -ms-transform: scale3d(@process);\n  -o-transform: scale3d(@process);\n  transform: scale3d(@process);\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/modal.less",
    "content": ".modal {\n\t.modal-content {\n\t\tbox-shadow: 0 5px 20px rgba(0, 0, 0, 0.31);\n\t\tborder-radius: 3px;\n\t\tborder: 0;\n\t}\n\n\t.modal-header {\n\t\tpadding: 23px 26px;\n\t}\n\n\t.modal-body {\n\t\tpadding: 0 26px 10px;\n\t}\n\n\t.modal-footer {\n\t\t.btn-link {\n\t\t\tfont-size: 14px;\n\t\t\tcolor: #000;\n\t\t\tfont-weight: 500;\n\n\t\t\t&:hover {\n\t\t\t\tbackground-color: #eee;\n\t\t\t}\n\t\t}\n\t}\n\n\t&:not([data-modal-color]) {\n\t\t.modal-footer {\n\t\t\t.btn-link {\n\t\t\t\tfont-weight: 500;\n\n\t\t\t\t&:hover {\n\t\t\t\t\tbackground-color: #eee;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t&[data-modal-color] {\n\t\tcolor: #fff;\n\n\t\t.modal-title,\n\t\t.modal-footer .btn-link {\n\t\t\tcolor: #fff;\n\t\t}\n\n\t\t.modal-footer {\n\t\t\tbackground: rgba(0,0,0,0.1);\n\t\t}\n\n\t\t.modal-backdrop {\n\t\t\tbackground: #fff;\n\t\t}\n\n\t\t.modal-footer {\n\t\t\t.btn-link {\n\t\t\t\tfont-weight: 400;\n\n\t\t\t\t&:hover {\n\t\t\t\t\tbackground-color: rgba(0,0,0,0.1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t&[data-modal-color=\"blue\"] .modal-content {\n\t\tbackground: @m-blue;\n\t}\n\n\t&[data-modal-color=\"cyan\"] .modal-content {\n\t\tbackground: @m-cyan;\n\t}\n\n\t&[data-modal-color=\"green\"] .modal-content {\n\t\tbackground: @m-green;\n\t}\n\n\t&[data-modal-color=\"lightgreen\"] .modal-content {\n\t\tbackground: @m-lightgreen;\n\t}\n\n\t&[data-modal-color=\"lightblue\"] .modal-content {\n\t\tbackground: @m-lightblue;\n\t}\n\n\t&[data-modal-color=\"amber\"] .modal-content {\n\t\tbackground: @m-amber;\n\t}\n\n\t&[data-modal-color=\"teal\"] .modal-content {\n\t\tbackground: @m-teal;\n\t}\n\n\t&[data-modal-color=\"orange\"] .modal-content {\n\t\tbackground: @m-orange;\n\t}\n\n\t&[data-modal-color=\"bluegray\"] .modal-content {\n\t\tbackground: @m-bluegray;\n\t}\n\n\t&[data-modal-color=\"red\"] .modal-content {\n\t\tbackground: @m-red;\n\t}\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/pagination.less",
    "content": ".pagination {\n    border-radius: 0;\n    \n    & > li {\n        margin: 0 2px;\n        display: inline-block;\n        vertical-align: top;\n        \n        & > a,\n        & > span {\n            border-radius: 50% !important;\n            padding: 0;\n            width: 40px;\n            height: 40px;\n            line-height: 38px;\n            text-align: center;\n            font-size: 14px;\n            z-index: 1;\n            position: relative;\n            cursor: pointer;\n            \n            & > .zmdi {\n                font-size: 22px;\n                line-height: 39px;\n            }\n        }\n         \n        &.disabled {\n            .opacity(0.5);\n        }  \n    }\n} \n\n/*\n * Listview Pagination\n */\n.lv-pagination {\n    width: 100%;\n    text-align: center;\n    padding: 40px 0;\n    border-top: 1px solid #F0F0F0;\n    margin-top: 0;\n    margin-bottom: 0;\n}\n\n/*\n * Pager\n */\n.pager li > a, .pager li > span {\n    padding: 5px 10px 6px; \n    color: @pagination-color;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/panel.less",
    "content": ".panel {\n    box-shadow: none;\n    border: 0;\n}\n\n.panel-heading {\n    padding: 0;\n}\n\n.panel-title {\n    & > a {\n        padding: 10px 15px;\n        display: block;\n        font-size: 13px;\n    }\n}\n \n.panel-collapse {\n    .panel-heading {\n        position: relative;\n        \n        .panel-title {\n            & > a {\n                padding: 8px 5px 16px 30px;\n                color: #000;\n                position: relative;\n                \n                &:after,\n                &:before {\n                    position: absolute;\n                    bottom: 0;\n                    left: 0;\n                    height: 2px;\n                    width: 100%;\n                    content: \"\";\n                    .transition(all);\n                    .transition-duration(300ms);\n                    .backface-visibility(hidden);\n                }\n                \n                &:after {\n                    .scale(0);\n                }\n            }\n        }\n        \n        &:not(.active) .panel-title > a {\n            &:before {\n                background: #eee;\n            }\n        }\n        \n        &:before,\n        &:after {\n            font-family: @font-icon-md;\n            font-size: 17px;\n            position: absolute;\n            left: 0;\n            .transition(all);\n            .transition-duration(300ms);\n            .backface-visibility(hidden);\n            top: 4px;\n        }\n        \n        &:before {\n            content: \"\\f278\";\n            .scale(1);\n        }\n        \n        &:after {\n            .scale(0);\n            content: \"\\f273\";\n        }\n        \n        &.active {\n            .panel-title > a {\n                &:after {\n                    .scale(1);\n                }\n            }\n            \n            &:before {\n                .scale-rotate(0, -90deg);\n            }\n            \n            &:after {\n                .scale(1);\n            }\n        }\n    }\n    \n    \n    .panel-body {\n        border-top: 0 !important;\n        padding-left: 5px;\n        padding-right: 5px;\n    }\n}\n\n.panel-collapse-color(@color) {\n    .panel-collapse {\n        .panel-heading {\n            &.active .panel-title > a {\n                &:after {\n                    background: @color;\n                }\n            }\n        }\n    }\n}\n\n.panel-group {\n    &:not([data-collapse-color]) {\n        .panel-collapse-color(@m-blue);\n    }\n    \n    &[data-collapse-color=\"red\"] {\n        .panel-collapse-color(@m-red);\n    }\n    \n    &[data-collapse-color=\"green\"] {\n        .panel-collapse-color(@m-green);\n    }\n    \n    &[data-collapse-color=\"amber\"] {\n        .panel-collapse-color(@m-amber);\n    }\n    \n    &[data-collapse-color=\"teal\"] {\n        .panel-collapse-color(@m-teal);\n    }\n    \n    &[data-collapse-color=\"black\"] {\n        .panel-collapse-color(@m-black);\n    }\n    \n    &[data-collapse-color=\"cyan\"] {\n        .panel-collapse-color(@m-cyan);\n    }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/photos.less",
    "content": ".photos {\n    margin: 2px 0 0;\n    \n    .lightbox {\n        margin: 0 -8px;\n    }\n    \n    &:not(.p-timeline) {\n        [data-src] {\n            padding: 3px; \n            .transition(all);\n            .transition-duration(150ms);\n        }\n    }\n}\n\n.p-timeline {\n    position: relative;\n    padding-left: 80px;\n    margin-bottom: 75px;\n    \n    [data-src] {\n        float: left;\n        width: 70px;\n        height: 70px;\n        margin: 0 3px 3px 0;\n    }\n    \n            \n    &:last-child .pt-line:before {\n        height: 100%;\n    }\n}\n\n.ptb-title { \n    font-size: 15px;\n    font-weight: 400; \n    margin-bottom: 20px; \n}\n\n.pt-line {\n    position: absolute;\n    left: 0;\n    top: 0;\n    height: 100%;\n    line-height: 14px;\n    \n    &:before,\n    &:after {\n        content: \"\";\n        position: absolute;\n    }\n    \n    &:before {\n        width: 1px;\n        height: ~\"calc(100% + 63px)\";\n        background: #E2E2E2;\n        top: 14px;\n        right: -20px;\n    }\n    \n    &:after {\n        top: 2px;\n        right: -26px;\n        width: 13px;\n        height: 13px;\n        border: 1px solid #C1C1C1;\n        border-radius: 50%;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/popover.less",
    "content": ".popover {\n    box-shadow: 0 2px 30px rgba(0, 0, 0, 0.2);\n}\n\n.popover-title {\n    border-bottom: 0;\n    padding: 15px; \n    font-size: 12px;\n    text-transform: uppercase;\n    \n    & + .popover-content { \n        padding-top: 0;\n    }\n}   \n\n.popover-content {\n    padding: 15px; \n    \n    p {\n        margin-bottom: 0; \n    }\n} "
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/preloader.less",
    "content": ".preloader {\n  position: relative;\n  margin: 0px auto;\n  display: inline-block;\n\n  &:not([class*=\"pl-\"]) {\n    width: 40px;\n  }\n\n  &:before {\n    content:'';\n    display: block;\n    padding-top: 100%;\n  }\n\n  &.pl-xs { width: 20px; }\n  &.pl-sm { width: 30px; }\n  &.pl-lg { width: 50px; }\n  &.pl-xl { width: 80px; }\n  &.pl-xxl { width: 100px; }\n\n  &:not([class*=\"pls-\"]) {\n    .plc-path {\n      animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;\n    }\n  }\n\n  &[class*=\"pls-\"] .plc-path {\n    animation: dash 1.5s ease-in-out infinite;\n  }\n\n  &.pls-red .plc-path { stroke: @m-red; }\n  &.pls-blue .plc-path { stroke: @m-blue; }\n  &.pls-green .plc-path { stroke: @m-green; }\n  &.pls-yellow .plc-path { stroke: @m-yellow; }\n  &.pls-bluegray .plc-path { stroke: @m-bluegray; }\n  &.pls-amber .plc-path { stroke: @m-amber; }\n  &.pls-teal .plc-path { stroke: @m-teal; }\n  &.pls-gray .plc-path { stroke: @m-gray; }\n  &.pls-pink .plc-path { stroke: @m-pink; }\n  &.pls-purple .plc-path { stroke: @m-purple; }\n  &.pls-white .plc-path { stroke: #fff; }\n}\n\n.pl-circular {\n  animation: rotate 2s linear infinite;\n  height: 100%;\n  transform-origin: center center;\n  width: 100%;\n  position: absolute;\n  top: 0; bottom: 0; left: 0; right: 0;\n  margin: auto;\n}\n\n.plc-path {\n  stroke-dasharray: 1,200;\n  stroke-dashoffset: 0;\n  stroke-linecap: round;\n  stroke-width: 2;\n  stroke-miterlimit: 10;\n  fill: none;\n}\n\n@keyframes rotate{\n  100%{\n    transform: rotate(360deg);\n  }\n}\n@keyframes dash{\n  0%{\n    stroke-dasharray: 1,200;\n    stroke-dashoffset: 0;\n  }\n  50%{\n    stroke-dasharray: 89,200;\n    stroke-dashoffset: -35px;\n  }\n  100%{\n    stroke-dasharray: 89,200;\n    stroke-dashoffset: -124px;\n  }\n}\n\n@keyframes color{\n  100%, 0%{\n    stroke: @m-red;\n  }\n  40%{\n    stroke: @m-blue;\n  }\n  66%{\n    stroke: @m-green;\n  }\n  80%, 90%{\n    stroke: @m-amber;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/pricing-table.less",
    "content": ".pt-inner {\n    text-align: center;\n\n    .pti-header {\n          padding: 45px 10px 70px;\n          color: #fff;\n          position: relative;\n        margin-bottom: 15px;\n\n\n        & > h2 {\n              margin: 0;\n              line-height: 100%;\n              color: #fff;\n              font-weight: 100;\n              font-size: 50px;\n\n            small {\n                  color: #fff;\n                  letter-spacing: 0;\n                  vertical-align: top;\n                  font-size: 16px;\n                  font-weight: 100;\n            }\n        }\n\n        .ptih-title {\n              background-color: rgba(0, 0, 0, 0.1);\n              padding: 8px 10px 9px;\n              text-transform: uppercase;\n              margin: 0 -10px;\n              position: absolute;\n              width: 100%;\n              bottom: 0;\n        }\n    }\n\n    .pti-body {\n        padding: 0 23px;\n\n        .ptib-item {\n            padding: 15px 0;\n            font-weight: 400;\n\n            &:not(:last-child) {\n                border-bottom: 1px solid #eee;\n            }\n        }\n    }\n\n    .pti-footer {\n        padding: 10px 20px 30px;\n\n        & > a {\n            width: 60px;\n            height: 60px;\n            border-radius: 50%;\n            text-align: center;\n            color: #fff;\n            display: inline-block;\n            line-height: 60px;\n            font-size: 30px;\n            .transition(all);\n            .transition-duration(300ms);\n\n            &:hover {\n                .opacity(0.85);\n                .z-depth(1);\n            }\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/print.less",
    "content": "@media print {    \n    @page {\n        margin: 0;\n        size: auto;\n    }\n    \n    body {\n        margin: 0mm 0mm 0mm 0mm !important;\n        padding: 0mm !important;\n    }\n    \n    #header,\n    #footer,\n    #sidebar,\n    #chat,\n    .growl-animated,\n    .m-btn {\n        display: none !important;\n    }\n    \n    /*\n     * INVOICE\n     */\n    \n    .invoice {\n        padding: 30px !important;\n        -webkit-print-color-adjust: exact !important; \n        \n        .card-header {\n            background: #eee !important;\n            padding: 20px;\n            margin-bottom: 20px;\n            margin: -60px -30px 25px -30px;\n        }\n        \n        \n        .block-header { \n            display: none;\n        } \n        \n        .highlight {\n            background: #eee !important; \n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/profile.less",
    "content": "#profile-main {\n    min-height: 500px;\n    \n    position: relative;\n    \n    .pm-overview {\n        overflow-y: auto;\n        \n        @media (min-width: 1200px) {\n            width: 300px;\n        }\n        \n        @media (min-width: @screen-sm-min) and (max-width: 1200px) {\n            width: 250px;\n        }\n        \n        @media (min-width: @screen-sm-min) {\n            position: absolute;\n            left: 0;\n            top: 0;\n            height: 100%;\n            background: #f8f8f8;\n            border-right: 1px solid #eee;\n        }\n        \n        @media (max-width: @screen-xs-max) {\n            width: 100%;\n            background: #333;\n            text-align: center;\n        }\n\n    }\n    \n    .pm-body {\n        @media (min-width: 1200px) {\n            padding-left: 300px;\n        }\n        \n        @media (min-width: @screen-sm-min) and (max-width: 1200px) {\n            padding-left: 250px;\n        }\n        \n        @media (max-width: @screen-xs-max) {\n            padding-left: 0; \n        }\n\n    }\n    \n    .pmo-pic {\n        position: relative;\n        margin: 20px;\n        \n        img { \n            @media(min-width: @screen-sm-min) {\n                width: 100%;\n                border-radius: 2px 2px 0 0;\n            }\n            \n            @media(max-width: @screen-xs-max) {\n                width: 180px;\n                display: inline-block;\n                height: 180px;\n                border-radius: 50%;\n                border: 4px solid #fff;\n                .z-depth(2);\n            }\n        }\n        \n        .pmo-stat {\n            border-radius: 0 0 2px 2px;\n            color: #fff;\n            text-align: center;\n            padding: 30px 5px 0;\n            \n            @media(min-width: @screen-sm-min) {\n                 background: @m-amber;\n                 padding-bottom: 15px;\n            }\n        }\n        \n        .pmop-edit {\n            position: absolute;\n            top: 0;\n            left: 0;\n            color: #fff;\n            background: rgba(0, 0, 0, 0.38);\n            text-align: center;\n            padding: 10px 10px 11px; \n            .transition(opacity);\n            .transition-duration(250ms);\n            \n            &:hover {\n                background: rgba(0, 0, 0, 0.8);\n            }\n            \n            i {\n                font-size: 18px;\n                vertical-align: middle;\n                margin-top: -3px;\n            }\n            \n            @media (min-width: @screen-sm-min) {\n                width: 100%;\n                .opacity(0);\n                \n                i {\n                    margin-right: 4px;\n                }\n            }\n        }\n        \n        &:hover {\n            .pmop-edit {\n                .opacity(1);\n            }\n        }\n        \n        .pmop-message  {\n            position: absolute;\n            bottom: 27px;\n            left: 50%; \n            margin-left: -25px;\n            \n            .dropdown-menu {\n                padding: 5px 0 55px; \n                left: -90px;\n                width: 228px;\n                height: 150px;\n                top: -74px;\n                .transform-origin(center);\n                \n                textarea {\n                    width: 100%;\n                    height: 95px;\n                    border: 0;\n                    resize: none;\n                    padding: 10px 19px;\n                }\n                \n                button {\n                    bottom: 5px;\n                    left: 88px;\n                }\n            }\n        }\n    }\n    \n    .pmb-block {\n        margin-bottom: 20px;\n        \n        @media (min-width: 1200px) {\n            padding: 40px 42px 0;\n        }\n        \n        @media (max-width: 1199px) {\n            padding: 30px 20px 0;\n        }\n        \n        &:last-child {\n            margin-bottom: 50px;\n        }\n        \n        .pmbb-header {\n            margin-bottom: 25px;\n            position: relative;\n            \n            .actions {\n                position: absolute;\n                top: -2px;\n                right: 0;\n            }\n            \n            h2 {\n                margin: 0;\n                font-weight: 100;\n                font-size: 20px;\n            }\n        }\n        \n        .pmbb-edit {\n            position: relative;\n            z-index: 1; \n            display: none;\n        }\n        \n        .pmbb-edit,\n        .pmbb-view {\n            .animated(fadeIn, 1000ms);\n        }\n        \n        &.toggled {\n            .pmbb-edit {\n                display: block;\n            }\n            \n            .pmbb-view {\n                display: none;\n            }\n        }\n    }\n    \n    .pmo-block {\n        padding: 25px;\n        \n        & > h2 {\n            font-size: 16px;\n            margin: 0 0 15px;\n        }\n    }\n    \n    .pmo-items {\n        .pmob-body {\n            padding: 0 10px;\n        }\n        \n        a {\n            display: block;\n            padding: 4px;\n            \n            img {\n                width: 100%;\n            }\n        }\n    }\n}\n\n.pmo-contact {\n    ul {\n        list-style: none;\n        margin: 0;\n        padding: 0; \n        \n        li {\n            position: relative;\n            padding: 8px 0 8px 35px;\n            \n            i {\n                font-size: 18px;\n                vertical-align: top;\n                line-height: 100%;\n                position: absolute;\n                left: 0;\n                width: 18px;\n                text-align: center;\n            }\n        }\n    }\n}\n\n.pmo-map {\n    margin: 20px -21px -18px;\n    display: block;\n    \n    img {\n        width: 100%;\n    }\n}\n\n.c-timeline {\n    @media(max-width: @screen-xs-max) {\n        background: @body-bg;\n        box-shadow: none;\n        \n        .tab-nav {\n            background: #fff;\n            box-shadow: 0 1px 1px rgba(0,0,0,.15);\n        }\n    }\n}\n\n.timeline {\n    position: relative;\n    \n    @media(min-width: @screen-sm-min) {\n        padding: 50px;\n        padding-left: 100px;\n    }\n    \n    @media(max-width: @screen-xs-max) {\n        margin-top: 30px;\n    }\n}\n\n.t-view {\n    border: 1px solid #eee;\n    position: relative;\n    margin-bottom: 35px;\n    \n    @media(max-width: @screen-xs-max) {\n        background: #fff;\n        box-shadow: 0 1px 1px rgba(0,0,0,.15);\n    }\n    \n    .tv-header {\n        padding: 16px 18px;\n        border-bottom: 1px solid #eee;\n        background: #F9F9F9;\n        \n        .actions {\n            position: absolute;\n            top: 5px;\n            right: 10px;\n        } \n    }\n    \n    .tv-body {\n        padding: 23px 25px;\n        \n        .tvb-lightbox {\n            margin: 0 -8px 15px;\n            \n            [data-src] {\n                padding: 0 5px;\n                margin-bottom: 5px;\n            }\n        }\n    }\n    \n    .tvh-user {\n        display: block;\n        \n        img {\n            width: 46px;\n            height: 46px;\n            border-radius: 50%;\n        }\n    }\n    \n    &:before {\n        position: absolute;\n        width: 40px;\n        height: 40px;\n        border-radius: 50%;\n        left: -70px;\n        top: 0;\n        border: 3px solid #FFF;\n        text-align: center;\n        font-size: 16px;\n        line-height: 34px;\n        color: #FFF;\n        font-family: @font-icon-md;\n        z-index: 1;\n        \n    }\n    \n    &:after {\n        content: \"\";\n        position: absolute;\n        top: 0;\n        left: -50px;\n        width: 1px;\n        height: ~\"calc(100% + 37px)\";\n        \n    }\n    \n    &[data-tv-type=\"text\"] {\n        &:before {\n            content: \"\\f24f\";\n            background: @m-cyan;\n            box-shadow: 0 0 0 1px @m-cyan;\n        }\n        \n        &:after {\n            background: @m-cyan;\n        }\n    }\n    \n    &[data-tv-type=\"image\"] {\n        &:before {\n            content: \"\\f17f\";\n            background: @m-green;\n            box-shadow: 0 0 0 1px @m-green;\n        }\n        \n        &:after {\n            background: @m-green;\n        }\n    }\n    \n    &[data-tv-type=\"video\"] {\n        &:before {\n            content: \"\\f3a9\";\n            background: @m-amber;\n            box-shadow: 0 0 0 1px @m-amber;\n        }\n        \n        &:after { \n            background: @m-amber;\n        }\n    }\n    \n\n    .tvb-stats {\n        list-style: none;\n        padding: 0;\n        margin: 10px 0 20px;\n        \n        & > li {\n            display: inline-block;\n            padding: 5px 10px 6px;\n            border: 1px solid #ccc;\n            margin-right: 2px;\n            \n            i {\n                font-size: 15px;\n                line-height: 100%;\n                vertical-align: top;\n                margin-top: 2px;\n            }\n            \n            &.tvbs-comments {\n                border-color: @m-green;\n                color: @m-green;\n            }\n            \n            &.tvbs-likes {\n                border-color: @m-lightblue;\n                color: @m-lightblue;\n            } \n            \n            &.tvbs-views {\n                border-color: @m-orange;\n                color: @m-orange;\n            }\n        }\n        \n        \n     }\n}\n\n.tv-comments {\n    \n    .tvc-lists {\n        padding: 0;\n        list-style: none;\n        margin: 0;\n        \n        & > li {\n            padding: 15px 20px;\n            margin: 0;\n            border-top: 1px solid #eee;\n        }\n    }\n}\n\n.tvc-more { \n    color: #333;\n    display: block;\n    margin-bottom: -10px;\n    \n    &:hover {\n        color: #000;\n    }\n    \n    i {\n        vertical-align: middle;\n        margin-right: 5px;\n    }\n}\n\n.p-header {\n    position: relative;\n    margin: 0 -7px;\n    \n    .actions {\n        position: absolute;\n        top: -18px;\n        right: 0;\n    }\n}\n\n.p-menu {\n    list-style: none;\n    padding: 0 5px;\n    margin: 0 0 30px;\n    \n    & > li {\n        display: inline-block;\n        vertical-align: top;\n        \n        & > a {\n            display: block;\n            padding: 5px 20px 5px 0;\n            font-weight: 500;\n            text-transform: uppercase;\n            font-size: 15px;\n            \n            & > i {\n                margin-right: 4px;\n                font-size: 20px;\n                vertical-align: middle;\n                margin-top: -5px;\n            }\n        }\n        \n        &:not(.active) > a {\n            color: #4285F4;\n            \n            &:hover {\n                color: #333;\n            }\n        }\n        \n        &.active > a {\n            color: #000;\n        }\n    }\n    \n    .pm-search {\n        @media(max-width: @screen-sm-max) {\n            margin: 20px 2px 30px;\n            display: block;\n            \n            input[type=\"text\"] {\n                width: 100%;\n                border: 1px solid #ccc;\n            }\n        }\n    }\n    \n    .pms-inner {\n        margin: -2px 0 0;\n        position: relative;\n        top: -2px;\n        overflow: hidden;\n        white-space: nowrap;\n        \n        i {\n            vertical-align: top;\n            font-size: 20px;\n            line-height: 100%;\n            position: absolute;\n            left: 9px;\n            top: 8px;\n            color: #333;\n        }\n        \n        input[type=\"text\"] {\n            height: 35px;\n            border-radius: 2px;\n            padding: 0 10px 0 40px;\n            \n            @media(min-width:  @screen-sm-min) {\n                border: 1px solid #fff;\n                width: 50px;\n                background: transparent;\n                position: relative;\n                z-index: 1;\n                .transition(all);\n                .transition-duration(300ms);\n            \n                &:focus {\n                    border-color: #DFDFDF;\n                    width: 200px;\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/progress-bar.less",
    "content": ".progress {\n    box-shadow: none;\n    border-radius: 0;\n    height: 5px;\n    margin-bottom: 0;\n    \n    .progress-bar {\n        box-shadow: none;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/shadow.less",
    "content": ".z-depth {\n    .z-depth-class();\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/sidebar.less",
    "content": ".sidebar {\n    position: fixed;\n    background: #fff; \n    box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n    height: ~\"calc(100% - 65px)\";\n    top: 65px;\n    .transition(all);\n    .transition-duration(300ms);\n    z-index: 10;\n    .opacity(0);\n    overflow-y: auto;\n    \n    &.toggled {\n        .opacity(1);\n    }\n}\n\n#sidebar {\n    width: @sidebar-left-width;\n    .translate3d(-@sidebar-left-width, 0, 0);\n    \n    &.toggled {\n        .translate3d(0, 0, 0);\n    }\n}\n\n.profile-menu {\n    & > a {\n        display: block;\n        height: 129px;\n        margin-bottom: 5px;\n        width: 100%;\n        background: url(../img/profile-menu.png) no-repeat left top;\n        background-size: 100%;\n        \n        .profile-pic {\n            padding: 12px;\n            \n            & > img {\n                width: 47px;\n                height: 47px;\n                border-radius: 50%;\n                border: 3px solid rgba(0, 0, 0, 0.14);\n                box-sizing: content-box;\n            }\n        }\n        \n        .profile-info {\n            background: rgba(0, 0, 0, 0.37);\n            padding: 7px 14px;\n            color: #fff;\n            margin-top: 20px;\n            position: relative;\n            \n            & > i {\n                font-size: 19px;\n                line-height: 100%;\n                position: absolute;\n                right: 15px;\n                top: 7px;\n                .transition(all);\n                .transition-duration(300ms);\n            }\n        }\n    }\n    .main-menu {\n        display: none;\n        margin: 0 0 0;\n        border-bottom: 1px solid #E6E6E6;\n        \n    }\n\n    &.toggled {\n        .profile-info {\n            & > i {\n                .rotate(180deg)\n            }\n        }\n    }\n}\n\n.main-menu {\n    list-style: none; \n    padding-left: 0;\n    margin: 20px 0 0 0;\n    \n    & > li {\n        & > a {\n            padding: 14px 20px 14px 52px;\n            display: block;\n            color: #4C4C4C;\n            font-weight: 500;\n            position: relative;\n            \n            &:hover {\n                color: #262626;\n                background-color: #f7f7f7;\n            }\n            \n            & > i {\n                position: absolute;\n                left: 16px;\n                font-size: 20px;\n                top: 0;\n                width: 25px;\n                text-align: center;\n                padding: 13px 0;\n            }\n        }\n        \n        &.active {\n            & > a {\n                color: #262626;\n                background-color: #F4F4F4;\n            }\n        }\n    }\n}\n\n.sub-menu {\n    & > a {\n        position: relative;\n        \n        &:before, &:after {\n            position: absolute;\n            top: 12px;\n            color: #575757;\n            font-family: @font-icon-md;\n            font-size: 17px;\n            right: 15px;\n            .transition(all);\n            .transition-duration(250ms);\n            .backface-visibility(hidden);\n        }\n        \n        &:before {\n            content: \"\\f278\";\n            .scale(1);\n        }\n        \n        &:after {\n            content: \"\\f273\";\n            .scale(0);\n        }\n    }\n    \n    .sub-menu > a {\n        &:before, &:after {\n            top: 5px;\n        }\n    }\n    \n    &.toggled {\n        & > a {\n            &:before {\n                content: \"\\f278\";\n                .scale(0);\n            }\n            \n            &:after {\n                content: \"\\f273\";\n                .scale(1);\n            }\n        }\n    }\n    \n    ul {\n        list-style: none;\n        display: none;\n        padding: 0;\n        \n        & > li {\n            & > a {\n                color: #7f7f7f;\n                padding: 8px 20px 8px 50px;\n                font-weight: 500;\n                display: block;\n                \n                &.active, &:hover {\n                    color: #000;\n                }\n            }\n            \n            &:first-child > a {\n                padding-top: 14px;\n            }\n            \n            &:last-child > a {\n                padding-bottom: 16px;\n            }\n             \n            ul {\n                font-size: 12px;\n                margin: 10px 0;\n                background-color: @app-gray;\n            }\n        }\n    }\n\n    &.active {\n        & > ul {\n            display: block;\n        }\n    } \n}\n\n/*\n * layout\n */\nbody {\n    &:not(.sw-toggled) {\n        #sidebar {\n            box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n        }\n    }\n\n    &.sw-toggled {\n        #sidebar {\n            @media (min-width: @screen-lg-min) {\n                .translate3d(0, 0, 0);\n                .opacity(1);\n                box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n            }\n\n            @media (max-width: @screen-md-max) {\n                box-shadow: 0 0 10px rgba(51, 51, 51, 0.38);\n            }\n        }\n    }\n}\n\n\n/*\n * For Stupid IE9\n */\n.ie9 {\n    body.sw-toggled #sidebar {\n        @media (min-width: @screen-lg-min) {\n            display: block;\n        }\n    }\n\n    body:not(.sw-toggled) {\n        #sidebar:not(.toggled) {\n            display: none;\n        }\n    }\n}\n\n\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/skin.less",
    "content": "/*\n * For header type 1 only\n * You may remove these if you opt header 2\n */\n#header {\n    .skin-switch {\n        padding: 10px 0 2px;\n        text-align: center;\n    }\n    \n    .ss-skin {\n        width: 16px;\n        height: 16px;\n        border-radius: 50%;\n        cursor: pointer;\n        display: inline-block;\n        margin: 2px 3px;\n    }\n}\n/* ----------------------------- End header type 1 ------------------------------------- */\n\n\n/*\n * For header type 2 only\n * You may remove these if you opt header 1\n */\n\n#header-2 {\n    .skin-switch {\n        position: absolute;\n        right: 50px;\n        bottom: 23px;\n        z-index: 1;\n        \n        .btn {\n            background: #fff;\n            width: 50px;\n            height: 50px;\n            border-radius: 50%;\n            font-size: 25px;\n            z-index: 2;\n        }\n        \n        .dropdown-menu {\n            min-width: 130px;\n            height: 130px;\n            border-radius: 50%;\n            width: 130px;\n            top: -42px;\n            left: -40px;\n            z-index: 1;\n            .transform-origin(center);\n            .scale-rotate(0, -360deg);\n            .transition-duration(500ms); \n            \n            .ss-skin {\n                position: absolute;\n                \n                &.ss-1 {\n                    margin-left: -8px;\n                    top: 12px;\n                    left: 50%;\n                }\n                \n                &.ss-2 {\n                    right: 24px;\n                    top: 26px;\n                }\n                \n                &.ss-3 {\n                    top: 50%;\n                    margin-top: -8px;\n                    right: 12px;\n                }\n                \n                &.ss-4 {\n                    right: 24px;\n                    bottom: 26px;\n                }\n                \n                &.ss-5 {\n                    margin-left: -8px;\n                    bottom: 12px;\n                    left: 50%;\n                }\n                \n                &.ss-6 {\n                    left: 24px;\n                    bottom: 26px;\n                }\n                \n                &.ss-7 {\n                    top: 50%;\n                    margin-top: -8px;\n                    left: 12px;\n                }\n                \n                &.ss-8 {\n                    left: 24px;\n                    top: 26px;\n                }\n            }\n        }\n        \n        &.open {\n            .dropdown-menu {\n                .scale-rotate(1, 0deg);\n            }\n        }\n    }\n}\n/* ----------------------------- End header type 2 ------------------------------------- */\n\n\n\n/*\n * Do not remove these\n * This is common for both\n */\n.ss-skin {\n    width: 16px;\n    height: 16px;\n    border-radius: 50%;\n    cursor: pointer;\n    \n    &:hover {\n        .opacity(0.8);\n    }\n}\n.current-skin(@color) {\n    background-color: @color;\n    \n    .ss-icon { color: @color; }\n    \n    .ha-menu {\n        @media (max-width: @screen-xs-max) {\n            background: @color;\n        }\n    }\n}\n\n[data-current-skin=\"lightblue\"] { .current-skin(@m-lightblue); }\n[data-current-skin=\"bluegray\"] { .current-skin(@m-bluegray); }\n[data-current-skin=\"blue\"] { .current-skin(@m-blue); }\n[data-current-skin=\"purple\"] { .current-skin(@m-purple); }\n[data-current-skin=\"orange\"] { .current-skin(@m-orange); }\n[data-current-skin=\"cyan\"] { .current-skin(@m-cyan); }\n[data-current-skin=\"green\"] { .current-skin(@m-green); }\n[data-current-skin=\"teal\"] { .current-skin(@m-teal); }\n[data-current-skin=\"pink\"] { .current-skin(@m-pink); }"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/table.less",
    "content": ".table {\n    background-color: @table-bg;\n    margin-bottom: 0;\n    \n    & > thead > tr > th {\n        background-color: #fff;\n        vertical-align: middle;\n        font-weight: 500;\n        color: #333;\n        border-width: 1px;\n        text-transform: uppercase;\n    }\n    \n    [class*=\"bg-\"] {\n        & > tr > th {\n            color: #fff;\n            border-bottom: 0; \n        }\n        \n        & + tbody > tr > td {\n            border-top: 0;\n        }\n    }\n    \n    &.table-inner {\n        border: 0;\n    }\n    \n    & > thead > tr,\n    & > tbody > tr,\n    & > tfoot > tr {\n        & > th, & > td {\n            &:first-child {\n                padding-left: 30px;\n            }\n            \n            &:last-child {\n                padding-right: 30px;\n            }\n            \n        }\n    }\n    \n    & > tbody, & > tfoot {\n        & > tr {\n            &.active,\n            &.info,\n            &.warning,\n            &.succes,\n            &.danger {\n                & > td {\n                    border: 0;\n                }\n            }\n            \n            &:last-child > td >  {\n                padding-bottom: 20px;\n            }\n        }\n    }\n}\n\n.table-striped {\n    td, th {\n        border: 0 !important;\n    }\n}\n\n.table-bordered {\n    border-bottom: 0;\n    border-left: 0;\n    border-right: 0; \n    \n    & > tbody > tr {\n        & > td, & > th {\n            border-bottom: 0;\n            border-left: 0;\n            \n            &:last-child {\n                border-right: 0;\n            }\n        }\n    }\n    \n    & > thead > tr > th {\n        border-left: 0;\n        \n        &:last-child {\n            border-right: 0;\n        }\n    }\n}\n\n.table-vmiddle {\n    td {\n        vertical-align: middle !important;\n    }\n}\n\n.table-responsive {\n    border: 0;\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/tabs.less",
    "content": ".tab-nav {\n    list-style: none;\n    padding: 0;\n    white-space: nowrap;\n    margin: 0;\n    overflow: auto;\n    box-shadow: inset 0 -2px 0 0 #eee;\n    width: 100%;\n        \n    li {\n        display: inline-block;\n        vertical-align: top;\n        \n        & > a {\n            display: inline-block;\n            color: #7a7a7a;\n            text-transform: uppercase;\n            position: relative;\n            width: 100%;\n            .transition(all);\n            .transition-duration(250ms);\n            font-weight: 500;\n             \n            &:after { \n                content: \"\";\n                height: 2px;\n                position: absolute;\n                width: 100%; \n                left: 0;\n                bottom: 0;\n                .transition(all);\n                .transition-duration(250ms);\n                .scale(0);\n            }\n            \n            @media (min-width: @screen-sm-min) {\n                padding: 15px;\n            }\n            \n            @media (max-width: @screen-sm-min) {\n                padding: 15px 8px;\n            }\n        }\n        \n        &.active {\n            & > a { \n                color: #000;\n                \n                &:after {\n                    .scale(1);\n                }\n            } \n        }\n    }\n    \n    &.tab-nav-right {\n        text-align: right;\n    }\n    \n    &.tn-justified {\n        & > li {\n            display: table-cell;\n            width: 1%;\n            text-align: center;\n        }\n    }\n    \n    &.tn-icon {\n        & > li {\n            .zmdi {\n                font-size: 22px;\n                line-height: 100%;\n                min-height: 25px;   \n            }\n        }\n    }\n    \n    &:not([data-tab-color]) {\n        & > li > a:after {\n            background: @m-blue;\n        }\n    }\n    \n    &[data-tab-color=\"green\"] {\n        & > li > a:after {\n            background: @m-green;\n        }\n    } \n    \n    &[data-tab-color=\"red\"] {\n        & > li > a:after {\n            background: @m-red;\n        }\n    }\n    \n    &[data-tab-color=\"teal\"] {\n        & > li > a:after {\n            background: @m-teal;\n        }\n    }\n    \n    &[data-tab-color=\"amber\"] {\n        & > li > a:after {\n            background: @m-amber;\n        }\n    }\n    \n    &[data-tab-color=\"black\"] {\n        & > li > a:after {\n            background: @m-black;\n        }\n    }\n    \n    &[data-tab-color=\"cyan\"] {\n        & > li > a:after {\n            background: @m-cyan;\n        }\n    }\n}\n\n.tab-content {\n    padding: 20px 0;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/todo.less",
    "content": "#todo-lists {\n    background: @m-amber;\n    color: #fff;\n    margin-bottom: 30px;\n    font-family: 'shadowsintolight', cursive;\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n}\n\n.tl-header {\n    position: relative;\n    padding: 25px;\n    \n    & > h2 {\n        margin: 0;\n        color: #fff;\n        line-height: 100%;\n    }\n    \n    & > small {\n        font-size: 17px;\n        display: block;\n        margin-top: 3px;\n    }\n    \n    .actions {\n        position: absolute; \n        right: 10px;\n        padding: 0;\n        list-style: none;\n        top: 15px;\n        \n        & > li {\n            display: inline-block;\n            vertical-align: baseline;\n        }\n    }\n}\n\n.tl-body {\n    min-height: 300px;\n    position: relative;\n    padding: 20px 10px 20px 25px;\n    background: rgba(0, 0, 0, 0.03);\n\n    .media-body {\n        padding-top: 3px;\n        font-size: 18px;\n    }\n\n    .checkbox {\n        margin-bottom: 15px;\n        \n        span {\n            display: inline-block;\n            margin-top: -3px;\n        }\n\n        input:checked + i + span {\n            text-decoration: line-through;\n        }\n        \n        .input-helper {\n            &:before {\n                border-color: rgba(255,255,255,0.8);\n                border-width: 2px;\n            }\n            \n            &:after {\n                border-color: #fff;\n            } \n        } \n    }\n}\n\n#add-tl-item {\n    width: 50px;\n    height: 50px;\n    border-radius: 50%;\n    position: absolute;\n    background: #fff;\n    top: -25px;\n    right: 23px;\n    .transition(all);\n    .backface-visibility(hidden);\n    .transition-duration(200ms);\n    \n    .add-new-item {\n        .transition(all);\n        .transition-duration(200ms);\n        .scale(1);\n    }\n    \n    .add-tl-body {\n        overflow: hidden;\n        .opacity(0);\n        .transition(all);\n        .transition-duration(300ms);\n        \n        textarea {\n            padding: 25px 25px 45px;\n            resize: none;\n            width: 100%;\n            font-size: 24px;\n            color: @m-amber;\n            position: absolute;\n            height: 100%;\n            border: 0;\n            outline: none;\n        }\n    }\n    \n    &:not(.toggled) {\n        overflow: hidden;\n        \n        .add-new-item {\n            position: relative;\n            z-index: 1;\n            display: inline-block;\n            width: 50px;\n            height: 50px;\n            .bg-option();\n            cursor: pointer;\n            text-align: center;\n            font-size: 23px;\n            color: @m-orange;\n            line-height: 50px;\n        }\n    }\n    \n    &.toggled {\n        width: ~\"calc(100% - 47px)\";\n        height: ~\"calc(100% - 25px)\";\n        border-radius: 2px;\n        top: 0;\n        z-index: 1;\n        box-shadow: 0 5px 8px rgba(0, 0, 0, 0.2);\n        max-height: 300px;\n        overflow: visible;\n        \n        .add-new-item {\n            .scale(0);\n            height: 0;\n            overflow: hidden;\n            float: left;\n        }\n\n        .add-tl-body {\n            .opacity(1);\n            \n            .add-tl-actions {\n                position: absolute;\n                bottom: 0;\n                width: 100%;\n                padding: 5px 10px;\n                border-top: 1px solid #EEE;\n                z-index: 1;\n\n                & > a {\n                    font-size: 25px;\n                    padding: 0 6px;\n                    border-radius: 50%; \n                    text-align: center;\n                    height: 40px;\n                    width: 40px;\n                    display: inline-block;\n                    line-height: 41px;\n                    border-radius: 50%;\n                    .transition(background-color);\n                    .transition-duration(300ms);\n                    \n                    &:hover {\n                        background-color: #eee;\n                    }\n                }\n                \n                [data-tl-action=\"dismiss\"] {\n                    color: @m-red;\n                }\n                \n                [data-tl-action=\"save\"] {\n                    color: @m-green;\n                }\n            } \n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/tooltip.less",
    "content": ".tooltip-inner {\n    border-radius: 1px;\n    padding: 3px 10px 5px;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/variables.less",
    "content": "/*\n * Font Icon Family\n */\n@font-icon-md:              'Material-Design-Iconic-Font';\n\n\n/*\n * Grid System\n */\n@container-tablet:                      100%;\n@container-desktop:                     100%;\n\n\n/* Typography + Scaffolding + Links */\n@body-bg:                   #edecec;\n@text-color:                #5E5E5E;\n@font-family-sans-serif:    roboto;\n@font-size-base:            13px;\n@link-hover-decoration:     none;\n@headings-color:\t\t\t#000000;\n\n/* Border Radius */\n@border-radius-base:        2px;\n@border-radius-large:       4px;\n@border-radius-small:       2px;\n\n/* Tabs */\n@nav-tabs-border-color:                     #fff;\n@nav-tabs-active-link-hover-border-color:   #fff;\n@nav-tabs-active-link-hover-bg:             transparent;\n\n/* Form */\n@input-border:              #e0e0e0;\n@input-color:               #000000;\n@input-border-radius:       0;\n@input-border-radius-large: 0px;\n@input-height-large:        40px;\n@input-height-base:         35px;\n@input-height-small:        30px;\n@input-border-focus:        #b4b4b4;\n\n/* Table */\n@table-bg:                      #fff;\n@table-border-color:            #f0f0f0;\n@table-cell-padding:            10px;\n@table-condensed-cell-padding:  7px;\n@table-bg-accent:               #f4f4f4;\n@table-bg-active:               #FFFCBE;\n\n/*\n * Input Group\n */\n@input-group-addon-bg: transparent;\n@input-group-addon-border-color: transparent;\n\n/*\n * Pagination\n */\n@pagination-bg:                 #E2E2E2;\n@pagination-border:             #fff;\n@pagination-color:              #7E7E7E;\n@pagination-active-bg:          @m-cyan;\n@pagination-active-border:      @pagination-border;\n@pagination-disabled-bg:        #E2E2E2;\n@pagination-disabled-border:    @pagination-border;\n@pagination-hover-color:        #333;\n@pagination-hover-bg:           #d7d7d7;\n@pagination-hover-border:       @pagination-border;\n@pager-border-radius:           5px;\n\n/*\n * Popover\n */\n@popover-fallback-border-color: transparent;\n@popover-border-color:          transparent;\n\n/*\n * Dropdown\n */\n@dropdown-fallback-border:      transparent;\n@dropdown-border:               transparent;\n@dropdown-divider-bg:           '';\n@dropdown-link-hover-bg:        rgba(0,0,0,0.075);\n@dropdown-link-color:           #333;\n@dropdown-link-hover-color:     #333;\n@dropdown-link-disabled-color:  #e4e4e4;\n@dropdown-divider-bg:           rgba(0,0,0,0.08);\n@dropdown-link-active-color:    #333;\n@dropdown-link-active-bg:       rgba(0, 0, 0, 0.075);\n@zindex-dropdown:               9;\n@dropdown-shadow:               0 2px 10px rgba(0, 0, 0, 0.2);\n\n/*\n * Thumbnail\n */\n@thumbnail-bg:                  #fff;\n\n/*\n * Alerts\n */\n@alert-success-border:                  transparent;\n@alert-info-border:                     transparent;\n@alert-warning-border:\t\t \t        transparent;\n@alert-danger-border:\t\t \t        transparent;\n@alert-inverse-border:\t\t \t        transparent;\n\n@alert-success-bg:                      fade(@m-green, 70%);\n@alert-info-bg:\t\t \t\t            fade(@m-blue, 70%);\n@alert-warning-bg:                      fade(@m-amber, 70%);\n@alert-danger-bg:                       fade(@m-red, 70%);\n@alert-inverse-bg:                      #333;\n\n@alert-success-text:                    #fff;\n@alert-info-text:                       #fff;\n@alert-warning-text:                    #fff;\n@alert-danger-text:                     #fff;\n@alert-inverse-text:                    #fff;\n\n/*\n * Form Validations\n */\n@state-success-text:                    lighten(@m-green, 8%);\n@state-warning-text:                    lighten(@m-orange, 8%);\n@state-danger-text:                     lighten(@m-red, 8%);\n\n@state-success-bg:                      lighten(@m-green, 8%);\n@state-warning-bg:                      lighten(@m-orange, 8%);\n@state-danger-bg:                       lighten(@m-red, 8%);\n\n\n\n/*\n * Buttons\n */\n@border-radius-base:            2px;\n@border-radius-large:           2px;\n@border-radius-small:           2px;\n@btn-font-weight:\t\t\t\t400;\n\n/*\n * Thumbnail\n */\n@thumbnail-border:\t\t\t\t#EDEDED;\n@thumbnail-padding:\t\t\t\t3px;\n\n/*\n * Carousel\n */\n@carousel-caption-color:        #fff;\n\n/*\n * Modal\n */\n@modal-content-fallback-border-color:\ttransparent;\n@modal-content-border-color:\t\t\ttransparent;\n@modal-backdrop-bg:\t\t\t\t\t\t#000;\n@modal-header-border-color:\t\t\t\ttransparent;\n@modal-title-line-height:\t\t\t\ttransparent;\n@modal-footer-border-color:\t\t\t\ttransparent;\n@zindex-modal-background: \t\t\t\t11;\n\n/*\n * Tooltips\n */\n@tooltip-bg:                #737373;\n@tooltip-opacity:           1;\n\n/*\n * Popover\n */\n@zindex-popover:                9;\n@popover-title-bg:              #fff;\n@popover-border-color:          #fff;\n@popover-fallback-border-color: #fff;\n\n/*\n * Breadcrumbs\n */\n@breadcrumb-bg:            transparent;\n@breadcrumb-padding-horizontal: 20px;\n@breadcrumb-active-color:       #7c7c7c;\n\n/*\n * Jumbotron\n */\n@jumbotron-bg:              #F7F7F7;\n\n/*\n * List Groups\n */\n@list-group-border:                 #E9E9E9;\n@list-group-active-color:           #000;\n@list-group-active-bg:              #f5f5f5;\n@list-group-active-border:          #e9e9e9;\n@list-group-disabled-color:         #B5B4B4;\n@list-group-disabled-bg:            #fff;\n@list-group-disabled-text-color:    #B5B4B4;\n\n/*\n * Badges\n */\n@badge-color:               #fff;\n@badge-bg:                  @brand-primary;\n@badge-border-radius:       2px;\n@badge-font-weight:         400;\n@badge-active-color:        #fff;\n@badge-active-bg:           @brand-primary;\n\n/*\n * Material Colors\n */\n@m-white:                  #ffffff;\n@m-black:                  #000000;\n@m-blue:                   #2196F3;\n@m-red:                    #F44336;\n@m-purple:                 #9C27B0;\n@m-deeppurple:             #673AB7;\n@m-lightblue:              #03A9F4;\n@m-cyan:                   #00BCD4;\n@m-teal:                   #009688;\n@m-green:                  #4CAF50;\n@m-lightgreen:             #8BC34A;\n@m-lime:                   #CDDC39;\n@m-yellow:                 #FFEB3B;\n@m-amber:                  #FFC107;\n@m-orange:                 #FF9800;\n@m-deeporange:             #FF5722;\n@m-gray:                   #9E9E9E;\n@m-bluegray:               #607D8B;\n@m-indigo:                 #3F51B5;\n@m-pink:                   #E91E63;\n@m-brown:                  #795548;\n\n\n/* Bootstrap Branding */\n@brand-primary:             @m-blue;\n@brand-success:             @m-green;\n@brand-info:                @m-cyan;\n@brand-warning:             @m-orange;\n@brand-danger:              @m-red;\n@app-gray:                  #F7F7F7;\n\n\n/*\n * Colors\n */\n@ace:                      #F7F7F7; \n\n/*\n * Blocks\n */\n@sidebar-left-width: 268px;\n@sidebar-right-width: 280px;\n@footer-height: 110px;\n@header-height: 70px;\n\n/*\n * Misc\n */\n@card-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/bootgrid.less",
    "content": ".bootgrid-footer .infoBar, .bootgrid-header .actionBar {\n    text-align: left; \n}\n\n.bootgrid-footer .search, .bootgrid-header .search {\n    vertical-align: top;\n}\n\n.bootgrid-header {\n    padding: 0 25px 10px;\n    \n    .search { \n        border: 1px solid #e0e0e0;\n        \n        .form-control, .input-group-addon {\n            border: 0;\n        }\n        \n        .glyphicon-search {\n            vertical-align: top;\n            padding: 9px 10px 0;\n\n            &:before {\n                content: \"\\f1c3\";\n                font-family: @font-icon-md;\n                font-size: 17px;\n                vertical-align: top;\n                line-height: 100%;\n            }\n        }\n        \n        @media (min-width: @screen-xs-min) {\n            width: 300px;   \n        }\n        \n        @media (max-width: @screen-xs-min) {\n            width: 100%;\n            padding-right: 90px;\n        }\n    }\n    \n    .actions {\n        box-shadow: none;\n\n        .btn-group {\n            border: 1px solid #e0e0e0;\n                \n            .btn {\n                height: 35px;\n                box-shadow: none !important;\n                background: transparent; \n            }\n            \n            .dropdown-menu {\n                padding: 10px 20px;\n                \n                .dropdown-item { \n                    padding: 0 0 0 27px !important;\n                    \n                    &:hover {\n                        background-color: #fff !important;\n                    }\n                }\n                \n                @media (min-width: @screen-sm-min) {\n                    left: 0;\n                    .transform-origin(top left);\n                    margin-top: 1px;\n                }\n            } \n            \n            .caret {\n                display: none;\n            }\n            \n            .zmdi {\n                line-height: 100%;\n                font-size: 18px;\n                vertical-align: top;\n                .transition(all);\n                .transition-duration(250ms);\n            }\n            \n            &.open {\n                .zmdi {\n                    .rotate(90deg);\n                }\n            }\n        }\n        \n        @media (max-width: @screen-xs-min) {\n            position: absolute;\n            top: 0;\n            right: 15px;\n        }\n    }\n}\n\n.bootgrid-table th > .column-header-anchor > .icon {\n    top: 0px;\n    font-size: 20px;\n    line-height: 100%;\n}\n\n.bootgrid-footer {    \n    .col-sm-6 {\n        padding: 10px 30px 20px;\n        \n        @media (max-width: @screen-sm-min) {\n            text-align: center;\n        }\n    }\n    \n    .infoBar {\n        @media (max-width: @screen-sm-min) {\n            display: none;\n        }\n        \n            .infos {\n                border: 1px solid #EEE;\n                display: inline-block;\n                float: right;\n                padding: 7px 30px;\n                font-size: 12px;\n                margin-top: 5px;\n            }\n    }\n}\n\n.select-cell {\n    .checkbox {\n        margin: 0;\n    }\n}\n\n.command-edit, .command-delete {\n    background: #fff;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/bootstrap-datetimepicker.less",
    "content": ".bootstrap-datetimepicker-widget {\n    padding: 0 !important;\n    margin: 0 !important;\n    width: auto !important;\n    \n    &:after, &:before { display: none !important; }\n    \n    table td {\n        text-shadow: none;\n        \n        span {\n            margin: 0;\n            \n            &:hover { background: transparent; }\n        }\n    }\n    \n    .glyphicon { font-family: @font-icon-md; font-size: 18px; }\n    .glyphicon-chevron-left:before { content: \"\\f2ff\"; }\n    .glyphicon-chevron-right:before { content: \"\\f301\"; }\n    .glyphicon-time:before { content: \"\\f337\"; }\n    .glyphicon-calendar:before { content: \"\\f32e\"; }\n    .glyphicon-chevron-up:before { content: \"\\f1e5\"; }\n    .glyphicon-chevron-down:before { content: \"\\f1e4\"; }\n    \n    [data-action=\"togglePicker\"] span {\n        font-size: 25px;\n        color: #ccc;\n        \n        &:hover {\n            color: #333;\n        }\n    }\n    \n    a[data-action] {\n        color: @m-teal;\n    }\n}\n\n.timepicker-picker {\n    .btn { box-shadow: none !important; }\n    \n    table {\n        tbody tr + tr:not(:last-child) {\n            background: @m-teal;\n            color: #fff;\n            \n            td {\n                border-radius: 0;\n            }\n        }\n    }\n    \n    .btn,\n    .btn:hover {\n        background: #fff; \n        color: #333;\n    }\n}\n\n.datepicker {    \n    &.top {\n        .transform-origin(0 100%) !important;\n    }\n     \n    table {\n        thead {\n            tr {\n                th {\n                    border-radius: 0;\n                    color: #fff;\n                    \n                    .glyphicon {\n                        width: 30px;\n                        height: 30px;\n                        border-radius: 50%;\n                        line-height: 29px;\n                    }\n                    \n                    &:hover .glyphicon {\n                        background: rgba(0, 0, 0, 0.2);\n                    }\n                }\n                \n                &:first-child {\n                    th {\n                        background: @m-teal;\n                        padding: 20px 0;\n                        \n                        &:hover {\n                            background: @m-teal;\n                        }\n                        \n                        &.picker-switch { \n                            font-size: 16px;\n                            font-weight: 400;\n                            text-transform: uppercase;\n                        }\n                    }\n                }\n                \n                &:last-child {\n                    th {\n                        &:first-child { padding-left: 20px; }\n                        &:last-child { padding-right: 20px; }\n                        \n                        text-transform: uppercase;\n                        font-weight: normal;\n                        font-size: 11px;\n                    }\n                    \n                    &:not(:only-child) {\n                        background: darken(@m-teal, 3%);  \n                    }\n                }\n            } \n        }\n        \n        tbody {\n            tr {\n                &:last-child {\n                    td {\n                        padding-bottom: 25px;\n                    }\n                }\n                    \n                td {\n                    &:first-child {\n                        padding-left: 13px;\n                    }\n                    \n                    &:last-child {\n                        padding-right: 13px;\n                    } \n                }\n            }\n        }\n        \n        td {\n    \n            &.day {\n                width: 35px;\n                height: 35px;\n                line-height: 20px;\n                color: #333;\n                position: relative;\n                padding: 0;\n                background: transparent;\n                \n                &:hover {\n                    background: none;\n                }\n                \n                &:before {\n                    content: \"\";\n                    width: 35px;\n                    height: 35px;\n                    border-radius: 50%;\n                    margin-bottom: -33px;\n                    display: inline-block;\n                    background: transparent;\n                    position: static;\n                    text-shadow: none;\n                }\n                \n                &.old, &.new {\n                    color: #CDCDCD;\n                }\n            }\n            \n            &:not(.today):not(.active) {\n                &:hover:before {\n                    background: #F0F0F0;\n                }\n            }\n            \n            &.today {\n                color: #333;\n                \n                &:before {\n                    background-color: #E2E2E2;\n                }\n            }\n            \n            &.active {\n                color: #fff;\n                \n                &:before {\n                    background-color: @m-teal;\n                }\n            }\n        }\n    }\n}\n\n.datepicker-months .month,\n.datepicker-years .year,\n.timepicker-minutes .minute,\n.timepicker-hours .hour {\n    border-radius: 50%;\n    \n    &:not(.active) {\n        &:hover {\n            background: #F0F0F0;\n        }\n    }\n    \n    &.active {\n        background: @m-teal;\n    }\n}\n\n.timepicker-minutes .minute,\n.timepicker-hours .hour {\n    padding: 0;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/bootstrap-select.less",
    "content": ".bootstrap-select {\n    .dropdown-menu {\n        padding: 0;\n    }\n    \n    .dropdown-toggle:focus {\n        outline: none !important;\n    }\n    \n    & > .btn-default {\n        background: none !important;\n        border-bottom: 1px solid #e0e0e0 !important;\n        border-radius: 0;\n        padding-left: 0;\n        padding-right: 0;\n        \n        &:before {\n            position: absolute;\n            top: 0; \n            right: 0;\n            content: \"\";\n            height: ~\"calc(100% - 2px)\";\n            width: 30px;\n            background-color: #FFF;\n            background-position: right ~\"calc(100% - 7px)\";\n            background-repeat: no-repeat;\n            .img-retina('../img/select.png', '../img/select@2x.png', 12px, 12px);\n            pointer-events: none;\n            z-index: 5;\n        }\n            \n        &:after {\n            position: absolute;\n            z-index: 3; \n            bottom: -1px;\n            left: 0;\n            height: 2px;\n            width: 0;\n            content: \"\"; \n            .transition(all);\n            .transition-duration(300ms);\n        }\n        \n        &:not(.disabled):after,\n        &:not(.readonly):after { \n            background: @m-blue;\n        }\n        \n        &.disabled:after,\n        &.readonly:after {\n            background: #ccc;\n        }\n    }\n    \n    &.open {\n        & > .btn-default:after {\n            width: 100%;\n        }\n    }\n    \n    .bs-searchbox {\n        padding: 5px 5px 5px 40px;\n        position: relative;\n        background: @ace;\n        \n        &:before {\n            position: absolute;\n            left: 0;\n            top: 0;\n            width: 40px;\n            height: 100%;\n            content: \"\\f1c3\";\n            font-family: @font-icon-md;\n            font-size: 25px;\n            padding: 4px 0 0 15px;\n        }\n        \n        input {\n            border: 0;\n            background: transparent;\n        }\n    }\n    \n    &.btn-group {\n        .dropdown-menu li a.opt {\n            padding-left: 17px;\n        }\n    }\n    \n    .check-mark {\n        margin-top: -5px !important;\n        font-size: 19px;\n        .transition(all);\n        .transition-duration(200ms);\n        .scale(0);\n        display: block !important;\n        position: absolute;\n        top: 11px;\n        right: 15px; \n        \n        &:before {\n            content: \"\\f26b\";\n            font-family: @font-icon-md;\n        }\n    }\n    \n    .selected {\n        .check-mark {\n            .scale(1);\n        }\n    }\n    \n    .notify {\n        bottom: 0 !important;\n        margin: 0 !important;\n        width: 100% !important;\n        border: 0 !important;\n        background: @m-red !important;\n        color: #fff !important;\n        text-align: center;\n    }\n    \n    &:not([class*=col-]):not([class*=form-control]):not(.input-group-btn) {\n        width: 100%;\n    }\n}\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/chosen.less",
    "content": ".chosen-container {\n    .chosen-drop {\n        box-shadow: @dropdown-shadow;\n        margin-top: 1px;\n        border: 0;\n        left: 0;\n        .scale(0);\n        .opacity(0);\n        .transform-origin(top left);\n        .transition(transform opacity);\n        .transition-duration(250ms);\n    }\n    \n    &.chosen-with-drop {\n        .chosen-drop {\n            .scale(1);\n            .opacity(1);\n        }\n        \n        .chosen-single:after {\n            width: 100%;\n        }\n    }\n    \n    .chosen-results {\n        margin: 0;\n        padding: 0;\n        max-height: 300px;\n        \n        li {\n            padding: 10px 17px;\n            width: 100%;\n            \n            &.highlighted {\n                background: @dropdown-link-hover-bg;\n                color: @dropdown-link-hover-color;\n            }\n            \n            &.result-selected {\n                background: transparent;\n                color: @text-color;\n                position: relative;\n                \n                &:before {\n                    content: \"\\f26b\";\n                    font-family: @font-icon-md;\n                    position: absolute;\n                    right: 15px;\n                    top: 10px;\n                    font-size: 19px;\n                }\n            }\n            \n            &.group-result {\n                &:not(:first-child) {\n                    border-top: 1px solid #eee;\n                }\n                \n                color: #B2B2B2;\n                font-weight: normal;\n                padding: 16px 15px 6px;\n                margin-top: 9px;\n            }\n        }\n    }\n}\n\n.chosen-container-single {\n    .chosen-single { \n        border-radius: 0;\n        overflow: visible;\n        height: 34px;\n        padding: 6px 0 6px;\n        text-transform: uppercase;\n        border: 0;\n        border-bottom: 1px solid @input-border;\n        background: none;\n        box-shadow: none;\n        \n        &:after {\n            content: \"\";\n            width: 0;\n            background: @m-blue;\n            height: 2px;\n            position: absolute;\n            left: 0;\n            bottom: -1px;\n            .transition(width);\n            .transition-duration(300ms);\n        }\n        \n        div b {\n            .img-retina('../img/select.png', '../img/select@2x.png', 12px, 12px);\n            background-repeat: no-repeat;\n            background-position: right 12px;\n        }\n    }\n    \n    .chosen-search {\n        padding: 5px 5px 5px 40px;\n        background: @ace; \n        \n        &:before {\n            content: \"\\f1c3\";\n            font-family: @font-icon-md;\n            position: absolute;\n            left: 0;\n            top: 0;\n            width: 40px;\n            height: 100%;\n            font-size: 25px;\n            padding: 5px 0 0 15px; \n        }\n        \n        input[type=text] {\n            border: 0;\n            height: 35px;\n            line-height: 1.42857143;\n            background: none;\n        }\n    }\n}\n\n.chosen-container-active.chosen-with-drop .chosen-single {\n    border:0;\n    background: none;\n}\n\n.chosen-container-multi {\n    .chosen-choices {\n        padding: 0;\n        border: 0;\n        border-bottom: 1px solid @input-border;\n        background: none;\n        box-shadow: none;\n        \n        li {\n            &.search-choice {\n                border-radius: 2px;\n                margin: 4px 4px 0 0;\n                background: darken(@ace, 5%); \n                padding: 5px 23px 5px 8px;\n                border: 0;\n                box-shadow: none;\n\n                .search-choice-close {\n                    background-image: none;\n\n                    &:before {\n                        display: inline-block;\n                        font-family: @font-icon-md;\n                        content: \"\\f135\";\n                        position: relative;\n                        top: 1px;\n                        color: #9C9C9C;\n                        z-index: 2;\n                        font-size: 12px;\n                    }\n                }\n            }\n            \n            &.search-field {\n                input[type=text] {\n                    padding: 0;\n                    height: 31px;\n                }\n            }\n        }        \n    }\n}\nselect.chosen {\n    display: none;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/farbtastic.less",
    "content": ".cp-container {\n    position: relative;\n    \n    & > .input-group {\n        \n        input.cp-value {\n            color: #000 !important;\n            background: transparent !important;\n        }\n        \n        .dropdown-menu {\n            padding: 20px;\n            margin-left: 10px;\n        }\n    }\n    \n    i.cp-value {\n        width: 25px;\n        height: 25px;\n        border-radius: 2px;\n        position: absolute;\n        top: 0;\n        right: 15px;\n    }\n} "
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/fileinput.less",
    "content": ".fileinput {\n    position: relative;\n    padding-right: 35px;\n    \n    .close {\n          position: absolute;\n          top: 5px;\n          font-size: 12px;\n          float: none;\n          opacity: 1;\n          font-weight: 500;\n          border: 1px solid #ccc;\n          width: 19px;\n          text-align: center;\n          height: 19px;\n          line-height: 15px;\n          border-radius: 50%;\n          right: 0;\n        \n          &:hover {\n            background: #eee;\n          }\n    }\n     \n    .btn-file {\n        \n    }\n    \n    .input-group-addon {\n        padding: 0 10px;\n        vertical-align: middle; \n    }\n    \n    .fileinput-preview {\n        width: 200px;\n        height: 150px;\n        position: relative;\n        \n        img {\n            display: inline-block;\n            vertical-align: middle;\n            margin-top: -13px;\n        }\n        \n        &:after {\n            content: \"\";\n            display: inline-block;\n            vertical-align: middle;\n        }\n    }\n} "
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/fullcalendar.less",
    "content": "/** CALENDAR WIDGET **/\n#calendar-widget {\n    margin-bottom: 30px;\n    box-shadow: 0 1px 1px rgba(0,0,0,.15);\n}\n\n#fc-actions {\n    position: absolute;\n    bottom: 10px;\n    right: 12px;\n}\n\n.fc {\n    background-color: #fff;\n    box-shadow: 0 1px 1px rgba(0, 0, 0, .15);\n    margin-bottom: 30px;\n\n    td, th {\n        border-color: @table-border-color;\n    }\n\n    th {\n        font-weight: 400;\n    }\n\n    table {\n        background: transparent;\n\n        tr {\n            & > td:first-child {\n                border-left-width: 0;\n            }\n        }\n    }\n}\n\n#calendar-widget {\n    .fc-toolbar {\n        background: @m-teal;\n    }\n\n    .fc-day-header {\n        color: #fff;\n        background: darken(@m-teal, 5%);\n        padding: 5px 0;\n        border-width: 0;\n    }\n\n    .fc-day-number {\n        text-align: center;\n        color: #ADADAD;\n        padding: 5px 0;\n    }\n\n    .fc-day-grid-event {\n        margin: 1px 3px 1px;\n    }\n\n\n    .ui-widget-header th,\n    .ui-widget-header {\n        border-width: 0;\n    }\n}\n\n#calendar {\n    .fc-toolbar {\n        height: 300px;\n        .bg-cover('../img/cal-header.jpg');\n        background-position: inherit;\n\n        &:before {\n            content: \"\";\n            height: 50px;\n            width: 100%;\n            background: rgba(0, 0, 0, 0.36);\n            position: absolute;\n            bottom: 0;\n            left: 0;\n        }\n\n        .fc-center {\n            margin-top: 238px;\n            position: relative;\n        }\n\n        @media screen and (max-width: @screen-sm-max) {\n            height: 200px;\n\n            .fc-center {\n                margin-top: 138px;\n            }\n        }\n    }\n\n    .fc-day-header {\n        color: #ADADAD;\n        text-align: left;\n        font-size: 14px;\n        border-bottom-width: 0;\n        border-right-color: #eee;\n        padding: 10px 12px;\n    }\n\n    .fc-day-number {\n        @media screen and (min-width: @screen-sm-max) {\n            font-size: 25px;\n            letter-spacing: -2px;\n        }\n\n        padding-left: 10px !important;\n        color: #CCC;\n        text-align: left !important;\n\n    }\n\n\n    .fc-day-grid-event {\n        margin: 1px 9px 0;\n    }\n}\n\n.fc-today {\n    color: @m-amber;\n}\n\n.fc-toolbar {\n    margin-bottom: 0;\n    padding: 20px 7px 19px;\n    position: relative;\n\n    h2 {\n        margin-top: 7px;\n        font-size: 20px;\n        font-weight: 400;\n        text-transform: uppercase;\n        color: #fff;\n    }\n\n    .ui-button  {\n        border: 0;\n        background: 0 0;\n        padding: 0;\n        outline: none !important;\n        text-align: center;\n        width: 30px;\n        height: 30px;\n        border-radius: 50%;\n        margin-top: 2px;\n        color: #fff;\n\n        &:hover {\n            background: #fff;\n            color: @m-teal;\n        }\n\n        & > span {\n            position: relative;\n            font-family: @font-icon-md;\n            font-size: 20px;\n            line-height: 100%;\n            width: 30px;\n            display: block;\n            margin-top: 2px;\n\n\n            &:before {\n                position: relative;\n                z-index: 1;\n            }\n\n            &.ui-icon-circle-triangle-w:before {\n                content: \"\\f2fa\";\n            }\n\n            &.ui-icon-circle-triangle-e:before {\n                content: \"\\f2fb\";\n            }\n\n        }\n    }\n}\n.fc-event {\n    padding: 0;\n    font-size: 11px;\n    border-radius: 0;\n    border: 0;\n\n    .fc-title {\n        padding: 2px 8px;\n        display: block;\n    }\n\n    .fc-time {\n        float: left;\n        background: rgba(0, 0, 0, 0.2);\n        padding: 2px 6px;\n        margin: 0 0 0 -1px;\n    }\n}\n\n.fc-view, .fc-view > table {\n    border: 0;\n    overflow: hidden;\n}\n\n.fc-view > table > tbody > tr > .ui-widget-content {\n    border-top: 0;\n}\n\ndiv.fc-row {\n    margin-right: 0 !important;\n    border: 0 !important;\n}\n\n\n.fc-today {\n    color: @m-amber !important;\n}\n\n/* Even Tag Color */\n.event-tag {\n    margin-top: 5px;\n\n    & > span {\n        border-radius: 50%;\n        width: 30px;\n        height: 30px;\n        margin-right: 3px;\n        position: relative;\n        display: inline-block;\n        cursor: pointer;\n\n        &:hover {\n            .opacity(0.8);\n        }\n\n        &.selected {\n            &:before {\n                font-family: @font-icon-md;\n                content: \"\\f26b\";\n                position: absolute;\n                text-align: center;\n                top: 3px;\n                width: 100%;\n                font-size: 17px;\n                color: #FFF;\n            }\n        }\n    }\n}\n\nhr.fc-divider {\n    border-width: 1px;\n    border-color: #eee;\n}\n\n.fc-day-grid-container.fc-scroller {\n    height: auto !important;\n    overflow: hidden !important;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/light-gallery.less",
    "content": "#lg-slider {\n    &:after {\n        content: \"\";\n        -webkit-animation-fill-mode: both;\n        animation-fill-mode: both;\n        height: 50px;\n        width: 50px;\n        border-radius: 100%;\n        border: 2px solid @m-blue;\n        -webkit-animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);\n        animation: ball-scale-ripple 1s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);\n        position: absolute;\n        left: 50%;\n        margin-left: -25px;\n        top: 50%;\n        margin-top: -25px;\n        z-index: -1;\n    }\n}\n\n#lg-outer {\n    background: rgba(255,255,255,0.95);\n    \n    .object {\n        .z-depth(1);\n        border-radius: 2px;\n    }\n}\n\n#lg-close {\n    display: none;\n}\n\n#lg-action {\n    top: 0;\n    width: 100%;\n    left: 0;\n    margin-left: 0 !important;\n    height: 40px;\n    text-align: center;\n    \n    & > a {\n        background: transparent;\n        color: #9D9D9D;\n        font-size: 18px;\n        width: 28px;\n        height: 37px;\n        \n        &:hover {\n            background: transparent;\n            color: #000;\n        }\n    }\n    \n    \n    .cl-thumb {\n        position: fixed;\n        right: 20px;\n        bottom: 20px;\n        width: 50px;\n        height: 50px;\n        border-radius: 50%;\n        line-height: 38px;\n        background: @m-red;\n        .transition(all);\n        .transition-duration(300ms);\n        .z-depth(1);\n        \n        &:after {\n            text-align: center;\n            left: 16px !important;\n            bottom: 6px !important;\n            color: #fff;\n        }\n        \n        &:hover {\n            background: darken(@m-red, 5%);\n        }\n        \n    } \n}\n\n#lg-gallery .thumb-cont {\n    background: @m-red;\n    text-align: center;\n    \n    .thumb-info {\n        background: @m-red;\n        \n        .count {\n            display: none;\n        }\n        \n        .close {\n            width: 14px;\n            margin-top: 0;\n            background: none;\n            \n            &:hover {\n                background: none;\n            }\n        }\n    }\n    \n    .thumb {\n        .opacity(1);\n    }\n    \n    .thumb-inner {\n        display: inline-block;\n        padding: 12px 12px 15px;\n    }\n}\n\n.lg-slide {\n    background: none !important;\n    \n    em {\n        font-style: normal;\n        \n        h3 {\n            margin-bottom: 5px;\n        }\n    }\n    \n    .video-cont {\n        .z-depth(2);\n    }\n}\n@-webkit-keyframes ball-scale-ripple {\n  0% {\n    -webkit-transform: scale(0.1);\n            transform: scale(0.1);\n    opacity: 1; }\n\n  70% {\n    -webkit-transform: scale(1);\n            transform: scale(1);\n    opacity: 0.7; }\n\n  100% {\n    opacity: 0.0; } \n}\n\n@keyframes ball-scale-ripple {\n  0% {\n    -webkit-transform: scale(0.1);\n            transform: scale(0.1);\n    opacity: 1; }\n\n  70% {\n    -webkit-transform: scale(1);\n            transform: scale(1);\n    opacity: 0.7; }\n\n  100% {\n    opacity: 0.0; } \n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/malihu-custom-scrollbar.less",
    "content": ".mCSB_scrollTools {\n    width: 5px;\n    \n    .mCSB_dragger_bar {\n        border-radius: 0 !important;\n    }\n    \n    &.mCSB_scrollTools_horizontal,\n    &.mCSB_scrollTools_vertical {\n        margin: 0 !important;  \n    }\n    \n    &.mCSB_scrollTools_horizontal {\n        height: 10px;\n    }\n}\n\n.mCS-minimal-dark {\n    &.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar {\n        background: rgba(0,0,0,0.4); \n    }\n    \n    &.mCSB_scrollTools_onDrag .mCSB_dragger .mCSB_dragger_bar {\n        background: rgba(0,0,0,0.5) !important; \n    }\n}\n\n.mCSB_inside > .mCSB_container {\n    margin-right: 0;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/mediaelement.less",
    "content": ".mejs-container {\n  outline: none;\n\n  .mejs-controls {\n    background: #ec592f;\n    height: 50px;\n    padding: 10px 5px 0;\n\n    div {\n      height: 5px;\n    }\n\n    div.mejs-time-rail {\n      position: absolute;\n      left: 0;\n      top: 0;\n      padding: 0;\n      width: 100% !important;\n\n      .mejs-time-total {\n        margin: 0;\n        width: 100% !important;\n        background: #ec592f;\n      }\n\n      .mejs-time-loaded {\n        background: #D04B25;\n      }\n\n      .mejs-time-current {\n        background: #ffea00;\n      }\n\n      .mejs-time-buffering {\n        background: #ec592f;\n      }\n\n      span:not(.mejs-time-float), a {\n        border-radius: 0;\n        height: 3px;\n      }\n    }\n\n\n\n    .mejs-button {\n      button {\n        background-color: #ec592f;\n        width: 15px;\n        height: 15px;\n        background-position: center;\n\n        &:focus {\n          outline: none !important;\n        }\n      }\n    }\n    .mejs-volume-button {\n      position: absolute;\n      right: 35px;\n    }\n\n    .mejs-play button {\n      .img-retina('../img/icons/play.png', '../img/icons/play@2x.png', 15px, 15px);\n    }\n\n    .mejs-pause button {\n      .img-retina('../img/icons/pause.png', '../img/icons/pause@2x.png', 15px, 15px);\n    }\n\n    .mejs-mute button {\n      .img-retina('../img/icons/speaker.png', '../img/icons/speaker@2x.png', 15px, 15px);\n    }\n\n    .mejs-unmute button {\n      .img-retina('../img/icons/speaker-2.png', '../img/icons/speaker-2@2x.png', 15px, 15px);\n    }\n \n    .mejs-fullscreen-button {\n      position: absolute;\n      right: 5px;\n      button {\n        .img-retina('../img/icons/fullscreen.png', '../img/icons/fullscreen@2x.png', 15px, 15px);\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/noUiSlider.less",
    "content": ".noUi-target {\n    border-radius: 0;\n    box-shadow: none;\n    border: 0;\n}\n\n.noUi-background {\n    background: #d4d4d4;\n    box-shadow: none;\n}\n\n.noUi-horizontal {\n    height: 3px;\n    \n    .noUi-handle {\n        top: -8px;\n    }\n}\n\n.noUi-vertical {\n    width: 3px;\n}\n\n.noUi-horizontal,\n.noUi-vertical {\n    .noUi-handle {\n        width: 19px;\n        height: 19px;\n        border: 0;\n        border-radius: 100%;\n        box-shadow: none;\n        .transition(box-shadow);\n        .transition-duration(200ms);\n        cursor: pointer;\n        position: relative;\n        \n        &:before,\n        &:after {\n            display: none;\n        }\n        \n        &:active {\n            background: #ccc !important;\n        }\n        \n        .is-tooltip {\n            position: absolute;\n            bottom: 32px;\n            height: 35px;\n            border-radius: 2px;\n            color: #fff;\n            text-align: center;\n            line-height: 33px;\n            width: 50px;\n            left: 50%;\n            margin-left: -25px;\n            padding: 0 10px;\n            .transition(all);\n            .transition-duration(200ms);\n            .backface-visibility(hidden);\n            .opacity(0);\n            .scale(0);\n            \n            &:after {\n                width: 0;\n                height: 0;\n                border-style: solid;\n                border-width: 15px 10px 0 10px;\n                position: absolute;\n                bottom: -8px;\n                left: 50%;\n                margin-left: -9px;\n                content: \"\";\n\n            }\n        }\n    }\n    \n    .noUi-active {\n        box-shadow: 0 0 0 13px rgba(0,0,0,0.1);\n        \n        .is-tooltip {\n            .scale(1);\n            bottom: 40px;\n            .opacity(1);\n        }\n    }\n}  \n\n.input-slider,\n.input-slider-range,\n.input-slider-values {\n    &:not([data-is-color]) {\n        .noUi-handle,\n        .noUi-connect, {\n            background: @m-teal !important;\n        }\n        \n        .is-tooltip {\n            background: @m-teal;\n            \n            &:after {\n                border-color: @m-teal transparent transparent transparent;\n            }\n        }\n    }\n    \n    &[data-is-color=red] {\n        .is-color-handle(@m-red);\n    }\n    \n    &[data-is-color=blue] {\n        .is-color-handle(@m-blue);\n    }\n    \n    &[data-is-color=cyan] {\n        .is-color-handle(@m-cyan);\n    }\n    \n    &[data-is-color=amber] {\n        .is-color-handle(@m-amber);\n    }\n    \n    &[data-is-color=green] {\n        .is-color-handle(@m-green);\n    }\n}\n\n.input-slider {\n    .noUi-origin {\n        background: #d4d4d4;\n    }\n    \n    &:not([data-is-color]) {\n        .noUi-base {\n            background: @m-teal !important;\n        }\n    }\n    \n    &[data-is-color=red] {\n        .is-color-base(@m-red);\n    }\n    \n    &[data-is-color=blue] {\n        .is-color-base(@m-blue);\n    }\n    \n    &[data-is-color=cyan] {\n        .is-color-base(@m-cyan);\n    }\n    \n    &[data-is-color=amber] {\n        .is-color-base(@m-amber);\n    }\n    \n    &[data-is-color=green] {\n        .is-color-base(@m-green);\n    }\n}\n\n.is-color-handle(@color) {\n    .noUi-handle,\n    .noUi-connect {\n        background: @color !important;\n    }\n}\n\n.is-color-base(@color) {\n    .noUi-base {\n        background: @color !important;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/summernote.less",
    "content": ".note-editor,\n.note-popover {\n    .note-toolbar,\n    .popover-content {\n        background: #fff;\n        border-color: #e4e4e4;\n        margin: 0;\n        padding: 10px 0 15px;\n        text-align: center;\n        \n        & > .btn-group {\n            display: inline-block;\n            float: none;\n            box-shadow: none;\n            \n            .btn {\n                margin: 0 1px;\n            }\n            \n            & > .active {\n                background: @m-cyan;\n                color: #fff;\n            }\n        }\n        \n            \n        .btn {\n            height: 40px;\n            border-radius: 2px !important;\n            box-shadow: none !important;\n            \n            &:active {\n                box-shadow: none;\n            }\n        }\n\n        .note-palette-title {\n            margin: 0 !important;\n            padding: 10px 0 !important;\n            font-size: 13px !important;\n            text-align: center !important;  \n            border: 0 !important;\n        }\n        \n        .note-color-reset {\n            padding: 0 0 10px !important;\n            margin: 0 !important;\n            background: none;\n            text-align: center;\n        }\n         \n        .note-color {\n            .dropdown-menu {\n                min-width: 335px;\n            }\n        }\n    }\n    \n    .note-statusbar {\n        .note-resizebar {\n            border-color: #E8E8E8;\n            \n            .note-icon-bar {\n                border-color: #BCBCBC;\n            }\n        }\n    }\n    \n    .fa {\n        font-style: normal;\n        font-size: 20px;\n        vertical-align: middle;\n        \n        &:before {\n            font-family: @font-icon-md;\n        }\n        \n        &.fa-magic:before {\n            content: \"\\f16a\";\n        }\n        \n        &.fa-bold:before {\n            content: \"\\f23d\";\n        }\n        \n        &.fa-italic:before {\n            content: \"\\f245\";\n        }\n        \n        &.fa-underline:before {\n            content: \"\\f24f\";\n        }\n        \n        &.fa-font:before {\n            content: \"\\f242\";\n        }\n        \n        &.fa-list-ul:before {\n            content: \"\\f247\";\n        }\n        \n        &.fa-list-ol:before {\n            content: \"\\f248\";\n        }\n\n        &.fa-align-left:before {\n            content: \"\\f23b\";\n        }\n        \n        &.fa-align-right:before {\n            content: \"\\f23c\";\n        }\n\n        &.fa-align-center:before {\n            content: \"\\f239\";\n        }\n\n        &.fa-align-justify:before {\n            content: \"\\f23a\";\n        }\n        \n        &.fa-indent:before {\n            content: \"\\f244\";\n        }\n        \n        &.fa-outdent:before {\n            content: \"\\f243\";\n        }\n        \n        &.fa-text-height:before {\n            content: \"\\f246\";\n        }\n        \n        &.fa-table:before {\n            content: \"\\f320\";\n        }\n        \n        &.fa-link:before {\n            content: \"\\f18e\";\n        }\n        \n        &.fa-picture-o:before {\n            content: \"\\f17f\";\n        }\n        \n        &.fa-minus:before {\n            content: \"\\f22f\";\n        }\n        \n        &.fa-arrows-alt:before {\n            content: \"\\f16d\";\n        }\n        \n        &.fa-code:before {\n            content: \"\\f13a\";\n        }\n        \n        &.fa-question:before {\n            content: \"\\f1f5\";\n        }\n        \n        &.fa-eraser:before {\n            content: \"\\f23f\";\n        }\n        \n        &.fa-square:before {\n            content: \"\\f279\";\n        }\n        \n        &.fa-circle-o:before {\n            content: \"\\f26c\";\n        }\n        \n        &.fa-times:before {\n            content: \"\\f136\";\n        }\n    }\n    \n    .note-air-popover {\n        .arrow {\n            left: 20px;\n        }\n    }\n}\n\n.note-editor {\n    overflow: visible;\n    border: 1px solid #e4e4e4;\n\n    .note-editable {\n        padding: 20px 23px;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/sweetalert.less",
    "content": ".sweet-alert {\n    border-radius: 2px;\n    padding: 10px 30px;\n    \n    h2 {\n        font-size: 16px;\n        font-weight: 400;\n        position: relative;\n        z-index: 1;\n    }\n    \n    .lead {\n        font-size: 13px;\n    }\n    \n    .btn {\n        padding: 6px 12px; \n        font-size: 13px;\n        margin: 20px 2px 0;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/typeahead.less",
    "content": ".twitter-typeahead {\n    width: 100%;\n    \n    .tt-menu {\n        min-width: 200px;\n        background: #fff;\n        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);\n        display: block !important;\n        z-index: 2 !important;\n        .scale(0);\n        .opacity(0);\n        .transition(all);\n        .transition-duration(300ms);\n        .backface-visibility(hidden);\n        .transform-origin(top left);\n        \n        &.tt-open:not(.tt-empty) {\n            .scale(1);\n            .opacity(1);   \n        }\n    }\n    \n    .tt-suggestion {\n        padding: 8px 17px;\n        color: #333;\n        cursor: pointer;\n    }\n\n    .tt-suggestion:hover,\n    .tt-cursor {\n        background-color: rgba(0,0,0,0.075);\n    }\n    \n    .tt-hint {\n        color: #818181 !important;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/vendor-overrides/waves.less",
    "content": ""
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/wall.less",
    "content": ".wall-attrs {\n    margin-bottom: 0;\n}\n\n.wa-stats {\n    float: left;\n    \n    & > span {\n        margin-right: -1px;\n        padding: 7px 12px;\n        border: 1px solid #E0E0E0;\n        float: left;\n        font-weight: 500;\n        \n        &.active {\n            color: @m-green;\n        }\n        \n        &:first-child {\n            border-radius: 2px 0 0 2px;\n        }\n        \n        &:last-child {\n            border-radius: 0 2px 2px 0;\n        }\n        \n        & > i { \n            line-height: 100%;\n            vertical-align: top;\n            position: relative;\n            top: 2px;\n            font-size: 15px;\n            margin-right: 2px;\n        }\n    }    \n}\n\n.wa-users {\n    float: right;\n    padding: 0 !important;\n    margin-right: -5px;\n    \n    & > a {\n        display: inline-block;\n        margin-left: 2px;\n        \n        & > img {\n            width: 33px;\n            height: 33px;\n            border-radius: 50%;\n            \n            &:hover {\n                .opacity(0.85);\n            }\n        }\n    }\n}\n\n.wcc-inner { \n    border: 1px solid #E4E4E4;\n    padding: 10px 15px;\n    resize: none;\n    border-radius: 2px;\n    background: #fff;\n    color: #9A9A9A;\n    cursor: pointer;\n} \n\n.wcci-text {\n    border: 0;\n    display: block;\n    width: 100%;\n    resize: none;\n    padding: 0;\n}\n\n.wall-comment-list {\n    padding: 20px;\n    background: @app-gray;\n    \n    .media {\n        position: relative;\n        \n        &:hover {\n            .actions {\n                display: block;\n            }\n        }\n    }\n    \n    .actions {\n        display: none; \n        position: absolute;\n        right: -20px;\n        top: -1px;\n    }\n}\n\n.wcl-list + .wcl-form {\n    margin-top: 25px; \n}\n\n.wp-text {\n    border: 0;\n    padding: 0;\n    display: block;\n    width: 100%;\n    resize: none;\n}\n\n.wp-media {\n    background: @app-gray;\n    border: 1px solid #E4E4E4;\n    padding: 12px 15px;\n    margin-top: 25px;\n    text-align: center;\n}\n\n.wpb-actions {\n    background: @app-gray;\n    margin: 0;\n    padding: 10px 20px;\n    \n    & > li:not(.pull-right) {\n        float: left;\n    }\n}\n\n.wall-attr-types(@color) {\n    color: @color;\n    \n    &:hover {\n        color: darken(@color, 5%);\n    }\n}\n\n\n[data-wpba=\"image\"] { .wall-attr-types(@m-green); }\n[data-wpba=\"video\"] { .wall-attr-types(@m-orange); }\n[data-wpba=\"link\"] { .wall-attr-types(@m-cyan); }\n \n.wpba-attrs {\n    & > ul {\n        & > li {\n            padding: 0;\n            margin-right: 5px;\n\n            & > a {\n                display: block;\n                width: 22px;\n\n                & > i {\n                    font-size: 20px;\n                }\n            } \n            \n            &.active i {\n                color: #333;\n            }\n        }\n    } \n}\n\n.wall-img-preview {\n    text-align: center;\n    \n    @media screen and (min-width: @screen-sm-min) {\n        margin: 0 -23px 20px;\n    }\n\n    @media screen and (max-width: @screen-sm-max) {\n        margin: 0 -16px 20px;\n    }\n\n    .wip-item {\n        display: block;\n        float: left;\n        position: relative;\n        overflow: hidden;\n        border: 2px solid #fff;\n        .bg-cover-inline();\n        \n        & > img { \n            display: none;\n        }\n\n        &:first-child:nth-last-child(2),\n        &:first-child:nth-last-child(2) ~ div {\n            width: 50%;\n            padding-bottom: 40%;\n        }\n        \n        &:first-child:nth-last-child(3), \n        &:first-child:nth-last-child(3) ~ div,\n        &:first-child:nth-last-child(4),\n        &:first-child:nth-last-child(4) ~ div:not(:last-child),\n        &:first-child:nth-last-child(5),\n        &:first-child:nth-last-child(5) ~ div:not(:nth-last-of-type(-n+2)),\n        &:first-child:nth-last-child(6),\n        &:first-child:nth-last-child(6) ~ div,\n        &:first-child:nth-last-child(7) ~ div:nth-last-of-type(-n+3) {\n            width: 33.333333%;\n            padding-bottom: 30%;\n        }\n\n        &:first-child:nth-last-child(5) ~ div:nth-last-of-type(-n+2) {\n            width: 50%;\n            padding-bottom: 40%;\n        }\n        \n        &:first-child:nth-last-child(7),\n        &:first-child:nth-last-child(7) ~ div:not(:nth-last-of-type(-n+3)),\n        &:first-child:nth-last-child(n+8),\n        &:first-child:nth-last-child(n+8) ~ div {\n            width: 25%;\n            padding-bottom: 22%;\n        }\n\n        &:only-child,\n        &:first-child:nth-last-child(4) ~ div:nth-child(4) {\n            width: 100%;\n            padding-bottom: 50%;\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/widgets.less",
    "content": ".dash-widget-item {\n    position: relative;\n    min-height: 380px;\n    margin-bottom: 30px;\n    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15); \n    \n    .dash-widget-header {\n        position: relative;\n        \n        .actions {\n            display: none;\n            position: absolute; \n            right: 4px;\n            top: 6px;\n        }\n    }\n    \n    .dash-widget-footer {\n        position: absolute;\n        left: 0;\n        bottom: 0;\n        width: 100%;\n    }\n    \n    .dash-widget-title {\n        padding: 12px 20px;\n        position: absolute;\n        width: 100%;\n        left: 0;\n        font-weight: 300; \n    }\n    \n    &:hover {\n        .dash-widget-header .actions {\n            display: block;\n        }\n    }\n}\n\n/*\n * Site Visits\n */\n#site-visits {\n    color: rgba(255, 255, 255, 0.9);\n    \n    .dash-widget-header {\n        padding-bottom: 38px;\n        background-color: rgba(0,0,0,0.13);\n    }\n    \n    .dash-widget-title {\n        bottom: 0;\n        background: rgba(0,0,0,0.15);\n        color: rgba(255,255,255,0.9);\n    }\n    \n    h3 {\n        color: rgba(255, 255, 255, 0.9);\n    }\n}\n\n/*\n * Best Selling Item\n */\n#best-selling {\n    background-color: #fff;\n    \n    .dash-widget-header {\n        & > img {\n            width: 100%;\n            height: 155px;\n        }\n        \n        .dash-widget-title {\n            padding-bottom: 30px;\n            top: 0;\n            color: #fff;\n            #gradient > .vertical(rgba(0,0,0,0.6); rgba(0,0,0,0));\n        }\n        \n        .main-item {\n            padding: 15px;\n            color: #fff;\n            position: absolute;\n            bottom: 0;\n            left: 0;\n            width: 100%;\n            #gradient > .vertical(rgba(0,0,0,0); rgba(0,0,0,0.6));\n            \n            & > h2 {\n                font-weight: 400;\n                font-size: 20px;\n                margin: 5px 0 0 0;\n                line-height: 100%;\n                color: #fff;\n            }\n        }\n    }\n}\n\n/*\n * Weather\n */\n#weather-widget {\n    color: #fff;\n    padding: 20px 20px 0;\n    \n    .weather-status {\n        font-size: 40px;\n        line-height: 100%;\n    }\n    \n    .weather-icon {\n        text-align: center;\n        margin-top: 10px;\n        height: 150px;\n        .bg-option();\n        \n        /* Weather Icons */\n        .wi-item(@icon) {\n            .img-retina('../img/icons/weather/@{icon}.png', '../img/icons/weather/@{icon}@2x.png', 125px, 125px);\n        }\n        \n        &.wi-0 { .wi-item(0); }\n        &.wi-1 { .wi-item(1); }\n        &.wi-2 { .wi-item(2); }\n        &.wi-3 { .wi-item(3); }\n        &.wi-4 { .wi-item(2); }\n        &.wi-5 { .wi-item(5); }\n        &.wi-6 { .wi-item(5); }\n        &.wi-7 { .wi-item(5); }\n        &.wi-8 { .wi-item(5); }\n        &.wi-9 { .wi-item(9); }\n        &.wi-10 { .wi-item(5); }\n        &.wi-11 { .wi-item(9); }\n        &.wi-12 { .wi-item(9); }\n        &.wi-13 { .wi-item(9); }\n        &.wi-14 { .wi-item(9); }\n        &.wi-15 { .wi-item(5); }\n        &.wi-16 { .wi-item(9); }\n        &.wi-17 { .wi-item(5); }\n        &.wi-18 { .wi-item(18); }\n        &.wi-19 { .wi-item(19); }\n        &.wi-20 { .wi-item(19); }\n        &.wi-21 { .wi-item(19); }\n        &.wi-22 { .wi-item(19); }\n        &.wi-23 { .wi-item(19); }\n        &.wi-24 { .wi-item(24); }\n        &.wi-25 { .wi-item(24); }\n        &.wi-26 { .wi-item(26); }\n        &.wi-27 { .wi-item(27); }\n        &.wi-28 { .wi-item(28); }\n        &.wi-29 { .wi-item(27); }\n        &.wi-30 { .wi-item(28); }\n        &.wi-31 { .wi-item(31); }\n        &.wi-32 { .wi-item(32); }\n        &.wi-33 { .wi-item(31); }\n        &.wi-34 { .wi-item(32); }\n        &.wi-35 { .wi-item(5); }\n        &.wi-36 { .wi-item(32); }\n        &.wi-37 { .wi-item(2); }\n        &.wi-38 { .wi-item(2); }\n        &.wi-39 { .wi-item(2); }\n        &.wi-40 { .wi-item(5); }\n        &.wi-41 { .wi-item(5); }\n        &.wi-42 { .wi-item(9); }\n        &.wi-43 { .wi-item(5); }\n        &.wi-44 { .wi-item(27); }\n        &.wi-45 { .wi-item(2); }\n        &.wi-46 { .wi-item(18); }\n        &.wi-47 { .wi-item(2); }\n    }\n    \n    .weather-info {\n        list-style: none;\n        padding: 0;\n        margin: 3px 0 0 0;\n        \n        & > li {\n            display: inline-block;\n            border: 1px solid rgba(255, 255, 255, 0.39);\n            padding: 2px 10px 3px;\n            margin-right: 5px;\n        }\n    }\n    \n    .weather-list {\n        background: rgba(0, 0, 0, 0.08);\n        padding: 5px 12px;\n        font-size: 16px;\n        height: 51px;\n        .text-overflow();\n            \n        & > span {\n            margin-right: 7px;\n            font-weight: 300;\n            display: inline-block;\n            line-height: 40px;\n            vertical-align: top;\n            \n            .wli-icon(@icon) {\n                background-image: url('../img/icons/weather/@{icon}.png');\n            }\n            \n            &.weather-list-icon {\n                width: 35px;\n                height: 35px;\n                .bg-option();\n                background-size: 30px 30px;\n                \n                &.wi-0 { .wli-icon(0); }\n                &.wi-1 { .wli-icon(1); }\n                &.wi-2 { .wli-icon(2); }\n                &.wi-3 { .wli-icon(3); }\n                &.wi-4 { .wli-icon(2); }\n                &.wi-5 { .wli-icon(5); }\n                &.wi-6 { .wli-icon(5); }\n                &.wi-7 { .wli-icon(5); }\n                &.wi-8 { .wli-icon(5); }\n                &.wi-9 { .wli-icon(9); }\n                &.wi-10 { .wli-icon(5); }\n                &.wi-11 { .wli-icon(9); }\n                &.wi-12 { .wli-icon(9); }\n                &.wi-13 { .wli-icon(9); }\n                &.wi-14 { .wli-icon(9); }\n                &.wi-15 { .wli-icon(5); }\n                &.wi-16 { .wli-icon(9); }\n                &.wi-17 { .wli-icon(5); }\n                &.wi-18 { .wli-icon(18); }\n                &.wi-19 { .wli-icon(19); }\n                &.wi-20 { .wli-icon(19); }\n                &.wi-21 { .wli-icon(19); }\n                &.wi-22 { .wli-icon(19); }\n                &.wi-23 { .wli-icon(19); }\n                &.wi-24 { .wli-icon(24); }\n                &.wi-25 { .wli-icon(24); }\n                &.wi-26 { .wli-icon(26); }\n                &.wi-27 { .wli-icon(27); }\n                &.wi-28 { .wli-icon(28); }\n                &.wi-29 { .wli-icon(27); }\n                &.wi-30 { .wli-icon(28); }\n                &.wi-31 { .wli-icon(31); }\n                &.wi-32 { .wli-icon(32); }\n                &.wi-33 { .wli-icon(31); }\n                &.wi-34 { .wli-icon(32); }\n                &.wi-35 { .wli-icon(5); }\n                &.wi-36 { .wli-icon(32); }\n                &.wi-37 { .wli-icon(2); }\n                &.wi-38 { .wli-icon(2); }\n                &.wi-39 { .wli-icon(2); }\n                &.wi-40 { .wli-icon(5); }\n                &.wi-41 { .wli-icon(5); }\n                &.wi-42 { .wli-icon(9); }\n                &.wi-43 { .wli-icon(5); }\n                &.wi-44 { .wli-icon(27); }\n                &.wi-45 { .wli-icon(2); }\n                &.wi-46 { .wli-icon(18); }\n                &.wi-47 { .wli-icon(2); }\n            }\n            \n            & > i {\n                line-height: 100%;\n                font-size: 39px;\n            }\n        }\n    }\n}\n\n/*\n * Pie Charts\n */\n#pie-charts {\n    background: #fff;\n    \n    .dash-widget-header {\n        color: rgba(255, 255, 255, 0.9);\n    }\n    \n}\n\n/*\n * Blog Post\n */\n\n.blog-post {\n    .bp-header {\n        position: relative;\n        \n        & > img {\n            width: 100%;\n        }\n         \n        .bp-title {\n            background: @m-indigo; \n            width: 100%;\n            padding: 20px;\n            color: #FFF;\n            display: block;\n            \n            & > h2 {\n                color: #FFF;\n                font-weight: 400;\n                margin: 0 0 2px;\n                line-height: 100%;\n                font-size: 21px;\n            }\n        }\n    }\n}\n\n/*\n * Profile View\n */\n.profile-view {\n    text-align: center;\n    .pv-header {\n        position: relative;\n        height: 145px;\n        width: 100%;\n        .bg-cover('../img/headers/sm/4.png');\n        \n        & > .pv-main {\n            border-radius: 50%;\n            width: 130px;\n            position: absolute;\n            height: 130px;\n            bottom: -50px;\n            left: 50%;\n            margin-left: -65px;\n          .transition(all);\n          .transition-duration(300ms);\n        }\n    }\n    \n    .pv-body {\n        margin-top: 70px;\n        padding: 0 20px 20px;\n        \n        & > h2 {\n            margin: 0;\n            line-height: 100%;\n            font-size: 20px;\n            font-weight: 400;\n        }\n        \n        & > small {\n            display: block;\n            color: #8E8E8E;\n            margin: 10px 0 15px;\n        }\n        \n        .pv-contact,\n        .pv-follow {\n            padding: 0;\n            list-style: none;\n            \n            & > li {\n                display: inline-block;\n            }\n        }\n        \n        .pv-follow {\n            margin: 20px -20px;\n            padding: 10px;\n            background-color: #F7F7F7;\n            border-top: 1px solid #EEE;\n            border-bottom: 1px solid #EEE;\n                   \n            & > li {\n                padding: 0 10px;\n            } \n        }\n        \n        .pv-contact {\n            & > li {\n                margin: 0 5px;\n                \n                & > .zmdi {\n                    line-height: 100%;\n                    vertical-align: text-bottom;\n                    font-size: 22px;\n                }\n            }\n        }\n        \n        .pv-follow-btn {\n            padding: 7px 20px;\n            background: @m-cyan;\n            color: #FFF;\n            border-radius: 3px;\n            text-transform: uppercase;\n            display: block;\n            .transition(all);\n            .transition-duration(300ms); \n            \n            &:hover {\n                background: darken(@m-cyan, 5%);\n            }\n        }\n    }\n\n  &:hover {\n    .pv-main {\n      .scale(1.2);\n    }\n  }\n}\n\n/*\n * Picture List\n */\n.picture-list {\n    .pl-body {\n        padding: 2px;\n        \n        [class*=\"col-\"] {\n            padding: 0;\n            padding: 2px;\n            \n            & > a {\n                display: block;\n                .hover-pop(rgba(0,0,0,0.3));\n            \n                img { \n                    width: 100%;\n                }\n            }\n            \n        }\n        \n        .clearfix();\n    }\n}\n\n/*\n * Social\n */\n.go-social {\n    .card-body {\n        padding: 0 15px 20px;\n        \n        [class*=\"col-\"] {\n            padding: 12px;\n            \n            img {\n                .transition(all);\n                .transition-duration(200ms);\n                .backface-visibility(hidden);    \n            }\n            \n            &:hover {\n                img {\n                    .scale(1.2);\n                }\n            }\n        }\n    }\n}\n\n/*\n * Rating\n */\n.rating-list {\n    padding: 0 0 10px;\n    \n    .rl-star {\n        margin-top: 10px;\n        margin-bottom: 4px;\n        \n        .zmdi {\n            font-size: 20px;\n            \n            &:not(.active) {\n                color: #ccc;\n            }\n            \n            &.active {\n                color: @m-orange;\n            }\n        }\n    }\n    \n    .lv-item {\n        .media {\n            .zmdi-star {\n                line-height: 100%;\n                font-size: 22px;\n                color: #FF9800;\n                vertical-align: middle;\n                position: relative;\n                top: -2px;\n                left: 6px;\n            }\n            \n            .media-body {\n                padding: 7px 10px 0 5px;\n            }\n        }\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/less/inc/wizard.less",
    "content": ".fw-container {\n    .tab-content {\n        padding: 25px 0;\n    }\n    \n    .fw-footer {\n        text-align: center;\n        margin: 30px 0 0;\n        width: 100%;\n        border-top: 2px solid #eee;\n        padding: 15px 0;\n    }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/message/history/message.js",
    "content": "/**\n * 系统参数管理初始化\n */\nvar Message = {\n    id: \"MessageTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nMessage.initColumn = function () {\n    return [\n\n             {field: 'selectItem', radio: true},\n            {title: 'ID', field: 'id', visible: true, align: 'center', valign: 'middle'},\n            {title: '消息模板', field: 'tplCode', visible: true, align: 'center', valign: 'middle'},\n            {title: '消息内容', field: 'content', visible: true, align: 'center', valign: 'middle',formatter:function(data,row){\n                console.log(row);\n                return '<a href=\"#\" onclick=\"Message.openDetail('+row.id+')\">'+data+'</a>'\n            }},\n            {title: '接收者', field: 'receiver', visible: true, align: 'center', valign: 'middle'},\n            {title: '发送时间', field: 'createTime', visible: true, align: 'center', valign: 'middle'}\n    ];\n};\n/**\n * 打开查看系统参数详情\n */\nMessage.openDetail = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '消息详情',\n            area: ['800px', '300px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/message/history/view/' + id\n        });\n        this.layerIndex = index;\n\n};\n\n/**\n * 删除系统参数\n */\nMessage.clear = function () {\n    var operation = function() {\n        var ajax = new $ax(Feng.ctxPath + \"/message/history/clear\", function (data) {\n            Feng.success(\"清除成功!\");\n            Message.table.refresh();\n        }, function (data) {\n            Feng.error(\"清除失败!\" + data.responseJSON.message + \"!\");\n        });\n        ajax.start();\n    };\n\n    Feng.confirm(\"清除后将无法恢复，确认该操作?\", operation);\n\n\n};\n\n/**\n * 查询系统参数列表\n */\nMessage.search = function () {\n    var queryData = {};\n    queryData['condition'] = $(\"#condition\").val();\n    Message.table.refresh({query: queryData});\n};\n\n$(function () {\n    var defaultColunms = Message.initColumn();\n    var table = new BSTable(Message.id, \"/message/history/list\", defaultColunms);\n    table.setPaginationType(\"server\");\n    Message.table = table.init();\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/message/sender/sender.js",
    "content": "/**\n * 消息发送器管理初始化\n */\nvar MessageSender = {\n    id: \"MessageSenderTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nMessageSender.initColumn = function () {\n    return [\n        {field: 'selectItem', radio: true},\n        {title: 'ID', field: 'id', visible: true, align: 'center', valign: 'middle'},\n        {title: '名称', field: 'name', visible: true, align: 'center', valign: 'middle',formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"MessageSender.openDetail('+row.id+')\">'+data+'</a>';\n        }},\n        {title: '发送类', field: 'className', visible: true, align: 'center', valign: 'middle'},\n        {title: '运营商短信模板编号', field: 'tplCode', visible: true, align: 'center', valign: 'middle'},\n        {title: '操作',formatter:function(data,row){\n            return   '<button type=\"button\" class=\"btn btn-info btn-icon waves-effect waves-circle\" onclick=\"MessageSender.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n            \n    ];\n};\n\n\n/**\n * 点击添加发送器\n */\nMessageSender.openAdd = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加发送器',\n        area: ['60%', '45%'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/message/sender/add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 打开查看发送器详情\n */\nMessageSender.openDetail = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '发送器详情',\n            area: ['60%', '50%'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/message/sender/update/' + id\n        });\n        this.layerIndex = index;\n};\n\n/**\n * 删除发送器\n */\nMessageSender.delete = function (id) {\n       var operation = function(){\n            var ajax = new $ax(Feng.ctxPath + \"/message/sender\", function (data) {\n                Feng.success(\"删除成功!\");\n                MessageSender.table.refresh();\n            }, function (data) {\n                Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n            });\n            ajax.set(\"id\",id);\n            ajax.setType(\"delete\");\n            ajax.start();\n        };\n        Feng.confirm(\"是否删除消息发送器？\",operation);\n};\n\n\n$(function () {\n    var defaultColunms = MessageSender.initColumn();\n    var table = new BSTable(MessageSender.id, \"/message/sender/list\", defaultColunms);\n    table.setPaginationType(\"server\");\n    MessageSender.table = table.init();\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/message/sender/sender_info.js",
    "content": "/**\n * 初始化发送器详情对话框\n */\nvar MessageSenderInfoDlg = {\n    formData : {}\n};\n\n/**\n * 清除数据\n */\nMessageSenderInfoDlg.clearData = function() {\n    this.formData = {};\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nMessageSenderInfoDlg.set = function(key, val) {\n    this.formData[key] = (typeof val == \"undefined\") ? $(\"#\" + key).val() : val;\n    return this;\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nMessageSenderInfoDlg.get = function(key) {\n    return $(\"#\" + key).val();\n}\n\n/**\n * 关闭此对话框\n */\nMessageSenderInfoDlg.close = function() {\n    parent.layer.close(window.parent.MessageSender.layerIndex);\n}\n\n/**\n * 收集数据\n */\nMessageSenderInfoDlg.collectData = function() {\n    this\n    .set('id')\n    .set('name')\n    .set('className')\n    .set('tplCode');\n}\n\n/**\n * 提交添加\n */\nMessageSenderInfoDlg.addSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/message/sender\", function(data){\n        Feng.success(\"添加成功!\");\n        window.parent.MessageSender.table.refresh();\n        MessageSenderInfoDlg.close();\n    },function(data){\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.formData);\n    ajax.start();\n}\n\n/**\n * 提交修改\n */\nMessageSenderInfoDlg.editSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/message/sender\", function(data){\n        Feng.success(\"修改成功!\");\n        window.parent.MessageSender.table.refresh();\n        MessageSenderInfoDlg.close();\n    },function(data){\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.formData);\n    ajax.start();\n}\n\n$(function() {\n\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/message/template/template.js",
    "content": "/**\n * 消息模板管理初始化\n */\nvar MessageTemplate = {\n    id: \"MessageTemplateTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nMessageTemplate.initColumn = function () {\n    return [\n        {field: 'selectItem', checkbox: true},\n        {title: 'ID', field: 'id', visible: true, align: 'center', valign: 'middle'},\n        {title: '编号', field: 'code', visible: true, align: 'center', valign: 'middle',formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"MessageTemplate.openDetail('+row.id+')\">'+data+'</a>';\n        }},\n        {title: '标题', field: 'title', visible: true, align: 'center', valign: 'middle'},\n        {title: '内容', field: 'content', visible: true, align: 'center', valign: 'middle'},\n        {title: '发送条件', field: 'cond', visible: true, align: 'center', valign: 'middle'},\n        {title: '类型', field: 'typeName', visible: true, align: 'center', valign: 'middle'},\n        {title: '模板', field: 'messageSender.name', visible: true, align: 'center', valign: 'middle'},\n        {title: '操作',formatter:function(data,row){\n            return   '<button type=\"button\" class=\"btn btn-info btn-icon waves-effect waves-circle\" onclick=\"MessageTemplate.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n            \n    ];\n};\n\n\n\n/**\n * 点击添加模板\n */\nMessageTemplate.openAdd = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加模板',\n        area: ['60%', '380px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/message/template/add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 打开查看模板详情\n */\nMessageTemplate.openDetail = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '模板详情',\n            area: ['60%', '380px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/message/template/update/' + id\n        });\n        this.layerIndex = index;\n};\n\n/**\n * 删除模板\n */\nMessageTemplate.delete = function (id) {\n\n    var operation = function() {\n        var ajax = new $ax(Feng.ctxPath + \"/message/template\", function (data) {\n            Feng.success(\"删除成功!\");\n            MessageTemplate.table.refresh();\n        }, function (data) {\n            Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n        });\n        ajax.set(\"id\", id);\n        ajax.setType(\"delete\");\n        ajax.start();\n    };\n    Feng.confirm(\"是否刪除模板?\", operation);\n\n};\n\n\n$(function () {\n    var defaultColunms = MessageTemplate.initColumn();\n    var table = new BSTable(MessageTemplate.id, \"/message/template/list\", defaultColunms);\n    table.setPaginationType(\"server\");\n    MessageTemplate.table = table.init();\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/message/template/template_info.js",
    "content": "/**\n * 初始化发送器详情对话框\n */\nvar MessageTemplateInfoDlg = {\n    formData : {}\n};\n\n/**\n * 清除数据\n */\nMessageTemplateInfoDlg.clearData = function() {\n    this.formData = {};\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nMessageTemplateInfoDlg.set = function(key, val) {\n    this.formData[key] = (typeof val == \"undefined\") ? $(\"#\" + key).val() : val;\n    return this;\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nMessageTemplateInfoDlg.get = function(key) {\n    return $(\"#\" + key).val();\n}\n\n/**\n * 关闭此对话框\n */\nMessageTemplateInfoDlg.close = function() {\n    parent.layer.close(window.parent.MessageTemplate.layerIndex);\n}\n\n/**\n * 收集数据\n */\nMessageTemplateInfoDlg.collectData = function() {\n    this\n    .set('id')\n    .set('code')\n    .set('title')\n    .set('content')\n    .set('cond')\n    .set('type')\n    .set('idMessageSender');\n}\n\n/**\n * 提交添加\n */\nMessageTemplateInfoDlg.addSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/message/template\", function(data){\n        Feng.success(\"添加成功!\");\n        window.parent.MessageTemplate.table.refresh();\n        MessageTemplateInfoDlg.close();\n    },function(data){\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.formData);\n    ajax.start();\n}\n\n/**\n * 提交修改\n */\nMessageTemplateInfoDlg.editSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/message/template\", function(data){\n        Feng.success(\"修改成功!\");\n        window.parent.MessageTemplate.table.refresh();\n        MessageTemplateInfoDlg.close();\n    },function(data){\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.formData);\n    ajax.start();\n}\n\n$(function() {\n\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/cfg/cfg.js",
    "content": "/**\n * 系统参数管理初始化\n */\nvar Cfg = {\n    id: \"CfgTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nCfg.initColumn = function () {\n    return [\n        {field: 'selectItem', checkbox: true},\n        {title: 'ID', field: 'id', visible: true, align: 'center', valign: 'middle'},\n        {title: '参数名', field: 'cfgName', visible: true, align: 'center', valign: 'middle',formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"Cfg.openCfgDetail('+row.id+')\">'+data+'</a>';\n        }},\n        {title: '参数值', field: 'cfgValue', visible: true, align: 'center', valign: 'middle'},\n        {title: '参数描述', field: 'cfgDesc', visible: true, align: 'center', valign: 'middle'},\n        {title: '操作',formatter:function(data,row){\n            return '<button type=\"button\" class=\"btn btn-danger btn-icon waves-effect waves-circle\" onclick=\"Cfg.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n    ];\n};\n\n\n/**\n * 点击添加系统参数\n */\nCfg.openAddCfg = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加系统参数',\n        area: ['65%', '280px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/cfg/cfg_add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 打开系统参数详情页\n */\nCfg.openCfgDetail = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '系统参数详情',\n            area: ['65%', '280px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/cfg/cfg_update/' + id\n        });\n        this.layerIndex = index;\n\n};\n\n/**\n * 删除系统参数\n */\nCfg.delete = function (id) {\n    var operation = function() {\n        var ajax = new $ax(Feng.ctxPath + \"/cfg/delete\", function (data) {\n            Feng.success(\"删除成功!\");\n            Cfg.table.refresh();\n        }, function (data) {\n            Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n        });\n        ajax.setType('delete');\n        ajax.set(\"cfgId\", id);\n        ajax.start();\n\n    };\n    Feng.confirm(\"确认删除该记录?\", operation);\n};\n\n/**\n * 查询系统参数列表\n */\nCfg.search = function () {\n    var queryData = {};\n    queryData['cfgName'] = $(\"#cfgName\").val();\n    queryData['cfgValue'] = $(\"#cfgValue\").val();\n    Cfg.table.refresh({query: queryData});\n};\n\nCfg.reset = function () {\n    $(\"#cfgName\").val(\"\");\n    $(\"#cfgValue\").val(\"\");\n    this.search();\n};\n$(function () {\n    var defaultColunms = Cfg.initColumn();\n    var table = new BSTable(Cfg.id, \"/cfg/list\", defaultColunms);\n    table.setPaginationType(\"server\");\n    Cfg.table = table.init();\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/cfg/cfg_info.js",
    "content": "/**\n * 初始化系统参数详情对话框\n */\nvar CfgInfoDlg = {\n    cfgInfoData : {}\n};\n\n/**\n * 清除数据\n */\nCfgInfoDlg.clearData = function() {\n    this.cfgInfoData = {};\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nCfgInfoDlg.set = function(key, val) {\n    this.cfgInfoData[key] = (typeof val == \"undefined\") ? $(\"#\" + key).val() : val;\n    return this;\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nCfgInfoDlg.get = function(key) {\n    return $(\"#\" + key).val();\n}\n\n/**\n * 关闭此对话框\n */\nCfgInfoDlg.close = function() {\n    parent.layer.close(window.parent.Cfg.layerIndex);\n}\n\n/**\n * 收集数据\n */\nCfgInfoDlg.collectData = function() {\n    this\n    .set('id')\n    .set('cfgName')\n    .set('cfgValue')\n    .set('cfgDesc');\n}\n\n/**\n * 提交添加\n */\nCfgInfoDlg.addSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/cfg/add\", function(data){\n        Feng.success(\"添加成功!\");\n        window.parent.Cfg.table.refresh();\n        CfgInfoDlg.close();\n    },function(data){\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.cfgInfoData);\n    ajax.start();\n}\n\n/**\n * 提交修改\n */\nCfgInfoDlg.editSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/cfg/update\", function(data){\n        Feng.success(\"修改成功!\");\n        window.parent.Cfg.table.refresh();\n        CfgInfoDlg.close();\n    },function(data){\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.cfgInfoData);\n    ajax.start();\n}\n\n$(function() {\n\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/dept/dept.js",
    "content": "/**\n * 部门管理初始化\n */\nvar Dept = {\n    id: \"DeptTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nDept.initColumn = function () {\n    return [\n        {title: 'id', field: 'id', align: 'center', valign: 'middle',width:'50px'},\n        {title: '部门简称', field: 'simplename', align: 'center', valign: 'middle', sortable: true,formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"Dept.openDeptDetail('+row.id+')\">'+row.simplename+'</a>';\n        }},\n        {title: '部门全称', field: 'fullname', align: 'center', valign: 'middle', sortable: true},\n        {title: '排序', field: 'num', align: 'center', valign: 'middle', sortable: true},\n        {title: '备注', field: 'tips', align: 'center', valign: 'middle', sortable: true},\n        {title: '操作',formatter:function(data,row){\n            return '<button type=\"button\" class=\"btn btn-danger btn-icon waves-effect waves-circle\" onclick=\"Dept.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n    ];\n};\n\n/**\n * 点击添加部门\n */\nDept.openAddDept = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加部门',\n        area: ['800px', '320px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/dept/dept_add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 打开查看部门详情\n */\nDept.openDeptDetail = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '部门详情',\n            area: ['800px', '320px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/dept/dept_update/' + id\n        });\n        this.layerIndex = index;\n\n};\n\n/**\n * 删除部门\n */\nDept.delete = function (id) {\n        var operation = function(){\n            var ajax = new $ax(Feng.ctxPath + \"/dept/delete\", function () {\n                Feng.success(\"删除成功!\");\n                Dept.table.refresh();\n            }, function (data) {\n                Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n            });\n            ajax.set(\"deptId\",id);\n            ajax.start();\n        };\n\n        Feng.confirm(\"是否刪除该部门?\", operation);\n\n};\n\n/**\n * 查询部门列表\n */\nDept.search = function () {\n    var queryData = {};\n    queryData['condition'] = $(\"#condition\").val();\n    Dept.table.refresh({query: queryData});\n};\n\n$(function () {\n    var defaultColunms = Dept.initColumn();\n    var table = new BSTreeTable(Dept.id, \"/dept/list\", defaultColunms);\n    table.setExpandColumn(2);\n    table.setIdField(\"id\");\n    table.setCodeField(\"id\");\n    table.setParentCodeField(\"pid\");\n    table.setExpandAll(true);\n    table.init();\n    Dept.table = table;\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/dept/dept_info.js",
    "content": "/**\n * 初始化部门详情对话框\n */\nvar DeptInfoDlg = {\n    deptInfoData : {},\n    zTreeInstance : null,\n    validateFields: {\n        simplename: {\n            validators: {\n                notEmpty: {\n                    message: '部门名称不能为空'\n                }\n            }\n        },\n        fullname: {\n            validators: {\n                notEmpty: {\n                    message: '部门全称不能为空'\n                }\n            }\n        },\n        pName: {\n            validators: {\n                notEmpty: {\n                    message: '上级名称不能为空'\n                }\n            }\n        }\n    }\n};\n\n/**\n * 清除数据\n */\nDeptInfoDlg.clearData = function() {\n    this.deptInfoData = {};\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nDeptInfoDlg.set = function(key, val) {\n    this.deptInfoData[key] = (typeof value == \"undefined\") ? $(\"#\" + key).val() : value;\n    return this;\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nDeptInfoDlg.get = function(key) {\n    return $(\"#\" + key).val();\n}\n\n/**\n * 关闭此对话框\n */\nDeptInfoDlg.close = function() {\n    parent.layer.close(window.parent.Dept.layerIndex);\n}\n\n/**\n * 点击部门ztree列表的选项时\n *\n * @param e\n * @param treeId\n * @param treeNode\n * @returns\n */\nDeptInfoDlg.onClickDept = function(e, treeId, treeNode) {\n    $(\"#pName\").attr(\"value\", DeptInfoDlg.zTreeInstance.getSelectedVal());\n    $(\"#pid\").attr(\"value\", treeNode.id);\n}\n\n/**\n * 显示部门选择的树\n *\n * @returns\n */\nDeptInfoDlg.showDeptSelectTree = function() {\n    var pName = $(\"#pName\");\n    var pNameOffset = $(\"#pName\").offset();\n    $(\"#parentDeptMenu\").css({\n        left : pNameOffset.left + \"px\",\n        top : pNameOffset.top + pName.outerHeight() + \"px\"\n    }).slideDown(\"fast\");\n\n    $(\"body\").bind(\"mousedown\", onBodyDown);\n}\n\n/**\n * 隐藏部门选择的树\n */\nDeptInfoDlg.hideDeptSelectTree = function() {\n    $(\"#parentDeptMenu\").fadeOut(\"fast\");\n    $(\"body\").unbind(\"mousedown\", onBodyDown);// mousedown当鼠标按下就可以触发，不用弹起\n}\n\n/**\n * 收集数据\n */\nDeptInfoDlg.collectData = function() {\n    this.set('id').set('simplename').set('fullname').set('tips').set('num').set('pid');\n}\n\n/**\n * 验证数据是否为空\n */\nDeptInfoDlg.validate = function () {\n    $('#deptInfoForm').data(\"bootstrapValidator\").resetForm();\n    $('#deptInfoForm').bootstrapValidator('validate');\n    return $(\"#deptInfoForm\").data('bootstrapValidator').isValid();\n}\n\n/**\n * 提交添加部门\n */\nDeptInfoDlg.addSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    if (!this.validate()) {\n        return;\n    }\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/dept/add\", function(data){\n        Feng.success(\"添加成功!\");\n        window.parent.Dept.table.refresh();\n        DeptInfoDlg.close();\n    },function(data){\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.deptInfoData);\n    ajax.start();\n}\n\n/**\n * 提交修改\n */\nDeptInfoDlg.editSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    if (!this.validate()) {\n        return;\n    }\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/dept/update\", function(data){\n        Feng.success(\"修改成功!\");\n        window.parent.Dept.table.refresh();\n        DeptInfoDlg.close();\n    },function(data){\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.deptInfoData);\n    ajax.start();\n}\n\nfunction onBodyDown(event) {\n    if (!(event.target.id == \"menuBtn\" || event.target.id == \"parentDeptMenu\" || $(\n            event.target).parents(\"#parentDeptMenu\").length > 0)) {\n        DeptInfoDlg.hideDeptSelectTree();\n    }\n}\n\n$(function() {\n    Feng.initValidator(\"deptInfoForm\", DeptInfoDlg.validateFields);\n\n    var ztree = new $ZTree(\"parentDeptMenuTree\", \"/dept/tree\");\n    ztree.bindOnClick(DeptInfoDlg.onClickDept);\n    ztree.init();\n    DeptInfoDlg.zTreeInstance = ztree;\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/dict/dict.js",
    "content": "/**\n * 字典管理初始化\n */\nvar Dict = {\n    id: \"DictTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nDict.initColumn = function () {\n    return [\n        {field: 'selectItem', checkbox: true},\n        {title: 'id', field: 'id', visible: false, align: 'center', valign: 'middle'},\n        {title: '名称', field: 'name', align: 'center', valign: 'middle', sortable: true,formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"Dict.openDictDetail('+row.id+')\">'+data+'</a>';\n        }},\n        {title: '详情', field: 'detail', align: 'center', valign: 'middle', sortable: true},\n        {title: '备注', field: 'tips', align: 'center', valign: 'middle', sortable: true},\n        {title: '操作',formatter:function(data,row){\n            return '<button type=\"button\" class=\"btn btn-danger btn-icon waves-effect waves-circle\" onclick=\"Dict.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n    ];\n};\n\n\n/**\n * 点击添加字典\n */\nDict.openAddDict = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加字典',\n        area: ['800px', '420px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/dict/dict_add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 打开查看字典详情\n */\nDict.openDictDetail = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '字典详情',\n            area: ['800px', '420px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/dict/dict_edit/' + id\n        });\n        this.layerIndex = index;\n};\n\n/**\n * 删除字典\n */\nDict.delete = function (id) {\n        var operation = function(){\n            var ajax = new $ax(Feng.ctxPath + \"/dict/delete\", function (data) {\n                Feng.success(\"删除成功!\");\n                Dict.table.refresh();\n            }, function (data) {\n                Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n            });\n            ajax.set(\"dictId\", id);\n            ajax.start();\n        };\n\n        Feng.confirm(\"确认删除该记录?\", operation);\n\n};\n\n/**\n * 查询字典列表\n */\nDict.search = function () {\n    var queryData = {};\n    queryData['condition'] = $(\"#condition\").val();\n    Dict.table.refresh({query: queryData});\n};\n\n$(function () {\n    var defaultColunms = Dict.initColumn();\n    var table = new BSTable(Dict.id, \"/dict/list\", defaultColunms);\n    table.setPaginationType(\"client\");\n    Dict.table = table.init();\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/dict/dict_info.js",
    "content": "/**\n * 初始化字典详情对话框\n */\nvar DictInfoDlg = {\n    count: $(\"#itemSize\").val(),\n    dictName: '',\t\t\t//字典的名称\n    mutiString: '',\t\t//拼接字符串内容(拼接字典条目)\n    itemTemplate: $(\"#itemTemplate\").html()\n};\n\n/**\n * item获取新的id\n */\nDictInfoDlg.newId = function () {\n    if(this.count == undefined){\n        this.count = 0;\n    }\n    this.count = this.count + 1;\n    return \"dictItem\" + this.count;\n};\n\n/**\n * 关闭此对话框\n */\nDictInfoDlg.close = function () {\n    parent.layer.close(window.parent.Dict.layerIndex);\n};\n\n/**\n * 添加条目\n */\nDictInfoDlg.addItem = function () {\n    $(\"#itemsArea\").append(this.itemTemplate);\n    $(\"#dictItem\").attr(\"id\", this.newId());\n};\n\n/**\n * 删除item\n */\nDictInfoDlg.deleteItem = function (event) {\n    var obj = Feng.eventParseObject(event);\n    obj = obj.is('button') ? obj : obj.parent();\n    obj.parent().parent().remove();\n};\n\n/**\n * 清除为空的item Dom\n */\nDictInfoDlg.clearNullDom = function(){\n    $(\"[name='dictItem']\").each(function(){\n        var num = $(this).find(\"[name='itemNum']\").val();\n        var name = $(this).find(\"[name='itemName']\").val();\n        if(num == '' || name == ''){\n            $(this).remove();\n        }\n    });\n};\n\n/**\n * 收集添加字典的数据\n */\nDictInfoDlg.collectData = function () {\n    this.clearNullDom();\n    var mutiString = \"\";\n    $(\"[name='dictItem']\").each(function(){\n        var num = $(this).find(\"[name='itemNum']\").val();\n        var name = $(this).find(\"[name='itemName']\").val();\n        mutiString = mutiString + (num + \":\" + name + \";\");\n    });\n    this.dictName = $(\"#dictName\").val();\n    this.mutiString = mutiString;\n};\n\n\n/**\n * 提交添加字典\n */\nDictInfoDlg.addSubmit = function () {\n    this.collectData();\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/dict/add\", function (data) {\n        Feng.success(\"添加成功!\");\n        window.parent.Dict.table.refresh();\n        DictInfoDlg.close();\n    }, function (data) {\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set('dictName',this.dictName);\n    ajax.set('dictValues',this.mutiString);\n    ajax.start();\n};\n\n/**\n * 提交修改\n */\nDictInfoDlg.editSubmit = function () {\n    this.collectData();\n    var ajax = new $ax(Feng.ctxPath + \"/dict/update\", function (data) {\n        Feng.success(\"修改成功!\");\n        window.parent.Dict.table.refresh();\n        DictInfoDlg.close();\n    }, function (data) {\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set('dictId',$(\"#dictId\").val());\n    ajax.set('dictName',this.dictName);\n    ajax.set('dictValues',this.mutiString);\n    ajax.start();\n};\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/menu/menu.js",
    "content": "/**\n * 角色管理的单例\n */\nvar Menu = {\n    id: \"menuTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nMenu.initColumn = function () {\n    var columns = [\n        {title: 'ID', field: 'id', visible: false, align: 'center', valign: 'middle'},\n        {title: '菜单名称', field: 'name', align: 'center', valign: 'middle', sortable: true, width: '17%',formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"Menu.openChangeMenu('+row.id+')\">'+row.name+'</a>';\n        }},\n        {title: '菜单编号', field: 'code', align: 'center', valign: 'middle', sortable: true, width: '12%'},\n        {title: '菜单父编号', field: 'pcode', align: 'center', valign: 'middle', sortable: true},\n        {title: '请求地址', field: 'url', align: 'center', valign: 'middle', sortable: true, width: '15%'},\n        {title: '排序', field: 'num', align: 'center', valign: 'middle', sortable: true},\n        {title: '层级', field: 'levels', align: 'center', valign: 'middle', sortable: true},\n        {title: '是否是菜单', field: 'isMenuName', align: 'center', valign: 'middle', sortable: true},\n        {title: '状态', field: 'statusName', align: 'center', valign: 'middle', sortable: true},\n        {title: '操作',formatter:function(data,row){\n            return   '<button type=\"button\" class=\"btn btn-danger btn-icon waves-effect waves-circle\" onclick=\"Menu.delMenu('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n        ]\n    return columns;\n};\n\n\n/**\n * 点击添加菜单\n */\nMenu.openAddMenu = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加菜单',\n        area: ['850px', '380px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/menu/menu_add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 点击修改\n */\nMenu.openChangeMenu = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '修改菜单',\n            area: ['850px', '380px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/menu/menu_edit/' + id\n        });\n        this.layerIndex = index;\n};\n\n/**\n * 删除\n */\nMenu.delMenu = function (id) {\n        var operation = function () {\n            var ajax = new $ax(Feng.ctxPath + \"/menu/remove\", function (data) {\n                Feng.success(\"删除成功!\");\n                Menu.table.refresh();\n            }, function (data) {\n                Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n            });\n            ajax.set(\"menuId\", id);\n            ajax.start();\n        };\n\n        Feng.confirm(\"是否删除该记录?\", operation);\n};\n\n/**\n * 搜索\n */\nMenu.search = function () {\n    var queryData = {};\n\n    queryData['menuName'] = $(\"#menuName\").val();\n    queryData['level'] = $(\"#level\").val();\n\n    Menu.table.refresh({query: queryData});\n}\n\n$(function () {\n    var defaultColunms = Menu.initColumn();\n    var table = new BSTreeTable(Menu.id, \"/menu/list\", defaultColunms);\n    table.setExpandColumn(2);\n    table.setIdField(\"id\");\n    table.setCodeField(\"code\");\n    table.setParentCodeField(\"pcode\");\n    table.setExpandAll(false);\n    table.init();\n    Menu.table = table;\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/menu/menu_info.js",
    "content": "/**\n * 菜单详情对话框\n */\nvar MenuInfoDlg = {\n    menuInfoData: {},\n    ztreeInstance: null,\n    validateFields: {\n        name: {\n            validators: {\n                notEmpty: {\n                    message: '菜单名称不能为空'\n                }\n            }\n        },\n        code: {\n            validators: {\n                notEmpty: {\n                    message: '菜单编号不能为空'\n                }\n            }\n        },\n        pcodeName: {\n            validators: {\n                notEmpty: {\n                    message: '父菜单不能为空'\n                }\n            }\n        },\n        url: {\n            validators: {\n                notEmpty: {\n                    message: '请求地址不能为空'\n                }\n            }\n        },\n        num: {\n            validators: {\n                notEmpty: {\n                    message: '序号不能为空'\n                }\n            }\n        }\n    }\n};\n\n/**\n * 清除数据\n */\nMenuInfoDlg.clearData = function () {\n    this.menuInfoData = {};\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nMenuInfoDlg.set = function (key, val) {\n    this.menuInfoData[key] = (typeof value == \"undefined\") ? $(\"#\" + key).val() : value;\n    return this;\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nMenuInfoDlg.get = function (key) {\n    return $(\"#\" + key).val();\n}\n\n/**\n * 关闭此对话框\n */\nMenuInfoDlg.close = function () {\n    parent.layer.close(window.parent.Menu.layerIndex);\n}\n\n/**\n * 收集数据\n */\nMenuInfoDlg.collectData = function () {\n    this.set('id').set('name').set('code').set('pcode').set('url').set('num').set('levels').set('icon').set(\"ismenu\");\n}\n\n/**\n * 验证数据是否为空\n */\nMenuInfoDlg.validate = function () {\n    $('#menuInfoForm').data(\"bootstrapValidator\").resetForm();\n    $('#menuInfoForm').bootstrapValidator('validate');\n    return $(\"#menuInfoForm\").data('bootstrapValidator').isValid();\n}\n\n/**\n * 提交添加用户\n */\nMenuInfoDlg.addSubmit = function () {\n\n    this.clearData();\n    this.collectData();\n\n    if (!this.validate()) {\n        return;\n    }\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/menu/add\", function (data) {\n        Feng.success(\"添加成功!\");\n        window.parent.Menu.table.refresh();\n        MenuInfoDlg.close();\n    }, function (data) {\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.menuInfoData);\n    ajax.start();\n}\n\n/**\n * 提交修改\n */\nMenuInfoDlg.editSubmit = function () {\n\n    this.clearData();\n    this.collectData();\n\n    if (!this.validate()) {\n        return;\n    }\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/menu/edit\", function (data) {\n        Feng.success(\"修改成功!\");\n        window.parent.Menu.table.refresh();\n        MenuInfoDlg.close();\n    }, function (data) {\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.menuInfoData);\n    ajax.start();\n}\n\n/**\n * 点击父级编号input框时\n */\nMenuInfoDlg.onClickDept = function (e, treeId, treeNode) {\n    $(\"#pcodeName\").attr(\"value\", MenuInfoDlg.ztreeInstance.getSelectedVal());\n    $(\"#pcode\").attr(\"value\", treeNode.code);\n};\n\n\n/**\n * 显示父级菜单选择的树\n */\nMenuInfoDlg.showMenuSelectTree = function () {\n    Feng.showInputTree(\"pcodeName\", \"pcodeTreeDiv\", 15, 34);\n};\n\n$(function () {\n    Feng.initValidator(\"menuInfoForm\", MenuInfoDlg.validateFields);\n\n    var ztree = new $ZTree(\"pcodeTree\", \"/menu/selectMenuTreeList\");\n    ztree.bindOnClick(MenuInfoDlg.onClickDept);\n    ztree.init();\n    MenuInfoDlg.ztreeInstance = ztree;\n\n    //初始化是否是菜单\n    if($(\"#ismenuValue\").val() == undefined){\n        $(\"#ismenu\").val(0);\n    }else{\n        $(\"#ismenu\").val($(\"#ismenuValue\").val());\n    }\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/role/role.js",
    "content": "/**\n * 角色管理的单例\n */\nvar Role = {\n    id: \"roleTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nRole.initColumn = function () {\n    var columns = [\n        {field: 'selectItem', checkbox: true },\n        {title: 'id', field: 'id', visible: false, align: 'center', valign: 'middle'},\n        {title: '名称', field: 'name', align: 'center', valign: 'middle', sortable: true,formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"Role.openChangeRole('+row.id+')\">'+data+'</a>';\n        }},\n        {title: '上级角色', field: 'pName', align: 'center', valign: 'middle', sortable: true},\n        {title: '所在部门', field: 'deptName', align: 'center', valign: 'middle', sortable: true},\n        {title: '别名', field: 'tips', align: 'center', valign: 'middle', sortable: true},\n        {title: '操作',formatter:function(data,row){\n            return '<button type=\"button\" class=\"btn btn-icon   waves-effect waves-circle\" onclick=\"Role.assign('+row.id+')\" title=\"分配权限\"><span class=\"zmdi zmdi-assignment-check\"></span></button>'\n                +\n                '<button type=\"button\" class=\"btn btn-danger btn-icon waves-effect waves-circle\" onclick=\"Role.delRole('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n    ]\n    return columns;\n};\n\n/**\n * 点击添加管理员\n */\nRole.openAddRole = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加角色',\n        area: ['800px', '330px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/role/role_add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 点击修改按钮时\n */\nRole.openChangeRole = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '修改角色',\n            area: ['800px', '330px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/role/role_edit/' + id\n        });\n        this.layerIndex = index;\n};\n\n/**\n * 删除角色\n */\nRole.delRole = function (id) {\n        var operation = function(){\n            var ajax = new $ax(Feng.ctxPath + \"/role/remove\", function () {\n                Feng.success(\"删除成功!\");\n                Role.table.refresh();\n            }, function (data) {\n                Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n            });\n            ajax.set(\"roleId\", id);\n            ajax.start();\n        };\n        Feng.confirm(\"确认删除该角色?\",operation);\n\n};\n\n/**\n * 权限配置\n */\nRole.assign = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '权限配置',\n            area: ['300px', '550px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/role/role_assign/' +id\n        });\n        this.layerIndex = index;\n};\n\n/**\n * 搜索角色\n */\nRole.search = function () {\n    var queryData = {};\n    queryData['roleName'] = $(\"#roleName\").val();\n    Role.table.refresh({query: queryData});\n}\n\n$(function () {\n    var defaultColunms = Role.initColumn();\n    var table = new BSTable(Role.id, \"/role/list\", defaultColunms);\n    table.setPaginationType(\"client\");\n    table.init();\n    Role.table = table;\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/role/role_info.js",
    "content": "/**\n * 角色详情对话框（可用于添加和修改对话框）\n */\nvar RolInfoDlg = {\n    roleInfoData: {},\n    deptZtree: null,\n    pNameZtree: null,\n    validateFields: {\n        name: {\n            validators: {\n                notEmpty: {\n                    message: '用户名不能为空'\n                }\n            }\n        },\n        tips: {\n            validators: {\n                notEmpty: {\n                    message: '别名不能为空'\n                }\n            }\n        },\n        pName: {\n            validators: {\n                notEmpty: {\n                    message: '父级名称不能为空'\n                }\n            }\n        }\n    }\n};\n\n/**\n * 清除数据\n */\nRolInfoDlg.clearData = function () {\n    this.roleInfoData = {};\n};\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nRolInfoDlg.set = function (key, val) {\n    this.roleInfoData[key] = (typeof value == \"undefined\") ? $(\"#\" + key).val() : value;\n    return this;\n};\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nRolInfoDlg.get = function (key) {\n    return $(\"#\" + key).val();\n};\n\n/**\n * 关闭此对话框\n */\nRolInfoDlg.close = function () {\n    parent.layer.close(window.parent.Role.layerIndex);\n};\n\n/**\n * 点击部门input框时\n *\n * @param e\n * @param treeId\n * @param treeNode\n * @returns\n */\nRolInfoDlg.onClickDept = function (e, treeId, treeNode) {\n    $(\"#deptName\").attr(\"value\", RolInfoDlg.deptZtree.getSelectedVal());\n    $(\"#deptid\").attr(\"value\", treeNode.id);\n};\nRolInfoDlg.onDblClickDept = function (e, treeId, treeNode) {\n    $(\"#deptName\").attr(\"value\", RolInfoDlg.deptZtree.getSelectedVal());\n    $(\"#deptid\").attr(\"value\", treeNode.id);\n    $(\"#deptContent\").fadeOut(\"fast\");\n};\n\n/**\n * 点击父级菜单input框时\n *\n * @param e\n * @param treeId\n * @param treeNode\n * @returns\n */\nRolInfoDlg.onClickPName = function (e, treeId, treeNode) {\n    $(\"#pName\").attr(\"value\", RolInfoDlg.pNameZtree.getSelectedVal());\n    $(\"#pid\").attr(\"value\", treeNode.id);\n};\n\n/**\n * 显示部门选择的树\n *\n * @returns\n */\nRolInfoDlg.showDeptSelectTree = function () {\n    Feng.showInputTree(\"deptName\", \"deptContent\");\n};\n\n/**\n * 显示父级菜单的树\n *\n * @returns\n */\nRolInfoDlg.showPNameSelectTree = function () {\n    Feng.showInputTree(\"pName\", \"pNameContent\");\n};\n\n/**\n * 收集数据\n */\nRolInfoDlg.collectData = function () {\n    this.set('id').set('name').set('pid').set('deptid').set('tips').set('num');\n};\n\n/**\n * 验证数据是否为空\n */\nRolInfoDlg.validate = function () {\n    $('#roleInfoForm').data(\"bootstrapValidator\").resetForm();\n    $('#roleInfoForm').bootstrapValidator('validate');\n    return $(\"#roleInfoForm\").data('bootstrapValidator').isValid();\n};\n\n/**\n * 提交添加用户\n */\nRolInfoDlg.addSubmit = function () {\n\n    this.clearData();\n    this.collectData();\n\n    if (!this.validate()) {\n        return;\n    }\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/role/add\", function (data) {\n        Feng.success(\"添加成功!\");\n        window.parent.Role.table.refresh();\n        RolInfoDlg.close();\n    }, function (data) {\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.roleInfoData);\n    ajax.start();\n};\n\n/**\n * 提交修改\n */\nRolInfoDlg.editSubmit = function () {\n\n    this.clearData();\n    this.collectData();\n\n    if (!this.validate()) {\n        return;\n    }\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/role/edit\", function (data) {\n        Feng.success(\"修改成功!\");\n        window.parent.Role.table.refresh();\n        RolInfoDlg.close();\n    }, function (data) {\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.roleInfoData);\n    ajax.start();\n};\n\n$(function () {\n    Feng.initValidator(\"roleInfoForm\", RolInfoDlg.validateFields);\n\n    var deptTree = new $ZTree(\"deptTree\", \"/dept/tree\");\n    deptTree.bindOnClick(RolInfoDlg.onClickDept);\n    deptTree.bindOnDblClick(RolInfoDlg.onDblClickDept)\n    deptTree.init();\n    RolInfoDlg.deptZtree = deptTree;\n\n    var pNameTree = new $ZTree(\"pNameTree\", \"/role/roleTreeList\");\n    pNameTree.bindOnClick(RolInfoDlg.onClickPName);\n    pNameTree.init();\n    RolInfoDlg.pNameZtree = pNameTree;\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/task/task.js",
    "content": "/**\n * 系统参数管理初始化\n */\nvar Task = {\n    id: \"TaskTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nTask.initColumn = function () {\n    return [\n            {field: 'selectItem', checkbox: true},\n            {title: 'ID', field: 'id', visible: true, align: 'center', valign: 'middle'},\n            {title: '任务名', field: 'name', visible: true, align: 'center', valign: 'middle',formatter:function(data,row){\n                return '<a href=\"javascript:;\" onclick=\"Task.openTaskDetail('+row.id+')\">'+data+'</a>';\n            }},\n            {title: '执行类', field: 'jobClass', visible: true, align: 'center', valign: 'middle'},\n            {title: '定时规则', field: 'cron', visible: true, align: 'center', valign: 'middle'},\n            {title: '任务说明', field: 'note', visible: true, align: 'center', valign: 'middle'},\n            {title: '最近执行时间',field:'execAt',visible:true,align:'center',valign:'middle'},\n            {title: '最近执行结果',field:'execResult',visible:true,align:'center',valign:'middle'},\n            {title: '状态',field:'disabled',visible:true,align:'center',valign:'middle',formatter:function(data,row){\n                var button = '';\n                console.log(data);\n                if(!data) {\n                    button += '<div class=\"toggle-switch\"> <input id=\"ts'+row.id+'\" type=\"checkbox\" hidden=\"hidden\" checked=\"checked\" onclick=\"Task.updateDisalbed('+row.id+','+!row.disabled+')\"> <label for=\"ts'+row.id+'\" class=\"ts-helper\"></label> </div>';\n                }else{\n                    button += '<div class=\"toggle-switch\"> <input id=\"ts'+row.id+'\" type=\"checkbox\" hidden=\"hidden\" onclick=\"Task.updateDisalbed('+row.id+','+!row.disabled+')\"\"> <label for=\"ts'+row.id+'\" class=\"ts-helper\"></label> </div>';\n                }\n                return button;\n            }},\n\n        {title: '操作', visible: true, align: 'center', valign: 'middle',\n            formatter:function(data,row){\n                var button = '';\n                button += '<button type=\"button\" class=\"btn bgm-lightgreen btn-icon waves-effect waves-circle\" onclick=\"Task.viewLog('+row.id+')\" title=\"查看日志\"><span class=\"zmdi zmdi-menu\"></span></button>';\n                button += '<button type=\"button\" class=\"btn btn-danger btn-icon waves-effect waves-circle\" onclick=\"Task.delete('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n                return button\n            }}\n    ];\n};\n\nTask.enable = function(id){\n    console.log(id);\n    Task.updateDisalbed(id,false)\n}\nTask.disable = function(id){\n    console.log(id);\n    Task.updateDisalbed(id,true);\n}\nTask.updateDisalbed=function(id,disabled){\n    var url = Feng.ctxPath;\n    console.log(disabled);\n    if(disabled){\n        //禁用\n        url += '/task/disable';\n    }else{\n        //启用\n        url += '/task/enable';\n    }\n    var ajax = new $ax(url, function (data) {\n        Feng.success(disabled?'禁用成功':'启用成功');\n        Task.table.refresh();\n    }, function (data) {\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(\"taskId\",id);\n    ajax.start();\n}\n\n/**\n * 检查是否选中\n */\nTask.check = function () {\n    var selected = $('#' + this.id).bootstrapTable('getSelections');\n    if(selected.length == 0){\n        Feng.info(\"请先选中表格中的某一记录！\");\n        return false;\n    }else{\n        Task.seItem = selected[0];\n        return true;\n    }\n};\n\n/**\n * 点击添加系统参数\n */\nTask.openAddTask = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加系统参数',\n        area: ['65%', '370px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/task/task_add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 打开查看系统参数详情\n */\nTask.openTaskDetail = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '系统参数详情',\n            area: ['65%', '400px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/task/task_update/' + id\n        });\n        this.layerIndex = index;\n};\n\nTask.viewLog = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '查看任务日志',\n            area: ['75%', '75%'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/task/viewLog/' + id\n        });\n        this.layerIndex = index;\n\n};\n/**\n * 删除系统参数\n */\nTask.delete = function (id) {\n    var operation = function() {\n        var ajax = new $ax(Feng.ctxPath + \"/task/delete\", function (data) {\n            Feng.success(\"删除成功!\");\n            Task.table.refresh();\n        }, function (data) {\n            Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n        });\n        ajax.set(\"taskId\", id);\n        ajax.start();\n    };\n\n    Feng.confirm(\"确认删除该记录?\", operation);\n};\n\n/**\n * 查询系统参数列表\n */\nTask.search = function () {\n    var queryData = {};\n    queryData['condition'] = $(\"#name\").val();\n    Task.table.refresh({query: queryData});\n};\n\n$(function () {\n    var defaultColunms = Task.initColumn();\n    var table = new BSTable(Task.id, \"/task/list\", defaultColunms);\n    table.setPaginationType(\"client\");\n    Task.table = table.init();\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/task/task_info.js",
    "content": "/**\n * 初始化系统参数详情对话框\n */\nvar TaskInfoDlg = {\n    taskInfoData : {}\n};\n\n/**\n * 清除数据\n */\nTaskInfoDlg.clearData = function() {\n    this.taskInfoData = {};\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nTaskInfoDlg.set = function(key, val) {\n    this.taskInfoData[key] = (typeof val == \"undefined\") ? $(\"#\" + key).val() : val;\n    return this;\n}\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nTaskInfoDlg.get = function(key) {\n    return $(\"#\" + key).val();\n}\n\n/**\n * 关闭此对话框\n */\nTaskInfoDlg.close = function() {\n    parent.layer.close(window.parent.Task.layerIndex);\n}\n\n/**\n * 收集数据\n */\nTaskInfoDlg.collectData = function() {\n    this\n    .set('id')\n    .set('name')\n    .set('jobClass')\n    .set('data')\n    .set('note')\n    .set('cron');\n}\n\n/**\n * 提交添加\n */\nTaskInfoDlg.addSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/task/add\", function(data){\n        Feng.success(\"添加成功!\");\n        window.parent.Task.table.refresh();\n        TaskInfoDlg.close();\n    },function(data){\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.taskInfoData);\n    ajax.start();\n}\n\n/**\n * 提交修改\n */\nTaskInfoDlg.editSubmit = function() {\n\n    this.clearData();\n    this.collectData();\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/task/update\", function(data){\n        Feng.success(\"修改成功!\");\n        window.parent.Task.table.refresh();\n        TaskInfoDlg.close();\n    },function(data){\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.taskInfoData);\n    ajax.start();\n}\n\n$(function() {\n\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/task/task_log.js",
    "content": "/**\n * 系统参数管理初始化\n */\nvar TaskLog = {\n    id: \"TaskLogTable\",\t//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1\n};\n\n/**\n * 初始化表格的列\n */\nTaskLog.initColumn = function () {\n    return [\n        {field: 'selectItem', radio: true,visible:false},\n        {title: '执行任务', field: 'name', visible: true, align: 'center', valign: 'middle'},\n        {title: '执行日期', field: 'execAt', visible: true, align: 'center', valign: 'middle'},\n        {\n            title: '执行结果',field: 'execSuccess',visible: true,align: 'center',valign: 'middle',\n            formatter: function (data, row) {\n                if (data == 1) {\n                    return \"执行成功\";\n                }\n                return \"执行失败\";\n            }\n        },\n        {title: '异常信息', field: 'jobException', visible: true, align: 'center', valign: 'middle'}\n\n    ];\n};\n\n$(function () {\n    var defaultColunms = TaskLog.initColumn();\n    var table = new BSTable(TaskLog.id, \"/task/logList/\"+taskId, defaultColunms);\n    table.setPaginationType(\"server\");\n    TaskLog.table = table.init();\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/user/user.js",
    "content": "/**\n * 系统管理--用户管理的单例对象\n */\nvar MgrUser = {\n    id: \"managerTable\",//表格id\n    seItem: null,\t\t//选中的条目\n    table: null,\n    layerIndex: -1,\n    deptid:0\n};\n\n/**\n * 初始化表格的列\n */\nMgrUser.initColumn = function () {\n    var columns = [\n        {field: 'selectItem', checkbox: true},\n        {title: 'ID', field: 'id', visible: false, align: 'center', valign: 'middle'},\n        {title: '账号', field: 'account', align: 'center', valign: 'middle', sortable: true,formatter:function(data,row){\n            return '<a href=\"javascript:;\" onclick=\"MgrUser.openChangeUser('+row.id+')\">'+row.account+'</a>';\n        }},\n        {title: '姓名', field: 'name', align: 'center', valign: 'middle', sortable: true},\n        {title: '性别', field: 'sexName', align: 'center', valign: 'middle', sortable: true},\n        {title: '角色', field: 'roleName', align: 'center', valign: 'middle', sortable: true,formatter:function(data,row){\n            if(data && data.length>5){\n                return '<i class=\"zmdi zmdi-more zmdi-hc-fw\" title=\"'+data+'\"></i>';\n            }\n            return data;\n        }},\n        {title: '部门', field: 'deptName', align: 'center', valign: 'middle', sortable: true},\n        {title: '邮箱', field: 'email', align: 'center', valign: 'middle', sortable: true},\n        {title: '电话', field: 'phone', align: 'center', valign: 'middle', sortable: true},\n        {title: '创建时间', field: 'createTime', align: 'center', valign: 'middle', sortable: true},\n        {title: '状态',field:'status',visible:true,align:'center',valign:'middle',formatter:function(data,row){\n\n            if(data == 3){\n                return '已删除';\n            }\n            if(data == 1) {\n                return '<div class=\"toggle-switch\"> <input id=\"ts'+row.id+'\" type=\"checkbox\" hidden=\"hidden\" checked=\"checked\" onclick=\"MgrUser.freezeAccount('+row.id+')\"> <label for=\"ts'+row.id+'\" class=\"ts-helper\"></label> </div>';\n            }\n            if(data == 2){\n                return   '<div class=\"toggle-switch\"> <input id=\"ts'+row.id+'\" type=\"checkbox\" hidden=\"hidden\" onclick=\"MgrUser.unfreeze('+row.id+')\"\"> <label for=\"ts'+row.id+'\" class=\"ts-helper\" style=\"font-size:10px;\"></label> </div>';\n            }\n        }},\n        {title: '操作',formatter:function(data,row){\n            return '<button type=\"button\" class=\"btn bgm-lightblue btn-icon waves-effect waves-circle\" onclick=\"MgrUser.resetPwd('+row.id+')\" title=\"重置密码\"><span class=\"zmdi zmdi-lock-open\"></span></button>'\n                +  '<button type=\"button\" class=\"btn bgm-lightgreen btn-icon waves-effect waves-circle\" onclick=\"MgrUser.roleAssign('+row.id+')\" title=\"分配角色\"><span class=\"zmdi zmdi-assignment-account\"></span></button>'\n            + '<button type=\"button\" class=\"btn btn-danger btn-icon waves-effect waves-circle\" onclick=\"MgrUser.delMgrUser('+row.id+')\" title=\"删除\"><span class=\"zmdi zmdi-delete\"></span></button>';\n\n        }}\n    ];\n    return columns;\n};\n\n/**\n * 检查是否选中\n */\nMgrUser.check = function () {\n    var selected = $('#' + this.id).bootstrapTable('getSelections');\n    if (selected.length == 0) {\n        Feng.info(\"请先选中表格中的某一记录！\");\n        return false;\n    } else {\n        MgrUser.seItem = selected[0];\n        return true;\n    }\n};\n\n/**\n * 点击添加管理员\n */\nMgrUser.openAddMgr = function () {\n    var index = layer.open({\n        type: 2,\n        title: '添加管理员',\n        area: ['70%', '500px'], //宽高\n        fix: false, //不固定\n        maxmin: true,\n        content: Feng.ctxPath + '/mgr/user_add'\n    });\n    this.layerIndex = index;\n};\n\n/**\n * 点击修改按钮时\n * @param userId 管理员id\n */\nMgrUser.openChangeUser = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '编辑管理员',\n            area: ['800px', '380px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/mgr/user_edit/' + id\n        });\n        this.layerIndex = index;\n};\n\n/**\n * 点击角色分配\n * @param\n */\nMgrUser.roleAssign = function (id) {\n        var index = layer.open({\n            type: 2,\n            title: '角色分配',\n            area: ['300px', '400px'], //宽高\n            fix: false, //不固定\n            maxmin: true,\n            content: Feng.ctxPath + '/mgr/role_assign/' + id\n        });\n        this.layerIndex = index;\n};\n\n/**\n * 删除用户\n */\nMgrUser.delMgrUser = function (id) {\n    var operation = function(){\n        var ajax = new $ax(Feng.ctxPath + \"/mgr/delete\", function () {\n            Feng.success(\"删除成功!\");\n            MgrUser.table.refresh();\n        }, function (data) {\n            Feng.error(\"删除失败!\" + data.responseJSON.message + \"!\");\n        });\n        ajax.set(\"userId\", id);\n        ajax.start();\n    };\n\n    Feng.confirm(\"是否删除该账户?\",operation,\"删除后该用户将无法恢复，请谨慎操作\");\n\n};\n\n/**\n * 冻结用户账户\n * @param userId\n */\nMgrUser.freezeAccount = function (id) {\n    console.log(id)\n        var ajax = new $ax(Feng.ctxPath + \"/mgr/freeze\", function (data) {\n            Feng.success(\"冻结成功!\");\n            MgrUser.table.refresh();\n        }, function (data) {\n            Feng.error(\"冻结失败!\" + data.responseJSON.message + \"!\");\n        });\n        ajax.set(\"userId\", id);\n        ajax.start();\n};\n\n/**\n * 解除冻结用户账户\n * @param userId\n */\nMgrUser.unfreeze = function (id) {\n\n    console.log(id)\n        var ajax = new $ax(Feng.ctxPath + \"/mgr/unfreeze\", function (data) {\n            Feng.success(\"解除冻结成功!\");\n            MgrUser.table.refresh();\n        }, function (data) {\n            Feng.error(\"解除冻结失败!\");\n        });\n        ajax.set(\"userId\", id);\n        ajax.start();\n}\n\n/**\n * 重置密码\n */\nMgrUser.resetPwd = function (id) {\n        Feng.confirm('是否重置密码为111111？', function () {\n            var ajax = new $ax(Feng.ctxPath + \"/mgr/reset\", function (data) {\n                Feng.success(\"重置密码成功!\");\n            }, function (data) {\n                Feng.error(\"重置密码失败!\");\n            });\n            ajax.set(\"userId\", id);\n            ajax.start();\n        });\n};\n\nMgrUser.resetSearch = function () {\n    $(\"#name\").val(\"\");\n    $(\"#beginTime\").val(\"\");\n    $(\"#endTime\").val(\"\");\n    MgrUser.search();\n}\n\nMgrUser.search = function () {\n    var queryData = {};\n\n    queryData['deptid'] = MgrUser.deptid;\n    queryData['name'] = $(\"#name\").val();\n    queryData['beginTime'] = $(\"#beginTime\").val();\n    queryData['endTime'] = $(\"#endTime\").val();\n\n    MgrUser.table.refresh({query: queryData});\n}\n\nMgrUser.onClickDept = function (e, treeId, treeNode) {\n    MgrUser.deptid = treeNode.id;\n    MgrUser.search();\n};\n\n$(function () {\n    var defaultColunms = MgrUser.initColumn();\n    var table = new BSTable(\"managerTable\", \"/mgr/list\", defaultColunms);\n    table.setPaginationType(\"client\");\n    MgrUser.table = table.init();\n    var ztree = new $ZTree(\"deptTree\", \"/dept/tree\");\n    ztree.bindOnClick(MgrUser.onClickDept);\n    ztree.init();\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/modular/system/user/user_info.js",
    "content": "/**\n * 用户详情对话框（可用于添加和修改对话框）\n */\nvar UserInfoDlg = {\n    userInfoData: {},\n    validateFields: {\n        account: {\n            validators: {\n                notEmpty: {\n                    message: '账户不能为空'\n                }\n            }\n        },\n        name: {\n            validators: {\n                notEmpty: {\n                    message: '姓名不能为空'\n                }\n            }\n        },\n        citySel: {\n            validators: {\n                notEmpty: {\n                    message: '部门不能为空'\n                }\n            }\n        },\n        password: {\n            validators: {\n                notEmpty: {\n                    message: '密码不能为空'\n                },\n                identical: {\n                    field: 'rePassword',\n                    message: '两次密码不一致'\n                },\n            }\n        },\n        rePassword: {\n            validators: {\n                notEmpty: {\n                    message: '密码不能为空'\n                },\n                identical: {\n                    field: 'password',\n                    message: '两次密码不一致'\n                },\n            }\n        }\n    }\n};\n\n/**\n * 清除数据\n */\nUserInfoDlg.clearData = function () {\n    this.userInfoData = {};\n};\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nUserInfoDlg.set = function (key, val) {\n    this.userInfoData[key] = (typeof value == \"undefined\") ? $(\"#\" + key).val() : value;\n    return this;\n};\n\n/**\n * 设置对话框中的数据\n *\n * @param key 数据的名称\n * @param val 数据的具体值\n */\nUserInfoDlg.get = function (key) {\n    return $(\"#\" + key).val();\n};\n\n/**\n * 关闭此对话框\n */\nUserInfoDlg.close = function () {\n    parent.layer.close(window.parent.MgrUser.layerIndex);\n};\n\n/**\n * 点击部门input框时\n *\n * @param e\n * @param treeId\n * @param treeNode\n * @returns\n */\nUserInfoDlg.onClickDept = function (e, treeId, treeNode) {\n    $(\"#citySel\").attr(\"value\", instance.getSelectedVal());\n    $(\"#deptid\").attr(\"value\", treeNode.id);\n};\n\n/**\n * 显示部门选择的树\n *\n * @returns\n */\nUserInfoDlg.showDeptSelectTree = function () {\n    var cityObj = $(\"#citySel\");\n    var cityOffset = $(\"#citySel\").offset();\n    $(\"#menuContent\").css({\n        left: cityOffset.left + \"px\",\n        top: cityOffset.top + cityObj.outerHeight() + \"px\"\n    }).slideDown(\"fast\");\n\n    $(\"body\").bind(\"mousedown\", onBodyDown);\n};\n\n/**\n * 显示用户详情部门选择的树\n *\n * @returns\n */\nUserInfoDlg.showInfoDeptSelectTree = function () {\n    var cityObj = $(\"#citySel\");\n    var cityPosition = $(\"#citySel\").position();\n    $(\"#menuContent\").css({\n        left: cityPosition.left + \"px\",\n        top: cityPosition.top + cityObj.outerHeight() + \"px\"\n    }).slideDown(\"fast\");\n\n    $(\"body\").bind(\"mousedown\", onBodyDown);\n};\n\n/**\n * 隐藏部门选择的树\n */\nUserInfoDlg.hideDeptSelectTree = function () {\n    $(\"#menuContent\").fadeOut(\"fast\");\n    $(\"body\").unbind(\"mousedown\", onBodyDown);// mousedown当鼠标按下就可以触发，不用弹起\n};\n\n\n\n/**\n * 收集数据\n */\nUserInfoDlg.collectData = function () {\n    this.set('id').set('account').set('sex').set('password').set('avatar')\n        .set('email').set('name').set('birthday').set('rePassword').set('deptid').set('phone');\n};\n\n/**\n * 验证两个密码是否一致\n */\nUserInfoDlg.validatePwd = function () {\n    var password = this.get(\"password\");\n    var rePassword = this.get(\"rePassword\");\n    if (password == rePassword) {\n        return true;\n    } else {\n        return false;\n    }\n};\n\n/**\n * 验证数据是否为空\n */\nUserInfoDlg.validate = function () {\n    $('#userInfoForm').data(\"bootstrapValidator\").resetForm();\n    $('#userInfoForm').bootstrapValidator('validate');\n    return $(\"#userInfoForm\").data('bootstrapValidator').isValid();\n};\n\n/**\n * 提交添加用户\n */\nUserInfoDlg.addSubmit = function () {\n\n    this.clearData();\n    this.collectData();\n\n    if (!this.validate()) {\n        return;\n    }\n\n    if (!this.validatePwd()) {\n        Feng.error(\"两次密码输入不一致\");\n        return;\n    }\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/mgr/add\", function (data) {\n        Feng.success(\"添加成功!\");\n        window.parent.MgrUser.table.refresh();\n        UserInfoDlg.close();\n    }, function (data) {\n        Feng.error(\"添加失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.userInfoData);\n    ajax.start();\n};\n\n/**\n * 提交修改\n */\nUserInfoDlg.editSubmit = function () {\n\n    this.clearData();\n    this.collectData();\n\n    if (!this.validate()) {\n        return;\n    }\n\n    //提交信息\n    var ajax = new $ax(Feng.ctxPath + \"/mgr/edit\", function (data) {\n        Feng.success(\"修改成功!\");\n        if (window.parent.MgrUser != undefined) {\n            window.parent.MgrUser.table.refresh();\n            UserInfoDlg.close();\n        }\n    }, function (data) {\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(this.userInfoData);\n    ajax.start();\n};\n\n/**\n * 修改密码\n */\nUserInfoDlg.chPwd = function () {\n    var ajax = new $ax(Feng.ctxPath + \"/mgr/changePwd\", function (data) {\n        Feng.success(\"修改成功!\");\n    }, function (data) {\n        Feng.error(\"修改失败!\" + data.responseJSON.message + \"!\");\n    });\n    ajax.set(\"oldPwd\");\n    ajax.set(\"newPwd\");\n    ajax.set(\"rePwd\");\n    ajax.start();\n\n};\n\nfunction onBodyDown(event) {\n    if (!(  event.target.id == \"menuContent\" || $(\n            event.target).parents(\"#menuContent\").length > 0)) {\n        UserInfoDlg.hideDeptSelectTree();\n    }\n}\n\nvar instance = null;\nvar eduOrgInstance = null;\n$(function () {\n    Feng.initValidator(\"userInfoForm\", UserInfoDlg.validateFields);\n\n    var ztree = new $ZTree(\"treeDemo\", \"/dept/tree\");\n    ztree.bindOnClick(UserInfoDlg.onClickDept);\n    ztree.init();\n    instance = ztree;\n\n    \n    //初始化性别选项\n    $(\"#sex\").val($(\"#sexValue\").val());\n\n    // 初始化头像上传\n    var avatarUp = new $WebUpload(\"avatar\");\n    avatarUp.setUploadBarId(\"progressBar\");\n    avatarUp.init();\n\n\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bootgrid/.bower.json",
    "content": "{\n  \"name\": \"jquery.bootgrid\",\n  \"description\": \"Nice, sleek and intuitive. A grid control especially designed for bootstrap.\",\n  \"keywords\": [\n    \"grid\",\n    \"table\",\n    \"data\",\n    \"sorting\",\n    \"filtering\",\n    \"UI\",\n    \"component\",\n    \"HTML5\",\n    \"accessibility\",\n    \"bootstrap\"\n  ],\n  \"version\": \"1.3.1\",\n  \"authors\": [\n    {\n      \"name\": \"Rafael Staib\",\n      \"email\": \"me@rafaelstaib.com\",\n      \"url\": \"http://www.rafaelstaib.com\"\n    }\n  ],\n  \"homepage\": \"http://www.jquery-bootgrid.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/rstaib/jquery-bootgrid.git\"\n  },\n  \"license\": \"MIT\",\n  \"main\": [\n    \"dist/jquery.bootgrid.js\",\n    \"dist/jquery.bootgrid.css\"\n  ],\n  \"ignore\": [\n    \"build\",\n    \"demo\",\n    \"dist/*.nupkg\",\n    \"dist/*.zip\",\n    \"docs\",\n    \"lib\",\n    \"test\",\n    \"*.nuspec\",\n    \".gitattributes\",\n    \".gitignore\",\n    \".travis.yml\",\n    \"bootgrid.jquery.json\",\n    \"Gruntfile.js\",\n    \"package.json\"\n  ],\n  \"dependencies\": {\n    \"jquery\": \">=1.9.0\",\n    \"bootstrap\": \">=3.1.1\"\n  },\n  \"_release\": \"1.3.1\",\n  \"_resolution\": {\n    \"type\": \"version\",\n    \"tag\": \"1.3.1\",\n    \"commit\": \"ada3cee7feb3259d90f8cbab6d630214cfa16b5e\"\n  },\n  \"_source\": \"git://github.com/rstaib/jquery-bootgrid.git\",\n  \"_target\": \"~1.3.1\",\n  \"_originalSource\": \"jquery.bootgrid\",\n  \"_direct\": true\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bootgrid/.npmignore",
    "content": "build\ndemo\ndist/*.nupkg\ndist/*.zip\ndocs\nlib\n*.nuspec\ntest\n.gitattributes\n.gitignore\n.travis.yml\nbootgrid.jquery.json\nbower.json\nGruntfile.js"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bootgrid/jquery.bootgrid.css",
    "content": "/*! \n * jQuery Bootgrid v1.3.1 - 09/11/2015\n * Copyright (c) 2014-2015 Rafael Staib (http://www.jquery-bootgrid.com)\n * Licensed under MIT http://www.opensource.org/licenses/MIT\n */\n.bootgrid-header,\n.bootgrid-footer {\n  margin: 15px 0;\n}\n.bootgrid-header a,\n.bootgrid-footer a {\n  outline: 0;\n}\n.bootgrid-header .search,\n.bootgrid-footer .search {\n  display: inline-block;\n  margin: 0 20px 0 0;\n  vertical-align: middle;\n  width: 180px;\n}\n.bootgrid-header .search .glyphicon,\n.bootgrid-footer .search .glyphicon {\n  top: 0;\n}\n.bootgrid-header .search .fa,\n.bootgrid-footer .search .fa {\n  display: table-cell;\n}\n.bootgrid-header .search.search-field::-ms-clear,\n.bootgrid-footer .search.search-field::-ms-clear,\n.bootgrid-header .search .search-field::-ms-clear,\n.bootgrid-footer .search .search-field::-ms-clear {\n  display: none;\n}\n.bootgrid-header .pagination,\n.bootgrid-footer .pagination {\n  margin: 0 !important;\n}\n.bootgrid-header .actionBar,\n.bootgrid-footer .infoBar {\n  text-align: right;\n}\n.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu,\n.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu {\n  text-align: left;\n}\n.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu .dropdown-item,\n.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu .dropdown-item {\n  cursor: pointer;\n  display: block;\n  margin: 0;\n  padding: 3px 20px;\n  white-space: nowrap;\n}\n.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu .dropdown-item:hover,\n.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu .dropdown-item:hover,\n.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu .dropdown-item:focus,\n.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu .dropdown-item:focus {\n  color: #262626;\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu .dropdown-item.dropdown-item-checkbox,\n.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu .dropdown-item.dropdown-item-checkbox,\n.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu .dropdown-item .dropdown-item-checkbox,\n.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu .dropdown-item .dropdown-item-checkbox {\n  margin: 0 2px 4px 0;\n  vertical-align: middle;\n}\n.bootgrid-header .actionBar .btn-group > .btn-group .dropdown-menu .dropdown-item.disabled,\n.bootgrid-footer .infoBar .btn-group > .btn-group .dropdown-menu .dropdown-item.disabled {\n  cursor: not-allowed;\n}\n.bootgrid-table {\n  table-layout: fixed;\n}\n.bootgrid-table a {\n  outline: 0;\n}\n.bootgrid-table th > .column-header-anchor {\n  color: #333;\n  cursor: not-allowed;\n  display: block;\n  position: relative;\n  text-decoration: none;\n}\n.bootgrid-table th > .column-header-anchor.sortable {\n  cursor: pointer;\n}\n.bootgrid-table th > .column-header-anchor > .text {\n  display: block;\n  margin: 0 16px 0 0;\n  overflow: hidden;\n  -ms-text-overflow: ellipsis;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.bootgrid-table th > .column-header-anchor > .icon {\n  display: block;\n  position: absolute;\n  right: 0;\n  top: 2px;\n}\n.bootgrid-table th:hover,\n.bootgrid-table th:active {\n  background: #fafafa;\n}\n.bootgrid-table td {\n  overflow: hidden;\n  -ms-text-overflow: ellipsis;\n  -o-text-overflow: ellipsis;\n  text-overflow: ellipsis;\n  white-space: nowrap;\n}\n.bootgrid-table td.loading,\n.bootgrid-table td.no-results {\n  background: #fff;\n  text-align: center;\n}\n.bootgrid-table th.select-cell,\n.bootgrid-table td.select-cell {\n  text-align: center;\n  width: 30px;\n}\n.bootgrid-table th.select-cell .select-box,\n.bootgrid-table td.select-cell .select-box {\n  margin: 0;\n  outline: 0;\n}\n.table-responsive .bootgrid-table {\n  table-layout: inherit !important;\n}\n.table-responsive .bootgrid-table th > .column-header-anchor > .text {\n  overflow: inherit !important;\n  -ms-text-overflow: inherit !important;\n  -o-text-overflow: inherit !important;\n  text-overflow: inherit !important;\n  white-space: inherit !important;\n}\n.table-responsive .bootgrid-table td {\n  overflow: inherit !important;\n  -ms-text-overflow: inherit !important;\n  -o-text-overflow: inherit !important;\n  text-overflow: inherit !important;\n  white-space: inherit !important;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bootgrid/jquery.bootgrid.fa.js",
    "content": "/*! \n * jQuery Bootgrid v1.3.1 - 09/11/2015\n * Copyright (c) 2014-2015 Rafael Staib (http://www.jquery-bootgrid.com)\n * Licensed under MIT http://www.opensource.org/licenses/MIT\n */\n;(function ($, window, undefined)\n{\n    /*jshint validthis: true */\n    \"use strict\";\n\n    $.extend($.fn.bootgrid.Constructor.defaults.css, {\n        icon: \"icon fa\",\n        iconColumns: \"fa-th-list\",\n        iconDown: \"fa-sort-desc\",\n        iconRefresh: \"fa-refresh\",\n        iconSearch: \"fa-search\",\n        iconUp: \"fa-sort-asc\"\n});\n})(jQuery, window);"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bootgrid/jquery.bootgrid.js",
    "content": "/*! \n * jQuery Bootgrid v1.3.1 - 09/11/2015\n * Copyright (c) 2014-2015 Rafael Staib (http://www.jquery-bootgrid.com)\n * Licensed under MIT http://www.opensource.org/licenses/MIT\n */\n;(function ($, window, undefined)\n{\n    /*jshint validthis: true */\n    \"use strict\";\n\n    // GRID INTERNAL FIELDS\n    // ====================\n\n    var namespace = \".rs.jquery.bootgrid\";\n\n    // GRID INTERNAL FUNCTIONS\n    // =====================\n\n    function appendRow(row)\n    {\n        var that = this;\n\n        function exists(item)\n        {\n            return that.identifier && item[that.identifier] === row[that.identifier];\n        }\n\n        if (!this.rows.contains(exists))\n        {\n            this.rows.push(row);\n            return true;\n        }\n\n        return false;\n    }\n\n    function findFooterAndHeaderItems(selector)\n    {\n        var footer = (this.footer) ? this.footer.find(selector) : $(),\n            header = (this.header) ? this.header.find(selector) : $();\n        return $.merge(footer, header);\n    }\n\n    function getParams(context)\n    {\n        return (context) ? $.extend({}, this.cachedParams, { ctx: context }) :\n            this.cachedParams;\n    }\n\n    function getRequest()\n    {\n        var request = {\n                current: this.current,\n                rowCount: this.rowCount,\n                sort: this.sortDictionary,\n                searchPhrase: this.searchPhrase\n            },\n            post = this.options.post;\n\n        post = ($.isFunction(post)) ? post() : post;\n        return this.options.requestHandler($.extend(true, request, post));\n    }\n\n    function getCssSelector(css)\n    {\n        return \".\" + $.trim(css).replace(/\\s+/gm, \".\");\n    }\n\n    function getUrl()\n    {\n        var url = this.options.url;\n        return ($.isFunction(url)) ? url() : url;\n    }\n\n    function init()\n    {\n        this.element.trigger(\"initialize\" + namespace);\n\n        loadColumns.call(this); // Loads columns from HTML thead tag\n        this.selection = this.options.selection && this.identifier != null;\n        loadRows.call(this); // Loads rows from HTML tbody tag if ajax is false\n        prepareTable.call(this);\n        renderTableHeader.call(this);\n        renderSearchField.call(this);\n        renderActions.call(this);\n        loadData.call(this);\n\n        this.element.trigger(\"initialized\" + namespace);\n    }\n\n    function highlightAppendedRows(rows)\n    {\n        if (this.options.highlightRows)\n        {\n            // todo: implement\n        }\n    }\n\n    function isVisible(column)\n    {\n        return column.visible;\n    }\n\n    function loadColumns()\n    {\n        var that = this,\n            firstHeadRow = this.element.find(\"thead > tr\").first(),\n            sorted = false;\n\n        /*jshint -W018*/\n        firstHeadRow.children().each(function ()\n        {\n            var $this = $(this),\n                data = $this.data(),\n                column = {\n                    id: data.columnId,\n                    identifier: that.identifier == null && data.identifier || false,\n                    converter: that.options.converters[data.converter || data.type] || that.options.converters[\"string\"],\n                    text: $this.text(),\n                    align: data.align || \"left\",\n                    headerAlign: data.headerAlign || \"left\",\n                    cssClass: data.cssClass || \"\",\n                    headerCssClass: data.headerCssClass || \"\",\n                    formatter: that.options.formatters[data.formatter] || null,\n                    order: (!sorted && (data.order === \"asc\" || data.order === \"desc\")) ? data.order : null,\n                    searchable: !(data.searchable === false), // default: true\n                    sortable: !(data.sortable === false), // default: true\n                    visible: !(data.visible === false), // default: true\n                    visibleInSelection: !(data.visibleInSelection === false), // default: true\n                    width: ($.isNumeric(data.width)) ? data.width + \"px\" : \n                        (typeof(data.width) === \"string\") ? data.width : null\n                };\n            that.columns.push(column);\n            if (column.order != null)\n            {\n                that.sortDictionary[column.id] = column.order;\n            }\n\n            // Prevents multiple identifiers\n            if (column.identifier)\n            {\n                that.identifier = column.id;\n                that.converter = column.converter;\n            }\n\n            // ensures that only the first order will be applied in case of multi sorting is disabled\n            if (!that.options.multiSort && column.order !== null)\n            {\n                sorted = true;\n            }\n        });\n        /*jshint +W018*/\n    }\n\n    /*\n    response = {\n        current: 1,\n        rowCount: 10,\n        rows: [{}, {}],\n        sort: [{ \"columnId\": \"asc\" }],\n        total: 101\n    }\n    */\n\n    function loadData()\n    {\n        var that = this;\n\n        this.element._bgBusyAria(true).trigger(\"load\" + namespace);\n        showLoading.call(this);\n\n        function containsPhrase(row)\n        {\n            var column,\n                searchPattern = new RegExp(that.searchPhrase, (that.options.caseSensitive) ? \"g\" : \"gi\");\n\n            for (var i = 0; i < that.columns.length; i++)\n            {\n                column = that.columns[i];\n                if (column.searchable && column.visible &&\n                    column.converter.to(row[column.id]).search(searchPattern) > -1)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        function update(rows, total)\n        {\n            that.currentRows = rows;\n            setTotals.call(that, total);\n\n            if (!that.options.keepSelection)\n            {\n                that.selectedRows = [];\n            }\n\n            renderRows.call(that, rows);\n            renderInfos.call(that);\n            renderPagination.call(that);\n\n            that.element._bgBusyAria(false).trigger(\"loaded\" + namespace);\n        }\n\n        if (this.options.ajax)\n        {\n            var request = getRequest.call(this),\n                url = getUrl.call(this);\n\n            if (url == null || typeof url !== \"string\" || url.length === 0)\n            {\n                throw new Error(\"Url setting must be a none empty string or a function that returns one.\");\n            }\n\n            // aborts the previous ajax request if not already finished or failed\n            if (this.xqr)\n            {\n                this.xqr.abort();\n            }\n\n            var settings = {\n                url: url,\n                data: request,\n                success: function(response)\n                {\n                    that.xqr = null;\n\n                    if (typeof (response) === \"string\")\n                    {\n                        response = $.parseJSON(response);\n                    }\n\n                    response = that.options.responseHandler(response);\n\n                    that.current = response.current;\n                    update(response.rows, response.total);\n                },\n                error: function (jqXHR, textStatus, errorThrown)\n                {\n                    that.xqr = null;\n\n                    if (textStatus !== \"abort\")\n                    {\n                        renderNoResultsRow.call(that); // overrides loading mask\n                        that.element._bgBusyAria(false).trigger(\"loaded\" + namespace);\n                    }\n                }\n            };\n            settings = $.extend(this.options.ajaxSettings, settings);\n\n            this.xqr = $.ajax(settings);\n        }\n        else\n        {\n            var rows = (this.searchPhrase.length > 0) ? this.rows.where(containsPhrase) : this.rows,\n                total = rows.length;\n            if (this.rowCount !== -1)\n            {\n                rows = rows.page(this.current, this.rowCount);\n            }\n\n            // todo: improve the following comment\n            // setTimeout decouples the initialization so that adding event handlers happens before\n            window.setTimeout(function () { update(rows, total); }, 10);\n        }\n    }\n\n    function loadRows()\n    {\n        if (!this.options.ajax)\n        {\n            var that = this,\n                rows = this.element.find(\"tbody > tr\");\n\n            rows.each(function ()\n            {\n                var $this = $(this),\n                    cells = $this.children(\"td\"),\n                    row = {};\n\n                $.each(that.columns, function (i, column)\n                {\n                    row[column.id] = column.converter.from(cells.eq(i).text());\n                });\n\n                appendRow.call(that, row);\n            });\n\n            setTotals.call(this, this.rows.length);\n            sortRows.call(this);\n        }\n    }\n\n    function setTotals(total)\n    {\n        this.total = total;\n        this.totalPages = (this.rowCount === -1) ? 1 :\n            Math.ceil(this.total / this.rowCount);\n    }\n\n    function prepareTable()\n    {\n        var tpl = this.options.templates,\n            wrapper = (this.element.parent().hasClass(this.options.css.responsiveTable)) ?\n                this.element.parent() : this.element;\n\n        this.element.addClass(this.options.css.table);\n\n        // checks whether there is an tbody element; otherwise creates one\n        if (this.element.children(\"tbody\").length === 0)\n        {\n            this.element.append(tpl.body);\n        }\n\n        if (this.options.navigation & 1)\n        {\n            this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + \"-header\" })));\n            wrapper.before(this.header);\n        }\n\n        if (this.options.navigation & 2)\n        {\n            this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + \"-footer\" })));\n            wrapper.after(this.footer);\n        }\n    }\n\n    function renderActions()\n    {\n        if (this.options.navigation !== 0)\n        {\n            var css = this.options.css,\n                selector = getCssSelector(css.actions),\n                actionItems = findFooterAndHeaderItems.call(this, selector);\n\n            if (actionItems.length > 0)\n            {\n                var that = this,\n                    tpl = this.options.templates,\n                    actions = $(tpl.actions.resolve(getParams.call(this)));\n\n                // Refresh Button\n                if (this.options.ajax)\n                {\n                    var refreshIcon = tpl.icon.resolve(getParams.call(this, { iconCss: css.iconRefresh })),\n                        refresh = $(tpl.actionButton.resolve(getParams.call(this,\n                        { content: refreshIcon, text: this.options.labels.refresh })))\n                            .on(\"click\" + namespace, function (e)\n                            {\n                                // todo: prevent multiple fast clicks (fast click detection)\n                                e.stopPropagation();\n                                that.current = 1;\n                                loadData.call(that);\n                            });\n                    actions.append(refresh);\n                }\n\n                // Row count selection\n                renderRowCountSelection.call(this, actions);\n\n                // Column selection\n                renderColumnSelection.call(this, actions);\n\n                replacePlaceHolder.call(this, actionItems, actions);\n            }\n        }\n    }\n\n    function renderColumnSelection(actions)\n    {\n        if (this.options.columnSelection && this.columns.length > 1)\n        {\n            var that = this,\n                css = this.options.css,\n                tpl = this.options.templates,\n                icon = tpl.icon.resolve(getParams.call(this, { iconCss: css.iconColumns })),\n                dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: icon }))),\n                selector = getCssSelector(css.dropDownItem),\n                checkboxSelector = getCssSelector(css.dropDownItemCheckbox),\n                itemsSelector = getCssSelector(css.dropDownMenuItems);\n\n            $.each(this.columns, function (i, column)\n            {\n                if (column.visibleInSelection)\n                {\n                    var item = $(tpl.actionDropDownCheckboxItem.resolve(getParams.call(that,\n                        { name: column.id, label: column.text, checked: column.visible })))\n                            .on(\"click\" + namespace, selector, function (e)\n                            {\n                                e.stopPropagation();\n        \n                                var $this = $(this),\n                                    checkbox = $this.find(checkboxSelector);\n                                if (!checkbox.prop(\"disabled\"))\n                                {\n                                    column.visible = checkbox.prop(\"checked\");\n                                    var enable = that.columns.where(isVisible).length > 1;\n                                    $this.parents(itemsSelector).find(selector + \":has(\" + checkboxSelector + \":checked)\")\n                                        ._bgEnableAria(enable).find(checkboxSelector)._bgEnableField(enable);\n        \n                                    that.element.find(\"tbody\").empty(); // Fixes an column visualization bug\n                                    renderTableHeader.call(that);\n                                    loadData.call(that);\n                                }\n                            });\n                    dropDown.find(getCssSelector(css.dropDownMenuItems)).append(item);\n                }\n            });\n            actions.append(dropDown);\n        }\n    }\n\n    function renderInfos()\n    {\n        if (this.options.navigation !== 0)\n        {\n            var selector = getCssSelector(this.options.css.infos),\n                infoItems = findFooterAndHeaderItems.call(this, selector);\n\n            if (infoItems.length > 0)\n            {\n                var end = (this.current * this.rowCount),\n                    infos = $(this.options.templates.infos.resolve(getParams.call(this, {\n                        end: (this.total === 0 || end === -1 || end > this.total) ? this.total : end,\n                        start: (this.total === 0) ? 0 : (end - this.rowCount + 1),\n                        total: this.total\n                    })));\n\n                replacePlaceHolder.call(this, infoItems, infos);\n            }\n        }\n    }\n\n    function renderNoResultsRow()\n    {\n        var tbody = this.element.children(\"tbody\").first(),\n            tpl = this.options.templates,\n            count = this.columns.where(isVisible).length;\n\n        if (this.selection)\n        {\n            count = count + 1;\n        }\n        tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count })));\n    }\n\n    function renderPagination()\n    {\n        if (this.options.navigation !== 0)\n        {\n            var selector = getCssSelector(this.options.css.pagination),\n                paginationItems = findFooterAndHeaderItems.call(this, selector)._bgShowAria(this.rowCount !== -1);\n\n            if (this.rowCount !== -1 && paginationItems.length > 0)\n            {\n                var tpl = this.options.templates,\n                    current = this.current,\n                    totalPages = this.totalPages,\n                    pagination = $(tpl.pagination.resolve(getParams.call(this))),\n                    offsetRight = totalPages - current,\n                    offsetLeft = (this.options.padding - current) * -1,\n                    startWith = ((offsetRight >= this.options.padding) ?\n                        Math.max(offsetLeft, 1) :\n                        Math.max((offsetLeft - this.options.padding + offsetRight), 1)),\n                    maxCount = this.options.padding * 2 + 1,\n                    count = (totalPages >= maxCount) ? maxCount : totalPages;\n\n                renderPaginationItem.call(this, pagination, \"first\", \"&laquo;\", \"first\")\n                    ._bgEnableAria(current > 1);\n                renderPaginationItem.call(this, pagination, \"prev\", \"&lt;\", \"prev\")\n                    ._bgEnableAria(current > 1);\n\n                for (var i = 0; i < count; i++)\n                {\n                    var pos = i + startWith;\n                    renderPaginationItem.call(this, pagination, pos, pos, \"page-\" + pos)\n                        ._bgEnableAria()._bgSelectAria(pos === current);\n                }\n\n                if (count === 0)\n                {\n                    renderPaginationItem.call(this, pagination, 1, 1, \"page-\" + 1)\n                        ._bgEnableAria(false)._bgSelectAria();\n                }\n\n                renderPaginationItem.call(this, pagination, \"next\", \"&gt;\", \"next\")\n                    ._bgEnableAria(totalPages > current);\n                renderPaginationItem.call(this, pagination, \"last\", \"&raquo;\", \"last\")\n                    ._bgEnableAria(totalPages > current);\n\n                replacePlaceHolder.call(this, paginationItems, pagination);\n            }\n        }\n    }\n\n    function renderPaginationItem(list, page, text, markerCss)\n    {\n        var that = this,\n            tpl = this.options.templates,\n            css = this.options.css,\n            values = getParams.call(this, { css: markerCss, text: text, page: page }),\n            item = $(tpl.paginationItem.resolve(values))\n                .on(\"click\" + namespace, getCssSelector(css.paginationButton), function (e)\n                {\n                    e.stopPropagation();\n                    e.preventDefault();\n\n                    var $this = $(this),\n                        parent = $this.parent();\n                    if (!parent.hasClass(\"active\") && !parent.hasClass(\"disabled\"))\n                    {\n                        var commandList = {\n                            first: 1,\n                            prev: that.current - 1,\n                            next: that.current + 1,\n                            last: that.totalPages\n                        };\n                        var command = $this.data(\"page\");\n                        that.current = commandList[command] || command;\n                        loadData.call(that);\n                    }\n                    $this.trigger(\"blur\");\n                });\n\n        list.append(item);\n        return item;\n    }\n\n    function renderRowCountSelection(actions)\n    {\n        var that = this,\n            rowCountList = this.options.rowCount;\n\n        function getText(value)\n        {\n            return (value === -1) ? that.options.labels.all : value;\n        }\n\n        if ($.isArray(rowCountList))\n        {\n            var css = this.options.css,\n                tpl = this.options.templates,\n                dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: getText(this.rowCount) }))),\n                menuSelector = getCssSelector(css.dropDownMenu),\n                menuTextSelector = getCssSelector(css.dropDownMenuText),\n                menuItemsSelector = getCssSelector(css.dropDownMenuItems),\n                menuItemSelector = getCssSelector(css.dropDownItemButton);\n\n            $.each(rowCountList, function (index, value)\n            {\n                var item = $(tpl.actionDropDownItem.resolve(getParams.call(that,\n                    { text: getText(value), action: value })))\n                        ._bgSelectAria(value === that.rowCount)\n                        .on(\"click\" + namespace, menuItemSelector, function (e)\n                        {\n                            e.preventDefault();\n\n                            var $this = $(this),\n                                newRowCount = $this.data(\"action\");\n                            if (newRowCount !== that.rowCount)\n                            {\n                                // todo: sophisticated solution needed for calculating which page is selected\n                                that.current = 1; // that.rowCount === -1 ---> All\n                                that.rowCount = newRowCount;\n                                $this.parents(menuItemsSelector).children().each(function ()\n                                {\n                                    var $item = $(this),\n                                        currentRowCount = $item.find(menuItemSelector).data(\"action\");\n                                    $item._bgSelectAria(currentRowCount === newRowCount);\n                                });\n                                $this.parents(menuSelector).find(menuTextSelector).text(getText(newRowCount));\n                                loadData.call(that);\n                            }\n                        });\n                dropDown.find(menuItemsSelector).append(item);\n            });\n            actions.append(dropDown);\n        }\n    }\n\n    function renderRows(rows)\n    {\n        if (rows.length > 0)\n        {\n            var that = this,\n                css = this.options.css,\n                tpl = this.options.templates,\n                tbody = this.element.children(\"tbody\").first(),\n                allRowsSelected = true,\n                html = \"\";\n\n            $.each(rows, function (index, row)\n            {\n                var cells = \"\",\n                    rowAttr = \" data-row-id=\\\"\" + ((that.identifier == null) ? index : row[that.identifier]) + \"\\\"\",\n                    rowCss = \"\";\n\n                if (that.selection)\n                {\n                    var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1),\n                        selectBox = tpl.select.resolve(getParams.call(that,\n                            { type: \"checkbox\", value: row[that.identifier], checked: selected }));\n                    cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell }));\n                    allRowsSelected = (allRowsSelected && selected);\n                    if (selected)\n                    {\n                        rowCss += css.selected;\n                        rowAttr += \" aria-selected=\\\"true\\\"\";\n                    }\n                }\n\n                var status = row.status != null && that.options.statusMapping[row.status];\n                if (status)\n                {\n                    rowCss += status;\n                }\n\n                $.each(that.columns, function (j, column)\n                {\n                    if (column.visible)\n                    {\n                        var value = ($.isFunction(column.formatter)) ?\n                                column.formatter.call(that, column, row) :\n                                    column.converter.to(row[column.id]),\n                            cssClass = (column.cssClass.length > 0) ? \" \" + column.cssClass : \"\";\n                        cells += tpl.cell.resolve(getParams.call(that, {\n                            content: (value == null || value === \"\") ? \"&nbsp;\" : value,\n                            css: ((column.align === \"right\") ? css.right : (column.align === \"center\") ?\n                                css.center : css.left) + cssClass,\n                            style: (column.width == null) ? \"\" : \"width:\" + column.width + \";\" }));\n                    }\n                });\n\n                if (rowCss.length > 0)\n                {\n                    rowAttr += \" class=\\\"\" + rowCss + \"\\\"\";\n                }\n                html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells }));\n            });\n\n            // sets or clears multi selectbox state\n            that.element.find(\"thead \" + getCssSelector(that.options.css.selectBox))\n                .prop(\"checked\", allRowsSelected);\n\n            tbody.html(html);\n\n            registerRowEvents.call(this, tbody);\n        }\n        else\n        {\n            renderNoResultsRow.call(this);\n        }\n    }\n\n    function registerRowEvents(tbody)\n    {\n        var that = this,\n            selectBoxSelector = getCssSelector(this.options.css.selectBox);\n\n        if (this.selection)\n        {\n            tbody.off(\"click\" + namespace, selectBoxSelector)\n                .on(\"click\" + namespace, selectBoxSelector, function(e)\n                {\n                    e.stopPropagation();\n\n                    var $this = $(this),\n                        id = that.converter.from($this.val());\n\n                    if ($this.prop(\"checked\"))\n                    {\n                        that.select([id]);\n                    }\n                    else\n                    {\n                        that.deselect([id]);\n                    }\n                });\n        }\n\n        tbody.off(\"click\" + namespace, \"> tr\")\n            .on(\"click\" + namespace, \"> tr\", function(e)\n            {\n                e.stopPropagation();\n\n                var $this = $(this),\n                    id = (that.identifier == null) ? $this.data(\"row-id\") :\n                        that.converter.from($this.data(\"row-id\") + \"\"),\n                    row = (that.identifier == null) ? that.currentRows[id] :\n                        that.currentRows.first(function (item) { return item[that.identifier] === id; });\n\n                if (that.selection && that.options.rowSelect)\n                {\n                    if ($this.hasClass(that.options.css.selected))\n                    {\n                        that.deselect([id]);\n                    }\n                    else\n                    {\n                        that.select([id]);\n                    }\n                }\n\n                that.element.trigger(\"click\" + namespace, [that.columns, row]);\n            });\n    }\n\n    function renderSearchField()\n    {\n        if (this.options.navigation !== 0)\n        {\n            var css = this.options.css,\n                selector = getCssSelector(css.search),\n                searchItems = findFooterAndHeaderItems.call(this, selector);\n\n            if (searchItems.length > 0)\n            {\n                var that = this,\n                    tpl = this.options.templates,\n                    timer = null, // fast keyup detection\n                    currentValue = \"\",\n                    searchFieldSelector = getCssSelector(css.searchField),\n                    search = $(tpl.search.resolve(getParams.call(this))),\n                    searchField = (search.is(searchFieldSelector)) ? search :\n                        search.find(searchFieldSelector);\n\n                searchField.on(\"keyup\" + namespace, function (e)\n                {\n                    e.stopPropagation();\n                    var newValue = $(this).val();\n                    if (currentValue !== newValue || (e.which === 13 && newValue !== \"\"))\n                    {\n                        currentValue = newValue;\n                        if (e.which === 13 || newValue.length === 0 || newValue.length >= that.options.searchSettings.characters)\n                        {\n                            window.clearTimeout(timer);\n                            timer = window.setTimeout(function ()\n                            {\n                                executeSearch.call(that, newValue);\n                            }, that.options.searchSettings.delay);\n                        }\n                    }\n                });\n\n                replacePlaceHolder.call(this, searchItems, search);\n            }\n        }\n    }\n\n    function executeSearch(phrase)\n    {\n        if (this.searchPhrase !== phrase)\n        {\n            this.current = 1;\n            this.searchPhrase = phrase;\n            loadData.call(this);\n        }\n    }\n\n    function renderTableHeader()\n    {\n        var that = this,\n            headerRow = this.element.find(\"thead > tr\"),\n            css = this.options.css,\n            tpl = this.options.templates,\n            html = \"\",\n            sorting = this.options.sorting;\n\n        if (this.selection)\n        {\n            var selectBox = (this.options.multiSelect) ?\n                tpl.select.resolve(getParams.call(that, { type: \"checkbox\", value: \"all\" })) : \"\";\n            html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox,\n                css: css.selectCell }));\n        }\n\n        $.each(this.columns, function (index, column)\n        {\n            if (column.visible)\n            {\n                var sortOrder = that.sortDictionary[column.id],\n                    iconCss = ((sorting && sortOrder && sortOrder === \"asc\") ? css.iconUp :\n                        (sorting && sortOrder && sortOrder === \"desc\") ? css.iconDown : \"\"),\n                    icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })),\n                    align = column.headerAlign,\n                    cssClass = (column.headerCssClass.length > 0) ? \" \" + column.headerCssClass : \"\";\n                html += tpl.headerCell.resolve(getParams.call(that, {\n                    column: column, icon: icon, sortable: sorting && column.sortable && css.sortable || \"\",\n                    css: ((align === \"right\") ? css.right : (align === \"center\") ?\n                        css.center : css.left) + cssClass,\n                    style: (column.width == null) ? \"\" : \"width:\" + column.width + \";\" }));\n            }\n        });\n\n        headerRow.html(html);\n\n        if (sorting)\n        {\n            var sortingSelector = getCssSelector(css.sortable);\n            headerRow.off(\"click\" + namespace, sortingSelector)\n                .on(\"click\" + namespace, sortingSelector, function (e)\n                {\n                    e.preventDefault();\n\n                    setTableHeaderSortDirection.call(that, $(this));\n                    sortRows.call(that);\n                    loadData.call(that);\n                });\n        }\n\n        // todo: create a own function for that piece of code\n        if (this.selection && this.options.multiSelect)\n        {\n            var selectBoxSelector = getCssSelector(css.selectBox);\n            headerRow.off(\"click\" + namespace, selectBoxSelector)\n                .on(\"click\" + namespace, selectBoxSelector, function(e)\n                {\n                    e.stopPropagation();\n\n                    if ($(this).prop(\"checked\"))\n                    {\n                        that.select();\n                    }\n                    else\n                    {\n                        that.deselect();\n                    }\n                });\n        }\n    }\n\n    function setTableHeaderSortDirection(element)\n    {\n        var css = this.options.css,\n            iconSelector = getCssSelector(css.icon),\n            columnId = element.data(\"column-id\") || element.parents(\"th\").first().data(\"column-id\"),\n            sortOrder = this.sortDictionary[columnId],\n            icon = element.find(iconSelector);\n\n        if (!this.options.multiSort)\n        {\n            element.parents(\"tr\").first().find(iconSelector).removeClass(css.iconDown + \" \" + css.iconUp);\n            this.sortDictionary = {};\n        }\n\n        if (sortOrder && sortOrder === \"asc\")\n        {\n            this.sortDictionary[columnId] = \"desc\";\n            icon.removeClass(css.iconUp).addClass(css.iconDown);\n        }\n        else if (sortOrder && sortOrder === \"desc\")\n        {\n            if (this.options.multiSort)\n            {\n                var newSort = {};\n                for (var key in this.sortDictionary)\n                {\n                    if (key !== columnId)\n                    {\n                        newSort[key] = this.sortDictionary[key];\n                    }\n                }\n                this.sortDictionary = newSort;\n                icon.removeClass(css.iconDown);\n            }\n            else\n            {\n                this.sortDictionary[columnId] = \"asc\";\n                icon.removeClass(css.iconDown).addClass(css.iconUp);\n            }\n        }\n        else\n        {\n            this.sortDictionary[columnId] = \"asc\";\n            icon.addClass(css.iconUp);\n        }\n    }\n\n    function replacePlaceHolder(placeholder, element)\n    {\n        placeholder.each(function (index, item)\n        {\n            // todo: check how append is implemented. Perhaps cloning here is superfluous.\n            $(item).before(element.clone(true)).remove();\n        });\n    }\n\n    function showLoading()\n    {\n        var that = this;\n\n        window.setTimeout(function()\n        {\n            if (that.element._bgAria(\"busy\") === \"true\")\n            {\n                var tpl = that.options.templates,\n                    thead = that.element.children(\"thead\").first(),\n                    tbody = that.element.children(\"tbody\").first(),\n                    firstCell = tbody.find(\"tr > td\").first(),\n                    padding = (that.element.height() - thead.height()) - (firstCell.height() + 20),\n                    count = that.columns.where(isVisible).length;\n\n                if (that.selection)\n                {\n                    count = count + 1;\n                }\n                tbody.html(tpl.loading.resolve(getParams.call(that, { columns: count })));\n                if (that.rowCount !== -1 && padding > 0)\n                {\n                    tbody.find(\"tr > td\").css(\"padding\", \"20px 0 \" + padding + \"px\");\n                }\n            }\n        }, 250);\n    }\n\n    function sortRows()\n    {\n        var sortArray = [];\n\n        function sort(x, y, current)\n        {\n            current = current || 0;\n            var next = current + 1,\n                item = sortArray[current];\n\n            function sortOrder(value)\n            {\n                return (item.order === \"asc\") ? value : value * -1;\n            }\n\n            return (x[item.id] > y[item.id]) ? sortOrder(1) :\n                (x[item.id] < y[item.id]) ? sortOrder(-1) :\n                    (sortArray.length > next) ? sort(x, y, next) : 0;\n        }\n\n        if (!this.options.ajax)\n        {\n            var that = this;\n\n            for (var key in this.sortDictionary)\n            {\n                if (this.options.multiSort || sortArray.length === 0)\n                {\n                    sortArray.push({\n                        id: key,\n                        order: this.sortDictionary[key]\n                    });\n                }\n            }\n\n            if (sortArray.length > 0)\n            {\n                this.rows.sort(sort);\n            }\n        }\n    }\n\n    // GRID PUBLIC CLASS DEFINITION\n    // ====================\n\n    /**\n     * Represents the jQuery Bootgrid plugin.\n     *\n     * @class Grid\n     * @constructor\n     * @param element {Object} The corresponding DOM element.\n     * @param options {Object} The options to override default settings.\n     * @chainable\n     **/\n    var Grid = function(element, options)\n    {\n        this.element = $(element);\n        this.origin = this.element.clone();\n        this.options = $.extend(true, {}, Grid.defaults, this.element.data(), options);\n        // overrides rowCount explicitly because deep copy ($.extend) leads to strange behaviour\n        var rowCount = this.options.rowCount = this.element.data().rowCount || options.rowCount || this.options.rowCount;\n        this.columns = [];\n        this.current = 1;\n        this.currentRows = [];\n        this.identifier = null; // The first column ID that is marked as identifier\n        this.selection = false;\n        this.converter = null; // The converter for the column that is marked as identifier\n        this.rowCount = ($.isArray(rowCount)) ? rowCount[0] : rowCount;\n        this.rows = [];\n        this.searchPhrase = \"\";\n        this.selectedRows = [];\n        this.sortDictionary = {};\n        this.total = 0;\n        this.totalPages = 0;\n        this.cachedParams = {\n            lbl: this.options.labels,\n            css: this.options.css,\n            ctx: {}\n        };\n        this.header = null;\n        this.footer = null;\n        this.xqr = null;\n\n        // todo: implement cache\n    };\n\n    /**\n     * An object that represents the default settings.\n     *\n     * @static\n     * @class defaults\n     * @for Grid\n     * @example\n     *   // Global approach\n     *   $.bootgrid.defaults.selection = true;\n     * @example\n     *   // Initialization approach\n     *   $(\"#bootgrid\").bootgrid({ selection = true });\n     **/\n    Grid.defaults = {\n        navigation: 3, // it's a flag: 0 = none, 1 = top, 2 = bottom, 3 = both (top and bottom)\n        padding: 2, // page padding (pagination)\n        columnSelection: true,\n        rowCount: [10, 25, 50, -1], // rows per page int or array of int (-1 represents \"All\")\n\n        /**\n         * Enables row selection (to enable multi selection see also `multiSelect`). Default value is `false`.\n         *\n         * @property selection\n         * @type Boolean\n         * @default false\n         * @for defaults\n         * @since 1.0.0\n         **/\n        selection: false,\n\n        /**\n         * Enables multi selection (`selection` must be set to `true` as well). Default value is `false`.\n         *\n         * @property multiSelect\n         * @type Boolean\n         * @default false\n         * @for defaults\n         * @since 1.0.0\n         **/\n        multiSelect: false,\n\n        /**\n         * Enables entire row click selection (`selection` must be set to `true` as well). Default value is `false`.\n         *\n         * @property rowSelect\n         * @type Boolean\n         * @default false\n         * @for defaults\n         * @since 1.1.0\n         **/\n        rowSelect: false,\n\n        /**\n         * Defines whether the row selection is saved internally on filtering, paging and sorting\n         * (even if the selected rows are not visible).\n         *\n         * @property keepSelection\n         * @type Boolean\n         * @default false\n         * @for defaults\n         * @since 1.1.0\n         **/\n        keepSelection: false,\n\n        highlightRows: false, // highlights new rows (find the page of the first new row)\n        sorting: true,\n        multiSort: false,\n\n        /**\n         * General search settings to configure the search field behaviour.\n         *\n         * @property searchSettings\n         * @type Object\n         * @for defaults\n         * @since 1.2.0\n         **/\n        searchSettings: {\n            /**\n             * The time in milliseconds to wait before search gets executed.\n             *\n             * @property delay\n             * @type Number\n             * @default 250\n             * @for searchSettings\n             **/\n            delay: 250,\n            \n            /**\n             * The characters to type before the search gets executed.\n             *\n             * @property characters\n             * @type Number\n             * @default 1\n             * @for searchSettings\n             **/\n            characters: 1\n        },\n\n        /**\n         * Defines whether the data shall be loaded via an asynchronous HTTP (Ajax) request.\n         *\n         * @property ajax\n         * @type Boolean\n         * @default false\n         * @for defaults\n         **/\n        ajax: false,\n\n        /**\n         * Ajax request settings that shall be used for server-side communication.\n         * All setting except data, error, success and url can be overridden.\n         * For the full list of settings go to http://api.jquery.com/jQuery.ajax/.\n         *\n         * @property ajaxSettings\n         * @type Object\n         * @for defaults\n         * @since 1.2.0\n         **/\n        ajaxSettings: {\n            /**\n             * Specifies the HTTP method which shall be used when sending data to the server.\n             * Go to http://api.jquery.com/jQuery.ajax/ for more details.\n             * This setting is overriden for backward compatibility.\n             *\n             * @property method\n             * @type String\n             * @default \"POST\"\n             * @for ajaxSettings\n             **/\n            method: \"POST\"\n        },\n\n        /**\n         * Enriches the request object with additional properties. Either a `PlainObject` or a `Function`\n         * that returns a `PlainObject` can be passed. Default value is `{}`.\n         *\n         * @property post\n         * @type Object|Function\n         * @default function (request) { return request; }\n         * @for defaults\n         * @deprecated Use instead `requestHandler`\n         **/\n        post: {}, // or use function () { return {}; } (reserved properties are \"current\", \"rowCount\", \"sort\" and \"searchPhrase\")\n\n        /**\n         * Sets the data URL to a data service (e.g. a REST service). Either a `String` or a `Function`\n         * that returns a `String` can be passed. Default value is `\"\"`.\n         *\n         * @property url\n         * @type String|Function\n         * @default \"\"\n         * @for defaults\n         **/\n        url: \"\", // or use function () { return \"\"; }\n\n        /**\n         * Defines whether the search is case sensitive or insensitive.\n         *\n         * @property caseSensitive\n         * @type Boolean\n         * @default true\n         * @for defaults\n         * @since 1.1.0\n         **/\n        caseSensitive: true,\n\n        // note: The following properties should not be used via data-api attributes\n\n        /**\n         * Transforms the JSON request object in what ever is needed on the server-side implementation.\n         *\n         * @property requestHandler\n         * @type Function\n         * @default function (request) { return request; }\n         * @for defaults\n         * @since 1.1.0\n         **/\n        requestHandler: function (request) { return request; },\n\n        /**\n         * Transforms the response object into the expected JSON response object.\n         *\n         * @property responseHandler\n         * @type Function\n         * @default function (response) { return response; }\n         * @for defaults\n         * @since 1.1.0\n         **/\n        responseHandler: function (response) { return response; },\n\n        /**\n         * A list of converters.\n         *\n         * @property converters\n         * @type Object\n         * @for defaults\n         * @since 1.0.0\n         **/\n        converters: {\n            numeric: {\n                from: function (value) { return +value; }, // converts from string to numeric\n                to: function (value) { return value + \"\"; } // converts from numeric to string\n            },\n            string: {\n                // default converter\n                from: function (value) { return value; },\n                to: function (value) { return value; }\n            }\n        },\n\n        /**\n         * Contains all css classes.\n         *\n         * @property css\n         * @type Object\n         * @for defaults\n         **/\n        css: {\n            actions: \"actions btn-group\", // must be a unique class name or constellation of class names within the header and footer\n            center: \"text-center\",\n            columnHeaderAnchor: \"column-header-anchor\", // must be a unique class name or constellation of class names within the column header cell\n            columnHeaderText: \"text\",\n            dropDownItem: \"dropdown-item\", // must be a unique class name or constellation of class names within the actionDropDown,\n            dropDownItemButton: \"dropdown-item-button\", // must be a unique class name or constellation of class names within the actionDropDown\n            dropDownItemCheckbox: \"dropdown-item-checkbox\", // must be a unique class name or constellation of class names within the actionDropDown\n            dropDownMenu: \"dropdown btn-group\", // must be a unique class name or constellation of class names within the actionDropDown\n            dropDownMenuItems: \"dropdown-menu pull-right\", // must be a unique class name or constellation of class names within the actionDropDown\n            dropDownMenuText: \"dropdown-text\", // must be a unique class name or constellation of class names within the actionDropDown\n            footer: \"bootgrid-footer container-fluid\",\n            header: \"bootgrid-header container-fluid\",\n            icon: \"icon glyphicon\",\n            iconColumns: \"glyphicon-th-list\",\n            iconDown: \"glyphicon-chevron-down\",\n            iconRefresh: \"glyphicon-refresh\",\n            iconSearch: \"glyphicon-search\",\n            iconUp: \"glyphicon-chevron-up\",\n            infos: \"infos\", // must be a unique class name or constellation of class names within the header and footer,\n            left: \"text-left\",\n            pagination: \"pagination\", // must be a unique class name or constellation of class names within the header and footer\n            paginationButton: \"button\", // must be a unique class name or constellation of class names within the pagination\n\n            /**\n             * CSS class to select the parent div which activates responsive mode.\n             *\n             * @property responsiveTable\n             * @type String\n             * @default \"table-responsive\"\n             * @for css\n             * @since 1.1.0\n             **/\n            responsiveTable: \"table-responsive\",\n\n            right: \"text-right\",\n            search: \"search form-group\", // must be a unique class name or constellation of class names within the header and footer\n            searchField: \"search-field form-control\",\n            selectBox: \"select-box\", // must be a unique class name or constellation of class names within the entire table\n            selectCell: \"select-cell\", // must be a unique class name or constellation of class names within the entire table\n\n            /**\n             * CSS class to highlight selected rows.\n             *\n             * @property selected\n             * @type String\n             * @default \"active\"\n             * @for css\n             * @since 1.1.0\n             **/\n            selected: \"active\",\n\n            sortable: \"sortable\",\n            table: \"bootgrid-table table\"\n        },\n\n        /**\n         * A dictionary of formatters.\n         *\n         * @property formatters\n         * @type Object\n         * @for defaults\n         * @since 1.0.0\n         **/\n        formatters: {},\n\n        /**\n         * Contains all labels.\n         *\n         * @property labels\n         * @type Object\n         * @for defaults\n         **/\n        labels: {\n            all: \"All\",\n            infos: \"Showing {{ctx.start}} to {{ctx.end}} of {{ctx.total}} entries\",\n            loading: \"Loading...\",\n            noResults: \"No results found!\",\n            refresh: \"Refresh\",\n            search: \"Search\"\n        },\n\n        /**\n         * Specifies the mapping between status and contextual classes to color rows.\n         *\n         * @property statusMapping\n         * @type Object\n         * @for defaults\n         * @since 1.2.0\n         **/\n        statusMapping: {\n            /**\n             * Specifies a successful or positive action.\n             *\n             * @property 0\n             * @type String\n             * @for statusMapping\n             **/\n            0: \"success\",\n\n            /**\n             * Specifies a neutral informative change or action.\n             *\n             * @property 1\n             * @type String\n             * @for statusMapping\n             **/\n            1: \"info\",\n\n            /**\n             * Specifies a warning that might need attention.\n             *\n             * @property 2\n             * @type String\n             * @for statusMapping\n             **/\n            2: \"warning\",\n            \n            /**\n             * Specifies a dangerous or potentially negative action.\n             *\n             * @property 3\n             * @type String\n             * @for statusMapping\n             **/\n            3: \"danger\"\n        },\n\n        /**\n         * Contains all templates.\n         *\n         * @property templates\n         * @type Object\n         * @for defaults\n         **/\n        templates: {\n            actionButton: \"<button class=\\\"btn btn-default\\\" type=\\\"button\\\" title=\\\"{{ctx.text}}\\\">{{ctx.content}}</button>\",\n            actionDropDown: \"<div class=\\\"{{css.dropDownMenu}}\\\"><button class=\\\"btn btn-default dropdown-toggle\\\" type=\\\"button\\\" data-toggle=\\\"dropdown\\\"><span class=\\\"{{css.dropDownMenuText}}\\\">{{ctx.content}}</span> <span class=\\\"caret\\\"></span></button><ul class=\\\"{{css.dropDownMenuItems}}\\\" role=\\\"menu\\\"></ul></div>\",\n            actionDropDownItem: \"<li><a data-action=\\\"{{ctx.action}}\\\" class=\\\"{{css.dropDownItem}} {{css.dropDownItemButton}}\\\">{{ctx.text}}</a></li>\",\n            actionDropDownCheckboxItem: \"<li><label class=\\\"{{css.dropDownItem}}\\\"><input name=\\\"{{ctx.name}}\\\" type=\\\"checkbox\\\" value=\\\"1\\\" class=\\\"{{css.dropDownItemCheckbox}}\\\" {{ctx.checked}} /> {{ctx.label}}</label></li>\",\n            actions: \"<div class=\\\"{{css.actions}}\\\"></div>\",\n            body: \"<tbody></tbody>\",\n            cell: \"<td class=\\\"{{ctx.css}}\\\" style=\\\"{{ctx.style}}\\\">{{ctx.content}}</td>\",\n            footer: \"<div id=\\\"{{ctx.id}}\\\" class=\\\"{{css.footer}}\\\"><div class=\\\"row\\\"><div class=\\\"col-sm-6\\\"><p class=\\\"{{css.pagination}}\\\"></p></div><div class=\\\"col-sm-6 infoBar\\\"><p class=\\\"{{css.infos}}\\\"></p></div></div></div>\",\n            header: \"<div id=\\\"{{ctx.id}}\\\" class=\\\"{{css.header}}\\\"><div class=\\\"row\\\"><div class=\\\"col-sm-12 actionBar\\\"><p class=\\\"{{css.search}}\\\"></p><p class=\\\"{{css.actions}}\\\"></p></div></div></div>\",\n            headerCell: \"<th data-column-id=\\\"{{ctx.column.id}}\\\" class=\\\"{{ctx.css}}\\\" style=\\\"{{ctx.style}}\\\"><a href=\\\"javascript:void(0);\\\" class=\\\"{{css.columnHeaderAnchor}} {{ctx.sortable}}\\\"><span class=\\\"{{css.columnHeaderText}}\\\">{{ctx.column.text}}</span>{{ctx.icon}}</a></th>\",\n            icon: \"<span class=\\\"{{css.icon}} {{ctx.iconCss}}\\\"></span>\",\n            infos: \"<div class=\\\"{{css.infos}}\\\">{{lbl.infos}}</div>\",\n            loading: \"<tr><td colspan=\\\"{{ctx.columns}}\\\" class=\\\"loading\\\">{{lbl.loading}}</td></tr>\",\n            noResults: \"<tr><td colspan=\\\"{{ctx.columns}}\\\" class=\\\"no-results\\\">{{lbl.noResults}}</td></tr>\",\n            pagination: \"<ul class=\\\"{{css.pagination}}\\\"></ul>\",\n            paginationItem: \"<li class=\\\"{{ctx.css}}\\\"><a data-page=\\\"{{ctx.page}}\\\" class=\\\"{{css.paginationButton}}\\\">{{ctx.text}}</a></li>\",\n            rawHeaderCell: \"<th class=\\\"{{ctx.css}}\\\">{{ctx.content}}</th>\", // Used for the multi select box\n            row: \"<tr{{ctx.attr}}>{{ctx.cells}}</tr>\",\n            search: \"<div class=\\\"{{css.search}}\\\"><div class=\\\"input-group\\\"><span class=\\\"{{css.icon}} input-group-addon {{css.iconSearch}}\\\"></span> <input type=\\\"text\\\" class=\\\"{{css.searchField}}\\\" placeholder=\\\"{{lbl.search}}\\\" /></div></div>\",\n            select: \"<input name=\\\"select\\\" type=\\\"{{ctx.type}}\\\" class=\\\"{{css.selectBox}}\\\" value=\\\"{{ctx.value}}\\\" {{ctx.checked}} />\"\n        }\n    };\n\n    /**\n     * Appends rows.\n     *\n     * @method append\n     * @param rows {Array} An array of rows to append\n     * @chainable\n     **/\n    Grid.prototype.append = function(rows)\n    {\n        if (this.options.ajax)\n        {\n            // todo: implement ajax PUT\n        }\n        else\n        {\n            var appendedRows = [];\n            for (var i = 0; i < rows.length; i++)\n            {\n                if (appendRow.call(this, rows[i]))\n                {\n                    appendedRows.push(rows[i]);\n                }\n            }\n            sortRows.call(this);\n            highlightAppendedRows.call(this, appendedRows);\n            loadData.call(this);\n            this.element.trigger(\"appended\" + namespace, [appendedRows]);\n        }\n\n        return this;\n    };\n\n    /**\n     * Removes all rows.\n     *\n     * @method clear\n     * @chainable\n     **/\n    Grid.prototype.clear = function()\n    {\n        if (this.options.ajax)\n        {\n            // todo: implement ajax POST\n        }\n        else\n        {\n            var removedRows = $.extend([], this.rows);\n            this.rows = [];\n            this.current = 1;\n            this.total = 0;\n            loadData.call(this);\n            this.element.trigger(\"cleared\" + namespace, [removedRows]);\n        }\n\n        return this;\n    };\n\n    /**\n     * Removes the control functionality completely and transforms the current state to the initial HTML structure.\n     *\n     * @method destroy\n     * @chainable\n     **/\n    Grid.prototype.destroy = function()\n    {\n        // todo: this method has to be optimized (the complete initial state must be restored)\n        $(window).off(namespace);\n        if (this.options.navigation & 1)\n        {\n            this.header.remove();\n        }\n        if (this.options.navigation & 2)\n        {\n            this.footer.remove();\n        }\n        this.element.before(this.origin).remove();\n\n        return this;\n    };\n\n    /**\n     * Resets the state and reloads rows.\n     *\n     * @method reload\n     * @chainable\n     **/\n    Grid.prototype.reload = function()\n    {\n        this.current = 1; // reset\n        loadData.call(this);\n\n        return this;\n    };\n\n    /**\n     * Removes rows by ids. Removes selected rows if no ids are provided.\n     *\n     * @method remove\n     * @param [rowsIds] {Array} An array of rows ids to remove\n     * @chainable\n     **/\n    Grid.prototype.remove = function(rowIds)\n    {\n        if (this.identifier != null)\n        {\n            var that = this;\n\n            if (this.options.ajax)\n            {\n                // todo: implement ajax DELETE\n            }\n            else\n            {\n                rowIds = rowIds || this.selectedRows;\n                var id,\n                    removedRows = [];\n\n                for (var i = 0; i < rowIds.length; i++)\n                {\n                    id = rowIds[i];\n\n                    for (var j = 0; j < this.rows.length; j++)\n                    {\n                        if (this.rows[j][this.identifier] === id)\n                        {\n                            removedRows.push(this.rows[j]);\n                            this.rows.splice(j, 1);\n                            break;\n                        }\n                    }\n                }\n\n                this.current = 1; // reset\n                loadData.call(this);\n                this.element.trigger(\"removed\" + namespace, [removedRows]);\n            }\n        }\n\n        return this;\n    };\n\n    /**\n     * Searches in all rows for a specific phrase (but only in visible cells). \n     * The search filter will be reseted, if no argument is provided.\n     *\n     * @method search\n     * @param [phrase] {String} The phrase to search for\n     * @chainable\n     **/\n    Grid.prototype.search = function(phrase)\n    {\n        phrase = phrase || \"\";\n\n        if (this.searchPhrase !== phrase)\n        {\n            var selector = getCssSelector(this.options.css.searchField),\n                searchFields = findFooterAndHeaderItems.call(this, selector);\n            searchFields.val(phrase);\n        }\n\n        executeSearch.call(this, phrase);\n\n\n        return this;\n    };\n\n    /**\n     * Selects rows by ids. Selects all visible rows if no ids are provided.\n     * In server-side scenarios only visible rows are selectable.\n     *\n     * @method select\n     * @param [rowsIds] {Array} An array of rows ids to select\n     * @chainable\n     **/\n    Grid.prototype.select = function(rowIds)\n    {\n        if (this.selection)\n        {\n            rowIds = rowIds || this.currentRows.propValues(this.identifier);\n\n            var id, i,\n                selectedRows = [];\n\n            while (rowIds.length > 0 && !(!this.options.multiSelect && selectedRows.length === 1))\n            {\n                id = rowIds.pop();\n                if ($.inArray(id, this.selectedRows) === -1)\n                {\n                    for (i = 0; i < this.currentRows.length; i++)\n                    {\n                        if (this.currentRows[i][this.identifier] === id)\n                        {\n                            selectedRows.push(this.currentRows[i]);\n                            this.selectedRows.push(id);\n                            break;\n                        }\n                    }\n                }\n            }\n\n            if (selectedRows.length > 0)\n            {\n                var selectBoxSelector = getCssSelector(this.options.css.selectBox),\n                    selectMultiSelectBox = this.selectedRows.length >= this.currentRows.length;\n\n                i = 0;\n                while (!this.options.keepSelection && selectMultiSelectBox && i < this.currentRows.length)\n                {\n                    selectMultiSelectBox = ($.inArray(this.currentRows[i++][this.identifier], this.selectedRows) !== -1);\n                }\n                this.element.find(\"thead \" + selectBoxSelector).prop(\"checked\", selectMultiSelectBox);\n\n                if (!this.options.multiSelect)\n                {\n                    this.element.find(\"tbody > tr \" + selectBoxSelector + \":checked\")\n                        .trigger(\"click\" + namespace);\n                }\n\n                for (i = 0; i < this.selectedRows.length; i++)\n                {\n                    this.element.find(\"tbody > tr[data-row-id=\\\"\" + this.selectedRows[i] + \"\\\"]\")\n                        .addClass(this.options.css.selected)._bgAria(\"selected\", \"true\")\n                        .find(selectBoxSelector).prop(\"checked\", true);\n                }\n\n                this.element.trigger(\"selected\" + namespace, [selectedRows]);\n            }\n        }\n\n        return this;\n    };\n\n    /**\n     * Deselects rows by ids. Deselects all visible rows if no ids are provided.\n     * In server-side scenarios only visible rows are deselectable.\n     *\n     * @method deselect\n     * @param [rowsIds] {Array} An array of rows ids to deselect\n     * @chainable\n     **/\n    Grid.prototype.deselect = function(rowIds)\n    {\n        if (this.selection)\n        {\n            rowIds = rowIds || this.currentRows.propValues(this.identifier);\n\n            var id, i, pos,\n                deselectedRows = [];\n\n            while (rowIds.length > 0)\n            {\n                id = rowIds.pop();\n                pos = $.inArray(id, this.selectedRows);\n                if (pos !== -1)\n                {\n                    for (i = 0; i < this.currentRows.length; i++)\n                    {\n                        if (this.currentRows[i][this.identifier] === id)\n                        {\n                            deselectedRows.push(this.currentRows[i]);\n                            this.selectedRows.splice(pos, 1);\n                            break;\n                        }\n                    }\n                }\n            }\n\n            if (deselectedRows.length > 0)\n            {\n                var selectBoxSelector = getCssSelector(this.options.css.selectBox);\n\n                this.element.find(\"thead \" + selectBoxSelector).prop(\"checked\", false);\n                for (i = 0; i < deselectedRows.length; i++)\n                {\n                    this.element.find(\"tbody > tr[data-row-id=\\\"\" + deselectedRows[i][this.identifier] + \"\\\"]\")\n                        .removeClass(this.options.css.selected)._bgAria(\"selected\", \"false\")\n                        .find(selectBoxSelector).prop(\"checked\", false);\n                }\n\n                this.element.trigger(\"deselected\" + namespace, [deselectedRows]);\n            }\n        }\n\n        return this;\n    };\n\n    /**\n     * Sorts the rows by a given sort descriptor dictionary. \n     * The sort filter will be reseted, if no argument is provided.\n     *\n     * @method sort\n     * @param [dictionary] {Object} A sort descriptor dictionary that contains the sort information\n     * @chainable\n     **/\n    Grid.prototype.sort = function(dictionary)\n    {\n        var values = (dictionary) ? $.extend({}, dictionary) : {};\n\n        if (values === this.sortDictionary)\n        {\n            return this;\n        }\n\n        this.sortDictionary = values;\n        renderTableHeader.call(this);\n        sortRows.call(this);\n        loadData.call(this);\n\n        return this;\n    };\n\n    /**\n     * Gets a list of the column settings.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getColumnSettings\n     * @return {Array} Returns a list of the column settings.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getColumnSettings = function()\n    {\n        return $.merge([], this.columns);\n    };\n\n    /**\n     * Gets the current page index.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getCurrentPage\n     * @return {Number} Returns the current page index.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getCurrentPage = function()\n    {\n        return this.current;\n    };\n\n    /**\n     * Gets the current rows.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getCurrentPage\n     * @return {Array} Returns the current rows.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getCurrentRows = function()\n    {\n        return $.merge([], this.currentRows);\n    };\n\n    /**\n     * Gets a number represents the row count per page.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getRowCount\n     * @return {Number} Returns the row count per page.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getRowCount = function()\n    {\n        return this.rowCount;\n    };\n\n    /**\n     * Gets the actual search phrase.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getSearchPhrase\n     * @return {String} Returns the actual search phrase.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getSearchPhrase = function()\n    {\n        return this.searchPhrase;\n    };\n\n    /**\n     * Gets the complete list of currently selected rows.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getSelectedRows\n     * @return {Array} Returns all selected rows.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getSelectedRows = function()\n    {\n        return $.merge([], this.selectedRows);\n    };\n\n    /**\n     * Gets the sort dictionary which represents the state of column sorting.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getSortDictionary\n     * @return {Object} Returns the sort dictionary.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getSortDictionary = function()\n    {\n        return $.extend({}, this.sortDictionary);\n    };\n\n    /**\n     * Gets a number represents the total page count.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getTotalPageCount\n     * @return {Number} Returns the total page count.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getTotalPageCount = function()\n    {\n        return this.totalPages;\n    };\n\n    /**\n     * Gets a number represents the total row count.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getTotalRowCount\n     * @return {Number} Returns the total row count.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getTotalRowCount = function()\n    {\n        return this.total;\n    };\n\n    // GRID COMMON TYPE EXTENSIONS\n    // ============\n\n    $.fn.extend({\n        _bgAria: function (name, value)\n        {\n            return (value) ? this.attr(\"aria-\" + name, value) : this.attr(\"aria-\" + name);\n        },\n\n        _bgBusyAria: function(busy)\n        {\n            return (busy == null || busy) ? \n                this._bgAria(\"busy\", \"true\") : \n                this._bgAria(\"busy\", \"false\");\n        },\n\n        _bgRemoveAria: function (name)\n        {\n            return this.removeAttr(\"aria-\" + name);\n        },\n\n        _bgEnableAria: function (enable)\n        {\n            return (enable == null || enable) ? \n                this.removeClass(\"disabled\")._bgAria(\"disabled\", \"false\") : \n                this.addClass(\"disabled\")._bgAria(\"disabled\", \"true\");\n        },\n\n        _bgEnableField: function (enable)\n        {\n            return (enable == null || enable) ? \n                this.removeAttr(\"disabled\") : \n                this.attr(\"disabled\", \"disable\");\n        },\n\n        _bgShowAria: function (show)\n        {\n            return (show == null || show) ? \n                this.show()._bgAria(\"hidden\", \"false\") :\n                this.hide()._bgAria(\"hidden\", \"true\");\n        },\n\n        _bgSelectAria: function (select)\n        {\n            return (select == null || select) ? \n                this.addClass(\"active\")._bgAria(\"selected\", \"true\") : \n                this.removeClass(\"active\")._bgAria(\"selected\", \"false\");\n        },\n\n        _bgId: function (id)\n        {\n            return (id) ? this.attr(\"id\", id) : this.attr(\"id\");\n        }\n    });\n\n    if (!String.prototype.resolve)\n    {\n        var formatter = {\n            \"checked\": function(value)\n            {\n                if (typeof value === \"boolean\")\n                {\n                    return (value) ? \"checked=\\\"checked\\\"\" : \"\";\n                }\n                return value;\n            }\n        };\n\n        String.prototype.resolve = function (substitutes, prefixes)\n        {\n            var result = this;\n            $.each(substitutes, function (key, value)\n            {\n                if (value != null && typeof value !== \"function\")\n                {\n                    if (typeof value === \"object\")\n                    {\n                        var keys = (prefixes) ? $.extend([], prefixes) : [];\n                        keys.push(key);\n                        result = result.resolve(value, keys) + \"\";\n                    }\n                    else\n                    {\n                        if (formatter && formatter[key] && typeof formatter[key] === \"function\")\n                        {\n                            value = formatter[key](value);\n                        }\n                        key = (prefixes) ? prefixes.join(\".\") + \".\" + key : key;\n                        var pattern = new RegExp(\"\\\\{\\\\{\" + key + \"\\\\}\\\\}\", \"gm\");\n                        result = result.replace(pattern, (value.replace) ? value.replace(/\\$/gi, \"&#36;\") : value);\n                    }\n                }\n            });\n            return result;\n        };\n    }\n\n    if (!Array.prototype.first)\n    {\n        Array.prototype.first = function (condition)\n        {\n            for (var i = 0; i < this.length; i++)\n            {\n                var item = this[i];\n                if (condition(item))\n                {\n                    return item;\n                }\n            }\n            return null;\n        };\n    }\n\n    if (!Array.prototype.contains)\n    {\n        Array.prototype.contains = function (condition)\n        {\n            for (var i = 0; i < this.length; i++)\n            {\n                var item = this[i];\n                if (condition(item))\n                {\n                    return true;\n                }\n            }\n            return false;\n        };\n    }\n\n    if (!Array.prototype.page)\n    {\n        Array.prototype.page = function (page, size)\n        {\n            var skip = (page - 1) * size,\n                end = skip + size;\n            return (this.length > skip) ? \n                (this.length > end) ? this.slice(skip, end) : \n                    this.slice(skip) : [];\n        };\n    }\n\n    if (!Array.prototype.where)\n    {\n        Array.prototype.where = function (condition)\n        {\n            var result = [];\n            for (var i = 0; i < this.length; i++)\n            {\n                var item = this[i];\n                if (condition(item))\n                {\n                    result.push(item);\n                }\n            }\n            return result;\n        };\n    }\n\n    if (!Array.prototype.propValues)\n    {\n        Array.prototype.propValues = function (propName)\n        {\n            var result = [];\n            for (var i = 0; i < this.length; i++)\n            {\n                result.push(this[i][propName]);\n            }\n            return result;\n        };\n    }\n\n    // GRID PLUGIN DEFINITION\n    // =====================\n\n    var old = $.fn.bootgrid;\n\n    $.fn.bootgrid = function (option)\n    {\n        var args = Array.prototype.slice.call(arguments, 1),\n            returnValue = null,\n            elements = this.each(function (index)\n            {\n                var $this = $(this),\n                    instance = $this.data(namespace),\n                    options = typeof option === \"object\" && option;\n\n                if (!instance && option === \"destroy\")\n                {\n                    return;\n                }\n                if (!instance)\n                {\n                    $this.data(namespace, (instance = new Grid(this, options)));\n                    init.call(instance);\n                }\n                if (typeof option === \"string\")\n                {\n                    if (option.indexOf(\"get\") === 0 && index === 0)\n                    {\n                        returnValue = instance[option].apply(instance, args);\n                    }\n                    else if (option.indexOf(\"get\") !== 0)\n                    {\n                        return instance[option].apply(instance, args);\n                    }\n                }\n            });\n        return (typeof option === \"string\" && option.indexOf(\"get\") === 0) ? returnValue : elements;\n    };\n\n    $.fn.bootgrid.Constructor = Grid;\n\n    // GRID NO CONFLICT\n    // ===============\n\n    $.fn.bootgrid.noConflict = function ()\n    {\n        $.fn.bootgrid = old;\n        return this;\n    };\n\n    // GRID DATA-API\n    // ============\n\n$(\"[data-toggle=\\\"bootgrid\\\"]\").bootgrid();\n})(jQuery, window);"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bootgrid/jquery.bootgrid.updated.js",
    "content": "/*! \n * jQuery Bootgrid v1.3.1 - 09/11/2015\n * Copyright (c) 2014-2015 Rafael Staib (http://www.jquery-bootgrid.com)\n * Licensed under MIT http://www.opensource.org/licenses/MIT\n */\n;(function ($, window, undefined)\n{\n    /*jshint validthis: true */\n    \"use strict\";\n\n    // GRID INTERNAL FIELDS\n    // ====================\n\n    var namespace = \".rs.jquery.bootgrid\";\n\n    // GRID INTERNAL FUNCTIONS\n    // =====================\n\n    function appendRow(row)\n    {\n        var that = this;\n\n        function exists(item)\n        {\n            return that.identifier && item[that.identifier] === row[that.identifier];\n        }\n\n        if (!this.rows.contains(exists))\n        {\n            this.rows.push(row);\n            return true;\n        }\n\n        return false;\n    }\n\n    function findFooterAndHeaderItems(selector)\n    {\n        var footer = (this.footer) ? this.footer.find(selector) : $(),\n            header = (this.header) ? this.header.find(selector) : $();\n        return $.merge(footer, header);\n    }\n\n    function getParams(context)\n    {\n        return (context) ? $.extend({}, this.cachedParams, { ctx: context }) :\n            this.cachedParams;\n    }\n\n    function getRequest()\n    {\n        var request = {\n                current: this.current,\n                rowCount: this.rowCount,\n                sort: this.sortDictionary,\n                searchPhrase: this.searchPhrase\n            },\n            post = this.options.post;\n\n        post = ($.isFunction(post)) ? post() : post;\n        return this.options.requestHandler($.extend(true, request, post));\n    }\n\n    function getCssSelector(css)\n    {\n        return \".\" + $.trim(css).replace(/\\s+/gm, \".\");\n    }\n\n    function getUrl()\n    {\n        var url = this.options.url;\n        return ($.isFunction(url)) ? url() : url;\n    }\n\n    function init()\n    {\n        this.element.trigger(\"initialize\" + namespace);\n\n        loadColumns.call(this); // Loads columns from HTML thead tag\n        this.selection = this.options.selection && this.identifier != null;\n        loadRows.call(this); // Loads rows from HTML tbody tag if ajax is false\n        prepareTable.call(this);\n        renderTableHeader.call(this);\n        renderSearchField.call(this);\n        renderActions.call(this);\n        loadData.call(this);\n\n        this.element.trigger(\"initialized\" + namespace);\n    }\n\n    function highlightAppendedRows(rows)\n    {\n        if (this.options.highlightRows)\n        {\n            // todo: implement\n        }\n    }\n\n    function isVisible(column)\n    {\n        return column.visible;\n    }\n\n    function loadColumns()\n    {\n        var that = this,\n            firstHeadRow = this.element.find(\"thead > tr\").first(),\n            sorted = false;\n\n        /*jshint -W018*/\n        firstHeadRow.children().each(function ()\n        {\n            var $this = $(this),\n                data = $this.data(),\n                column = {\n                    id: data.columnId,\n                    identifier: that.identifier == null && data.identifier || false,\n                    converter: that.options.converters[data.converter || data.type] || that.options.converters[\"string\"],\n                    text: $this.text(),\n                    align: data.align || \"left\",\n                    headerAlign: data.headerAlign || \"left\",\n                    cssClass: data.cssClass || \"\",\n                    headerCssClass: data.headerCssClass || \"\",\n                    formatter: that.options.formatters[data.formatter] || null,\n                    order: (!sorted && (data.order === \"asc\" || data.order === \"desc\")) ? data.order : null,\n                    searchable: !(data.searchable === false), // default: true\n                    sortable: !(data.sortable === false), // default: true\n                    visible: !(data.visible === false), // default: true\n                    visibleInSelection: !(data.visibleInSelection === false), // default: true\n                    width: ($.isNumeric(data.width)) ? data.width + \"px\" : \n                        (typeof(data.width) === \"string\") ? data.width : null\n                };\n            that.columns.push(column);\n            if (column.order != null)\n            {\n                that.sortDictionary[column.id] = column.order;\n            }\n\n            // Prevents multiple identifiers\n            if (column.identifier)\n            {\n                that.identifier = column.id;\n                that.converter = column.converter;\n            }\n\n            // ensures that only the first order will be applied in case of multi sorting is disabled\n            if (!that.options.multiSort && column.order !== null)\n            {\n                sorted = true;\n            }\n        });\n        /*jshint +W018*/\n    }\n\n    /*\n    response = {\n        current: 1,\n        rowCount: 10,\n        rows: [{}, {}],\n        sort: [{ \"columnId\": \"asc\" }],\n        total: 101\n    }\n    */\n\n    function loadData()\n    {\n        var that = this;\n\n        this.element._bgBusyAria(true).trigger(\"load\" + namespace);\n        showLoading.call(this);\n\n        function containsPhrase(row)\n        {\n            var column,\n                searchPattern = new RegExp(that.searchPhrase, (that.options.caseSensitive) ? \"g\" : \"gi\");\n\n            for (var i = 0; i < that.columns.length; i++)\n            {\n                column = that.columns[i];\n                if (column.searchable && column.visible &&\n                    column.converter.to(row[column.id]).search(searchPattern) > -1)\n                {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        function update(rows, total)\n        {\n            that.currentRows = rows;\n            setTotals.call(that, total);\n\n            if (!that.options.keepSelection)\n            {\n                that.selectedRows = [];\n            }\n\n            renderRows.call(that, rows);\n            renderInfos.call(that);\n            renderPagination.call(that);\n\n            that.element._bgBusyAria(false).trigger(\"loaded\" + namespace);\n        }\n\n        if (this.options.ajax)\n        {\n            var request = getRequest.call(this),\n                url = getUrl.call(this);\n\n            if (url == null || typeof url !== \"string\" || url.length === 0)\n            {\n                throw new Error(\"Url setting must be a none empty string or a function that returns one.\");\n            }\n\n            // aborts the previous ajax request if not already finished or failed\n            if (this.xqr)\n            {\n                this.xqr.abort();\n            }\n\n            var settings = {\n                url: url,\n                data: request,\n                success: function(response)\n                {\n                    that.xqr = null;\n\n                    if (typeof (response) === \"string\")\n                    {\n                        response = $.parseJSON(response);\n                    }\n\n                    response = that.options.responseHandler(response);\n\n                    that.current = response.current;\n                    update(response.rows, response.total);\n                },\n                error: function (jqXHR, textStatus, errorThrown)\n                {\n                    that.xqr = null;\n\n                    if (textStatus !== \"abort\")\n                    {\n                        renderNoResultsRow.call(that); // overrides loading mask\n                        that.element._bgBusyAria(false).trigger(\"loaded\" + namespace);\n                    }\n                }\n            };\n            settings = $.extend(this.options.ajaxSettings, settings);\n\n            this.xqr = $.ajax(settings);\n        }\n        else\n        {\n            var rows = (this.searchPhrase.length > 0) ? this.rows.where(containsPhrase) : this.rows,\n                total = rows.length;\n            if (this.rowCount !== -1)\n            {\n                rows = rows.page(this.current, this.rowCount);\n            }\n\n            // todo: improve the following comment\n            // setTimeout decouples the initialization so that adding event handlers happens before\n            window.setTimeout(function () { update(rows, total); }, 10);\n        }\n    }\n\n    function loadRows()\n    {\n        if (!this.options.ajax)\n        {\n            var that = this,\n                rows = this.element.find(\"tbody > tr\");\n\n            rows.each(function ()\n            {\n                var $this = $(this),\n                    cells = $this.children(\"td\"),\n                    row = {};\n\n                $.each(that.columns, function (i, column)\n                {\n                    row[column.id] = column.converter.from(cells.eq(i).text());\n                });\n\n                appendRow.call(that, row);\n            });\n\n            setTotals.call(this, this.rows.length);\n            sortRows.call(this);\n        }\n    }\n\n    function setTotals(total)\n    {\n        this.total = total;\n        this.totalPages = (this.rowCount === -1) ? 1 :\n            Math.ceil(this.total / this.rowCount);\n    }\n\n    function prepareTable()\n    {\n        var tpl = this.options.templates,\n            wrapper = (this.element.parent().hasClass(this.options.css.responsiveTable)) ?\n                this.element.parent() : this.element;\n\n        this.element.addClass(this.options.css.table);\n\n        // checks whether there is an tbody element; otherwise creates one\n        if (this.element.children(\"tbody\").length === 0)\n        {\n            this.element.append(tpl.body);\n        }\n\n        if (this.options.navigation & 1)\n        {\n            this.header = $(tpl.header.resolve(getParams.call(this, { id: this.element._bgId() + \"-header\" })));\n            wrapper.before(this.header);\n        }\n\n        if (this.options.navigation & 2)\n        {\n            this.footer = $(tpl.footer.resolve(getParams.call(this, { id: this.element._bgId() + \"-footer\" })));\n            wrapper.after(this.footer);\n        }\n    }\n\n    function renderActions()\n    {\n        if (this.options.navigation !== 0)\n        {\n            var css = this.options.css,\n                selector = getCssSelector(css.actions),\n                actionItems = findFooterAndHeaderItems.call(this, selector);\n\n            if (actionItems.length > 0)\n            {\n                var that = this,\n                    tpl = this.options.templates,\n                    actions = $(tpl.actions.resolve(getParams.call(this)));\n\n                // Refresh Button\n                if (this.options.ajax)\n                {\n                    var refreshIcon = tpl.icon.resolve(getParams.call(this, { iconCss: css.iconRefresh })),\n                        refresh = $(tpl.actionButton.resolve(getParams.call(this,\n                        { content: refreshIcon, text: this.options.labels.refresh })))\n                            .on(\"click\" + namespace, function (e)\n                            {\n                                // todo: prevent multiple fast clicks (fast click detection)\n                                e.stopPropagation();\n                                that.current = 1;\n                                loadData.call(that);\n                            });\n                    actions.append(refresh);\n                }\n\n                // Row count selection\n                renderRowCountSelection.call(this, actions);\n\n                // Column selection\n                renderColumnSelection.call(this, actions);\n\n                replacePlaceHolder.call(this, actionItems, actions);\n            }\n        }\n    }\n\n    function renderColumnSelection(actions)\n    {\n        if (this.options.columnSelection && this.columns.length > 1)\n        {\n            var that = this,\n                css = this.options.css,\n                tpl = this.options.templates,\n                icon = tpl.icon.resolve(getParams.call(this, { iconCss: css.iconColumns })),\n                dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: icon }))),\n                selector = getCssSelector(css.dropDownItem),\n                checkboxSelector = getCssSelector(css.dropDownItemCheckbox),\n                itemsSelector = getCssSelector(css.dropDownMenuItems);\n\n            $.each(this.columns, function (i, column)\n            {\n                if (column.visibleInSelection)\n                {\n                    var item = $(tpl.actionDropDownCheckboxItem.resolve(getParams.call(that,\n                        { name: column.id, label: column.text, checked: column.visible })))\n                            .on(\"click\" + namespace, selector, function (e)\n                            {\n                                e.stopPropagation();\n        \n                                var $this = $(this),\n                                    checkbox = $this.find(checkboxSelector);\n                                if (!checkbox.prop(\"disabled\"))\n                                {\n                                    column.visible = checkbox.prop(\"checked\");\n                                    var enable = that.columns.where(isVisible).length > 1;\n                                    $this.parents(itemsSelector).find(selector + \":has(\" + checkboxSelector + \":checked)\")\n                                        ._bgEnableAria(enable).find(checkboxSelector)._bgEnableField(enable);\n        \n                                    that.element.find(\"tbody\").empty(); // Fixes an column visualization bug\n                                    renderTableHeader.call(that);\n                                    loadData.call(that);\n                                }\n                            });\n                    dropDown.find(getCssSelector(css.dropDownMenuItems)).append(item);\n                }\n            });\n            actions.append(dropDown);\n        }\n    }\n\n    function renderInfos()\n    {\n        if (this.options.navigation !== 0)\n        {\n            var selector = getCssSelector(this.options.css.infos),\n                infoItems = findFooterAndHeaderItems.call(this, selector);\n\n            if (infoItems.length > 0)\n            {\n                var end = (this.current * this.rowCount),\n                    infos = $(this.options.templates.infos.resolve(getParams.call(this, {\n                        end: (this.total === 0 || end === -1 || end > this.total) ? this.total : end,\n                        start: (this.total === 0) ? 0 : (end - this.rowCount + 1),\n                        total: this.total\n                    })));\n\n                replacePlaceHolder.call(this, infoItems, infos);\n            }\n        }\n    }\n\n    function renderNoResultsRow()\n    {\n        var tbody = this.element.children(\"tbody\").first(),\n            tpl = this.options.templates,\n            count = this.columns.where(isVisible).length;\n\n        if (this.selection)\n        {\n            count = count + 1;\n        }\n        tbody.html(tpl.noResults.resolve(getParams.call(this, { columns: count })));\n    }\n\n    function renderPagination()\n    {\n        if (this.options.navigation !== 0)\n        {\n            var selector = getCssSelector(this.options.css.pagination),\n                paginationItems = findFooterAndHeaderItems.call(this, selector)._bgShowAria(this.rowCount !== -1);\n\n            if (this.rowCount !== -1 && paginationItems.length > 0)\n            {\n                var tpl = this.options.templates,\n                    current = this.current,\n                    totalPages = this.totalPages,\n                    pagination = $(tpl.pagination.resolve(getParams.call(this))),\n                    offsetRight = totalPages - current,\n                    offsetLeft = (this.options.padding - current) * -1,\n                    startWith = ((offsetRight >= this.options.padding) ?\n                        Math.max(offsetLeft, 1) :\n                        Math.max((offsetLeft - this.options.padding + offsetRight), 1)),\n                    maxCount = this.options.padding * 2 + 1,\n                    count = (totalPages >= maxCount) ? maxCount : totalPages;\n\n                renderPaginationItem.call(this, pagination, \"first\", \"<i class='zmdi zmdi-more-horiz'></i>\", \"first\")\n                    ._bgEnableAria(current > 1);\n                renderPaginationItem.call(this, pagination, \"prev\", \"<i class='zmdi zmdi-chevron-left'></i>\", \"prev\")\n                    ._bgEnableAria(current > 1);\n\n                for (var i = 0; i < count; i++)\n                {\n                    var pos = i + startWith;\n                    renderPaginationItem.call(this, pagination, pos, pos, \"page-\" + pos)\n                        ._bgEnableAria()._bgSelectAria(pos === current);\n                }\n\n                if (count === 0)\n                {\n                    renderPaginationItem.call(this, pagination, 1, 1, \"page-\" + 1)\n                        ._bgEnableAria(false)._bgSelectAria();\n                }\n\n                renderPaginationItem.call(this, pagination, \"next\", \"<i class='zmdi zmdi-chevron-right'></i>\", \"next\")\n                    ._bgEnableAria(totalPages > current);\n                renderPaginationItem.call(this, pagination, \"last\", \"<i class='zmdi zmdi-more-horiz'></i>\", \"last\")\n                    ._bgEnableAria(totalPages > current);\n\n                replacePlaceHolder.call(this, paginationItems, pagination);\n            }\n        }\n    }\n\n    function renderPaginationItem(list, page, text, markerCss)\n    {\n        var that = this,\n            tpl = this.options.templates,\n            css = this.options.css,\n            values = getParams.call(this, { css: markerCss, text: text, page: page }),\n            item = $(tpl.paginationItem.resolve(values))\n                .on(\"click\" + namespace, getCssSelector(css.paginationButton), function (e)\n                {\n                    e.stopPropagation();\n                    e.preventDefault();\n\n                    var $this = $(this),\n                        parent = $this.parent();\n                    if (!parent.hasClass(\"active\") && !parent.hasClass(\"disabled\"))\n                    {\n                        var commandList = {\n                            first: 1,\n                            prev: that.current - 1,\n                            next: that.current + 1,\n                            last: that.totalPages\n                        };\n                        var command = $this.data(\"page\");\n                        that.current = commandList[command] || command;\n                        loadData.call(that);\n                    }\n                    $this.trigger(\"blur\");\n                });\n\n        list.append(item);\n        return item;\n    }\n\n    function renderRowCountSelection(actions)\n    {\n        var that = this,\n            rowCountList = this.options.rowCount;\n\n        function getText(value)\n        {\n            return (value === -1) ? that.options.labels.all : value;\n        }\n\n        if ($.isArray(rowCountList))\n        {\n            var css = this.options.css,\n                tpl = this.options.templates,\n                dropDown = $(tpl.actionDropDown.resolve(getParams.call(this, { content: getText(this.rowCount) }))),\n                menuSelector = getCssSelector(css.dropDownMenu),\n                menuTextSelector = getCssSelector(css.dropDownMenuText),\n                menuItemsSelector = getCssSelector(css.dropDownMenuItems),\n                menuItemSelector = getCssSelector(css.dropDownItemButton);\n\n            $.each(rowCountList, function (index, value)\n            {\n                var item = $(tpl.actionDropDownItem.resolve(getParams.call(that,\n                    { text: getText(value), action: value })))\n                        ._bgSelectAria(value === that.rowCount)\n                        .on(\"click\" + namespace, menuItemSelector, function (e)\n                        {\n                            e.preventDefault();\n\n                            var $this = $(this),\n                                newRowCount = $this.data(\"action\");\n                            if (newRowCount !== that.rowCount)\n                            {\n                                // todo: sophisticated solution needed for calculating which page is selected\n                                that.current = 1; // that.rowCount === -1 ---> All\n                                that.rowCount = newRowCount;\n                                $this.parents(menuItemsSelector).children().each(function ()\n                                {\n                                    var $item = $(this),\n                                        currentRowCount = $item.find(menuItemSelector).data(\"action\");\n                                    $item._bgSelectAria(currentRowCount === newRowCount);\n                                });\n                                $this.parents(menuSelector).find(menuTextSelector).text(getText(newRowCount));\n                                loadData.call(that);\n                            }\n                        });\n                dropDown.find(menuItemsSelector).append(item);\n            });\n            actions.append(dropDown);\n        }\n    }\n\n    function renderRows(rows)\n    {\n        if (rows.length > 0)\n        {\n            var that = this,\n                css = this.options.css,\n                tpl = this.options.templates,\n                tbody = this.element.children(\"tbody\").first(),\n                allRowsSelected = true,\n                html = \"\";\n\n            $.each(rows, function (index, row)\n            {\n                var cells = \"\",\n                    rowAttr = \" data-row-id=\\\"\" + ((that.identifier == null) ? index : row[that.identifier]) + \"\\\"\",\n                    rowCss = \"\";\n\n                if (that.selection)\n                {\n                    var selected = ($.inArray(row[that.identifier], that.selectedRows) !== -1),\n                        selectBox = tpl.select.resolve(getParams.call(that,\n                            { type: \"checkbox\", value: row[that.identifier], checked: selected }));\n                    cells += tpl.cell.resolve(getParams.call(that, { content: selectBox, css: css.selectCell }));\n                    allRowsSelected = (allRowsSelected && selected);\n                    if (selected)\n                    {\n                        rowCss += css.selected;\n                        rowAttr += \" aria-selected=\\\"true\\\"\";\n                    }\n                }\n\n                var status = row.status != null && that.options.statusMapping[row.status];\n                if (status)\n                {\n                    rowCss += status;\n                }\n\n                $.each(that.columns, function (j, column)\n                {\n                    if (column.visible)\n                    {\n                        var value = ($.isFunction(column.formatter)) ?\n                                column.formatter.call(that, column, row) :\n                                    column.converter.to(row[column.id]),\n                            cssClass = (column.cssClass.length > 0) ? \" \" + column.cssClass : \"\";\n                        cells += tpl.cell.resolve(getParams.call(that, {\n                            content: (value == null || value === \"\") ? \"&nbsp;\" : value,\n                            css: ((column.align === \"right\") ? css.right : (column.align === \"center\") ?\n                                css.center : css.left) + cssClass,\n                            style: (column.width == null) ? \"\" : \"width:\" + column.width + \";\" }));\n                    }\n                });\n\n                if (rowCss.length > 0)\n                {\n                    rowAttr += \" class=\\\"\" + rowCss + \"\\\"\";\n                }\n                html += tpl.row.resolve(getParams.call(that, { attr: rowAttr, cells: cells }));\n            });\n\n            // sets or clears multi selectbox state\n            that.element.find(\"thead \" + getCssSelector(that.options.css.selectBox))\n                .prop(\"checked\", allRowsSelected);\n\n            tbody.html(html);\n\n            registerRowEvents.call(this, tbody);\n        }\n        else\n        {\n            renderNoResultsRow.call(this);\n        }\n    }\n\n    function registerRowEvents(tbody)\n    {\n        var that = this,\n            selectBoxSelector = getCssSelector(this.options.css.selectBox);\n\n        if (this.selection)\n        {\n            tbody.off(\"click\" + namespace, selectBoxSelector)\n                .on(\"click\" + namespace, selectBoxSelector, function(e)\n                {\n                    e.stopPropagation();\n\n                    var $this = $(this),\n                        id = that.converter.from($this.val());\n\n                    if ($this.prop(\"checked\"))\n                    {\n                        that.select([id]);\n                    }\n                    else\n                    {\n                        that.deselect([id]);\n                    }\n                });\n        }\n\n        tbody.off(\"click\" + namespace, \"> tr\")\n            .on(\"click\" + namespace, \"> tr\", function(e)\n            {\n                e.stopPropagation();\n\n                var $this = $(this),\n                    id = (that.identifier == null) ? $this.data(\"row-id\") :\n                        that.converter.from($this.data(\"row-id\") + \"\"),\n                    row = (that.identifier == null) ? that.currentRows[id] :\n                        that.currentRows.first(function (item) { return item[that.identifier] === id; });\n\n                if (that.selection && that.options.rowSelect)\n                {\n                    if ($this.hasClass(that.options.css.selected))\n                    {\n                        that.deselect([id]);\n                    }\n                    else\n                    {\n                        that.select([id]);\n                    }\n                }\n\n                that.element.trigger(\"click\" + namespace, [that.columns, row]);\n            });\n    }\n\n    function renderSearchField()\n    {\n        if (this.options.navigation !== 0)\n        {\n            var css = this.options.css,\n                selector = getCssSelector(css.search),\n                searchItems = findFooterAndHeaderItems.call(this, selector);\n\n            if (searchItems.length > 0)\n            {\n                var that = this,\n                    tpl = this.options.templates,\n                    timer = null, // fast keyup detection\n                    currentValue = \"\",\n                    searchFieldSelector = getCssSelector(css.searchField),\n                    search = $(tpl.search.resolve(getParams.call(this))),\n                    searchField = (search.is(searchFieldSelector)) ? search :\n                        search.find(searchFieldSelector);\n\n                searchField.on(\"keyup\" + namespace, function (e)\n                {\n                    e.stopPropagation();\n                    var newValue = $(this).val();\n                    if (currentValue !== newValue || (e.which === 13 && newValue !== \"\"))\n                    {\n                        currentValue = newValue;\n                        if (e.which === 13 || newValue.length === 0 || newValue.length >= that.options.searchSettings.characters)\n                        {\n                            window.clearTimeout(timer);\n                            timer = window.setTimeout(function ()\n                            {\n                                executeSearch.call(that, newValue);\n                            }, that.options.searchSettings.delay);\n                        }\n                    }\n                });\n\n                replacePlaceHolder.call(this, searchItems, search);\n            }\n        }\n    }\n\n    function executeSearch(phrase)\n    {\n        if (this.searchPhrase !== phrase)\n        {\n            this.current = 1;\n            this.searchPhrase = phrase;\n            loadData.call(this);\n        }\n    }\n\n    function renderTableHeader()\n    {\n        var that = this,\n            headerRow = this.element.find(\"thead > tr\"),\n            css = this.options.css,\n            tpl = this.options.templates,\n            html = \"\",\n            sorting = this.options.sorting;\n\n        if (this.selection)\n        {\n            var selectBox = (this.options.multiSelect) ?\n                tpl.select.resolve(getParams.call(that, { type: \"checkbox\", value: \"all\" })) : \"\";\n            html += tpl.rawHeaderCell.resolve(getParams.call(that, { content: selectBox,\n                css: css.selectCell }));\n        }\n\n        $.each(this.columns, function (index, column)\n        {\n            if (column.visible)\n            {\n                var sortOrder = that.sortDictionary[column.id],\n                    iconCss = ((sorting && sortOrder && sortOrder === \"asc\") ? css.iconUp :\n                        (sorting && sortOrder && sortOrder === \"desc\") ? css.iconDown : \"\"),\n                    icon = tpl.icon.resolve(getParams.call(that, { iconCss: iconCss })),\n                    align = column.headerAlign,\n                    cssClass = (column.headerCssClass.length > 0) ? \" \" + column.headerCssClass : \"\";\n                html += tpl.headerCell.resolve(getParams.call(that, {\n                    column: column, icon: icon, sortable: sorting && column.sortable && css.sortable || \"\",\n                    css: ((align === \"right\") ? css.right : (align === \"center\") ?\n                        css.center : css.left) + cssClass,\n                    style: (column.width == null) ? \"\" : \"width:\" + column.width + \";\" }));\n            }\n        });\n\n        headerRow.html(html);\n\n        if (sorting)\n        {\n            var sortingSelector = getCssSelector(css.sortable);\n            headerRow.off(\"click\" + namespace, sortingSelector)\n                .on(\"click\" + namespace, sortingSelector, function (e)\n                {\n                    e.preventDefault();\n\n                    setTableHeaderSortDirection.call(that, $(this));\n                    sortRows.call(that);\n                    loadData.call(that);\n                });\n        }\n\n        // todo: create a own function for that piece of code\n        if (this.selection && this.options.multiSelect)\n        {\n            var selectBoxSelector = getCssSelector(css.selectBox);\n            headerRow.off(\"click\" + namespace, selectBoxSelector)\n                .on(\"click\" + namespace, selectBoxSelector, function(e)\n                {\n                    e.stopPropagation();\n\n                    if ($(this).prop(\"checked\"))\n                    {\n                        that.select();\n                    }\n                    else\n                    {\n                        that.deselect();\n                    }\n                });\n        }\n    }\n\n    function setTableHeaderSortDirection(element)\n    {\n        var css = this.options.css,\n            iconSelector = getCssSelector(css.icon),\n            columnId = element.data(\"column-id\") || element.parents(\"th\").first().data(\"column-id\"),\n            sortOrder = this.sortDictionary[columnId],\n            icon = element.find(iconSelector);\n\n        if (!this.options.multiSort)\n        {\n            element.parents(\"tr\").first().find(iconSelector).removeClass(css.iconDown + \" \" + css.iconUp);\n            this.sortDictionary = {};\n        }\n\n        if (sortOrder && sortOrder === \"asc\")\n        {\n            this.sortDictionary[columnId] = \"desc\";\n            icon.removeClass(css.iconUp).addClass(css.iconDown);\n        }\n        else if (sortOrder && sortOrder === \"desc\")\n        {\n            if (this.options.multiSort)\n            {\n                var newSort = {};\n                for (var key in this.sortDictionary)\n                {\n                    if (key !== columnId)\n                    {\n                        newSort[key] = this.sortDictionary[key];\n                    }\n                }\n                this.sortDictionary = newSort;\n                icon.removeClass(css.iconDown);\n            }\n            else\n            {\n                this.sortDictionary[columnId] = \"asc\";\n                icon.removeClass(css.iconDown).addClass(css.iconUp);\n            }\n        }\n        else\n        {\n            this.sortDictionary[columnId] = \"asc\";\n            icon.addClass(css.iconUp);\n        }\n    }\n\n    function replacePlaceHolder(placeholder, element)\n    {\n        placeholder.each(function (index, item)\n        {\n            // todo: check how append is implemented. Perhaps cloning here is superfluous.\n            $(item).before(element.clone(true)).remove();\n        });\n    }\n\n    function showLoading()\n    {\n        var that = this;\n\n        window.setTimeout(function()\n        {\n            if (that.element._bgAria(\"busy\") === \"true\")\n            {\n                var tpl = that.options.templates,\n                    thead = that.element.children(\"thead\").first(),\n                    tbody = that.element.children(\"tbody\").first(),\n                    firstCell = tbody.find(\"tr > td\").first(),\n                    padding = (that.element.height() - thead.height()) - (firstCell.height() + 20),\n                    count = that.columns.where(isVisible).length;\n\n                if (that.selection)\n                {\n                    count = count + 1;\n                }\n                tbody.html(tpl.loading.resolve(getParams.call(that, { columns: count })));\n                if (that.rowCount !== -1 && padding > 0)\n                {\n                    tbody.find(\"tr > td\").css(\"padding\", \"20px 0 \" + padding + \"px\");\n                }\n            }\n        }, 250);\n    }\n\n    function sortRows()\n    {\n        var sortArray = [];\n\n        function sort(x, y, current)\n        {\n            current = current || 0;\n            var next = current + 1,\n                item = sortArray[current];\n\n            function sortOrder(value)\n            {\n                return (item.order === \"asc\") ? value : value * -1;\n            }\n\n            return (x[item.id] > y[item.id]) ? sortOrder(1) :\n                (x[item.id] < y[item.id]) ? sortOrder(-1) :\n                    (sortArray.length > next) ? sort(x, y, next) : 0;\n        }\n\n        if (!this.options.ajax)\n        {\n            var that = this;\n\n            for (var key in this.sortDictionary)\n            {\n                if (this.options.multiSort || sortArray.length === 0)\n                {\n                    sortArray.push({\n                        id: key,\n                        order: this.sortDictionary[key]\n                    });\n                }\n            }\n\n            if (sortArray.length > 0)\n            {\n                this.rows.sort(sort);\n            }\n        }\n    }\n\n    // GRID PUBLIC CLASS DEFINITION\n    // ====================\n\n    /**\n     * Represents the jQuery Bootgrid plugin.\n     *\n     * @class Grid\n     * @constructor\n     * @param element {Object} The corresponding DOM element.\n     * @param options {Object} The options to override default settings.\n     * @chainable\n     **/\n    var Grid = function(element, options)\n    {\n        this.element = $(element);\n        this.origin = this.element.clone();\n        this.options = $.extend(true, {}, Grid.defaults, this.element.data(), options);\n        // overrides rowCount explicitly because deep copy ($.extend) leads to strange behaviour\n        var rowCount = this.options.rowCount = this.element.data().rowCount || options.rowCount || this.options.rowCount;\n        this.columns = [];\n        this.current = 1;\n        this.currentRows = [];\n        this.identifier = null; // The first column ID that is marked as identifier\n        this.selection = false;\n        this.converter = null; // The converter for the column that is marked as identifier\n        this.rowCount = ($.isArray(rowCount)) ? rowCount[0] : rowCount;\n        this.rows = [];\n        this.searchPhrase = \"\";\n        this.selectedRows = [];\n        this.sortDictionary = {};\n        this.total = 0;\n        this.totalPages = 0;\n        this.cachedParams = {\n            lbl: this.options.labels,\n            css: this.options.css,\n            ctx: {}\n        };\n        this.header = null;\n        this.footer = null;\n        this.xqr = null;\n\n        // todo: implement cache\n    };\n\n    /**\n     * An object that represents the default settings.\n     *\n     * @static\n     * @class defaults\n     * @for Grid\n     * @example\n     *   // Global approach\n     *   $.bootgrid.defaults.selection = true;\n     * @example\n     *   // Initialization approach\n     *   $(\"#bootgrid\").bootgrid({ selection = true });\n     **/\n    Grid.defaults = {\n        navigation: 3, // it's a flag: 0 = none, 1 = top, 2 = bottom, 3 = both (top and bottom)\n        padding: 2, // page padding (pagination)\n        columnSelection: true,\n        rowCount: [10, 25, 50, -1], // rows per page int or array of int (-1 represents \"All\")\n\n        /**\n         * Enables row selection (to enable multi selection see also `multiSelect`). Default value is `false`.\n         *\n         * @property selection\n         * @type Boolean\n         * @default false\n         * @for defaults\n         * @since 1.0.0\n         **/\n        selection: false,\n\n        /**\n         * Enables multi selection (`selection` must be set to `true` as well). Default value is `false`.\n         *\n         * @property multiSelect\n         * @type Boolean\n         * @default false\n         * @for defaults\n         * @since 1.0.0\n         **/\n        multiSelect: false,\n\n        /**\n         * Enables entire row click selection (`selection` must be set to `true` as well). Default value is `false`.\n         *\n         * @property rowSelect\n         * @type Boolean\n         * @default false\n         * @for defaults\n         * @since 1.1.0\n         **/\n        rowSelect: false,\n\n        /**\n         * Defines whether the row selection is saved internally on filtering, paging and sorting\n         * (even if the selected rows are not visible).\n         *\n         * @property keepSelection\n         * @type Boolean\n         * @default false\n         * @for defaults\n         * @since 1.1.0\n         **/\n        keepSelection: false,\n\n        highlightRows: false, // highlights new rows (find the page of the first new row)\n        sorting: true,\n        multiSort: false,\n\n        /**\n         * General search settings to configure the search field behaviour.\n         *\n         * @property searchSettings\n         * @type Object\n         * @for defaults\n         * @since 1.2.0\n         **/\n        searchSettings: {\n            /**\n             * The time in milliseconds to wait before search gets executed.\n             *\n             * @property delay\n             * @type Number\n             * @default 250\n             * @for searchSettings\n             **/\n            delay: 250,\n            \n            /**\n             * The characters to type before the search gets executed.\n             *\n             * @property characters\n             * @type Number\n             * @default 1\n             * @for searchSettings\n             **/\n            characters: 1\n        },\n\n        /**\n         * Defines whether the data shall be loaded via an asynchronous HTTP (Ajax) request.\n         *\n         * @property ajax\n         * @type Boolean\n         * @default false\n         * @for defaults\n         **/\n        ajax: false,\n\n        /**\n         * Ajax request settings that shall be used for server-side communication.\n         * All setting except data, error, success and url can be overridden.\n         * For the full list of settings go to http://api.jquery.com/jQuery.ajax/.\n         *\n         * @property ajaxSettings\n         * @type Object\n         * @for defaults\n         * @since 1.2.0\n         **/\n        ajaxSettings: {\n            /**\n             * Specifies the HTTP method which shall be used when sending data to the server.\n             * Go to http://api.jquery.com/jQuery.ajax/ for more details.\n             * This setting is overriden for backward compatibility.\n             *\n             * @property method\n             * @type String\n             * @default \"POST\"\n             * @for ajaxSettings\n             **/\n            method: \"POST\"\n        },\n\n        /**\n         * Enriches the request object with additional properties. Either a `PlainObject` or a `Function`\n         * that returns a `PlainObject` can be passed. Default value is `{}`.\n         *\n         * @property post\n         * @type Object|Function\n         * @default function (request) { return request; }\n         * @for defaults\n         * @deprecated Use instead `requestHandler`\n         **/\n        post: {}, // or use function () { return {}; } (reserved properties are \"current\", \"rowCount\", \"sort\" and \"searchPhrase\")\n\n        /**\n         * Sets the data URL to a data service (e.g. a REST service). Either a `String` or a `Function`\n         * that returns a `String` can be passed. Default value is `\"\"`.\n         *\n         * @property url\n         * @type String|Function\n         * @default \"\"\n         * @for defaults\n         **/\n        url: \"\", // or use function () { return \"\"; }\n\n        /**\n         * Defines whether the search is case sensitive or insensitive.\n         *\n         * @property caseSensitive\n         * @type Boolean\n         * @default true\n         * @for defaults\n         * @since 1.1.0\n         **/\n        caseSensitive: true,\n\n        // note: The following properties should not be used via data-api attributes\n\n        /**\n         * Transforms the JSON request object in what ever is needed on the server-side implementation.\n         *\n         * @property requestHandler\n         * @type Function\n         * @default function (request) { return request; }\n         * @for defaults\n         * @since 1.1.0\n         **/\n        requestHandler: function (request) { return request; },\n\n        /**\n         * Transforms the response object into the expected JSON response object.\n         *\n         * @property responseHandler\n         * @type Function\n         * @default function (response) { return response; }\n         * @for defaults\n         * @since 1.1.0\n         **/\n        responseHandler: function (response) { return response; },\n\n        /**\n         * A list of converters.\n         *\n         * @property converters\n         * @type Object\n         * @for defaults\n         * @since 1.0.0\n         **/\n        converters: {\n            numeric: {\n                from: function (value) { return +value; }, // converts from string to numeric\n                to: function (value) { return value + \"\"; } // converts from numeric to string\n            },\n            string: {\n                // default converter\n                from: function (value) { return value; },\n                to: function (value) { return value; }\n            }\n        },\n\n        /**\n         * Contains all css classes.\n         *\n         * @property css\n         * @type Object\n         * @for defaults\n         **/\n        css: {\n            actions: \"actions btn-group\", // must be a unique class name or constellation of class names within the header and footer\n            center: \"text-center\",\n            columnHeaderAnchor: \"column-header-anchor\", // must be a unique class name or constellation of class names within the column header cell\n            columnHeaderText: \"text\",\n            dropDownItem: \"dropdown-item\", // must be a unique class name or constellation of class names within the actionDropDown,\n            dropDownItemButton: \"dropdown-item-button\", // must be a unique class name or constellation of class names within the actionDropDown\n            dropDownItemCheckbox: \"dropdown-item-checkbox\", // must be a unique class name or constellation of class names within the actionDropDown\n            dropDownMenu: \"dropdown btn-group\", // must be a unique class name or constellation of class names within the actionDropDown\n            dropDownMenuItems: \"dropdown-menu pull-right\", // must be a unique class name or constellation of class names within the actionDropDown\n            dropDownMenuText: \"dropdown-text\", // must be a unique class name or constellation of class names within the actionDropDown\n            footer: \"bootgrid-footer container-fluid\",\n            header: \"bootgrid-header container-fluid\",\n            icon: \"icon glyphicon\",\n            iconColumns: \"glyphicon-th-list\",\n            iconDown: \"glyphicon-chevron-down\",\n            iconRefresh: \"glyphicon-refresh\",\n            iconSearch: \"glyphicon-search\",\n            iconUp: \"glyphicon-chevron-up\",\n            infos: \"infos\", // must be a unique class name or constellation of class names within the header and footer,\n            left: \"text-left\",\n            pagination: \"pagination\", // must be a unique class name or constellation of class names within the header and footer\n            paginationButton: \"button\", // must be a unique class name or constellation of class names within the pagination\n\n            /**\n             * CSS class to select the parent div which activates responsive mode.\n             *\n             * @property responsiveTable\n             * @type String\n             * @default \"table-responsive\"\n             * @for css\n             * @since 1.1.0\n             **/\n            responsiveTable: \"table-responsive\",\n\n            right: \"text-right\",\n            search: \"search form-group\", // must be a unique class name or constellation of class names within the header and footer\n            searchField: \"search-field form-control\",\n            selectBox: \"select-box\", // must be a unique class name or constellation of class names within the entire table\n            selectCell: \"select-cell\", // must be a unique class name or constellation of class names within the entire table\n\n            /**\n             * CSS class to highlight selected rows.\n             *\n             * @property selected\n             * @type String\n             * @default \"active\"\n             * @for css\n             * @since 1.1.0\n             **/\n            selected: \"active\",\n\n            sortable: \"sortable\",\n            table: \"bootgrid-table table\"\n        },\n\n        /**\n         * A dictionary of formatters.\n         *\n         * @property formatters\n         * @type Object\n         * @for defaults\n         * @since 1.0.0\n         **/\n        formatters: {},\n\n        /**\n         * Contains all labels.\n         *\n         * @property labels\n         * @type Object\n         * @for defaults\n         **/\n        labels: {\n            all: \"All\",\n            infos: \"Showing {{ctx.start}} to {{ctx.end}} of {{ctx.total}} entries\",\n            loading: \"Loading...\",\n            noResults: \"No results found!\",\n            refresh: \"Refresh\",\n            search: \"Search\"\n        },\n\n        /**\n         * Specifies the mapping between status and contextual classes to color rows.\n         *\n         * @property statusMapping\n         * @type Object\n         * @for defaults\n         * @since 1.2.0\n         **/\n        statusMapping: {\n            /**\n             * Specifies a successful or positive action.\n             *\n             * @property 0\n             * @type String\n             * @for statusMapping\n             **/\n            0: \"success\",\n\n            /**\n             * Specifies a neutral informative change or action.\n             *\n             * @property 1\n             * @type String\n             * @for statusMapping\n             **/\n            1: \"info\",\n\n            /**\n             * Specifies a warning that might need attention.\n             *\n             * @property 2\n             * @type String\n             * @for statusMapping\n             **/\n            2: \"warning\",\n            \n            /**\n             * Specifies a dangerous or potentially negative action.\n             *\n             * @property 3\n             * @type String\n             * @for statusMapping\n             **/\n            3: \"danger\"\n        },\n\n        /**\n         * Contains all templates.\n         *\n         * @property templates\n         * @type Object\n         * @for defaults\n         **/\n        templates: {\n            actionButton: \"<button class=\\\"btn btn-default\\\" type=\\\"button\\\" title=\\\"{{ctx.text}}\\\">{{ctx.content}}</button>\",\n            actionDropDown: \"<div class=\\\"{{css.dropDownMenu}}\\\"><button class=\\\"btn btn-default dropdown-toggle\\\" type=\\\"button\\\" data-toggle=\\\"dropdown\\\"><span class=\\\"{{css.dropDownMenuText}}\\\">{{ctx.content}}</span> <span class=\\\"caret\\\"></span></button><ul class=\\\"{{css.dropDownMenuItems}}\\\" role=\\\"menu\\\"></ul></div>\",\n            actionDropDownItem: \"<li><a data-action=\\\"{{ctx.action}}\\\" class=\\\"{{css.dropDownItem}} {{css.dropDownItemButton}}\\\">{{ctx.text}}</a></li>\",\n            actionDropDownCheckboxItem: \"<li><div class=\\\"checkbox\\\"><label class=\\\"{{css.dropDownItem}}\\\"><input name=\\\"{{ctx.name}}\\\" type=\\\"checkbox\\\" value=\\\"1\\\" class=\\\"{{css.dropDownItemCheckbox}}\\\" {{ctx.checked}} /> {{ctx.label}}<i class=\\\"input-helper\\\"></i></label></div></li>\",\n            actions: \"<div class=\\\"{{css.actions}}\\\"></div>\",\n            body: \"<tbody></tbody>\",\n            cell: \"<td class=\\\"{{ctx.css}}\\\" style=\\\"{{ctx.style}}\\\">{{ctx.content}}</td>\",\n            footer: \"<div id=\\\"{{ctx.id}}\\\" class=\\\"{{css.footer}}\\\"><div class=\\\"row\\\"><div class=\\\"col-sm-6\\\"><p class=\\\"{{css.pagination}}\\\"></p></div><div class=\\\"col-sm-6 infoBar\\\"><p class=\\\"{{css.infos}}\\\"></p></div></div></div>\",\n            header: \"<div id=\\\"{{ctx.id}}\\\" class=\\\"{{css.header}}\\\"><div class=\\\"row\\\"><div class=\\\"col-sm-12 actionBar\\\"><p class=\\\"{{css.search}}\\\"></p><p class=\\\"{{css.actions}}\\\"></p></div></div></div>\",\n            headerCell: \"<th data-column-id=\\\"{{ctx.column.id}}\\\" class=\\\"{{ctx.css}}\\\" style=\\\"{{ctx.style}}\\\"><a href=\\\"javascript:void(0);\\\" class=\\\"{{css.columnHeaderAnchor}} {{ctx.sortable}}\\\"><span class=\\\"{{css.columnHeaderText}}\\\">{{ctx.column.text}}</span>{{ctx.icon}}</a></th>\",\n            icon: \"<span class=\\\"{{css.icon}} {{ctx.iconCss}}\\\"></span>\",\n            infos: \"<div class=\\\"{{css.infos}}\\\">{{lbl.infos}}</div>\",\n            loading: \"<tr><td colspan=\\\"{{ctx.columns}}\\\" class=\\\"loading\\\">{{lbl.loading}}</td></tr>\",\n            noResults: \"<tr><td colspan=\\\"{{ctx.columns}}\\\" class=\\\"no-results\\\">{{lbl.noResults}}</td></tr>\",\n            pagination: \"<ul class=\\\"{{css.pagination}}\\\"></ul>\",\n            paginationItem: \"<li class=\\\"{{ctx.css}}\\\"><a data-page=\\\"{{ctx.page}}\\\" class=\\\"{{css.paginationButton}}\\\">{{ctx.text}}</a></li>\",\n            rawHeaderCell: \"<th class=\\\"{{ctx.css}}\\\">{{ctx.content}}</th>\", // Used for the multi select box\n            row: \"<tr{{ctx.attr}}>{{ctx.cells}}</tr>\",\n            search: \"<div class=\\\"{{css.search}}\\\"><div class=\\\"input-group\\\"><span class=\\\"{{css.icon}} input-group-addon {{css.iconSearch}}\\\"></span> <input type=\\\"text\\\" class=\\\"{{css.searchField}}\\\" placeholder=\\\"{{lbl.search}}\\\" /></div></div>\",\n            select: \"<div class=\\\"checkbox\\\"><label><input name=\\\"select\\\" type=\\\"{{ctx.type}}\\\" class=\\\"{{css.selectBox}}\\\" value=\\\"{{ctx.value}}\\\" {{ctx.checked}} /><i class=\\\"input-helper\\\"></i></label></div>\"\n        }\n    };\n\n    /**\n     * Appends rows.\n     *\n     * @method append\n     * @param rows {Array} An array of rows to append\n     * @chainable\n     **/\n    Grid.prototype.append = function(rows)\n    {\n        if (this.options.ajax)\n        {\n            // todo: implement ajax PUT\n        }\n        else\n        {\n            var appendedRows = [];\n            for (var i = 0; i < rows.length; i++)\n            {\n                if (appendRow.call(this, rows[i]))\n                {\n                    appendedRows.push(rows[i]);\n                }\n            }\n            sortRows.call(this);\n            highlightAppendedRows.call(this, appendedRows);\n            loadData.call(this);\n            this.element.trigger(\"appended\" + namespace, [appendedRows]);\n        }\n\n        return this;\n    };\n\n    /**\n     * Removes all rows.\n     *\n     * @method clear\n     * @chainable\n     **/\n    Grid.prototype.clear = function()\n    {\n        if (this.options.ajax)\n        {\n            // todo: implement ajax POST\n        }\n        else\n        {\n            var removedRows = $.extend([], this.rows);\n            this.rows = [];\n            this.current = 1;\n            this.total = 0;\n            loadData.call(this);\n            this.element.trigger(\"cleared\" + namespace, [removedRows]);\n        }\n\n        return this;\n    };\n\n    /**\n     * Removes the control functionality completely and transforms the current state to the initial HTML structure.\n     *\n     * @method destroy\n     * @chainable\n     **/\n    Grid.prototype.destroy = function()\n    {\n        // todo: this method has to be optimized (the complete initial state must be restored)\n        $(window).off(namespace);\n        if (this.options.navigation & 1)\n        {\n            this.header.remove();\n        }\n        if (this.options.navigation & 2)\n        {\n            this.footer.remove();\n        }\n        this.element.before(this.origin).remove();\n\n        return this;\n    };\n\n    /**\n     * Resets the state and reloads rows.\n     *\n     * @method reload\n     * @chainable\n     **/\n    Grid.prototype.reload = function()\n    {\n        this.current = 1; // reset\n        loadData.call(this);\n\n        return this;\n    };\n\n    /**\n     * Removes rows by ids. Removes selected rows if no ids are provided.\n     *\n     * @method remove\n     * @param [rowsIds] {Array} An array of rows ids to remove\n     * @chainable\n     **/\n    Grid.prototype.remove = function(rowIds)\n    {\n        if (this.identifier != null)\n        {\n            var that = this;\n\n            if (this.options.ajax)\n            {\n                // todo: implement ajax DELETE\n            }\n            else\n            {\n                rowIds = rowIds || this.selectedRows;\n                var id,\n                    removedRows = [];\n\n                for (var i = 0; i < rowIds.length; i++)\n                {\n                    id = rowIds[i];\n\n                    for (var j = 0; j < this.rows.length; j++)\n                    {\n                        if (this.rows[j][this.identifier] === id)\n                        {\n                            removedRows.push(this.rows[j]);\n                            this.rows.splice(j, 1);\n                            break;\n                        }\n                    }\n                }\n\n                this.current = 1; // reset\n                loadData.call(this);\n                this.element.trigger(\"removed\" + namespace, [removedRows]);\n            }\n        }\n\n        return this;\n    };\n\n    /**\n     * Searches in all rows for a specific phrase (but only in visible cells). \n     * The search filter will be reseted, if no argument is provided.\n     *\n     * @method search\n     * @param [phrase] {String} The phrase to search for\n     * @chainable\n     **/\n    Grid.prototype.search = function(phrase)\n    {\n        phrase = phrase || \"\";\n\n        if (this.searchPhrase !== phrase)\n        {\n            var selector = getCssSelector(this.options.css.searchField),\n                searchFields = findFooterAndHeaderItems.call(this, selector);\n            searchFields.val(phrase);\n        }\n\n        executeSearch.call(this, phrase);\n\n\n        return this;\n    };\n\n    /**\n     * Selects rows by ids. Selects all visible rows if no ids are provided.\n     * In server-side scenarios only visible rows are selectable.\n     *\n     * @method select\n     * @param [rowsIds] {Array} An array of rows ids to select\n     * @chainable\n     **/\n    Grid.prototype.select = function(rowIds)\n    {\n        if (this.selection)\n        {\n            rowIds = rowIds || this.currentRows.propValues(this.identifier);\n\n            var id, i,\n                selectedRows = [];\n\n            while (rowIds.length > 0 && !(!this.options.multiSelect && selectedRows.length === 1))\n            {\n                id = rowIds.pop();\n                if ($.inArray(id, this.selectedRows) === -1)\n                {\n                    for (i = 0; i < this.currentRows.length; i++)\n                    {\n                        if (this.currentRows[i][this.identifier] === id)\n                        {\n                            selectedRows.push(this.currentRows[i]);\n                            this.selectedRows.push(id);\n                            break;\n                        }\n                    }\n                }\n            }\n\n            if (selectedRows.length > 0)\n            {\n                var selectBoxSelector = getCssSelector(this.options.css.selectBox),\n                    selectMultiSelectBox = this.selectedRows.length >= this.currentRows.length;\n\n                i = 0;\n                while (!this.options.keepSelection && selectMultiSelectBox && i < this.currentRows.length)\n                {\n                    selectMultiSelectBox = ($.inArray(this.currentRows[i++][this.identifier], this.selectedRows) !== -1);\n                }\n                this.element.find(\"thead \" + selectBoxSelector).prop(\"checked\", selectMultiSelectBox);\n\n                if (!this.options.multiSelect)\n                {\n                    this.element.find(\"tbody > tr \" + selectBoxSelector + \":checked\")\n                        .trigger(\"click\" + namespace);\n                }\n\n                for (i = 0; i < this.selectedRows.length; i++)\n                {\n                    this.element.find(\"tbody > tr[data-row-id=\\\"\" + this.selectedRows[i] + \"\\\"]\")\n                        .addClass(this.options.css.selected)._bgAria(\"selected\", \"true\")\n                        .find(selectBoxSelector).prop(\"checked\", true);\n                }\n\n                this.element.trigger(\"selected\" + namespace, [selectedRows]);\n            }\n        }\n\n        return this;\n    };\n\n    /**\n     * Deselects rows by ids. Deselects all visible rows if no ids are provided.\n     * In server-side scenarios only visible rows are deselectable.\n     *\n     * @method deselect\n     * @param [rowsIds] {Array} An array of rows ids to deselect\n     * @chainable\n     **/\n    Grid.prototype.deselect = function(rowIds)\n    {\n        if (this.selection)\n        {\n            rowIds = rowIds || this.currentRows.propValues(this.identifier);\n\n            var id, i, pos,\n                deselectedRows = [];\n\n            while (rowIds.length > 0)\n            {\n                id = rowIds.pop();\n                pos = $.inArray(id, this.selectedRows);\n                if (pos !== -1)\n                {\n                    for (i = 0; i < this.currentRows.length; i++)\n                    {\n                        if (this.currentRows[i][this.identifier] === id)\n                        {\n                            deselectedRows.push(this.currentRows[i]);\n                            this.selectedRows.splice(pos, 1);\n                            break;\n                        }\n                    }\n                }\n            }\n\n            if (deselectedRows.length > 0)\n            {\n                var selectBoxSelector = getCssSelector(this.options.css.selectBox);\n\n                this.element.find(\"thead \" + selectBoxSelector).prop(\"checked\", false);\n                for (i = 0; i < deselectedRows.length; i++)\n                {\n                    this.element.find(\"tbody > tr[data-row-id=\\\"\" + deselectedRows[i][this.identifier] + \"\\\"]\")\n                        .removeClass(this.options.css.selected)._bgAria(\"selected\", \"false\")\n                        .find(selectBoxSelector).prop(\"checked\", false);\n                }\n\n                this.element.trigger(\"deselected\" + namespace, [deselectedRows]);\n            }\n        }\n\n        return this;\n    };\n\n    /**\n     * Sorts the rows by a given sort descriptor dictionary. \n     * The sort filter will be reseted, if no argument is provided.\n     *\n     * @method sort\n     * @param [dictionary] {Object} A sort descriptor dictionary that contains the sort information\n     * @chainable\n     **/\n    Grid.prototype.sort = function(dictionary)\n    {\n        var values = (dictionary) ? $.extend({}, dictionary) : {};\n\n        if (values === this.sortDictionary)\n        {\n            return this;\n        }\n\n        this.sortDictionary = values;\n        renderTableHeader.call(this);\n        sortRows.call(this);\n        loadData.call(this);\n\n        return this;\n    };\n\n    /**\n     * Gets a list of the column settings.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getColumnSettings\n     * @return {Array} Returns a list of the column settings.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getColumnSettings = function()\n    {\n        return $.merge([], this.columns);\n    };\n\n    /**\n     * Gets the current page index.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getCurrentPage\n     * @return {Number} Returns the current page index.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getCurrentPage = function()\n    {\n        return this.current;\n    };\n\n    /**\n     * Gets the current rows.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getCurrentPage\n     * @return {Array} Returns the current rows.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getCurrentRows = function()\n    {\n        return $.merge([], this.currentRows);\n    };\n\n    /**\n     * Gets a number represents the row count per page.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getRowCount\n     * @return {Number} Returns the row count per page.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getRowCount = function()\n    {\n        return this.rowCount;\n    };\n\n    /**\n     * Gets the actual search phrase.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getSearchPhrase\n     * @return {String} Returns the actual search phrase.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getSearchPhrase = function()\n    {\n        return this.searchPhrase;\n    };\n\n    /**\n     * Gets the complete list of currently selected rows.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getSelectedRows\n     * @return {Array} Returns all selected rows.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getSelectedRows = function()\n    {\n        return $.merge([], this.selectedRows);\n    };\n\n    /**\n     * Gets the sort dictionary which represents the state of column sorting.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getSortDictionary\n     * @return {Object} Returns the sort dictionary.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getSortDictionary = function()\n    {\n        return $.extend({}, this.sortDictionary);\n    };\n\n    /**\n     * Gets a number represents the total page count.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getTotalPageCount\n     * @return {Number} Returns the total page count.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getTotalPageCount = function()\n    {\n        return this.totalPages;\n    };\n\n    /**\n     * Gets a number represents the total row count.\n     * This method returns only for the first grid instance a value.\n     * Therefore be sure that only one grid instance is catched by your selector.\n     *\n     * @method getTotalRowCount\n     * @return {Number} Returns the total row count.\n     * @since 1.2.0\n     **/\n    Grid.prototype.getTotalRowCount = function()\n    {\n        return this.total;\n    };\n\n    // GRID COMMON TYPE EXTENSIONS\n    // ============\n\n    $.fn.extend({\n        _bgAria: function (name, value)\n        {\n            return (value) ? this.attr(\"aria-\" + name, value) : this.attr(\"aria-\" + name);\n        },\n\n        _bgBusyAria: function(busy)\n        {\n            return (busy == null || busy) ? \n                this._bgAria(\"busy\", \"true\") : \n                this._bgAria(\"busy\", \"false\");\n        },\n\n        _bgRemoveAria: function (name)\n        {\n            return this.removeAttr(\"aria-\" + name);\n        },\n\n        _bgEnableAria: function (enable)\n        {\n            return (enable == null || enable) ? \n                this.removeClass(\"disabled\")._bgAria(\"disabled\", \"false\") : \n                this.addClass(\"disabled\")._bgAria(\"disabled\", \"true\");\n        },\n\n        _bgEnableField: function (enable)\n        {\n            return (enable == null || enable) ? \n                this.removeAttr(\"disabled\") : \n                this.attr(\"disabled\", \"disable\");\n        },\n\n        _bgShowAria: function (show)\n        {\n            return (show == null || show) ? \n                this.show()._bgAria(\"hidden\", \"false\") :\n                this.hide()._bgAria(\"hidden\", \"true\");\n        },\n\n        _bgSelectAria: function (select)\n        {\n            return (select == null || select) ? \n                this.addClass(\"active\")._bgAria(\"selected\", \"true\") : \n                this.removeClass(\"active\")._bgAria(\"selected\", \"false\");\n        },\n\n        _bgId: function (id)\n        {\n            return (id) ? this.attr(\"id\", id) : this.attr(\"id\");\n        }\n    });\n\n    if (!String.prototype.resolve)\n    {\n        var formatter = {\n            \"checked\": function(value)\n            {\n                if (typeof value === \"boolean\")\n                {\n                    return (value) ? \"checked=\\\"checked\\\"\" : \"\";\n                }\n                return value;\n            }\n        };\n\n        String.prototype.resolve = function (substitutes, prefixes)\n        {\n            var result = this;\n            $.each(substitutes, function (key, value)\n            {\n                if (value != null && typeof value !== \"function\")\n                {\n                    if (typeof value === \"object\")\n                    {\n                        var keys = (prefixes) ? $.extend([], prefixes) : [];\n                        keys.push(key);\n                        result = result.resolve(value, keys) + \"\";\n                    }\n                    else\n                    {\n                        if (formatter && formatter[key] && typeof formatter[key] === \"function\")\n                        {\n                            value = formatter[key](value);\n                        }\n                        key = (prefixes) ? prefixes.join(\".\") + \".\" + key : key;\n                        var pattern = new RegExp(\"\\\\{\\\\{\" + key + \"\\\\}\\\\}\", \"gm\");\n                        result = result.replace(pattern, (value.replace) ? value.replace(/\\$/gi, \"&#36;\") : value);\n                    }\n                }\n            });\n            return result;\n        };\n    }\n\n    if (!Array.prototype.first)\n    {\n        Array.prototype.first = function (condition)\n        {\n            for (var i = 0; i < this.length; i++)\n            {\n                var item = this[i];\n                if (condition(item))\n                {\n                    return item;\n                }\n            }\n            return null;\n        };\n    }\n\n    if (!Array.prototype.contains)\n    {\n        Array.prototype.contains = function (condition)\n        {\n            for (var i = 0; i < this.length; i++)\n            {\n                var item = this[i];\n                if (condition(item))\n                {\n                    return true;\n                }\n            }\n            return false;\n        };\n    }\n\n    if (!Array.prototype.page)\n    {\n        Array.prototype.page = function (page, size)\n        {\n            var skip = (page - 1) * size,\n                end = skip + size;\n            return (this.length > skip) ? \n                (this.length > end) ? this.slice(skip, end) : \n                    this.slice(skip) : [];\n        };\n    }\n\n    if (!Array.prototype.where)\n    {\n        Array.prototype.where = function (condition)\n        {\n            var result = [];\n            for (var i = 0; i < this.length; i++)\n            {\n                var item = this[i];\n                if (condition(item))\n                {\n                    result.push(item);\n                }\n            }\n            return result;\n        };\n    }\n\n    if (!Array.prototype.propValues)\n    {\n        Array.prototype.propValues = function (propName)\n        {\n            var result = [];\n            for (var i = 0; i < this.length; i++)\n            {\n                result.push(this[i][propName]);\n            }\n            return result;\n        };\n    }\n\n    // GRID PLUGIN DEFINITION\n    // =====================\n\n    var old = $.fn.bootgrid;\n\n    $.fn.bootgrid = function (option)\n    {\n        var args = Array.prototype.slice.call(arguments, 1),\n            returnValue = null,\n            elements = this.each(function (index)\n            {\n                var $this = $(this),\n                    instance = $this.data(namespace),\n                    options = typeof option === \"object\" && option;\n\n                if (!instance && option === \"destroy\")\n                {\n                    return;\n                }\n                if (!instance)\n                {\n                    $this.data(namespace, (instance = new Grid(this, options)));\n                    init.call(instance);\n                }\n                if (typeof option === \"string\")\n                {\n                    if (option.indexOf(\"get\") === 0 && index === 0)\n                    {\n                        returnValue = instance[option].apply(instance, args);\n                    }\n                    else if (option.indexOf(\"get\") !== 0)\n                    {\n                        return instance[option].apply(instance, args);\n                    }\n                }\n            });\n        return (typeof option === \"string\" && option.indexOf(\"get\") === 0) ? returnValue : elements;\n    };\n\n    $.fn.bootgrid.Constructor = Grid;\n\n    // GRID NO CONFLICT\n    // ===============\n\n    $.fn.bootgrid.noConflict = function ()\n    {\n        $.fn.bootgrid = old;\n        return this;\n    };\n\n    // GRID DATA-API\n    // ============\n\n$(\"[data-toggle=\\\"bootgrid\\\"]\").bootgrid();\n})(jQuery, window);"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bootstrap-growl/bootstrap-growl.js",
    "content": "/*\n*  Project: Bootstrap Growl - v2.0.1\n*  Description: Turns standard Bootstrap alerts into \"Growl-like\" notifications.\n*  Author: Mouse0270 aka Robert McIntosh\n*  License: MIT License\n*  Website: https://github.com/mouse0270/bootstrap-growl\n*/\n;(function ( $, window, document, undefined ) {\n\t// Create the defaults once\n\tvar pluginName = \"growl\",\n\t\tdataKey = \"plugin_\" + pluginName,\n\t\tdefaults = {\n\t\t\telement: 'body',\n\t\t\ttype: \"info\",\n\t\t\tallow_dismiss: true,\n\t\t\tplacement: {\n\t\t\t\tfrom: \"top\",\n\t\t\t\talign: \"right\"\n\t\t\t},\n\t\t\toffset: 20,\n\t\t\tspacing: 10,\n\t\t\tz_index: 1031,\n\t\t\tdelay: 5000,\n\t\t\ttimer: 1000,\n\t\t\turl_target: '_blank',\n\t\t\tmouse_over: false,\n\t\t\tanimate: {\n\t\t\t\tenter: 'animated fadeInDown',\n\t\t\t\texit: 'animated fadeOutUp'\n\t\t\t},\n\t\t\tonShow: null,\n\t\t\tonShown: null,\n\t\t\tonHide: null,\n\t\t\tonHidden: null,\n\t\t\ticon_type: 'class',\n\t\t\ttemplate: '<div data-growl=\"container\" class=\"alert\" role=\"alert\"><button type=\"button\" aria-hidden=\"true\" class=\"close\" data-growl=\"dismiss\">&times;</button><span data-growl=\"icon\"></span><span data-growl=\"title\"></span><span data-growl=\"message\"></span><a href=\"#\" data-growl=\"url\"></a></div>'\n\t\t};\n\n\t// The actual plugin constructor\n\tvar setDefaults = function(element, options) {\n\t\tdefaults = $.extend(true, {}, defaults, options);\n\t},\n\tcloseAll = function(options) {\n\t\tif (!options) {\n\t\t\t$('[data-growl=\"container\"]').find('[data-growl=\"dismiss\"]').trigger('click');\n\t\t}else{\n\t\t\t$('[data-growl=\"container\"][data-growl-position=\"'+options+'\"]').find('[data-growl=\"dismiss\"]').trigger('click');\n\t\t}\n\t},\n\tPlugin = function (element, content, options) {\n\t\tvar content = {\n\t\t\tcontent: {\n\t\t\t\tmessage: typeof content == 'object' ? content.message : content,\n\t\t\t\ttitle: content.title ? content.title : null,\n\t\t\t\ticon: content.icon ? content.icon : null,\n\t\t\t\turl: content.url ? content.url : null\n\t\t\t}\n\t\t};\n\n\t\toptions = $.extend(true, {}, content, options);\n\t\tthis.settings = $.extend(true, {}, defaults, options);\n\t\tplugin = this;\n\t\tinit(options, this.settings, plugin);\n\t\tthis.$template = $template;\n\t},\n\tinit = function (options, settings, plugin) {\n\n\t\tvar base = {\n\t\t\t\tsettings: settings,\n\t\t\t\telement: settings.element,\n\t\t\t\ttemplate: settings.template\n\t\t\t};\n\n\t\tif (typeof settings.offset == 'number') {\n\t\t    settings.offset = {\n\t\t    \tx: settings.offset,\n\t\t    \ty: settings.offset\n\t\t    };\n\t\t}\n\n\t\t$template = buildGrowl(base);\n\t\taddContent($template, base.settings);\n\t\tplacement($template, base.settings);\n\t\tbindControls($template, base.settings,plugin);\n\t},\n\tbuildGrowl = function(base) {\n\n\t\tvar $template = $(base.settings.template);\n\n\t\t$template.addClass('alert-' + base.settings.type);\n\t\t$template.attr('data-growl-position', base.settings.placement.from + '-' + base.settings.placement.align);\n\n\t\t$template.find('[data-growl=\"dismiss\"]').css('display', 'none');\n\t\t$template.removeClass('alert-dismissable');\n\t\tif (base.settings.allow_dismiss) {\n  \t\t$template.addClass('alert-dismissable');\n\t\t\t$template.find('[data-growl=\"dismiss\"]').css('display', 'block');\n\t\t}\n\n\t\treturn $template;\n\t},\n\taddContent = function($template, settings) {\n\n\t\t$template.find('[data-growl=\"dismiss\"]').css({\n\t\t\t'z-index': ((settings.z_index-1) >= 1 ? (settings.z_index-1) : 1)\n\t\t});\n\n\t\tif (settings.content.icon) {\n\t\t\tif (settings.icon_type.toLowerCase() == 'class') {\n\t\t\t\t$template.find('[data-growl=\"icon\"]').addClass(settings.content.icon);\n\t\t\t}else{\n\t\t\t\tif ($template.find('[data-growl=\"icon\"]').is('img')) {\n\t\t\t\t\t$template.find('[data-growl=\"icon\"]').attr('src', settings.content.icon);\n\t\t\t\t}else{\n\t\t\t\t\t$template.find('[data-growl=\"icon\"]').append('<img src=\"'+settings.content.icon+'\" />');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (settings.content.title) {\n\t\t\t$template.find('[data-growl=\"title\"]').html(settings.content.title);\n\t\t}\n\n\t\tif (settings.content.message) {\n\t\t\t$template.find('[data-growl=\"message\"]').html(settings.content.message);\n\t\t}\n\n\t\tif (settings.content.url) {\n\t\t\t$template.find('[data-growl=\"url\"]').attr('href', settings.content.url).attr('target', settings.url_target);\n\t\t\t$template.find('[data-growl=\"url\"]').css({\n\t\t\t\t'position': 'absolute',\n\t\t\t\t'top': 0,\n\t\t\t\t'left': 0,\n\t\t\t\t'width': '100%',\n\t\t\t\t'height': '100%',\n\t\t\t\t'z-index': ((settings.z_index-2) >= 1 ? (settings.z_index-2) : 1)\n\t\t\t});\n\t\t}\n\t},\n\tplacement = function($template, settings) {\n\t\tvar offsetAmt = settings.offset.y,\n\t\t\tgCSS = {\n\t\t\t\t'position': (settings.element === 'body' ? 'fixed' : 'absolute'),\n\t\t\t\t'margin': 0,\n\t\t\t\t'z-index': settings.z_index,\n\t\t\t\t'display': 'inline-block'\n\t\t\t},\n\t\t\thasAnimation = false;\n\n\t\t$('[data-growl-position=\"' + settings.placement.from + '-' + settings.placement.align + '\"]').each(function() {\n\t\t\treturn offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + $(this).outerHeight() + settings.spacing);\n\t\t});\n\n\t\tgCSS[settings.placement.from] = offsetAmt + \"px\";\n\t\t$template.css(gCSS);\n\n\t\tif (settings.onShow) {\n\t\t\tsettings.onShow(event);\n\t\t}\n\n\t\t$(settings.element).append($template);\n\n\t\tswitch (settings.placement.align) {\n\t\t\tcase 'center':\n\t\t\t\t$template.css({\n\t\t\t\t\t'left': '50%',\n\t\t\t\t\t'marginLeft': -($template.outerWidth() / 2) + 'px'\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase 'left':\n\t\t\t\t$template.css('left', settings.offset.x + 'px');\n\t\t\t\tbreak;\n\t\t\tcase 'right':\n\t\t\t\t$template.css('right', settings.offset.x + 'px');\n\t\t\t\tbreak;\n\t\t}\n\t\t$template.addClass('growl-animated');\n\n\t\t$template.one('webkitAnimationStart oanimationstart MSAnimationStart animationstart', function(event) {\n\t\t\thasAnimation = true;\n\t\t});\n\n\t\t$template.one('webkitAnimationEnd oanimationend MSAnimationEnd animationend', function(event) {\n\t\t\tif (settings.onShown) {\n\t\t\t\tsettings.onShown(event);\n\t\t\t}\n\t\t});\n\n\t\tsetTimeout(function() {\n\t\t\tif (!hasAnimation) {\n\t\t\t\tif (settings.onShown) {\n\t\t\t\t\tsettings.onShown(event);\n\t\t\t\t}\n\t\t\t}\n\t\t}, 600);\n\t},\n\tbindControls = function($template, settings, plugin) {\n\t\t$template.addClass(settings.animate.enter);\n\n\t\t$template.find('[data-growl=\"dismiss\"]').on('click', function() {\n\t\t\tplugin.close();\n\t\t});\n\n\t\t$template.on('mouseover', function(e) {\n\t\t\t$template.addClass('hovering');\n\t\t}).on('mouseout', function() {\n\t\t\t$template.removeClass('hovering');\n\t\t});\n\n\t\tif (settings.delay >= 1) {\n\t\t\t$template.data('growl-delay', settings.delay);\n\t\t\tvar timer = setInterval(function() {\n\n\t\t\t\tvar delay = parseInt($template.data('growl-delay')) - settings.timer;\n\t\t\t\tif ((!$template.hasClass('hovering') && settings.mouse_over == 'pause') || settings.mouse_over != 'pause') {\n\t\t\t\t\t$template.data('growl-delay', delay);\n\t\t\t\t}\n\n\t\t\t\tif (delay <= 0) {\n\t\t\t\t\tclearInterval(timer);\n\t\t\t\t\tplugin.close();\n\t\t\t\t}\n\t\t\t}, settings.timer);\n\t\t}\n\t};\n\n\t// Avoid Plugin.prototype conflicts\n\tPlugin.prototype = {\n\t\tupdate: function(command, update) {\n\t\t\tswitch (command) {\n\t\t\t\tcase 'icon':\n\t\t\t\t\tif (this.settings.icon_type.toLowerCase() == 'class') {\n\t\t\t\t\t\tthis.$template.find('[data-growl=\"icon\"]').removeClass(this.settings.content.icon);\n\t\t\t\t\t\tthis.$template.find('[data-growl=\"icon\"]').addClass(update);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tif (this.$template.find('[data-growl=\"icon\"]').is('img')) {\n\t\t\t\t\t\t\tthis.$template.find('[data-growl=\"icon\"]')\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tthis.$template.find('[data-growl=\"icon\"]').find('img').attr().attr('src', update);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'url':\n\t\t\t\t\tthis.$template.find('[data-growl=\"url\"]').attr('href', update);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'type':\n\t\t\t\t\tthis.$template.removeClass(function (index, css) {\n\t\t\t\t\t\treturn (css.match (/(^|\\s)alert-\\S+/g) || []).join(' ');\n\t\t\t\t\t});\n\t\t\t\t\tthis.$template.addClass('alert-' + update);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.$template.find('[data-growl=\"' + command +'\"]').html(update);\n\t\t\t}\n\n\t\t\treturn this;\n\t\t},\n\t\tclose: function() {\n\t\t\tvar base = this.$template,\n\t\t\t\tsettings = this.settings,\n\t\t\t\tposX = base.css(settings.placement.from),\n\t\t\t\thasAnimation = false;\n\n\t\t\tif (settings.onHide) {\n\t\t\t\tsettings.onHide(event);\n\t\t\t}\n\n\t\t\tbase.addClass(this.settings.animate.exit);\n\n\t\t\tbase.nextAll('[data-growl-position=\"' + this.settings.placement.from + '-' + this.settings.placement.align + '\"]').each(function() {\n\t\t\t\t$(this).css(settings.placement.from, posX);\n\t\t\t\tposX = (parseInt(posX)+(settings.spacing)) + $(this).outerHeight();\n\t\t\t});\n\n\t\t\tbase.one('webkitAnimationStart oanimationstart MSAnimationStart animationstart', function(event) {\n\t\t\t\thasAnimation = true;\n\t\t\t});\n\n\t\t\tbase.one('webkitAnimationEnd oanimationend MSAnimationEnd animationend', function(event) {\n\t\t\t\t$(this).remove();\n\t\t\t\tif (settings.onHidden) {\n\t\t\t\t\tsettings.onHidden(event);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tsetTimeout(function() {\n\t\t\t\tif (!hasAnimation) {\n\t\t\t\t\tbase.remove();\n\t\t\t\t\tif (settings.onHidden) {\n\t\t\t\t\t\tsettings.onHidden(event);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 100);\n\n \t\t\treturn this;\n\t\t}\n\t};\n\n\t// A really lightweight plugin wrapper around the constructor,\n\t// preventing against multiple instantiations\n\t$.growl = function ( content, options ) {\n\t\tif (content == false && options.command == \"closeAll\") {\n\t\t\tcloseAll(options.position);\n\t\t\treturn false;\n\t\t}else if (content == false) {\n\t\t\tsetDefaults(this, options);\n\t\t\treturn false;\n\t\t}\n\t\tvar plugin = new Plugin( this, content, options );\n\t\treturn plugin;\n\t};\n\n})( jQuery, window, document );\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bootstrap-wizard/jquery.bootstrap.wizard.js",
    "content": "/*!\n * jQuery twitter bootstrap wizard plugin\n * Examples and documentation at: http://github.com/VinceG/twitter-bootstrap-wizard\n * version 1.0\n * Requires jQuery v1.3.2 or later\n * Supports Bootstrap 2.2.x, 2.3.x, 3.0\n * Dual licensed under the MIT and GPL licenses:\n * http://www.opensource.org/licenses/mit-license.php\n * http://www.gnu.org/licenses/gpl.html\n * Authors: Vadim Vincent Gabriel (http://vadimg.com), Jason Gill (www.gilluminate.com)\n */\n;(function($) {\nvar bootstrapWizardCreate = function(element, options) {\n\tvar element = $(element);\n\tvar obj = this;\n\t\n\t// selector skips any 'li' elements that do not contain a child with a tab data-toggle\n\tvar baseItemSelector = 'li:has([data-toggle=\"tab\"])';\n\tvar historyStack = [];\n\n\t// Merge options with defaults\n\tvar $settings = $.extend({}, $.fn.bootstrapWizard.defaults, options);\n\tvar $activeTab = null;\n\tvar $navigation = null;\n\t\n\tthis.rebindClick = function(selector, fn)\n\t{\n\t\tselector.unbind('click', fn).bind('click', fn);\n\t}\n\n\tthis.fixNavigationButtons = function() {\n\t\t// Get the current active tab\n\t\tif(!$activeTab.length) {\n\t\t\t// Select first one\n\t\t\t$navigation.find('a:first').tab('show');\n\t\t\t$activeTab = $navigation.find(baseItemSelector + ':first');\n\t\t}\n\n\t\t// See if we're currently in the first/last then disable the previous and last buttons\n\t\t$($settings.previousSelector, element).toggleClass('disabled', (obj.firstIndex() >= obj.currentIndex()));\n\t\t$($settings.nextSelector, element).toggleClass('disabled', (obj.currentIndex() >= obj.navigationLength()));\n\t\t$($settings.nextSelector, element).toggleClass('hidden', (obj.currentIndex() >= obj.navigationLength() && $($settings.finishSelector, element).length > 0));\n\t\t$($settings.lastSelector, element).toggleClass('hidden', (obj.currentIndex() >= obj.navigationLength() && $($settings.finishSelector, element).length > 0));\n\t\t$($settings.finishSelector, element).toggleClass('hidden', (obj.currentIndex() < obj.navigationLength()));\n\t\t$($settings.backSelector, element).toggleClass('disabled', (historyStack.length == 0));\n\t\t$($settings.backSelector, element).toggleClass('hidden', (obj.currentIndex() >= obj.navigationLength() && $($settings.finishSelector, element).length > 0));\n\n\t\t// We are unbinding and rebinding to ensure single firing and no double-click errors\n\t\tobj.rebindClick($($settings.nextSelector, element), obj.next);\n\t\tobj.rebindClick($($settings.previousSelector, element), obj.previous);\n\t\tobj.rebindClick($($settings.lastSelector, element), obj.last);\n\t\tobj.rebindClick($($settings.firstSelector, element), obj.first);\n\t\tobj.rebindClick($($settings.finishSelector, element), obj.finish);\n\t\tobj.rebindClick($($settings.backSelector, element), obj.back);\n\n\t\tif($settings.onTabShow && typeof $settings.onTabShow === 'function' && $settings.onTabShow($activeTab, $navigation, obj.currentIndex())===false){\n\t\t\treturn false;\n\t\t}\n\t};\n\n\tthis.next = function(e) {\n\t\t// If we clicked the last then dont activate this\n\t\tif(element.hasClass('last')) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif($settings.onNext && typeof $settings.onNext === 'function' && $settings.onNext($activeTab, $navigation, obj.nextIndex())===false){\n\t\t\treturn false;\n\t\t}\n\n\t\tvar formerIndex = obj.currentIndex();\n\t\t$index = obj.nextIndex();\n\n\t  // Did we click the last button\n\t\tif($index > obj.navigationLength()) {\n\t\t} else {\n\t\t  historyStack.push(formerIndex);\n\t\t  $navigation.find(baseItemSelector + ':eq(' + $index + ') a').tab('show');\n\t\t}\n\t};\n\n\tthis.previous = function(e) {\n\t\t// If we clicked the first then dont activate this\n\t\tif(element.hasClass('first')) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif($settings.onPrevious && typeof $settings.onPrevious === 'function' && $settings.onPrevious($activeTab, $navigation, obj.previousIndex())===false){\n\t\t\treturn false;\n\t\t}\n\n\t\tvar formerIndex = obj.currentIndex();\n\t\t$index = obj.previousIndex();\n\n\t\tif($index < 0) {\n\t\t} else {\n\t\t  historyStack.push(formerIndex);\n\t\t  $navigation.find(baseItemSelector + ':eq(' + $index + ') a').tab('show');\n\t\t}\n\t};\n\n\tthis.first = function (e) {\n\t\tif($settings.onFirst && typeof $settings.onFirst === 'function' && $settings.onFirst($activeTab, $navigation, obj.firstIndex())===false){\n\t\t\treturn false;\n\t\t}\n\n\t\t// If the element is disabled then we won't do anything\n\t\tif(element.hasClass('disabled')) {\n\t\t\treturn false;\n\t\t}\n\n\t\thistoryStack.push(obj.currentIndex());\n\t\t$navigation.find(baseItemSelector + ':eq(0) a').tab('show');\n\t};\n\n\tthis.last = function(e) {\n\t\tif($settings.onLast && typeof $settings.onLast === 'function' && $settings.onLast($activeTab, $navigation, obj.lastIndex())===false){\n\t\t\treturn false;\n\t\t}\n\n\t\t// If the element is disabled then we won't do anything\n\t\tif(element.hasClass('disabled')) {\n\t\t\treturn false;\n\t\t}\n\n\t\thistoryStack.push(obj.currentIndex());\n\t\t$navigation.find(baseItemSelector + ':eq(' + obj.navigationLength() + ') a').tab('show');\n\t};\n\n\tthis.finish = function (e) {\n\t  if ($settings.onFinish && typeof $settings.onFinish === 'function') {\n\t    $settings.onFinish($activeTab, $navigation, obj.lastIndex());\n\t  }\n\t};\n\n\tthis.back = function () {\n\t  if (historyStack.length == 0) {\n\t    return null;\n\t  }\n\n\t  var formerIndex = historyStack.pop();\n\t  if ($settings.onBack && typeof $settings.onBack === 'function' && $settings.onBack($activeTab, $navigation, formerIndex) === false) {\n\t    historyStack.push(formerIndex);\n\t    return false;\n\t  }\n\n\t  element.find(baseItemSelector + ':eq(' + formerIndex + ') a').tab('show');\n\t};\n\n\tthis.currentIndex = function() {\n\t\treturn $navigation.find(baseItemSelector).index($activeTab);\n\t};\n\n\tthis.firstIndex = function() {\n\t\treturn 0;\n\t};\n\n\tthis.lastIndex = function() {\n\t\treturn obj.navigationLength();\n\t};\n\tthis.getIndex = function(e) {\n\t\treturn $navigation.find(baseItemSelector).index(e);\n\t};\n\tthis.nextIndex = function() {\n\t\treturn $navigation.find(baseItemSelector).index($activeTab) + 1;\n\t};\n\tthis.previousIndex = function() {\n\t\treturn $navigation.find(baseItemSelector).index($activeTab) - 1;\n\t};\n\tthis.navigationLength = function() {\n\t\treturn $navigation.find(baseItemSelector).length - 1;\n\t};\n\tthis.activeTab = function() {\n\t\treturn $activeTab;\n\t};\n\tthis.nextTab = function() {\n\t\treturn $navigation.find(baseItemSelector + ':eq('+(obj.currentIndex()+1)+')').length ? $navigation.find(baseItemSelector + ':eq('+(obj.currentIndex()+1)+')') : null;\n\t};\n\tthis.previousTab = function() {\n\t\tif(obj.currentIndex() <= 0) {\n\t\t\treturn null;\n\t\t}\n\t\treturn $navigation.find(baseItemSelector + ':eq('+parseInt(obj.currentIndex()-1)+')');\n\t};\n\tthis.show = function(index) {\n\t  var tabToShow = isNaN(index) ? \n      element.find(baseItemSelector + ' a[href=#' + index + ']') : \n      element.find(baseItemSelector + ':eq(' + index + ') a');\n\t  if (tabToShow.length > 0) {\n\t    historyStack.push(obj.currentIndex());\n\t    tabToShow.tab('show');\n\t  }\n\t};\n\tthis.disable = function (index) {\n\t\t$navigation.find(baseItemSelector + ':eq('+index+')').addClass('disabled');\n\t};\n\tthis.enable = function(index) {\n\t\t$navigation.find(baseItemSelector + ':eq('+index+')').removeClass('disabled');\n\t};\n\tthis.hide = function(index) {\n\t\t$navigation.find(baseItemSelector + ':eq('+index+')').hide();\n\t};\n\tthis.display = function(index) {\n\t\t$navigation.find(baseItemSelector + ':eq('+index+')').show();\n\t};\n\tthis.remove = function(args) {\n\t\tvar $index = args[0];\n\t\tvar $removeTabPane = typeof args[1] != 'undefined' ? args[1] : false;\n\t\tvar $item = $navigation.find(baseItemSelector + ':eq('+$index+')');\n\n\t\t// Remove the tab pane first if needed\n\t\tif($removeTabPane) {\n\t\t\tvar $href = $item.find('a').attr('href');\n\t\t\t$($href).remove();\n\t\t}\n\n\t\t// Remove menu item\n\t\t$item.remove();\n\t};\n\t\n\tvar innerTabClick = function (e) {\n\t\t// Get the index of the clicked tab\n\t\tvar $ul = $navigation.find(baseItemSelector);\n\t\tvar clickedIndex = $ul.index($(e.currentTarget).parent(baseItemSelector));\n\t\tvar $clickedTab = $( $ul[clickedIndex] );\n\t\tif($settings.onTabClick && typeof $settings.onTabClick === 'function' && $settings.onTabClick($activeTab, $navigation, obj.currentIndex(), clickedIndex, $clickedTab)===false){\n\t\t    return false;\n\t\t}\n\t};\n\t\n\tvar innerTabShown = function (e) {  // use shown instead of show to help prevent double firing\n\t\t$element = $(e.target).parent();\n\t\tvar nextTab = $navigation.find(baseItemSelector).index($element);\n\n\t\t// If it's disabled then do not change\n\t\tif($element.hasClass('disabled')) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif($settings.onTabChange && typeof $settings.onTabChange === 'function' && $settings.onTabChange($activeTab, $navigation, obj.currentIndex(), nextTab)===false){\n\t\t\t\treturn false;\n\t\t}\n\n\t\t$activeTab = $element; // activated tab\n\t\tobj.fixNavigationButtons();\n\t};\n\t\n\tthis.resetWizard = function() {\n\t\t\n\t\t// remove the existing handlers\n\t\t$('a[data-toggle=\"tab\"]', $navigation).off('click', innerTabClick);\n\t\t$('a[data-toggle=\"tab\"]', $navigation).off('shown shown.bs.tab', innerTabShown);\n\t\t\n\t\t// reset elements based on current state of the DOM\n\t\t$navigation = element.find('ul:first', element);\n\t\t$activeTab = $navigation.find(baseItemSelector + '.active', element);\n\t\t\n\t\t// re-add handlers\n\t\t$('a[data-toggle=\"tab\"]', $navigation).on('click', innerTabClick);\n\t\t$('a[data-toggle=\"tab\"]', $navigation).on('shown shown.bs.tab', innerTabShown);\n\t\t\n\t\tobj.fixNavigationButtons();\n\t};\n\n\t$navigation = element.find('ul:first', element);\n\t$activeTab = $navigation.find(baseItemSelector + '.active', element);\n\n\tif(!$navigation.hasClass($settings.tabClass)) {\n\t\t$navigation.addClass($settings.tabClass);\n\t}\n\n\t// Load onInit\n\tif($settings.onInit && typeof $settings.onInit === 'function'){\n\t\t$settings.onInit($activeTab, $navigation, 0);\n\t}\n\n\t// Load onShow\n\tif($settings.onShow && typeof $settings.onShow === 'function'){\n\t\t$settings.onShow($activeTab, $navigation, obj.nextIndex());\n\t}\n\n\t$('a[data-toggle=\"tab\"]', $navigation).on('click', innerTabClick);\n\n\t// attach to both shown and shown.bs.tab to support Bootstrap versions 2.3.2 and 3.0.0\n\t$('a[data-toggle=\"tab\"]', $navigation).on('shown shown.bs.tab', innerTabShown);\n};\n$.fn.bootstrapWizard = function(options) {\n\t//expose methods\n\tif (typeof options == 'string') {\n\t\tvar args = Array.prototype.slice.call(arguments, 1)\n\t\tif(args.length === 1) {\n\t\t\targs.toString();\n\t\t}\n\t\treturn this.data('bootstrapWizard')[options](args);\n\t}\n\treturn this.each(function(index){\n\t\tvar element = $(this);\n\t\t// Return early if this element already has a plugin instance\n\t\tif (element.data('bootstrapWizard')) return;\n\t\t// pass options to plugin constructor\n\t\tvar wizard = new bootstrapWizardCreate(element, options);\n\t\t// Store plugin object in this element's data\n\t\telement.data('bootstrapWizard', wizard);\n\t\t// and then trigger initial change\n\t\twizard.fixNavigationButtons();\n\t});\n};\n\n// expose options\n$.fn.bootstrapWizard.defaults = {\n\ttabClass:         'nav nav-pills',\n\tnextSelector:     '.wizard li.next',\n\tpreviousSelector: '.wizard li.previous',\n\tfirstSelector:    '.wizard li.first',\n\tlastSelector:     '.wizard li.last',\n  finishSelector:   '.wizard li.finish',\n\tbackSelector:     '.wizard li.back',\n\tonShow:           null,\n\tonInit:           null,\n\tonNext:           null,\n\tonPrevious:       null,\n\tonLast:           null,\n\tonFirst:          null,\n  onFinish:         null,\n  onBack:           null,\n\tonTabChange:      null, \n\tonTabClick:       null,\n\tonTabShow:        null\n};\n\n})(jQuery);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower.json",
    "content": "{\n  \"name\": \"vendors\",\n  \"version\": \"0.0.0\",\n  \"authors\": [],\n  \"description\": \"\",\n  \"main\": \"\",\n  \"moduleType\": [],\n  \"license\": \"MIT\",\n  \"homepage\": \"\",\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"bower_components\",\n    \"test\",\n    \"tests\"\n  ],\n  \"dependencies\": {\n    \"animate.css\": \"~3.4.0\",\n    \"autosize\": \"~3.0.6\",\n    \"bootstrap-select\": \"silviomoreto/bootstrap-select#~1.7.2\",\n    \"bootstrap-sweetalert\": \"~0.4.5\",\n    \"bower\": \"*\",\n    \"eonasdan-bootstrap-datetimepicker\": \"Eonasdan/bootstrap-datetimepicker#~4.7.14\",\n    \"farbtastic\": \"mattfarina/farbtastic#~2.0.0-alpha.1\",\n    \"flot-orderBars\": \"emmerich/flot-orderBars\",\n    \"flot.curvedlines\": \"MichaelZinsmaier/CurvedLines#~1.1.1\",\n    \"flot.tooltip\": \"~0.8.5\",\n    \"fullcalendar\": \"~2.4.0\",\n    \"install\": \"~1.0.4\",\n    \"jquery-placeholder\": \"~2.1.2\",\n    \"jquery.easy-pie-chart\": \"~2.1.6\",\n    \"jquery.bootgrid\": \"~1.3.1\",\n    \"lightgallery\": \"~1.1.5\",\n    \"malihu-custom-scrollbar-plugin\": \"~3.1.0\",\n    \"material-design-iconic-font\": \"~2.1.1\",\n    \"material-shadows\": \"~2.0.1\",\n    \"mediaelement\": \"johndyer/mediaelement#~2.16.4\",\n    \"nouislider\": \"leongersen/noUiSlider#~7.0.10\",\n    \"summernote\": \"~0.6.16\",\n    \"sweetalert\": \"~1.0.1\",\n    \"typeahead.js\": \"~0.11.1\",\n    \"Waves\": \"waves#~0.7.4\",\n    \"jquery\": \"~2.1.4\",\n    \"moment\": \"~2.10.6\",\n    \"chosen\": \"~1.4.2\"\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/Waves/0.7.4/waves.css",
    "content": "/*!\n * Waves v0.7.4\n * http://fian.my.id/Waves \n * \n * Copyright 2014 Alfiana E. Sibuea and other contributors \n * Released under the MIT license \n * https://github.com/fians/Waves/blob/master/LICENSE \n */\n.waves-effect {\n  position: relative;\n  cursor: pointer;\n  display: inline-block;\n  overflow: hidden;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  user-select: none;\n  -webkit-tap-highlight-color: transparent;\n}\n.waves-effect .waves-ripple {\n  position: absolute;\n  border-radius: 50%;\n  width: 100px;\n  height: 100px;\n  margin-top: -50px;\n  margin-left: -50px;\n  opacity: 0;\n  background: rgba(0, 0, 0, 0.2);\n  background: -webkit-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -o-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -moz-radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: radial-gradient(rgba(0, 0, 0, 0.2) 0, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0.4) 50%, rgba(0, 0, 0, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  -webkit-transition: all 0.5s ease-out;\n  -moz-transition: all 0.5s ease-out;\n  -o-transition: all 0.5s ease-out;\n  transition: all 0.5s ease-out;\n  -webkit-transition-property: -webkit-transform, opacity;\n  -moz-transition-property: -moz-transform, opacity;\n  -o-transition-property: -o-transform, opacity;\n  transition-property: transform, opacity;\n  -webkit-transform: scale(0) translate(0, 0);\n  -moz-transform: scale(0) translate(0, 0);\n  -ms-transform: scale(0) translate(0, 0);\n  -o-transform: scale(0) translate(0, 0);\n  transform: scale(0) translate(0, 0);\n  pointer-events: none;\n}\n.waves-effect.waves-light .waves-ripple {\n  background: rgba(255, 255, 255, 0.4);\n  background: -webkit-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -o-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: -moz-radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n  background: radial-gradient(rgba(255, 255, 255, 0.2) 0, rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.5) 60%, rgba(255, 255, 255, 0) 70%);\n}\n.waves-effect.waves-classic .waves-ripple {\n  background: rgba(0, 0, 0, 0.2);\n}\n.waves-effect.waves-classic.waves-light .waves-ripple {\n  background: rgba(255, 255, 255, 0.4);\n}\n.waves-notransition {\n  -webkit-transition: none !important;\n  -moz-transition: none !important;\n  -o-transition: none !important;\n  transition: none !important;\n}\n.waves-button,\n.waves-circle {\n  -webkit-transform: translateZ(0);\n  -moz-transform: translateZ(0);\n  -ms-transform: translateZ(0);\n  -o-transform: translateZ(0);\n  transform: translateZ(0);\n  -webkit-mask-image: -webkit-radial-gradient(circle, #ffffff 100%, #000000 100%);\n}\n.waves-button,\n.waves-button:hover,\n.waves-button:visited,\n.waves-button-input {\n  white-space: nowrap;\n  vertical-align: middle;\n  cursor: pointer;\n  border: none;\n  outline: none;\n  color: inherit;\n  background-color: rgba(0, 0, 0, 0);\n  font-size: 1em;\n  line-height: 1em;\n  text-align: center;\n  text-decoration: none;\n  z-index: 1;\n}\n.waves-button {\n  padding: 0.85em 1.1em;\n  border-radius: 0.2em;\n}\n.waves-button-input {\n  margin: 0;\n  padding: 0.85em 1.1em;\n}\n.waves-input-wrapper {\n  border-radius: 0.2em;\n  vertical-align: bottom;\n}\n.waves-input-wrapper.waves-button {\n  padding: 0;\n}\n.waves-input-wrapper .waves-button-input {\n  position: relative;\n  top: 0;\n  left: 0;\n  z-index: 1;\n}\n.waves-circle {\n  text-align: center;\n  width: 2.5em;\n  height: 2.5em;\n  line-height: 2.5em;\n  border-radius: 50%;\n}\n.waves-float {\n  -webkit-mask-image: none;\n  -webkit-box-shadow: 0px 1px 1.5px 1px rgba(0, 0, 0, 0.12);\n  box-shadow: 0px 1px 1.5px 1px rgba(0, 0, 0, 0.12);\n  -webkit-transition: all 300ms;\n  -moz-transition: all 300ms;\n  -o-transition: all 300ms;\n  transition: all 300ms;\n}\n.waves-float:active {\n  -webkit-box-shadow: 0px 8px 20px 1px rgba(0, 0, 0, 0.3);\n  box-shadow: 0px 8px 20px 1px rgba(0, 0, 0, 0.3);\n}\n.waves-block {\n  display: block;\n}\n/* Firefox Bug: link not triggered */\na.waves-effect .waves-ripple {\n  z-index: -1;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/Waves/0.7.4/waves.js",
    "content": "/*!\n * Waves v0.7.4\n * http://fian.my.id/Waves\n *\n * Copyright 2014 Alfiana E. Sibuea and other contributors\n * Released under the MIT license\n * https://github.com/fians/Waves/blob/master/LICENSE\n */\n\n;(function(window, factory) {\n    'use strict';\n\n    // AMD. Register as an anonymous module.  Wrap in function so we have access\n    // to root via `this`.\n    if (typeof define === 'function' && define.amd) {\n        define([], function() {\n            return factory.apply(window);\n        });\n    }\n\n    // Node. Does not work with strict CommonJS, but only CommonJS-like\n    // environments that support module.exports, like Node.\n    else if (typeof exports === 'object') {\n        module.exports = factory.call(window);\n    }\n\n    // Browser globals.\n    else {\n        window.Waves = factory.call(window);\n    }\n})(typeof global === 'object' ? global : this, function() {\n    'use strict';\n\n    var Waves            = Waves || {};\n    var $$               = document.querySelectorAll.bind(document);\n    var toString         = Object.prototype.toString;\n    var isTouchAvailable = 'ontouchstart' in window;\n\n\n    // Find exact position of element\n    function isWindow(obj) {\n        return obj !== null && obj === obj.window;\n    }\n\n    function getWindow(elem) {\n        return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;\n    }\n\n    function isObject(value) {\n        var type = typeof value;\n        return type === 'function' || type === 'object' && !!value;\n    }\n\n    function isDOMNode(obj) {\n        return isObject(obj) && obj.nodeType > 0;\n    }\n\n    function getWavesElements(nodes) {\n        var stringRepr = toString.call(nodes);\n\n        if (stringRepr === '[object String]') {\n            return $$(nodes);\n        } else if (isObject(nodes) && /^\\[object (HTMLCollection|NodeList|Object)\\]$/.test(stringRepr) && nodes.hasOwnProperty('length')) {\n            return nodes;\n        } else if (isDOMNode(nodes)) {\n            return [nodes];\n        }\n\n        return [];\n    }\n\n    function offset(elem) {\n        var docElem, win,\n            box = { top: 0, left: 0 },\n            doc = elem && elem.ownerDocument;\n\n        docElem = doc.documentElement;\n\n        if (typeof elem.getBoundingClientRect !== typeof undefined) {\n            box = elem.getBoundingClientRect();\n        }\n        win = getWindow(doc);\n        return {\n            top: box.top + win.pageYOffset - docElem.clientTop,\n            left: box.left + win.pageXOffset - docElem.clientLeft\n        };\n    }\n\n    function convertStyle(styleObj) {\n        var style = '';\n\n        for (var prop in styleObj) {\n            if (styleObj.hasOwnProperty(prop)) {\n                style += (prop + ':' + styleObj[prop] + ';');\n            }\n        }\n\n        return style;\n    }\n\n    var Effect = {\n\n        // Effect duration\n        duration: 750,\n\n        // Effect delay (check for scroll before showing effect)\n        delay: 200,\n\n        show: function(e, element, velocity) {\n\n            // Disable right click\n            if (e.button === 2) {\n                return false;\n            }\n\n            element = element || this;\n\n            // Create ripple\n            var ripple = document.createElement('div');\n            ripple.className = 'waves-ripple waves-rippling';\n            element.appendChild(ripple);\n\n            // Get click coordinate and element width\n            var pos       = offset(element);\n            var relativeY = 0;\n            var relativeX = 0;\n            // Support for touch devices\n            if('touches' in e && e.touches.length) {\n                relativeY   = (e.touches[0].pageY - pos.top);\n                relativeX   = (e.touches[0].pageX - pos.left);\n            }\n            //Normal case\n            else {\n                relativeY   = (e.pageY - pos.top);\n                relativeX   = (e.pageX - pos.left);\n            }\n            // Support for synthetic events\n            relativeX = relativeX >= 0 ? relativeX : 0;\n            relativeY = relativeY >= 0 ? relativeY : 0;\n\n            var scale     = 'scale(' + ((element.clientWidth / 100) * 3) + ')';\n            var translate = 'translate(0,0)';\n\n            if (velocity) {\n                translate = 'translate(' + (velocity.x) + 'px, ' + (velocity.y) + 'px)';\n            }\n\n            // Attach data to element\n            ripple.setAttribute('data-hold', Date.now());\n            ripple.setAttribute('data-x', relativeX);\n            ripple.setAttribute('data-y', relativeY);\n            ripple.setAttribute('data-scale', scale);\n            ripple.setAttribute('data-translate', translate);\n\n            // Set ripple position\n            var rippleStyle = {\n                top: relativeY + 'px',\n                left: relativeX + 'px'\n            };\n\n            ripple.classList.add('waves-notransition');\n            ripple.setAttribute('style', convertStyle(rippleStyle));\n            ripple.classList.remove('waves-notransition');\n\n            // Scale the ripple\n            rippleStyle['-webkit-transform'] = scale + ' ' + translate;\n            rippleStyle['-moz-transform'] = scale + ' ' + translate;\n            rippleStyle['-ms-transform'] = scale + ' ' + translate;\n            rippleStyle['-o-transform'] = scale + ' ' + translate;\n            rippleStyle.transform = scale + ' ' + translate;\n            rippleStyle.opacity = '1';\n\n            var duration = e.type === 'mousemove' ? 2500 : Effect.duration;\n            rippleStyle['-webkit-transition-duration'] = duration + 'ms';\n            rippleStyle['-moz-transition-duration']    = duration + 'ms';\n            rippleStyle['-o-transition-duration']      = duration + 'ms';\n            rippleStyle['transition-duration']         = duration + 'ms';\n\n            ripple.setAttribute('style', convertStyle(rippleStyle));\n        },\n\n        hide: function(e, element) {\n            element = element || this;\n\n            var ripples = element.getElementsByClassName('waves-rippling');\n\n            for (var i = 0, len = ripples.length; i < len; i++) {\n                removeRipple(e, element, ripples[i]);\n            }\n        }\n    };\n\n    /**\n     * Collection of wrapper for HTML element that only have single tag\n     * like <input> and <img>\n     */\n    var TagWrapper = {\n\n        // Wrap <input> tag so it can perform the effect\n        input: function(element) {\n\n            var parent = element.parentNode;\n\n            // If input already have parent just pass through\n            if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) {\n                return;\n            }\n\n            // Put element class and style to the specified parent\n            var wrapper       = document.createElement('i');\n            wrapper.className = element.className + ' waves-input-wrapper';\n            element.className = 'waves-button-input';\n\n            // Put element as child\n            parent.replaceChild(wrapper, element);\n            wrapper.appendChild(element);\n\n            // Apply element color and background color to wrapper\n            var elementStyle    = window.getComputedStyle(element, null);\n            var color           = elementStyle.color;\n            var backgroundColor = elementStyle.backgroundColor;\n\n            wrapper.setAttribute('style', 'color:' + color + ';background:' + backgroundColor);\n            element.setAttribute('style', 'background-color:rgba(0,0,0,0);');\n\n        },\n\n        // Wrap <img> tag so it can perform the effect\n        img: function(element) {\n\n            var parent = element.parentNode;\n\n            // If input already have parent just pass through\n            if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) {\n                return;\n            }\n\n            // Put element as child\n            var wrapper  = document.createElement('i');\n            parent.replaceChild(wrapper, element);\n            wrapper.appendChild(element);\n\n        }\n    };\n\n    /**\n     * Hide the effect and remove the ripple. Must be\n     * a separate function to pass the JSLint...\n     */\n    function removeRipple(e, el, ripple) {\n\n        // Check if the ripple still exist\n        if (!ripple) {\n            return;\n        }\n\n        ripple.classList.remove('waves-rippling');\n\n        var relativeX = ripple.getAttribute('data-x');\n        var relativeY = ripple.getAttribute('data-y');\n        var scale     = ripple.getAttribute('data-scale');\n        var translate = ripple.getAttribute('data-translate');\n\n        // Get delay beetween mousedown and mouse leave\n        var diff = Date.now() - Number(ripple.getAttribute('data-hold'));\n        var delay = 350 - diff;\n\n        if (delay < 0) {\n            delay = 0;\n        }\n\n        if (e.type === 'mousemove') {\n            delay = 150;\n        }\n\n        // Fade out ripple after delay\n        var duration = e.type === 'mousemove' ? 2500 : Effect.duration;\n\n        setTimeout(function() {\n\n            var style = {\n                top: relativeY + 'px',\n                left: relativeX + 'px',\n                opacity: '0',\n\n                // Duration\n                '-webkit-transition-duration': duration + 'ms',\n                '-moz-transition-duration': duration + 'ms',\n                '-o-transition-duration': duration + 'ms',\n                'transition-duration': duration + 'ms',\n                '-webkit-transform': scale + ' ' + translate,\n                '-moz-transform': scale + ' ' + translate,\n                '-ms-transform': scale + ' ' + translate,\n                '-o-transform': scale + ' ' + translate,\n                'transform': scale + ' ' + translate\n            };\n\n            ripple.setAttribute('style', convertStyle(style));\n\n            setTimeout(function() {\n                try {\n                    el.removeChild(ripple);\n                } catch (e) {\n                    return false;\n                }\n            }, duration);\n\n        }, delay);\n    }\n\n\n    /**\n     * Disable mousedown event for 500ms during and after touch\n     */\n    var TouchHandler = {\n\n        /* uses an integer rather than bool so there's no issues with\n         * needing to clear timeouts if another touch event occurred\n         * within the 500ms. Cannot mouseup between touchstart and\n         * touchend, nor in the 500ms after touchend. */\n        touches: 0,\n\n        allowEvent: function(e) {\n\n            var allow = true;\n\n            if (/^(mousedown|mousemove)$/.test(e.type) && TouchHandler.touches) {\n                allow = false;\n            }\n\n            return allow;\n        },\n        registerEvent: function(e) {\n            var eType = e.type;\n\n            if (eType === 'touchstart') {\n\n                TouchHandler.touches += 1; // push\n\n            } else if (/^(touchend|touchcancel)$/.test(eType)) {\n\n                setTimeout(function() {\n                    if (TouchHandler.touches) {\n                        TouchHandler.touches -= 1; // pop after 500ms\n                    }\n                }, 500);\n\n            }\n        }\n    };\n\n\n    /**\n     * Delegated click handler for .waves-effect element.\n     * returns null when .waves-effect element not in \"click tree\"\n     */\n    function getWavesEffectElement(e) {\n\n        if (TouchHandler.allowEvent(e) === false) {\n            return null;\n        }\n\n        var element = null;\n        var target = e.target || e.srcElement;\n\n        while (target.parentElement !== null) {\n            if (target.classList.contains('waves-effect') && (!(target instanceof SVGElement))) {\n                element = target;\n                break;\n            }\n            target = target.parentElement;\n        }\n\n        return element;\n    }\n\n    /**\n     * Bubble the click and show effect if .waves-effect elem was found\n     */\n    function showEffect(e) {\n\n        // Disable effect if element has \"disabled\" property on it\n        // In some cases, the event is not triggered by the current element\n        // if (e.target.getAttribute('disabled') !== null) {\n        //     return;\n        // }\n\n        var element = getWavesEffectElement(e);\n\n        if (element !== null) {\n\n            // Make it sure the element has either disabled property, disabled attribute or 'disabled' class\n            if (element.disabled || element.getAttribute('disabled') || element.classList.contains('disabled')) {\n                return;\n            }\n\n            TouchHandler.registerEvent(e);\n\n            if (e.type === 'touchstart' && Effect.delay) {\n\n                var hidden = false;\n\n                var timer = setTimeout(function () {\n                    timer = null;\n                    Effect.show(e, element);\n                }, Effect.delay);\n\n                var hideEffect = function(hideEvent) {\n\n                    // if touch hasn't moved, and effect not yet started: start effect now\n                    if (timer) {\n                        clearTimeout(timer);\n                        timer = null;\n                        Effect.show(e, element);\n                    }\n                    if (!hidden) {\n                        hidden = true;\n                        Effect.hide(hideEvent, element);\n                    }\n                };\n\n                var touchMove = function(moveEvent) {\n                    if (timer) {\n                        clearTimeout(timer);\n                        timer = null;\n                    }\n                    hideEffect(moveEvent);\n                };\n\n                element.addEventListener('touchmove', touchMove, false);\n                element.addEventListener('touchend', hideEffect, false);\n                element.addEventListener('touchcancel', hideEffect, false);\n\n            } else {\n\n                Effect.show(e, element);\n\n                if (isTouchAvailable) {\n                    element.addEventListener('touchend', Effect.hide, false);\n                    element.addEventListener('touchcancel', Effect.hide, false);\n                }\n\n                element.addEventListener('mouseup', Effect.hide, false);\n                element.addEventListener('mouseleave', Effect.hide, false);\n            }\n        }\n    }\n\n    Waves.init = function(options) {\n        var body = document.body;\n\n        options = options || {};\n\n        if ('duration' in options) {\n            Effect.duration = options.duration;\n        }\n\n        if ('delay' in options) {\n            Effect.delay = options.delay;\n        }\n\n        if (isTouchAvailable) {\n            body.addEventListener('touchstart', showEffect, false);\n            body.addEventListener('touchcancel', TouchHandler.registerEvent, false);\n            body.addEventListener('touchend', TouchHandler.registerEvent, false);\n        }\n\n        body.addEventListener('mousedown', showEffect, false);\n    };\n\n\n    /**\n     * Attach Waves to dynamically loaded inputs, or add .waves-effect and other\n     * waves classes to a set of elements. Set drag to true if the ripple mouseover\n     * or skimming effect should be applied to the elements.\n     */\n    Waves.attach = function(elements, classes) {\n\n        elements = getWavesElements(elements);\n\n        if (toString.call(classes) === '[object Array]') {\n            classes = classes.join(' ');\n        }\n\n        classes = classes ? ' ' + classes : '';\n\n        var element, tagName;\n\n        for (var i = 0, len = elements.length; i < len; i++) {\n\n            element = elements[i];\n            tagName = element.tagName.toLowerCase();\n\n            if (['input', 'img'].indexOf(tagName) !== -1) {\n                TagWrapper[tagName](element);\n                element = element.parentElement;\n            }\n\n            if (element.className.indexOf('waves-effect') === -1) {\n                element.className += ' waves-effect' + classes;\n            }\n        }\n    };\n\n\n    /**\n     * Cause a ripple to appear in an element via code.\n     */\n    Waves.ripple = function(elements, options) {\n        elements = getWavesElements(elements);\n        var elementsLen = elements.length;\n\n        options          = options || {};\n        options.wait     = options.wait || 0;\n        options.position = options.position || null; // default = centre of element\n\n\n        if (elementsLen) {\n            var element, pos, off, centre = {}, i = 0;\n            var mousedown = {\n                type: 'mousedown',\n                button: 1\n            };\n            var hideRipple = function(mouseup, element) {\n                return function() {\n                    Effect.hide(mouseup, element);\n                };\n            };\n\n            for (; i < elementsLen; i++) {\n                element = elements[i];\n                pos = options.position || {\n                    x: element.clientWidth / 2,\n                    y: element.clientHeight / 2\n                };\n\n                off      = offset(element);\n                centre.x = off.left + pos.x;\n                centre.y = off.top + pos.y;\n\n                mousedown.pageX = centre.x;\n                mousedown.pageY = centre.y;\n\n                Effect.show(mousedown, element);\n\n                if (options.wait >= 0 && options.wait !== null) {\n                    var mouseup = {\n                        type: 'mouseup',\n                        button: 1\n                    };\n\n                    setTimeout(hideRipple(mouseup, element), options.wait);\n                }\n            }\n        }\n    };\n\n    /**\n     * Remove all ripples from an element.\n     */\n    Waves.calm = function(elements) {\n        elements = getWavesElements(elements);\n        var mouseup = {\n            type: 'mouseup',\n            button: 1\n        };\n\n        for (var i = 0, len = elements.length; i < len; i++) {\n            Effect.hide(mouseup, elements[i]);\n        }\n    };\n\n    /**\n     * Deprecated API fallback\n     */\n    Waves.displayEffect = function(options) {\n        console.error('Waves.displayEffect() has been deprecated and will be removed in future version. Please use Waves.init() to initialize Waves effect');\n        Waves.init(options);\n    };\n\n    return Waves;\n});\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/animate.css/animate.css",
    "content": "@charset \"UTF-8\";\n\n/*!\nAnimate.css - http://daneden.me/animate\nLicensed under the MIT license - http://opensource.org/licenses/MIT\n\nCopyright (c) 2015 Daniel Eden\n*/\n\n.animated {\n  -webkit-animation-duration: 1s;\n  animation-duration: 1s;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n\n.animated.infinite {\n  -webkit-animation-iteration-count: infinite;\n  animation-iteration-count: infinite;\n}\n\n.animated.hinge {\n  -webkit-animation-duration: 2s;\n  animation-duration: 2s;\n}\n\n.animated.bounceIn,\n.animated.bounceOut {\n  -webkit-animation-duration: .75s;\n  animation-duration: .75s;\n}\n\n.animated.flipOutX,\n.animated.flipOutY {\n  -webkit-animation-duration: .75s;\n  animation-duration: .75s;\n}\n\n@-webkit-keyframes bounce {\n  from, 20%, 53%, 80%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    -webkit-transform: translate3d(0,0,0);\n    transform: translate3d(0,0,0);\n  }\n\n  40%, 43% {\n    -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    -webkit-transform: translate3d(0, -30px, 0);\n    transform: translate3d(0, -30px, 0);\n  }\n\n  70% {\n    -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    -webkit-transform: translate3d(0, -15px, 0);\n    transform: translate3d(0, -15px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0,-4px,0);\n    transform: translate3d(0,-4px,0);\n  }\n}\n\n@keyframes bounce {\n  from, 20%, 53%, 80%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    -webkit-transform: translate3d(0,0,0);\n    transform: translate3d(0,0,0);\n  }\n\n  40%, 43% {\n    -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    -webkit-transform: translate3d(0, -30px, 0);\n    transform: translate3d(0, -30px, 0);\n  }\n\n  70% {\n    -webkit-animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    animation-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);\n    -webkit-transform: translate3d(0, -15px, 0);\n    transform: translate3d(0, -15px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0,-4px,0);\n    transform: translate3d(0,-4px,0);\n  }\n}\n\n.bounce {\n  -webkit-animation-name: bounce;\n  animation-name: bounce;\n  -webkit-transform-origin: center bottom;\n  transform-origin: center bottom;\n}\n\n@-webkit-keyframes flash {\n  from, 50%, 100% {\n    opacity: 1;\n  }\n\n  25%, 75% {\n    opacity: 0;\n  }\n}\n\n@keyframes flash {\n  from, 50%, 100% {\n    opacity: 1;\n  }\n\n  25%, 75% {\n    opacity: 0;\n  }\n}\n\n.flash {\n  -webkit-animation-name: flash;\n  animation-name: flash;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes pulse {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  50% {\n    -webkit-transform: scale3d(1.05, 1.05, 1.05);\n    transform: scale3d(1.05, 1.05, 1.05);\n  }\n\n  100% {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n@keyframes pulse {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  50% {\n    -webkit-transform: scale3d(1.05, 1.05, 1.05);\n    transform: scale3d(1.05, 1.05, 1.05);\n  }\n\n  100% {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.pulse {\n  -webkit-animation-name: pulse;\n  animation-name: pulse;\n}\n\n@-webkit-keyframes rubberBand {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  30% {\n    -webkit-transform: scale3d(1.25, 0.75, 1);\n    transform: scale3d(1.25, 0.75, 1);\n  }\n\n  40% {\n    -webkit-transform: scale3d(0.75, 1.25, 1);\n    transform: scale3d(0.75, 1.25, 1);\n  }\n\n  50% {\n    -webkit-transform: scale3d(1.15, 0.85, 1);\n    transform: scale3d(1.15, 0.85, 1);\n  }\n\n  65% {\n    -webkit-transform: scale3d(.95, 1.05, 1);\n    transform: scale3d(.95, 1.05, 1);\n  }\n\n  75% {\n    -webkit-transform: scale3d(1.05, .95, 1);\n    transform: scale3d(1.05, .95, 1);\n  }\n\n  100% {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n@keyframes rubberBand {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  30% {\n    -webkit-transform: scale3d(1.25, 0.75, 1);\n    transform: scale3d(1.25, 0.75, 1);\n  }\n\n  40% {\n    -webkit-transform: scale3d(0.75, 1.25, 1);\n    transform: scale3d(0.75, 1.25, 1);\n  }\n\n  50% {\n    -webkit-transform: scale3d(1.15, 0.85, 1);\n    transform: scale3d(1.15, 0.85, 1);\n  }\n\n  65% {\n    -webkit-transform: scale3d(.95, 1.05, 1);\n    transform: scale3d(.95, 1.05, 1);\n  }\n\n  75% {\n    -webkit-transform: scale3d(1.05, .95, 1);\n    transform: scale3d(1.05, .95, 1);\n  }\n\n  100% {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.rubberBand {\n  -webkit-animation-name: rubberBand;\n  animation-name: rubberBand;\n}\n\n@-webkit-keyframes shake {\n  from, 100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  10%, 30%, 50%, 70%, 90% {\n    -webkit-transform: translate3d(-10px, 0, 0);\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  20%, 40%, 60%, 80% {\n    -webkit-transform: translate3d(10px, 0, 0);\n    transform: translate3d(10px, 0, 0);\n  }\n}\n\n@keyframes shake {\n  from, 100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  10%, 30%, 50%, 70%, 90% {\n    -webkit-transform: translate3d(-10px, 0, 0);\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  20%, 40%, 60%, 80% {\n    -webkit-transform: translate3d(10px, 0, 0);\n    transform: translate3d(10px, 0, 0);\n  }\n}\n\n.shake {\n  -webkit-animation-name: shake;\n  animation-name: shake;\n}\n\n@-webkit-keyframes swing {\n  20% {\n    -webkit-transform: rotate3d(0, 0, 1, 15deg);\n    transform: rotate3d(0, 0, 1, 15deg);\n  }\n\n  40% {\n    -webkit-transform: rotate3d(0, 0, 1, -10deg);\n    transform: rotate3d(0, 0, 1, -10deg);\n  }\n\n  60% {\n    -webkit-transform: rotate3d(0, 0, 1, 5deg);\n    transform: rotate3d(0, 0, 1, 5deg);\n  }\n\n  80% {\n    -webkit-transform: rotate3d(0, 0, 1, -5deg);\n    transform: rotate3d(0, 0, 1, -5deg);\n  }\n\n  100% {\n    -webkit-transform: rotate3d(0, 0, 1, 0deg);\n    transform: rotate3d(0, 0, 1, 0deg);\n  }\n}\n\n@keyframes swing {\n  20% {\n    -webkit-transform: rotate3d(0, 0, 1, 15deg);\n    transform: rotate3d(0, 0, 1, 15deg);\n  }\n\n  40% {\n    -webkit-transform: rotate3d(0, 0, 1, -10deg);\n    transform: rotate3d(0, 0, 1, -10deg);\n  }\n\n  60% {\n    -webkit-transform: rotate3d(0, 0, 1, 5deg);\n    transform: rotate3d(0, 0, 1, 5deg);\n  }\n\n  80% {\n    -webkit-transform: rotate3d(0, 0, 1, -5deg);\n    transform: rotate3d(0, 0, 1, -5deg);\n  }\n\n  100% {\n    -webkit-transform: rotate3d(0, 0, 1, 0deg);\n    transform: rotate3d(0, 0, 1, 0deg);\n  }\n}\n\n.swing {\n  -webkit-transform-origin: top center;\n  transform-origin: top center;\n  -webkit-animation-name: swing;\n  animation-name: swing;\n}\n\n@-webkit-keyframes tada {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  10%, 20% {\n    -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);\n    transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);\n  }\n\n  30%, 50%, 70%, 90% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n  }\n\n  40%, 60%, 80% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n  }\n\n  100% {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n@keyframes tada {\n  from {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n\n  10%, 20% {\n    -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);\n    transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);\n  }\n\n  30%, 50%, 70%, 90% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);\n  }\n\n  40%, 60%, 80% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n    transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);\n  }\n\n  100% {\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.tada {\n  -webkit-animation-name: tada;\n  animation-name: tada;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes wobble {\n  from {\n    -webkit-transform: none;\n    transform: none;\n  }\n\n  15% {\n    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n  }\n\n  30% {\n    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n  }\n\n  45% {\n    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n  }\n\n  60% {\n    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n  }\n\n  75% {\n    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes wobble {\n  from {\n    -webkit-transform: none;\n    transform: none;\n  }\n\n  15% {\n    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);\n  }\n\n  30% {\n    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);\n  }\n\n  45% {\n    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);\n  }\n\n  60% {\n    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);\n  }\n\n  75% {\n    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.wobble {\n  -webkit-animation-name: wobble;\n  animation-name: wobble;\n}\n\n@-webkit-keyframes jello {\n  from, 11.1%, 100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n\n  22.2% {\n    -webkit-transform: skewX(-12.5deg) skewY(-12.5deg);\n    transform: skewX(-12.5deg) skewY(-12.5deg);\n  }\n\n  33.3% {\n    -webkit-transform: skewX(6.25deg) skewY(6.25deg);\n    transform: skewX(6.25deg) skewY(6.25deg);\n  }\n\n  44.4% {\n    -webkit-transform: skewX(-3.125deg) skewY(-3.125deg);\n    transform: skewX(-3.125deg) skewY(-3.125deg);\n  }\n\n  55.5% {\n    -webkit-transform: skewX(1.5625deg) skewY(1.5625deg);\n    transform: skewX(1.5625deg) skewY(1.5625deg);\n  }\n\n  66.6% {\n    -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);\n    transform: skewX(-0.78125deg) skewY(-0.78125deg);\n  }\n\n  77.7% {\n    -webkit-transform: skewX(0.390625deg) skewY(0.390625deg);\n    transform: skewX(0.390625deg) skewY(0.390625deg);\n  }\n\n  88.8% {\n    -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n  }\n}\n\n@keyframes jello {\n  from, 11.1%, 100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n\n  22.2% {\n    -webkit-transform: skewX(-12.5deg) skewY(-12.5deg);\n    transform: skewX(-12.5deg) skewY(-12.5deg);\n  }\n\n  33.3% {\n    -webkit-transform: skewX(6.25deg) skewY(6.25deg);\n    transform: skewX(6.25deg) skewY(6.25deg);\n  }\n\n  44.4% {\n    -webkit-transform: skewX(-3.125deg) skewY(-3.125deg);\n    transform: skewX(-3.125deg) skewY(-3.125deg);\n  }\n\n  55.5% {\n    -webkit-transform: skewX(1.5625deg) skewY(1.5625deg);\n    transform: skewX(1.5625deg) skewY(1.5625deg);\n  }\n\n  66.6% {\n    -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);\n    transform: skewX(-0.78125deg) skewY(-0.78125deg);\n  }\n\n  77.7% {\n    -webkit-transform: skewX(0.390625deg) skewY(0.390625deg);\n    transform: skewX(0.390625deg) skewY(0.390625deg);\n  }\n\n  88.8% {\n    -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n    transform: skewX(-0.1953125deg) skewY(-0.1953125deg);\n  }\n}\n\n.jello {\n  -webkit-animation-name: jello;\n  animation-name: jello;\n  -webkit-transform-origin: center;\n  transform-origin: center;\n}\n\n@-webkit-keyframes bounceIn {\n  from, 20%, 40%, 60%, 80%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: scale3d(.3, .3, .3);\n    transform: scale3d(.3, .3, .3);\n  }\n\n  20% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1);\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  40% {\n    -webkit-transform: scale3d(.9, .9, .9);\n    transform: scale3d(.9, .9, .9);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(1.03, 1.03, 1.03);\n    transform: scale3d(1.03, 1.03, 1.03);\n  }\n\n  80% {\n    -webkit-transform: scale3d(.97, .97, .97);\n    transform: scale3d(.97, .97, .97);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n@keyframes bounceIn {\n  from, 20%, 40%, 60%, 80%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: scale3d(.3, .3, .3);\n    transform: scale3d(.3, .3, .3);\n  }\n\n  20% {\n    -webkit-transform: scale3d(1.1, 1.1, 1.1);\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  40% {\n    -webkit-transform: scale3d(.9, .9, .9);\n    transform: scale3d(.9, .9, .9);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(1.03, 1.03, 1.03);\n    transform: scale3d(1.03, 1.03, 1.03);\n  }\n\n  80% {\n    -webkit-transform: scale3d(.97, .97, .97);\n    transform: scale3d(.97, .97, .97);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: scale3d(1, 1, 1);\n    transform: scale3d(1, 1, 1);\n  }\n}\n\n.bounceIn {\n  -webkit-animation-name: bounceIn;\n  animation-name: bounceIn;\n}\n\n@-webkit-keyframes bounceInDown {\n  from, 60%, 75%, 90%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -3000px, 0);\n    transform: translate3d(0, -3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 25px, 0);\n    transform: translate3d(0, 25px, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(0, -10px, 0);\n    transform: translate3d(0, -10px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, 5px, 0);\n    transform: translate3d(0, 5px, 0);\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes bounceInDown {\n  from, 60%, 75%, 90%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -3000px, 0);\n    transform: translate3d(0, -3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 25px, 0);\n    transform: translate3d(0, 25px, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(0, -10px, 0);\n    transform: translate3d(0, -10px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, 5px, 0);\n    transform: translate3d(0, 5px, 0);\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.bounceInDown {\n  -webkit-animation-name: bounceInDown;\n  animation-name: bounceInDown;\n}\n\n@-webkit-keyframes bounceInLeft {\n  from, 60%, 75%, 90%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: translate3d(-3000px, 0, 0);\n    transform: translate3d(-3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(25px, 0, 0);\n    transform: translate3d(25px, 0, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(-10px, 0, 0);\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(5px, 0, 0);\n    transform: translate3d(5px, 0, 0);\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes bounceInLeft {\n  from, 60%, 75%, 90%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  0% {\n    opacity: 0;\n    -webkit-transform: translate3d(-3000px, 0, 0);\n    transform: translate3d(-3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(25px, 0, 0);\n    transform: translate3d(25px, 0, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(-10px, 0, 0);\n    transform: translate3d(-10px, 0, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(5px, 0, 0);\n    transform: translate3d(5px, 0, 0);\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.bounceInLeft {\n  -webkit-animation-name: bounceInLeft;\n  animation-name: bounceInLeft;\n}\n\n@-webkit-keyframes bounceInRight {\n  from, 60%, 75%, 90%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(3000px, 0, 0);\n    transform: translate3d(3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(-25px, 0, 0);\n    transform: translate3d(-25px, 0, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(10px, 0, 0);\n    transform: translate3d(10px, 0, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(-5px, 0, 0);\n    transform: translate3d(-5px, 0, 0);\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes bounceInRight {\n  from, 60%, 75%, 90%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(3000px, 0, 0);\n    transform: translate3d(3000px, 0, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(-25px, 0, 0);\n    transform: translate3d(-25px, 0, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(10px, 0, 0);\n    transform: translate3d(10px, 0, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(-5px, 0, 0);\n    transform: translate3d(-5px, 0, 0);\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.bounceInRight {\n  -webkit-animation-name: bounceInRight;\n  animation-name: bounceInRight;\n}\n\n@-webkit-keyframes bounceInUp {\n  from, 60%, 75%, 90%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 3000px, 0);\n    transform: translate3d(0, 3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(0, 10px, 0);\n    transform: translate3d(0, 10px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, -5px, 0);\n    transform: translate3d(0, -5px, 0);\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes bounceInUp {\n  from, 60%, 75%, 90%, 100% {\n    -webkit-animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n    animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);\n  }\n\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 3000px, 0);\n    transform: translate3d(0, 3000px, 0);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n  }\n\n  75% {\n    -webkit-transform: translate3d(0, 10px, 0);\n    transform: translate3d(0, 10px, 0);\n  }\n\n  90% {\n    -webkit-transform: translate3d(0, -5px, 0);\n    transform: translate3d(0, -5px, 0);\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.bounceInUp {\n  -webkit-animation-name: bounceInUp;\n  animation-name: bounceInUp;\n}\n\n@-webkit-keyframes bounceOut {\n  20% {\n    -webkit-transform: scale3d(.9, .9, .9);\n    transform: scale3d(.9, .9, .9);\n  }\n\n  50%, 55% {\n    opacity: 1;\n    -webkit-transform: scale3d(1.1, 1.1, 1.1);\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale3d(.3, .3, .3);\n    transform: scale3d(.3, .3, .3);\n  }\n}\n\n@keyframes bounceOut {\n  20% {\n    -webkit-transform: scale3d(.9, .9, .9);\n    transform: scale3d(.9, .9, .9);\n  }\n\n  50%, 55% {\n    opacity: 1;\n    -webkit-transform: scale3d(1.1, 1.1, 1.1);\n    transform: scale3d(1.1, 1.1, 1.1);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale3d(.3, .3, .3);\n    transform: scale3d(.3, .3, .3);\n  }\n}\n\n.bounceOut {\n  -webkit-animation-name: bounceOut;\n  animation-name: bounceOut;\n}\n\n@-webkit-keyframes bounceOutDown {\n  20% {\n    -webkit-transform: translate3d(0, 10px, 0);\n    transform: translate3d(0, 10px, 0);\n  }\n\n  40%, 45% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n@keyframes bounceOutDown {\n  20% {\n    -webkit-transform: translate3d(0, 10px, 0);\n    transform: translate3d(0, 10px, 0);\n  }\n\n  40%, 45% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, -20px, 0);\n    transform: translate3d(0, -20px, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n.bounceOutDown {\n  -webkit-animation-name: bounceOutDown;\n  animation-name: bounceOutDown;\n}\n\n@-webkit-keyframes bounceOutLeft {\n  20% {\n    opacity: 1;\n    -webkit-transform: translate3d(20px, 0, 0);\n    transform: translate3d(20px, 0, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n@keyframes bounceOutLeft {\n  20% {\n    opacity: 1;\n    -webkit-transform: translate3d(20px, 0, 0);\n    transform: translate3d(20px, 0, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n.bounceOutLeft {\n  -webkit-animation-name: bounceOutLeft;\n  animation-name: bounceOutLeft;\n}\n\n@-webkit-keyframes bounceOutRight {\n  20% {\n    opacity: 1;\n    -webkit-transform: translate3d(-20px, 0, 0);\n    transform: translate3d(-20px, 0, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n@keyframes bounceOutRight {\n  20% {\n    opacity: 1;\n    -webkit-transform: translate3d(-20px, 0, 0);\n    transform: translate3d(-20px, 0, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n.bounceOutRight {\n  -webkit-animation-name: bounceOutRight;\n  animation-name: bounceOutRight;\n}\n\n@-webkit-keyframes bounceOutUp {\n  20% {\n    -webkit-transform: translate3d(0, -10px, 0);\n    transform: translate3d(0, -10px, 0);\n  }\n\n  40%, 45% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 20px, 0);\n    transform: translate3d(0, 20px, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n@keyframes bounceOutUp {\n  20% {\n    -webkit-transform: translate3d(0, -10px, 0);\n    transform: translate3d(0, -10px, 0);\n  }\n\n  40%, 45% {\n    opacity: 1;\n    -webkit-transform: translate3d(0, 20px, 0);\n    transform: translate3d(0, 20px, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n.bounceOutUp {\n  -webkit-animation-name: bounceOutUp;\n  animation-name: bounceOutUp;\n}\n\n@-webkit-keyframes fadeIn {\n  from {\n    opacity: 0;\n  }\n\n  100% {\n    opacity: 1;\n  }\n}\n\n@keyframes fadeIn {\n  from {\n    opacity: 0;\n  }\n\n  100% {\n    opacity: 1;\n  }\n}\n\n.fadeIn {\n  -webkit-animation-name: fadeIn;\n  animation-name: fadeIn;\n}\n\n@-webkit-keyframes fadeInDown {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes fadeInDown {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.fadeInDown {\n  -webkit-animation-name: fadeInDown;\n  animation-name: fadeInDown;\n}\n\n@-webkit-keyframes fadeInDownBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes fadeInDownBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.fadeInDownBig {\n  -webkit-animation-name: fadeInDownBig;\n  animation-name: fadeInDownBig;\n}\n\n@-webkit-keyframes fadeInLeft {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes fadeInLeft {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.fadeInLeft {\n  -webkit-animation-name: fadeInLeft;\n  animation-name: fadeInLeft;\n}\n\n@-webkit-keyframes fadeInLeftBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes fadeInLeftBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.fadeInLeftBig {\n  -webkit-animation-name: fadeInLeftBig;\n  animation-name: fadeInLeftBig;\n}\n\n@-webkit-keyframes fadeInRight {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes fadeInRight {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.fadeInRight {\n  -webkit-animation-name: fadeInRight;\n  animation-name: fadeInRight;\n}\n\n@-webkit-keyframes fadeInRightBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes fadeInRightBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.fadeInRightBig {\n  -webkit-animation-name: fadeInRightBig;\n  animation-name: fadeInRightBig;\n}\n\n@-webkit-keyframes fadeInUp {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes fadeInUp {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.fadeInUp {\n  -webkit-animation-name: fadeInUp;\n  animation-name: fadeInUp;\n}\n\n@-webkit-keyframes fadeInUpBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes fadeInUpBig {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.fadeInUpBig {\n  -webkit-animation-name: fadeInUpBig;\n  animation-name: fadeInUpBig;\n}\n\n@-webkit-keyframes fadeOut {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n  }\n}\n\n@keyframes fadeOut {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n  }\n}\n\n.fadeOut {\n  -webkit-animation-name: fadeOut;\n  animation-name: fadeOut;\n}\n\n@-webkit-keyframes fadeOutDown {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n@keyframes fadeOutDown {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n.fadeOutDown {\n  -webkit-animation-name: fadeOutDown;\n  animation-name: fadeOutDown;\n}\n\n@-webkit-keyframes fadeOutDownBig {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n@keyframes fadeOutDownBig {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, 2000px, 0);\n    transform: translate3d(0, 2000px, 0);\n  }\n}\n\n.fadeOutDownBig {\n  -webkit-animation-name: fadeOutDownBig;\n  animation-name: fadeOutDownBig;\n}\n\n@-webkit-keyframes fadeOutLeft {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n@keyframes fadeOutLeft {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n.fadeOutLeft {\n  -webkit-animation-name: fadeOutLeft;\n  animation-name: fadeOutLeft;\n}\n\n@-webkit-keyframes fadeOutLeftBig {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n@keyframes fadeOutLeftBig {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(-2000px, 0, 0);\n    transform: translate3d(-2000px, 0, 0);\n  }\n}\n\n.fadeOutLeftBig {\n  -webkit-animation-name: fadeOutLeftBig;\n  animation-name: fadeOutLeftBig;\n}\n\n@-webkit-keyframes fadeOutRight {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n@keyframes fadeOutRight {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n.fadeOutRight {\n  -webkit-animation-name: fadeOutRight;\n  animation-name: fadeOutRight;\n}\n\n@-webkit-keyframes fadeOutRightBig {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n@keyframes fadeOutRightBig {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(2000px, 0, 0);\n    transform: translate3d(2000px, 0, 0);\n  }\n}\n\n.fadeOutRightBig {\n  -webkit-animation-name: fadeOutRightBig;\n  animation-name: fadeOutRightBig;\n}\n\n@-webkit-keyframes fadeOutUp {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n@keyframes fadeOutUp {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n.fadeOutUp {\n  -webkit-animation-name: fadeOutUp;\n  animation-name: fadeOutUp;\n}\n\n@-webkit-keyframes fadeOutUpBig {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n@keyframes fadeOutUpBig {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(0, -2000px, 0);\n    transform: translate3d(0, -2000px, 0);\n  }\n}\n\n.fadeOutUpBig {\n  -webkit-animation-name: fadeOutUpBig;\n  animation-name: fadeOutUpBig;\n}\n\n@-webkit-keyframes flip {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -360deg);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);\n    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  50% {\n    -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);\n    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) scale3d(.95, .95, .95);\n    transform: perspective(400px) scale3d(.95, .95, .95);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n}\n\n@keyframes flip {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -360deg);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);\n    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);\n    -webkit-animation-timing-function: ease-out;\n    animation-timing-function: ease-out;\n  }\n\n  50% {\n    -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);\n    transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) scale3d(.95, .95, .95);\n    transform: perspective(400px) scale3d(.95, .95, .95);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n}\n\n.animated.flip {\n  -webkit-backface-visibility: visible;\n  backface-visibility: visible;\n  -webkit-animation-name: flip;\n  animation-name: flip;\n}\n\n@-webkit-keyframes flipInX {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n  }\n\n  100% {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n}\n\n@keyframes flipInX {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -5deg);\n  }\n\n  100% {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n}\n\n.flipInX {\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipInX;\n  animation-name: flipInX;\n}\n\n@-webkit-keyframes flipInY {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n  }\n\n  100% {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n}\n\n@keyframes flipInY {\n  from {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n    opacity: 0;\n  }\n\n  40% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -20deg);\n    -webkit-animation-timing-function: ease-in;\n    animation-timing-function: ease-in;\n  }\n\n  60% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 10deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -5deg);\n  }\n\n  100% {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n}\n\n.flipInY {\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipInY;\n  animation-name: flipInY;\n}\n\n@-webkit-keyframes flipOutX {\n  from {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n\n  30% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes flipOutX {\n  from {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n\n  30% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, -20deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    transform: perspective(400px) rotate3d(1, 0, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n.flipOutX {\n  -webkit-animation-name: flipOutX;\n  animation-name: flipOutX;\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n}\n\n@-webkit-keyframes flipOutY {\n  from {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n\n  30% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes flipOutY {\n  from {\n    -webkit-transform: perspective(400px);\n    transform: perspective(400px);\n  }\n\n  30% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, -15deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    transform: perspective(400px) rotate3d(0, 1, 0, 90deg);\n    opacity: 0;\n  }\n}\n\n.flipOutY {\n  -webkit-backface-visibility: visible !important;\n  backface-visibility: visible !important;\n  -webkit-animation-name: flipOutY;\n  animation-name: flipOutY;\n}\n\n@-webkit-keyframes lightSpeedIn {\n  from {\n    -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);\n    transform: translate3d(100%, 0, 0) skewX(-30deg);\n    opacity: 0;\n  }\n\n  60% {\n    -webkit-transform: skewX(20deg);\n    transform: skewX(20deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: skewX(-5deg);\n    transform: skewX(-5deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n@keyframes lightSpeedIn {\n  from {\n    -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);\n    transform: translate3d(100%, 0, 0) skewX(-30deg);\n    opacity: 0;\n  }\n\n  60% {\n    -webkit-transform: skewX(20deg);\n    transform: skewX(20deg);\n    opacity: 1;\n  }\n\n  80% {\n    -webkit-transform: skewX(-5deg);\n    transform: skewX(-5deg);\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.lightSpeedIn {\n  -webkit-animation-name: lightSpeedIn;\n  animation-name: lightSpeedIn;\n  -webkit-animation-timing-function: ease-out;\n  animation-timing-function: ease-out;\n}\n\n@-webkit-keyframes lightSpeedOut {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);\n    transform: translate3d(100%, 0, 0) skewX(30deg);\n    opacity: 0;\n  }\n}\n\n@keyframes lightSpeedOut {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);\n    transform: translate3d(100%, 0, 0) skewX(30deg);\n    opacity: 0;\n  }\n}\n\n.lightSpeedOut {\n  -webkit-animation-name: lightSpeedOut;\n  animation-name: lightSpeedOut;\n  -webkit-animation-timing-function: ease-in;\n  animation-timing-function: ease-in;\n}\n\n@-webkit-keyframes rotateIn {\n  from {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: rotate3d(0, 0, 1, -200deg);\n    transform: rotate3d(0, 0, 1, -200deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n@keyframes rotateIn {\n  from {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: rotate3d(0, 0, 1, -200deg);\n    transform: rotate3d(0, 0, 1, -200deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateIn {\n  -webkit-animation-name: rotateIn;\n  animation-name: rotateIn;\n}\n\n@-webkit-keyframes rotateInDownLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInDownLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateInDownLeft {\n  -webkit-animation-name: rotateInDownLeft;\n  animation-name: rotateInDownLeft;\n}\n\n@-webkit-keyframes rotateInDownRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInDownRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateInDownRight {\n  -webkit-animation-name: rotateInDownRight;\n  animation-name: rotateInDownRight;\n}\n\n@-webkit-keyframes rotateInUpLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInUpLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateInUpLeft {\n  -webkit-animation-name: rotateInUpLeft;\n  animation-name: rotateInUpLeft;\n}\n\n@-webkit-keyframes rotateInUpRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -90deg);\n    transform: rotate3d(0, 0, 1, -90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n@keyframes rotateInUpRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -90deg);\n    transform: rotate3d(0, 0, 1, -90deg);\n    opacity: 0;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: none;\n    transform: none;\n    opacity: 1;\n  }\n}\n\n.rotateInUpRight {\n  -webkit-animation-name: rotateInUpRight;\n  animation-name: rotateInUpRight;\n}\n\n@-webkit-keyframes rotateOut {\n  from {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: rotate3d(0, 0, 1, 200deg);\n    transform: rotate3d(0, 0, 1, 200deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOut {\n  from {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: center;\n    transform-origin: center;\n    -webkit-transform: rotate3d(0, 0, 1, 200deg);\n    transform: rotate3d(0, 0, 1, 200deg);\n    opacity: 0;\n  }\n}\n\n.rotateOut {\n  -webkit-animation-name: rotateOut;\n  animation-name: rotateOut;\n}\n\n@-webkit-keyframes rotateOutDownLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutDownLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 45deg);\n    transform: rotate3d(0, 0, 1, 45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutDownLeft {\n  -webkit-animation-name: rotateOutDownLeft;\n  animation-name: rotateOutDownLeft;\n}\n\n@-webkit-keyframes rotateOutDownRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutDownRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutDownRight {\n  -webkit-animation-name: rotateOutDownRight;\n  animation-name: rotateOutDownRight;\n}\n\n@-webkit-keyframes rotateOutUpLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutUpLeft {\n  from {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: left bottom;\n    transform-origin: left bottom;\n    -webkit-transform: rotate3d(0, 0, 1, -45deg);\n    transform: rotate3d(0, 0, 1, -45deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutUpLeft {\n  -webkit-animation-name: rotateOutUpLeft;\n  animation-name: rotateOutUpLeft;\n}\n\n@-webkit-keyframes rotateOutUpRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 90deg);\n    transform: rotate3d(0, 0, 1, 90deg);\n    opacity: 0;\n  }\n}\n\n@keyframes rotateOutUpRight {\n  from {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform-origin: right bottom;\n    transform-origin: right bottom;\n    -webkit-transform: rotate3d(0, 0, 1, 90deg);\n    transform: rotate3d(0, 0, 1, 90deg);\n    opacity: 0;\n  }\n}\n\n.rotateOutUpRight {\n  -webkit-animation-name: rotateOutUpRight;\n  animation-name: rotateOutUpRight;\n}\n\n@-webkit-keyframes hinge {\n  0% {\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  20%, 60% {\n    -webkit-transform: rotate3d(0, 0, 1, 80deg);\n    transform: rotate3d(0, 0, 1, 80deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  40%, 80% {\n    -webkit-transform: rotate3d(0, 0, 1, 60deg);\n    transform: rotate3d(0, 0, 1, 60deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 700px, 0);\n    transform: translate3d(0, 700px, 0);\n    opacity: 0;\n  }\n}\n\n@keyframes hinge {\n  0% {\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  20%, 60% {\n    -webkit-transform: rotate3d(0, 0, 1, 80deg);\n    transform: rotate3d(0, 0, 1, 80deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n  }\n\n  40%, 80% {\n    -webkit-transform: rotate3d(0, 0, 1, 60deg);\n    transform: rotate3d(0, 0, 1, 60deg);\n    -webkit-transform-origin: top left;\n    transform-origin: top left;\n    -webkit-animation-timing-function: ease-in-out;\n    animation-timing-function: ease-in-out;\n    opacity: 1;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 700px, 0);\n    transform: translate3d(0, 700px, 0);\n    opacity: 0;\n  }\n}\n\n.hinge {\n  -webkit-animation-name: hinge;\n  animation-name: hinge;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes rollIn {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n@keyframes rollIn {\n  from {\n    opacity: 0;\n    -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n    transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);\n  }\n\n  100% {\n    opacity: 1;\n    -webkit-transform: none;\n    transform: none;\n  }\n}\n\n.rollIn {\n  -webkit-animation-name: rollIn;\n  animation-name: rollIn;\n}\n\n/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */\n\n@-webkit-keyframes rollOut {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n  }\n}\n\n@keyframes rollOut {\n  from {\n    opacity: 1;\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n    transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);\n  }\n}\n\n.rollOut {\n  -webkit-animation-name: rollOut;\n  animation-name: rollOut;\n}\n\n@-webkit-keyframes zoomIn {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.3, .3, .3);\n    transform: scale3d(.3, .3, .3);\n  }\n\n  50% {\n    opacity: 1;\n  }\n}\n\n@keyframes zoomIn {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.3, .3, .3);\n    transform: scale3d(.3, .3, .3);\n  }\n\n  50% {\n    opacity: 1;\n  }\n}\n\n.zoomIn {\n  -webkit-animation-name: zoomIn;\n  animation-name: zoomIn;\n}\n\n@-webkit-keyframes zoomInDown {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);\n    transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n@keyframes zoomInDown {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);\n    transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomInDown {\n  -webkit-animation-name: zoomInDown;\n  animation-name: zoomInDown;\n}\n\n@-webkit-keyframes zoomInLeft {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);\n    transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);\n    transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n@keyframes zoomInLeft {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);\n    transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);\n    transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomInLeft {\n  -webkit-animation-name: zoomInLeft;\n  animation-name: zoomInLeft;\n}\n\n@-webkit-keyframes zoomInRight {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);\n    transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);\n    transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n@keyframes zoomInRight {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);\n    transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);\n    transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomInRight {\n  -webkit-animation-name: zoomInRight;\n  animation-name: zoomInRight;\n}\n\n@-webkit-keyframes zoomInUp {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);\n    transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n@keyframes zoomInUp {\n  from {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);\n    transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  60% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomInUp {\n  -webkit-animation-name: zoomInUp;\n  animation-name: zoomInUp;\n}\n\n@-webkit-keyframes zoomOut {\n  from {\n    opacity: 1;\n  }\n\n  50% {\n    opacity: 0;\n    -webkit-transform: scale3d(.3, .3, .3);\n    transform: scale3d(.3, .3, .3);\n  }\n\n  100% {\n    opacity: 0;\n  }\n}\n\n@keyframes zoomOut {\n  from {\n    opacity: 1;\n  }\n\n  50% {\n    opacity: 0;\n    -webkit-transform: scale3d(.3, .3, .3);\n    transform: scale3d(.3, .3, .3);\n  }\n\n  100% {\n    opacity: 0;\n  }\n}\n\n.zoomOut {\n  -webkit-animation-name: zoomOut;\n  animation-name: zoomOut;\n}\n\n@-webkit-keyframes zoomOutDown {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);\n    transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n@keyframes zoomOutDown {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);\n    transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomOutDown {\n  -webkit-animation-name: zoomOutDown;\n  animation-name: zoomOutDown;\n}\n\n@-webkit-keyframes zoomOutLeft {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);\n    transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale(.1) translate3d(-2000px, 0, 0);\n    transform: scale(.1) translate3d(-2000px, 0, 0);\n    -webkit-transform-origin: left center;\n    transform-origin: left center;\n  }\n}\n\n@keyframes zoomOutLeft {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);\n    transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale(.1) translate3d(-2000px, 0, 0);\n    transform: scale(.1) translate3d(-2000px, 0, 0);\n    -webkit-transform-origin: left center;\n    transform-origin: left center;\n  }\n}\n\n.zoomOutLeft {\n  -webkit-animation-name: zoomOutLeft;\n  animation-name: zoomOutLeft;\n}\n\n@-webkit-keyframes zoomOutRight {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);\n    transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale(.1) translate3d(2000px, 0, 0);\n    transform: scale(.1) translate3d(2000px, 0, 0);\n    -webkit-transform-origin: right center;\n    transform-origin: right center;\n  }\n}\n\n@keyframes zoomOutRight {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);\n    transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale(.1) translate3d(2000px, 0, 0);\n    transform: scale(.1) translate3d(2000px, 0, 0);\n    -webkit-transform-origin: right center;\n    transform-origin: right center;\n  }\n}\n\n.zoomOutRight {\n  -webkit-animation-name: zoomOutRight;\n  animation-name: zoomOutRight;\n}\n\n@-webkit-keyframes zoomOutUp {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);\n    transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n@keyframes zoomOutUp {\n  40% {\n    opacity: 1;\n    -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);\n    -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n    animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);\n  }\n\n  100% {\n    opacity: 0;\n    -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);\n    transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);\n    -webkit-transform-origin: center bottom;\n    transform-origin: center bottom;\n    -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n    animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);\n  }\n}\n\n.zoomOutUp {\n  -webkit-animation-name: zoomOutUp;\n  animation-name: zoomOutUp;\n}\n\n@-webkit-keyframes slideInDown {\n  from {\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n    visibility: visible;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes slideInDown {\n  from {\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n    visibility: visible;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInDown {\n  -webkit-animation-name: slideInDown;\n  animation-name: slideInDown;\n}\n\n@-webkit-keyframes slideInLeft {\n  from {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    visibility: visible;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes slideInLeft {\n  from {\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n    visibility: visible;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInLeft {\n  -webkit-animation-name: slideInLeft;\n  animation-name: slideInLeft;\n}\n\n@-webkit-keyframes slideInRight {\n  from {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    visibility: visible;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes slideInRight {\n  from {\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n    visibility: visible;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInRight {\n  -webkit-animation-name: slideInRight;\n  animation-name: slideInRight;\n}\n\n@-webkit-keyframes slideInUp {\n  from {\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n    visibility: visible;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n@keyframes slideInUp {\n  from {\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n    visibility: visible;\n  }\n\n  100% {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n}\n\n.slideInUp {\n  -webkit-animation-name: slideInUp;\n  animation-name: slideInUp;\n}\n\n@-webkit-keyframes slideOutDown {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  100% {\n    visibility: hidden;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n@keyframes slideOutDown {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  100% {\n    visibility: hidden;\n    -webkit-transform: translate3d(0, 100%, 0);\n    transform: translate3d(0, 100%, 0);\n  }\n}\n\n.slideOutDown {\n  -webkit-animation-name: slideOutDown;\n  animation-name: slideOutDown;\n}\n\n@-webkit-keyframes slideOutLeft {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  100% {\n    visibility: hidden;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n@keyframes slideOutLeft {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  100% {\n    visibility: hidden;\n    -webkit-transform: translate3d(-100%, 0, 0);\n    transform: translate3d(-100%, 0, 0);\n  }\n}\n\n.slideOutLeft {\n  -webkit-animation-name: slideOutLeft;\n  animation-name: slideOutLeft;\n}\n\n@-webkit-keyframes slideOutRight {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  100% {\n    visibility: hidden;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n@keyframes slideOutRight {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  100% {\n    visibility: hidden;\n    -webkit-transform: translate3d(100%, 0, 0);\n    transform: translate3d(100%, 0, 0);\n  }\n}\n\n.slideOutRight {\n  -webkit-animation-name: slideOutRight;\n  animation-name: slideOutRight;\n}\n\n@-webkit-keyframes slideOutUp {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  100% {\n    visibility: hidden;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n@keyframes slideOutUp {\n  from {\n    -webkit-transform: translate3d(0, 0, 0);\n    transform: translate3d(0, 0, 0);\n  }\n\n  100% {\n    visibility: hidden;\n    -webkit-transform: translate3d(0, -100%, 0);\n    transform: translate3d(0, -100%, 0);\n  }\n}\n\n.slideOutUp {\n  -webkit-animation-name: slideOutUp;\n  animation-name: slideOutUp;\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/autosize/3.0.5/autosize.js",
    "content": "/*!\n\tAutosize 3.0.5\n\tlicense: MIT\n\thttp://www.jacklmoore.com/autosize\n*/\n(function (global, factory) {\n\tif (typeof define === 'function' && define.amd) {\n\t\tdefine(['exports', 'module'], factory);\n\t} else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {\n\t\tfactory(exports, module);\n\t} else {\n\t\tvar mod = {\n\t\t\texports: {}\n\t\t};\n\t\tfactory(mod.exports, mod);\n\t\tglobal.autosize = mod.exports;\n\t}\n})(this, function (exports, module) {\n\t'use strict';\n\n\tfunction assign(ta) {\n\t\tvar _ref = arguments[1] === undefined ? {} : arguments[1];\n\n\t\tvar _ref$setOverflowX = _ref.setOverflowX;\n\t\tvar setOverflowX = _ref$setOverflowX === undefined ? true : _ref$setOverflowX;\n\t\tvar _ref$setOverflowY = _ref.setOverflowY;\n\t\tvar setOverflowY = _ref$setOverflowY === undefined ? true : _ref$setOverflowY;\n\n\t\tif (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || ta.hasAttribute('data-autosize-on')) return;\n\n\t\tvar heightOffset = null;\n\t\tvar overflowY = 'hidden';\n\n\t\tfunction init() {\n\t\t\tvar style = window.getComputedStyle(ta, null);\n\n\t\t\tif (style.resize === 'vertical') {\n\t\t\t\tta.style.resize = 'none';\n\t\t\t} else if (style.resize === 'both') {\n\t\t\t\tta.style.resize = 'horizontal';\n\t\t\t}\n\n\t\t\tif (style.boxSizing === 'content-box') {\n\t\t\t\theightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));\n\t\t\t} else {\n\t\t\t\theightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);\n\t\t\t}\n\n\t\t\tupdate();\n\t\t}\n\n\t\tfunction changeOverflow(value) {\n\t\t\t{\n\t\t\t\t// Chrome/Safari-specific fix:\n\t\t\t\t// When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space\n\t\t\t\t// made available by removing the scrollbar. The following forces the necessary text reflow.\n\t\t\t\tvar width = ta.style.width;\n\t\t\t\tta.style.width = '0px';\n\t\t\t\t// Force reflow:\n\t\t\t\t/* jshint ignore:start */\n\t\t\t\tta.offsetWidth;\n\t\t\t\t/* jshint ignore:end */\n\t\t\t\tta.style.width = width;\n\t\t\t}\n\n\t\t\toverflowY = value;\n\n\t\t\tif (setOverflowY) {\n\t\t\t\tta.style.overflowY = value;\n\t\t\t}\n\n\t\t\tupdate();\n\t\t}\n\n\t\tfunction update() {\n\t\t\tvar startHeight = ta.style.height;\n\t\t\tvar htmlTop = document.documentElement.scrollTop;\n\t\t\tvar bodyTop = document.body.scrollTop;\n\t\t\tvar originalHeight = ta.style.height;\n\n\t\t\tta.style.height = 'auto';\n\n\t\t\tvar endHeight = ta.scrollHeight + heightOffset;\n\n\t\t\tif (ta.scrollHeight === 0) {\n\t\t\t\t// If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.\n\t\t\t\tta.style.height = originalHeight;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tta.style.height = endHeight + 'px';\n\n\t\t\t// prevents scroll-position jumping\n\t\t\tdocument.documentElement.scrollTop = htmlTop;\n\t\t\tdocument.body.scrollTop = bodyTop;\n\n\t\t\tvar style = window.getComputedStyle(ta, null);\n\n\t\t\tif (style.height !== ta.style.height) {\n\t\t\t\tif (overflowY !== 'visible') {\n\t\t\t\t\tchangeOverflow('visible');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (overflowY !== 'hidden') {\n\t\t\t\t\tchangeOverflow('hidden');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (startHeight !== ta.style.height) {\n\t\t\t\tvar evt = document.createEvent('Event');\n\t\t\t\tevt.initEvent('autosize:resized', true, false);\n\t\t\t\tta.dispatchEvent(evt);\n\t\t\t}\n\t\t}\n\n\t\tvar destroy = (function (style) {\n\t\t\twindow.removeEventListener('resize', update);\n\t\t\tta.removeEventListener('input', update);\n\t\t\tta.removeEventListener('keyup', update);\n\t\t\tta.removeAttribute('data-autosize-on');\n\t\t\tta.removeEventListener('autosize:destroy', destroy);\n\n\t\t\tObject.keys(style).forEach(function (key) {\n\t\t\t\tta.style[key] = style[key];\n\t\t\t});\n\t\t}).bind(ta, {\n\t\t\theight: ta.style.height,\n\t\t\tresize: ta.style.resize,\n\t\t\toverflowY: ta.style.overflowY,\n\t\t\toverflowX: ta.style.overflowX,\n\t\t\twordWrap: ta.style.wordWrap });\n\n\t\tta.addEventListener('autosize:destroy', destroy);\n\n\t\t// IE9 does not fire onpropertychange or oninput for deletions,\n\t\t// so binding to onkeyup to catch most of those events.\n\t\t// There is no way that I know of to detect something like 'cut' in IE9.\n\t\tif ('onpropertychange' in ta && 'oninput' in ta) {\n\t\t\tta.addEventListener('keyup', update);\n\t\t}\n\n\t\twindow.addEventListener('resize', update);\n\t\tta.addEventListener('input', update);\n\t\tta.addEventListener('autosize:update', update);\n\t\tta.setAttribute('data-autosize-on', true);\n\n\t\tif (setOverflowY) {\n\t\t\tta.style.overflowY = 'hidden';\n\t\t}\n\t\tif (setOverflowX) {\n\t\t\tta.style.overflowX = 'hidden';\n\t\t\tta.style.wordWrap = 'break-word';\n\t\t}\n\n\t\tinit();\n\t}\n\n\tfunction destroy(ta) {\n\t\tif (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;\n\t\tvar evt = document.createEvent('Event');\n\t\tevt.initEvent('autosize:destroy', true, false);\n\t\tta.dispatchEvent(evt);\n\t}\n\n\tfunction update(ta) {\n\t\tif (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;\n\t\tvar evt = document.createEvent('Event');\n\t\tevt.initEvent('autosize:update', true, false);\n\t\tta.dispatchEvent(evt);\n\t}\n\n\tvar autosize = null;\n\n\t// Do nothing in Node.js environment and IE8 (or lower)\n\tif (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {\n\t\tautosize = function (el) {\n\t\t\treturn el;\n\t\t};\n\t\tautosize.destroy = function (el) {\n\t\t\treturn el;\n\t\t};\n\t\tautosize.update = function (el) {\n\t\t\treturn el;\n\t\t};\n\t} else {\n\t\tautosize = function (el, options) {\n\t\t\tif (el) {\n\t\t\t\tArray.prototype.forEach.call(el.length ? el : [el], function (x) {\n\t\t\t\t\treturn assign(x, options);\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn el;\n\t\t};\n\t\tautosize.destroy = function (el) {\n\t\t\tif (el) {\n\t\t\t\tArray.prototype.forEach.call(el.length ? el : [el], destroy);\n\t\t\t}\n\t\t\treturn el;\n\t\t};\n\t\tautosize.update = function (el) {\n\t\t\tif (el) {\n\t\t\t\tArray.prototype.forEach.call(el.length ? el : [el], update);\n\t\t\t}\n\t\t\treturn el;\n\t\t};\n\t}\n\n\tmodule.exports = autosize;\n});"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap/3.3.6/css/bootstrap-theme.css",
    "content": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 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": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap/3.3.6/css/bootstrap.css",
    "content": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 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: thin dotted;\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: thin dotted;\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: thin dotted;\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": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap/3.3.6/js/bootstrap.js",
    "content": "/*!\n * Bootstrap v3.3.6 (http://getbootstrap.com)\n * Copyright 2011-2015 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] > 2)) {\n    throw new Error('Bootstrap\\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3')\n  }\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: transition.js v3.3.6\n * http://getbootstrap.com/javascript/#transitions\n * ========================================================================\n * Copyright 2011-2015 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.6\n * http://getbootstrap.com/javascript/#alerts\n * ========================================================================\n * Copyright 2011-2015 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.6'\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)\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.6\n * http://getbootstrap.com/javascript/#buttons\n * ========================================================================\n * Copyright 2011-2015 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.6'\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)\n      } else if (this.isLoading) {\n        this.isLoading = false\n        $el.removeClass(d).removeAttr(d)\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)\n      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n      Plugin.call($btn, 'toggle')\n      if (!($(e.target).is('input[type=\"radio\"]') || $(e.target).is('input[type=\"checkbox\"]'))) e.preventDefault()\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.6\n * http://getbootstrap.com/javascript/#carousel\n * ========================================================================\n * Copyright 2011-2015 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.6'\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.6\n * http://getbootstrap.com/javascript/#collapse\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\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.6'\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.6\n * http://getbootstrap.com/javascript/#dropdowns\n * ========================================================================\n * Copyright 2011-2015 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.6'\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.6\n * http://getbootstrap.com/javascript/#modals\n * ========================================================================\n * Copyright 2011-2015 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.6'\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 (this.$element[0] !== e.target && !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.6\n * http://getbootstrap.com/javascript/#tooltip\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ========================================================================\n * Copyright 2011-2015 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.6'\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      that.$element\n        .removeAttr('aria-describedby')\n        .trigger('hidden.bs.' + that.type)\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 elOffset  = isBody ? { top: 0, left: 0 } : $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    })\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.6\n * http://getbootstrap.com/javascript/#popovers\n * ========================================================================\n * Copyright 2011-2015 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.6'\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.6\n * http://getbootstrap.com/javascript/#scrollspy\n * ========================================================================\n * Copyright 2011-2015 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.6'\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.6\n * http://getbootstrap.com/javascript/#tabs\n * ========================================================================\n * Copyright 2011-2015 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.6'\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.6\n * http://getbootstrap.com/javascript/#affix\n * ========================================================================\n * Copyright 2011-2015 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.6'\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": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap/3.3.6/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": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/css/bootstrap-select.css",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n.bootstrap-select {\n  width: 220px \\0;\n  /*IE9 and below*/\n}\n.bootstrap-select > .dropdown-toggle {\n  width: 100%;\n  padding-right: 25px;\n}\n.has-error .bootstrap-select .dropdown-toggle,\n.error .bootstrap-select .dropdown-toggle {\n  border-color: #b94a48;\n}\n.bootstrap-select.fit-width {\n  width: auto !important;\n}\n.bootstrap-select:not([class*=\"col-\"]):not([class*=\"form-control\"]):not(.input-group-btn) {\n  width: 220px;\n}\n.bootstrap-select .dropdown-toggle:focus {\n  outline: thin dotted #333333 !important;\n  outline: 5px auto -webkit-focus-ring-color !important;\n  outline-offset: -2px;\n}\n.bootstrap-select.form-control {\n  margin-bottom: 0;\n  padding: 0;\n  border: none;\n}\n.bootstrap-select.form-control:not([class*=\"col-\"]) {\n  width: 100%;\n}\n.bootstrap-select.form-control.input-group-btn {\n  z-index: auto;\n}\n.bootstrap-select.btn-group:not(.input-group-btn),\n.bootstrap-select.btn-group[class*=\"col-\"] {\n  float: none;\n  display: inline-block;\n  margin-left: 0;\n}\n.bootstrap-select.btn-group.dropdown-menu-right,\n.bootstrap-select.btn-group[class*=\"col-\"].dropdown-menu-right,\n.row .bootstrap-select.btn-group[class*=\"col-\"].dropdown-menu-right {\n  float: right;\n}\n.form-inline .bootstrap-select.btn-group,\n.form-horizontal .bootstrap-select.btn-group,\n.form-group .bootstrap-select.btn-group {\n  margin-bottom: 0;\n}\n.form-group-lg .bootstrap-select.btn-group.form-control,\n.form-group-sm .bootstrap-select.btn-group.form-control {\n  padding: 0;\n}\n.form-inline .bootstrap-select.btn-group .form-control {\n  width: 100%;\n}\n.bootstrap-select.btn-group.disabled,\n.bootstrap-select.btn-group > .disabled {\n  cursor: not-allowed;\n}\n.bootstrap-select.btn-group.disabled:focus,\n.bootstrap-select.btn-group > .disabled:focus {\n  outline: none !important;\n}\n.bootstrap-select.btn-group .dropdown-toggle .filter-option {\n  display: inline-block;\n  overflow: hidden;\n  width: 100%;\n  text-align: left;\n}\n.bootstrap-select.btn-group .dropdown-toggle .caret {\n  position: absolute;\n  top: 50%;\n  right: 12px;\n  margin-top: -2px;\n  vertical-align: middle;\n}\n.bootstrap-select.btn-group[class*=\"col-\"] .dropdown-toggle {\n  width: 100%;\n}\n.bootstrap-select.btn-group .dropdown-menu {\n  min-width: 100%;\n  z-index: 1035;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n.bootstrap-select.btn-group .dropdown-menu.inner {\n  position: static;\n  float: none;\n  border: 0;\n  padding: 0;\n  margin: 0;\n  border-radius: 0;\n  -webkit-box-shadow: none;\n          box-shadow: none;\n}\n.bootstrap-select.btn-group .dropdown-menu li {\n  position: relative;\n}\n.bootstrap-select.btn-group .dropdown-menu li.active small {\n  color: #fff;\n}\n.bootstrap-select.btn-group .dropdown-menu li.disabled a {\n  cursor: not-allowed;\n}\n.bootstrap-select.btn-group .dropdown-menu li a {\n  cursor: pointer;\n}\n.bootstrap-select.btn-group .dropdown-menu li a.opt {\n  position: relative;\n  padding-left: 2.25em;\n}\n.bootstrap-select.btn-group .dropdown-menu li a span.check-mark {\n  display: none;\n}\n.bootstrap-select.btn-group .dropdown-menu li a span.text {\n  display: inline-block;\n}\n.bootstrap-select.btn-group .dropdown-menu li small {\n  padding-left: 0.5em;\n}\n.bootstrap-select.btn-group .dropdown-menu .notify {\n  position: absolute;\n  bottom: 5px;\n  width: 96%;\n  margin: 0 2%;\n  min-height: 26px;\n  padding: 3px 5px;\n  background: #f5f5f5;\n  border: 1px solid #e3e3e3;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n          box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n  pointer-events: none;\n  opacity: 0.9;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n.bootstrap-select.btn-group .no-results {\n  padding: 3px;\n  background: #f5f5f5;\n  margin: 0 5px;\n  white-space: nowrap;\n}\n.bootstrap-select.btn-group.fit-width .dropdown-toggle .filter-option {\n  position: static;\n}\n.bootstrap-select.btn-group.fit-width .dropdown-toggle .caret {\n  position: static;\n  top: auto;\n  margin-top: -1px;\n}\n.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark {\n  position: absolute;\n  display: inline-block;\n  right: 15px;\n  margin-top: 5px;\n}\n.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {\n  margin-right: 34px;\n}\n.bootstrap-select.show-menu-arrow.open > .dropdown-toggle {\n  z-index: 1036;\n}\n.bootstrap-select.show-menu-arrow .dropdown-toggle:before {\n  content: '';\n  border-left: 7px solid transparent;\n  border-right: 7px solid transparent;\n  border-bottom: 7px solid rgba(204, 204, 204, 0.2);\n  position: absolute;\n  bottom: -4px;\n  left: 9px;\n  display: none;\n}\n.bootstrap-select.show-menu-arrow .dropdown-toggle:after {\n  content: '';\n  border-left: 6px solid transparent;\n  border-right: 6px solid transparent;\n  border-bottom: 6px solid white;\n  position: absolute;\n  bottom: -4px;\n  left: 10px;\n  display: none;\n}\n.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before {\n  bottom: auto;\n  top: -3px;\n  border-top: 7px solid rgba(204, 204, 204, 0.2);\n  border-bottom: 0;\n}\n.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after {\n  bottom: auto;\n  top: -3px;\n  border-top: 6px solid white;\n  border-bottom: 0;\n}\n.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before {\n  right: 12px;\n  left: auto;\n}\n.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after {\n  right: 13px;\n  left: auto;\n}\n.bootstrap-select.show-menu-arrow.open > .dropdown-toggle:before,\n.bootstrap-select.show-menu-arrow.open > .dropdown-toggle:after {\n  display: block;\n}\n.bs-searchbox,\n.bs-actionsbox,\n.bs-donebutton {\n  padding: 4px 8px;\n}\n.bs-actionsbox {\n  float: left;\n  width: 100%;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n.bs-actionsbox .btn-group button {\n  width: 50%;\n}\n.bs-donebutton {\n  float: left;\n  width: 100%;\n  -webkit-box-sizing: border-box;\n     -moz-box-sizing: border-box;\n          box-sizing: border-box;\n}\n.bs-donebutton .btn-group button {\n  width: 100%;\n}\n.bs-searchbox + .bs-actionsbox {\n  padding: 0 8px 4px;\n}\n.bs-searchbox .form-control {\n  margin-bottom: 0;\n  width: 100%;\n}\nselect.bs-select-hidden,\nselect.selectpicker {\n  display: none !important;\n}\nselect.mobile-device {\n  position: absolute !important;\n  top: 0;\n  left: 0;\n  display: block !important;\n  width: 100%;\n  height: 100% !important;\n  opacity: 0;\n}\n/*# sourceMappingURL=bootstrap-select.css.map */"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/bootstrap-select.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  'use strict';\n\n  //<editor-fold desc=\"Shims\">\n  if (!String.prototype.includes) {\n    (function () {\n      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`\n      var toString = {}.toString;\n      var defineProperty = (function () {\n        // IE 8 only supports `Object.defineProperty` on DOM elements\n        try {\n          var object = {};\n          var $defineProperty = Object.defineProperty;\n          var result = $defineProperty(object, object, object) && $defineProperty;\n        } catch (error) {\n        }\n        return result;\n      }());\n      var indexOf = ''.indexOf;\n      var includes = function (search) {\n        if (this == null) {\n          throw TypeError();\n        }\n        var string = String(this);\n        if (search && toString.call(search) == '[object RegExp]') {\n          throw TypeError();\n        }\n        var stringLength = string.length;\n        var searchString = String(search);\n        var searchLength = searchString.length;\n        var position = arguments.length > 1 ? arguments[1] : undefined;\n        // `ToInteger`\n        var pos = position ? Number(position) : 0;\n        if (pos != pos) { // better `isNaN`\n          pos = 0;\n        }\n        var start = Math.min(Math.max(pos, 0), stringLength);\n        // Avoid the `indexOf` call if no match is possible\n        if (searchLength + start > stringLength) {\n          return false;\n        }\n        return indexOf.call(string, searchString, pos) != -1;\n      };\n      if (defineProperty) {\n        defineProperty(String.prototype, 'includes', {\n          'value': includes,\n          'configurable': true,\n          'writable': true\n        });\n      } else {\n        String.prototype.includes = includes;\n      }\n    }());\n  }\n\n  if (!String.prototype.startsWith) {\n    (function () {\n      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`\n      var defineProperty = (function () {\n        // IE 8 only supports `Object.defineProperty` on DOM elements\n        try {\n          var object = {};\n          var $defineProperty = Object.defineProperty;\n          var result = $defineProperty(object, object, object) && $defineProperty;\n        } catch (error) {\n        }\n        return result;\n      }());\n      var toString = {}.toString;\n      var startsWith = function (search) {\n        if (this == null) {\n          throw TypeError();\n        }\n        var string = String(this);\n        if (search && toString.call(search) == '[object RegExp]') {\n          throw TypeError();\n        }\n        var stringLength = string.length;\n        var searchString = String(search);\n        var searchLength = searchString.length;\n        var position = arguments.length > 1 ? arguments[1] : undefined;\n        // `ToInteger`\n        var pos = position ? Number(position) : 0;\n        if (pos != pos) { // better `isNaN`\n          pos = 0;\n        }\n        var start = Math.min(Math.max(pos, 0), stringLength);\n        // Avoid the `indexOf` call if no match is possible\n        if (searchLength + start > stringLength) {\n          return false;\n        }\n        var index = -1;\n        while (++index < searchLength) {\n          if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {\n            return false;\n          }\n        }\n        return true;\n      };\n      if (defineProperty) {\n        defineProperty(String.prototype, 'startsWith', {\n          'value': startsWith,\n          'configurable': true,\n          'writable': true\n        });\n      } else {\n        String.prototype.startsWith = startsWith;\n      }\n    }());\n  }\n\n  if (!Object.keys) {\n    Object.keys = function (\n      o, // object\n      k, // key\n      r  // result array\n      ){\n      // initialize object and result\n      r=[];\n      // iterate over object keys\n      for (k in o) \n          // fill result array with non-prototypical keys\n        r.hasOwnProperty.call(o, k) && r.push(k);\n      // return result\n      return r\n    };\n  }\n  //</editor-fold>\n\n  // Case insensitive contains search\n  $.expr[':'].icontains = function (obj, index, meta) {\n    var $obj = $(obj);\n    var haystack = ($obj.data('tokens') || $obj.text()).toUpperCase();\n    return haystack.includes(meta[3].toUpperCase());\n  };\n\n  // Case insensitive begins search\n  $.expr[':'].ibegins = function (obj, index, meta) {\n    var $obj = $(obj);\n    var haystack = ($obj.data('tokens') || $obj.text()).toUpperCase();\n    return haystack.startsWith(meta[3].toUpperCase());\n  };\n\n  // Case and accent insensitive contains search\n  $.expr[':'].aicontains = function (obj, index, meta) {\n    var $obj = $(obj);\n    var haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toUpperCase();\n    return haystack.includes(meta[3].toUpperCase());\n  };\n\n  // Case and accent insensitive begins search\n  $.expr[':'].aibegins = function (obj, index, meta) {\n    var $obj = $(obj);\n    var haystack = ($obj.data('tokens') || $obj.data('normalizedText') || $obj.text()).toUpperCase();\n    return haystack.startsWith(meta[3].toUpperCase());\n  };\n\n  /**\n   * Remove all diatrics from the given text.\n   * @access private\n   * @param {String} text\n   * @returns {String}\n   */\n  function normalizeToBase(text) {\n    var rExps = [\n      {re: /[\\xC0-\\xC6]/g, ch: \"A\"},\n      {re: /[\\xE0-\\xE6]/g, ch: \"a\"},\n      {re: /[\\xC8-\\xCB]/g, ch: \"E\"},\n      {re: /[\\xE8-\\xEB]/g, ch: \"e\"},\n      {re: /[\\xCC-\\xCF]/g, ch: \"I\"},\n      {re: /[\\xEC-\\xEF]/g, ch: \"i\"},\n      {re: /[\\xD2-\\xD6]/g, ch: \"O\"},\n      {re: /[\\xF2-\\xF6]/g, ch: \"o\"},\n      {re: /[\\xD9-\\xDC]/g, ch: \"U\"},\n      {re: /[\\xF9-\\xFC]/g, ch: \"u\"},\n      {re: /[\\xC7-\\xE7]/g, ch: \"c\"},\n      {re: /[\\xD1]/g, ch: \"N\"},\n      {re: /[\\xF1]/g, ch: \"n\"}\n    ];\n    $.each(rExps, function () {\n      text = text.replace(this.re, this.ch);\n    });\n    return text;\n  }\n\n\n  function htmlEscape(html) {\n    var escapeMap = {\n      '&': '&amp;',\n      '<': '&lt;',\n      '>': '&gt;',\n      '\"': '&quot;',\n      \"'\": '&#x27;',\n      '`': '&#x60;'\n    };\n    var source = '(?:' + Object.keys(escapeMap).join('|') + ')',\n        testRegexp = new RegExp(source),\n        replaceRegexp = new RegExp(source, 'g'),\n        string = html == null ? '' : '' + html;\n    return testRegexp.test(string) ? string.replace(replaceRegexp, function (match) {\n      return escapeMap[match];\n    }) : string;\n  }\n\n  var Selectpicker = function (element, options, e) {\n    if (e) {\n      e.stopPropagation();\n      e.preventDefault();\n    }\n\n    this.$element = $(element);\n    this.$newElement = null;\n    this.$button = null;\n    this.$menu = null;\n    this.$lis = null;\n    this.options = options;\n\n    // If we have no title yet, try to pull it from the html title attribute (jQuery doesnt' pick it up as it's not a\n    // data-attribute)\n    if (this.options.title === null) {\n      this.options.title = this.$element.attr('title');\n    }\n\n    //Expose public methods\n    this.val = Selectpicker.prototype.val;\n    this.render = Selectpicker.prototype.render;\n    this.refresh = Selectpicker.prototype.refresh;\n    this.setStyle = Selectpicker.prototype.setStyle;\n    this.selectAll = Selectpicker.prototype.selectAll;\n    this.deselectAll = Selectpicker.prototype.deselectAll;\n    this.destroy = Selectpicker.prototype.remove;\n    this.remove = Selectpicker.prototype.remove;\n    this.show = Selectpicker.prototype.show;\n    this.hide = Selectpicker.prototype.hide;\n\n    this.init();\n  };\n\n  Selectpicker.VERSION = '1.7.2';\n\n  // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.\n  Selectpicker.DEFAULTS = {\n    noneSelectedText: 'Nothing selected',\n    noneResultsText: 'No results matched {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      return (numSelected == 1) ? \"{0} item selected\" : \"{0} items selected\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',\n        (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'\n      ];\n    },\n    selectAllText: 'Select All',\n    deselectAllText: 'Deselect All',\n    doneButton: false,\n    doneButtonText: 'Close',\n    multipleSeparator: ', ',\n    styleBase: 'btn',\n    style: 'btn-default',\n    size: 'auto',\n    title: null,\n    selectedTextFormat: 'values',\n    width: false,\n    container: false,\n    hideDisabled: false,\n    showSubtext: false,\n    showIcon: true,\n    showContent: true,\n    dropupAuto: true,\n    header: false,\n    liveSearch: false,\n    liveSearchPlaceholder: null,\n    liveSearchNormalize: false,\n    liveSearchStyle: 'contains',\n    actionsBox: false,\n    iconBase: 'glyphicon',\n    tickIcon: 'glyphicon-ok',\n    maxOptions: false,\n    mobile: false,\n    selectOnTab: false,\n    dropdownAlignRight: false\n  };\n\n  Selectpicker.prototype = {\n\n    constructor: Selectpicker,\n\n    init: function () {\n      var that = this,\n          id = this.$element.attr('id');\n\n      this.$element.addClass('bs-select-hidden');\n      // store originalIndex (key) and newIndex (value) in this.liObj for fast accessibility\n      // allows us to do this.$lis.eq(that.liObj[index]) instead of this.$lis.filter('[data-original-index=\"' + index + '\"]')\n      this.liObj = {};\n      this.multiple = this.$element.prop('multiple');\n      this.autofocus = this.$element.prop('autofocus');\n      this.$newElement = this.createView();\n      this.$element.after(this.$newElement);\n      this.$button = this.$newElement.children('button');\n      this.$menu = this.$newElement.children('.dropdown-menu');\n      this.$menuInner = this.$menu.children('.inner');\n      this.$searchbox = this.$menu.find('input');\n\n      if (this.options.dropdownAlignRight)\n        this.$menu.addClass('dropdown-menu-right');\n\n      if (typeof id !== 'undefined') {\n        this.$button.attr('data-id', id);\n        $('label[for=\"' + id + '\"]').click(function (e) {\n          e.preventDefault();\n          that.$button.focus();\n        });\n      }\n\n      this.checkDisabled();\n      this.clickListener();\n      if (this.options.liveSearch) this.liveSearchListener();\n      this.render();\n      this.setStyle();\n      this.setWidth();\n      if (this.options.container) this.selectPosition();\n      this.$menu.data('this', this);\n      this.$newElement.data('this', this);\n      if (this.options.mobile) this.mobile();\n\n      this.$newElement.on('hide.bs.dropdown', function (e) {\n        that.$element.trigger('hide.bs.select', e);\n      });\n      \n      this.$newElement.on('hidden.bs.dropdown', function (e) {\n        that.$element.trigger('hidden.bs.select', e);\n      });\n      \n      this.$newElement.on('show.bs.dropdown', function (e) {\n        that.$element.trigger('show.bs.select', e);\n      });\n      \n      this.$newElement.on('shown.bs.dropdown', function (e) {\n        that.$element.trigger('shown.bs.select', e);\n      });\n\n      setTimeout(function () {\n        that.$element.trigger('loaded.bs.select');\n      });\n    },\n\n    createDropdown: function () {\n      // Options\n      // If we are multiple, then add the show-tick class by default\n      var multiple = this.multiple ? ' show-tick' : '',\n          inputGroup = this.$element.parent().hasClass('input-group') ? ' input-group-btn' : '',\n          autofocus = this.autofocus ? ' autofocus' : '';\n      // Elements\n      var header = this.options.header ? '<div class=\"popover-title\"><button type=\"button\" class=\"close\" aria-hidden=\"true\">&times;</button>' + this.options.header + '</div>' : '';\n      var searchbox = this.options.liveSearch ?\n      '<div class=\"bs-searchbox\">' +\n      '<input type=\"text\" class=\"form-control\" autocomplete=\"off\"' +\n      (null === this.options.liveSearchPlaceholder ? '' : ' placeholder=\"' + htmlEscape(this.options.liveSearchPlaceholder) + '\"') + '>' +\n      '</div>'\n          : '';\n      var actionsbox = this.multiple && this.options.actionsBox ?\n      '<div class=\"bs-actionsbox\">' +\n      '<div class=\"btn-group btn-group-sm btn-block\">' +\n      '<button type=\"button\" class=\"actions-btn bs-select-all btn btn-default\">' +\n      this.options.selectAllText +\n      '</button>' +\n      '<button type=\"button\" class=\"actions-btn bs-deselect-all btn btn-default\">' +\n      this.options.deselectAllText +\n      '</button>' +\n      '</div>' +\n      '</div>'\n          : '';\n      var donebutton = this.multiple && this.options.doneButton ?\n      '<div class=\"bs-donebutton\">' +\n      '<div class=\"btn-group btn-block\">' +\n      '<button type=\"button\" class=\"btn btn-sm btn-default\">' +\n      this.options.doneButtonText +\n      '</button>' +\n      '</div>' +\n      '</div>'\n          : '';\n      var drop =\n          '<div class=\"btn-group bootstrap-select' + multiple + inputGroup + '\">' +\n          '<button type=\"button\" class=\"' + this.options.styleBase + ' dropdown-toggle\" data-toggle=\"dropdown\"' + autofocus + '>' +\n          '<span class=\"filter-option pull-left\"></span>&nbsp;' +\n          '<span class=\"caret\"></span>' +\n          '</button>' +\n          '<div class=\"dropdown-menu open\">' +\n          header +\n          searchbox +\n          actionsbox +\n          '<ul class=\"dropdown-menu inner\" role=\"menu\">' +\n          '</ul>' +\n          donebutton +\n          '</div>' +\n          '</div>';\n\n      return $(drop);\n    },\n\n    createView: function () {\n      var $drop = this.createDropdown(),\n          li = this.createLi();\n\n      $drop.find('ul')[0].innerHTML = li;\n      return $drop;\n    },\n\n    reloadLi: function () {\n      //Remove all children.\n      this.destroyLi();\n      //Re build\n      var li = this.createLi();\n      this.$menuInner[0].innerHTML = li;\n    },\n\n    destroyLi: function () {\n      this.$menu.find('li').remove();\n    },\n\n    createLi: function () {\n      var that = this,\n          _li = [],\n          optID = 0,\n          titleOption = document.createElement('option'),\n          liIndex = -1; // increment liIndex whenever a new <li> element is created to ensure liObj is correct\n\n      // Helper functions\n      /**\n       * @param content\n       * @param [index]\n       * @param [classes]\n       * @param [optgroup]\n       * @returns {string}\n       */\n      var generateLI = function (content, index, classes, optgroup) {\n        return '<li' +\n            ((typeof classes !== 'undefined' & '' !== classes) ? ' class=\"' + classes + '\"' : '') +\n            ((typeof index !== 'undefined' & null !== index) ? ' data-original-index=\"' + index + '\"' : '') +\n            ((typeof optgroup !== 'undefined' & null !== optgroup) ? 'data-optgroup=\"' + optgroup + '\"' : '') +\n            '>' + content + '</li>';\n      };\n\n      /**\n       * @param text\n       * @param [classes]\n       * @param [inline]\n       * @param [tokens]\n       * @returns {string}\n       */\n      var generateA = function (text, classes, inline, tokens) {\n        return '<a tabindex=\"0\"' +\n            (typeof classes !== 'undefined' ? ' class=\"' + classes + '\"' : '') +\n            (typeof inline !== 'undefined' ? ' style=\"' + inline + '\"' : '') +\n            (that.options.liveSearchNormalize ? ' data-normalized-text=\"' + normalizeToBase(htmlEscape(text)) + '\"' : '') +\n            (typeof tokens !== 'undefined' || tokens !== null ? ' data-tokens=\"' + tokens + '\"' : '') +\n            '>' + text +\n            '<span class=\"' + that.options.iconBase + ' ' + that.options.tickIcon + ' check-mark\"></span>' +\n            '</a>';\n      };\n\n      if (this.options.title && !this.multiple) {\n        // this option doesn't create a new <li> element, but does add a new option, so liIndex is decreased\n        // since liObj is recalculated on every refresh, liIndex needs to be decreased even if the titleOption is already appended\n        liIndex--;\n\n        if (!this.$element.find('.bs-title-option').length) {\n          // Use native JS to prepend option (faster)\n          var element = this.$element[0];\n          titleOption.className = 'bs-title-option';\n          titleOption.appendChild(document.createTextNode(this.options.title));\n          titleOption.value = '';\n          element.insertBefore(titleOption, element.firstChild);\n          // Check if selected attribute is already set on an option. If not, select the titleOption option.\n          if (element.options[element.selectedIndex].getAttribute('selected') === null) titleOption.selected = true;\n        }\n      }\n\n      this.$element.find('option').each(function (index) {\n        var $this = $(this);\n\n        liIndex++;\n\n        if ($this.hasClass('bs-title-option')) return;\n\n        // Get the class and text for the option\n        var optionClass = this.className || '',\n            inline = this.style.cssText,\n            text = $this.data('content') ? $this.data('content') : $this.html(),\n            tokens = $this.data('tokens') ? $this.data('tokens') : null,\n            subtext = typeof $this.data('subtext') !== 'undefined' ? '<small class=\"text-muted\">' + $this.data('subtext') + '</small>' : '',\n            icon = typeof $this.data('icon') !== 'undefined' ? '<span class=\"' + that.options.iconBase + ' ' + $this.data('icon') + '\"></span> ' : '',\n            isDisabled = this.disabled || this.parentElement.tagName === 'OPTGROUP' && this.parentElement.disabled;\n\n        if (icon !== '' && isDisabled) {\n          icon = '<span>' + icon + '</span>';\n        }\n\n        if (that.options.hideDisabled && isDisabled) {\n          liIndex--;\n          return;\n        }\n\n        if (!$this.data('content')) {\n          // Prepend any icon and append any subtext to the main text.\n          text = icon + '<span class=\"text\">' + text + subtext + '</span>';\n        }\n\n        if (this.parentElement.tagName === 'OPTGROUP' && $this.data('divider') !== true) {\n          if ($this.index() === 0) { // Is it the first option of the optgroup?\n            optID += 1;\n\n            // Get the opt group label\n            var label = this.parentElement.label,\n                labelSubtext = typeof $this.parent().data('subtext') !== 'undefined' ? '<small class=\"text-muted\">' + $this.parent().data('subtext') + '</small>' : '',\n                labelIcon = $this.parent().data('icon') ? '<span class=\"' + that.options.iconBase + ' ' + $this.parent().data('icon') + '\"></span> ' : '',\n                optGroupClass = ' ' + this.parentElement.className || '';\n            \n            label = labelIcon + '<span class=\"text\">' + label + labelSubtext + '</span>';\n\n            if (index !== 0 && _li.length > 0) { // Is it NOT the first option of the select && are there elements in the dropdown?\n              liIndex++;\n              _li.push(generateLI('', null, 'divider', optID + 'div'));\n            }\n            liIndex++;\n            _li.push(generateLI(label, null, 'dropdown-header' + optGroupClass, optID));\n          }\n          _li.push(generateLI(generateA(text, 'opt ' + optionClass + optGroupClass, inline, tokens), index, '', optID));\n        } else if ($this.data('divider') === true) {\n          _li.push(generateLI('', index, 'divider'));\n        } else if ($this.data('hidden') === true) {\n          _li.push(generateLI(generateA(text, optionClass, inline, tokens), index, 'hidden is-hidden'));\n        } else {\n          if (this.previousElementSibling && this.previousElementSibling.tagName === 'OPTGROUP') {\n            liIndex++;\n            _li.push(generateLI('', null, 'divider', optID + 'div'));\n          }\n          _li.push(generateLI(generateA(text, optionClass, inline, tokens), index));\n        }\n\n        that.liObj[index] = liIndex;\n      });\n\n      //If we are not multiple, we don't have a selected item, and we don't have a title, select the first element so something is set in the button\n      if (!this.multiple && this.$element.find('option:selected').length === 0 && !this.options.title) {\n        this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');\n      }\n\n      return _li.join('');\n    },\n\n    findLis: function () {\n      if (this.$lis == null) this.$lis = this.$menu.find('li');\n      return this.$lis;\n    },\n\n    /**\n     * @param [updateLi] defaults to true\n     */\n    render: function (updateLi) {\n      var that = this,\n          notDisabled;\n\n      //Update the LI to match the SELECT\n      if (updateLi !== false) {\n        this.$element.find('option').each(function (index) {\n          var $lis = that.findLis().eq(that.liObj[index]);\n\n          that.setDisabled(index, this.disabled || this.parentElement.tagName === 'OPTGROUP' && this.parentElement.disabled, $lis);\n          that.setSelected(index, this.selected, $lis);\n        });\n      }\n\n      this.tabIndex();\n\n      var selectedItems = this.$element.find('option').map(function () {\n        if (this.selected) {\n          if (that.options.hideDisabled && (this.disabled || this.parentElement.tagName === 'OPTGROUP' && this.parentElement.disabled)) return false;\n\n          var $this = $(this),\n              icon = $this.data('icon') && that.options.showIcon ? '<i class=\"' + that.options.iconBase + ' ' + $this.data('icon') + '\"></i> ' : '',\n              subtext;\n\n          if (that.options.showSubtext && $this.data('subtext') && !that.multiple) {\n            subtext = ' <small class=\"text-muted\">' + $this.data('subtext') + '</small>';\n          } else {\n            subtext = '';\n          }\n          if (typeof $this.attr('title') !== 'undefined') {\n            return $this.attr('title');\n          } else if ($this.data('content') && that.options.showContent) {\n            return $this.data('content');\n          } else {\n            return icon + $this.html() + subtext;\n          }\n        }\n      }).toArray();\n\n      //Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled\n      //Convert all the values into a comma delimited string\n      var title = !this.multiple ? selectedItems[0] : selectedItems.join(this.options.multipleSeparator);\n\n      //If this is multi select, and the selectText type is count, the show 1 of 2 selected etc..\n      if (this.multiple && this.options.selectedTextFormat.indexOf('count') > -1) {\n        var max = this.options.selectedTextFormat.split('>');\n        if ((max.length > 1 && selectedItems.length > max[1]) || (max.length == 1 && selectedItems.length >= 2)) {\n          notDisabled = this.options.hideDisabled ? ', [disabled]' : '';\n          var totalCount = this.$element.find('option').not('[data-divider=\"true\"], [data-hidden=\"true\"]' + notDisabled).length,\n              tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedItems.length, totalCount) : this.options.countSelectedText;\n          title = tr8nText.replace('{0}', selectedItems.length.toString()).replace('{1}', totalCount.toString());\n        }\n      }\n\n      if (this.options.title == undefined) {\n        this.options.title = this.$element.attr('title');\n      }\n\n      if (this.options.selectedTextFormat == 'static') {\n        title = this.options.title;\n      }\n\n      //If we dont have a title, then use the default, or if nothing is set at all, use the not selected text\n      if (!title) {\n        title = typeof this.options.title !== 'undefined' ? this.options.title : this.options.noneSelectedText;\n      }\n\n      //strip all html-tags and trim the result\n      this.$button.attr('title', $.trim(title.replace(/<[^>]*>?/g, '')));\n      this.$button.children('.filter-option').html(title);\n\n      this.$element.trigger('rendered.bs.select');\n    },\n\n    /**\n     * @param [style]\n     * @param [status]\n     */\n    setStyle: function (style, status) {\n      if (this.$element.attr('class')) {\n        this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\\[.*\\]/gi, ''));\n      }\n\n      var buttonClass = style ? style : this.options.style;\n\n      if (status == 'add') {\n        this.$button.addClass(buttonClass);\n      } else if (status == 'remove') {\n        this.$button.removeClass(buttonClass);\n      } else {\n        this.$button.removeClass(this.options.style);\n        this.$button.addClass(buttonClass);\n      }\n    },\n\n    liHeight: function (refresh) {\n      if (!refresh && (this.options.size === false || this.sizeInfo)) return;\n\n      var newElement = document.createElement('div'),\n          menu = document.createElement('div'),\n          menuInner = document.createElement('ul'),\n          divider = document.createElement('li'),\n          li = document.createElement('li'),\n          a = document.createElement('a'),\n          text = document.createElement('span'),\n          header = this.options.header ? this.$menu.find('.popover-title')[0].cloneNode(true) : null,\n          search = this.options.liveSearch ? document.createElement('div') : null,\n          actions = this.options.actionsBox && this.multiple ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,\n          doneButton = this.options.doneButton && this.multiple ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null;\n\n      text.className = 'text';\n      newElement.className = this.$menu[0].parentNode.className + ' open';\n      menu.className = 'dropdown-menu open';\n      menuInner.className = 'dropdown-menu inner';\n      divider.className = 'divider';\n\n      text.appendChild(document.createTextNode('Inner text'));\n      a.appendChild(text);\n      li.appendChild(a);\n      menuInner.appendChild(li);\n      menuInner.appendChild(divider);\n      if (header) menu.appendChild(header);\n      if (search) {\n        // create a span instead of input as creating an input element is slower\n        var input = document.createElement('span');\n        search.className = 'bs-searchbox';\n        input.className = 'form-control';\n        search.appendChild(input);\n        menu.appendChild(search);\n      }\n      if (actions) menu.appendChild(actions);\n      menu.appendChild(menuInner);\n      if (doneButton) menu.appendChild(doneButton);\n      newElement.appendChild(menu);\n\n      document.body.appendChild(newElement);\n\n      var liHeight = a.offsetHeight,\n          headerHeight = header ? header.offsetHeight : 0,\n          searchHeight = search ? search.offsetHeight : 0,\n          actionsHeight = actions ? actions.offsetHeight : 0,\n          doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,\n          dividerHeight = $(divider).outerHeight(true),\n          // fall back to jQuery if getComputedStyle is not supported\n          menuStyle = getComputedStyle ? getComputedStyle(menu) : false,\n          $menu = menuStyle ? $(menu) : null,\n          menuPadding = parseInt(menuStyle ? menuStyle.paddingTop : $menu.css('paddingTop')) +\n                        parseInt(menuStyle ? menuStyle.paddingBottom : $menu.css('paddingBottom')) +\n                        parseInt(menuStyle ? menuStyle.borderTopWidth : $menu.css('borderTopWidth')) +\n                        parseInt(menuStyle ? menuStyle.borderBottomWidth : $menu.css('borderBottomWidth')),\n          menuExtras =  menuPadding + \n                        parseInt(menuStyle ? menuStyle.marginTop : $menu.css('marginTop')) + \n                        parseInt(menuStyle ? menuStyle.marginBottom : $menu.css('marginBottom')) + 2;\n\n      document.body.removeChild(newElement);\n\n      this.sizeInfo = {\n        liHeight: liHeight,\n        headerHeight: headerHeight,\n        searchHeight: searchHeight,\n        actionsHeight: actionsHeight,\n        doneButtonHeight: doneButtonHeight,\n        dividerHeight: dividerHeight,\n        menuPadding: menuPadding,\n        menuExtras: menuExtras\n      };\n    },\n\n    setSize: function () {\n      this.findLis();\n      this.liHeight();\n      var that = this,\n          $menu = this.$menu,\n          $menuInner = this.$menuInner,\n          $window = $(window),\n          selectHeight = this.$newElement[0].offsetHeight,\n          liHeight = this.sizeInfo['liHeight'],\n          headerHeight = this.sizeInfo['headerHeight'],\n          searchHeight = this.sizeInfo['searchHeight'],\n          actionsHeight = this.sizeInfo['actionsHeight'],\n          doneButtonHeight = this.sizeInfo['doneButtonHeight'],\n          divHeight = this.sizeInfo['dividerHeight'],\n          menuPadding = this.sizeInfo['menuPadding'],\n          menuExtras = this.sizeInfo['menuExtras'],\n          notDisabled = this.options.hideDisabled ? '.disabled' : '',\n          menuHeight,\n          getHeight,\n          selectOffsetTop,\n          selectOffsetBot,\n          posVert = function () {\n            selectOffsetTop = that.$newElement.offset().top - $window.scrollTop();\n            selectOffsetBot = $window.height() - selectOffsetTop - selectHeight;\n          };\n\n      posVert();\n\n      if (this.options.header) $menu.css('padding-top', 0);\n\n      if (this.options.size === 'auto') {\n        var getSize = function () {\n          var minHeight,\n              hasClass = function (className, include) {\n                return function (element) {\n                    if (include) {\n                        return (element.classList ? element.classList.contains(className) : $(element).hasClass(className));\n                    } else {\n                        return !(element.classList ? element.classList.contains(className) : $(element).hasClass(className));\n                    }\n                };\n              },\n              lis = that.$menuInner[0].getElementsByTagName('li'),\n              lisVisible = Array.prototype.filter ? Array.prototype.filter.call(lis, hasClass('hidden', false)) : that.$lis.not('.hidden'),\n              optGroup = Array.prototype.filter ? Array.prototype.filter.call(lisVisible, hasClass('dropdown-header', true)) : lisVisible.filter('.dropdown-header');\n\n          posVert();\n          menuHeight = selectOffsetBot - menuExtras;\n\n          if (that.options.container) {\n            if (!$menu.data('height')) $menu.data('height', $menu.height());\n            getHeight = $menu.data('height');\n          } else {\n            getHeight = $menu.height();\n          }\n\n          if (that.options.dropupAuto) {\n            that.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras) < getHeight);\n          }\n          if (that.$newElement.hasClass('dropup')) {\n            menuHeight = selectOffsetTop - menuExtras;\n          }\n\n          if ((lisVisible.length + optGroup.length) > 3) {\n            minHeight = liHeight * 3 + menuExtras - 2;\n          } else {\n            minHeight = 0;\n          }\n\n          $menu.css({\n            'max-height': menuHeight + 'px',\n            'overflow': 'hidden',\n            'min-height': minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px'\n          });\n          $menuInner.css({\n            'max-height': menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding + 'px',\n            'overflow-y': 'auto',\n            'min-height': Math.max(minHeight - menuPadding, 0) + 'px'\n          });\n        };\n        getSize();\n        this.$searchbox.off('input.getSize propertychange.getSize').on('input.getSize propertychange.getSize', getSize);\n        $window.off('resize.getSize scroll.getSize').on('resize.getSize scroll.getSize', getSize);\n      } else if (this.options.size && this.options.size != 'auto' && this.$lis.not(notDisabled).length > this.options.size) {\n        var optIndex = this.$lis.not('.divider').not(notDisabled).children().slice(0, this.options.size).last().parent().index(),\n            divLength = this.$lis.slice(0, optIndex + 1).filter('.divider').length;\n        menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding;\n\n        if (that.options.container) {\n          if (!$menu.data('height')) $menu.data('height', $menu.height());\n          getHeight = $menu.data('height');\n        } else {\n          getHeight = $menu.height();\n        }\n\n        if (that.options.dropupAuto) {\n          //noinspection JSUnusedAssignment\n          this.$newElement.toggleClass('dropup', selectOffsetTop > selectOffsetBot && (menuHeight - menuExtras) < getHeight);\n        }\n        $menu.css({\n          'max-height': menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight + 'px',\n          'overflow': 'hidden',\n          'min-height': ''\n        });\n        $menuInner.css({\n          'max-height': menuHeight - menuPadding + 'px',\n          'overflow-y': 'auto',\n          'min-height': ''\n        });\n      }\n    },\n\n    setWidth: function () {\n      if (this.options.width === 'auto') {\n        this.$menu.css('min-width', '0');\n\n        // Get correct width if element is hidden\n        var $selectClone = this.$menu.parent().clone().appendTo('body'),\n            $selectClone2 = this.options.container ? this.$newElement.clone().appendTo('body') : $selectClone,\n            ulWidth = $selectClone.children('.dropdown-menu').outerWidth(),\n            btnWidth = $selectClone2.css('width', 'auto').children('button').outerWidth();\n\n        $selectClone.remove();\n        $selectClone2.remove();\n\n        // Set width to whatever's larger, button title or longest option\n        this.$newElement.css('width', Math.max(ulWidth, btnWidth) + 'px');\n      } else if (this.options.width === 'fit') {\n        // Remove inline min-width so width can be changed from 'auto'\n        this.$menu.css('min-width', '');\n        this.$newElement.css('width', '').addClass('fit-width');\n      } else if (this.options.width) {\n        // Remove inline min-width so width can be changed from 'auto'\n        this.$menu.css('min-width', '');\n        this.$newElement.css('width', this.options.width);\n      } else {\n        // Remove inline min-width/width so width can be changed\n        this.$menu.css('min-width', '');\n        this.$newElement.css('width', '');\n      }\n      // Remove fit-width class if width is changed programmatically\n      if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {\n        this.$newElement.removeClass('fit-width');\n      }\n    },\n\n    selectPosition: function () {\n      var that = this,\n          drop = '<div />',\n          $drop = $(drop),\n          pos,\n          actualHeight,\n          getPlacement = function ($element) {\n            $drop.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass('dropup', $element.hasClass('dropup'));\n            pos = $element.offset();\n            actualHeight = $element.hasClass('dropup') ? 0 : $element[0].offsetHeight;\n            $drop.css({\n              'top': pos.top + actualHeight,\n              'left': pos.left,\n              'width': $element[0].offsetWidth,\n              'position': 'absolute'\n            });\n          };\n\n      this.$newElement.on('click', function () {\n        if (that.isDisabled()) {\n          return;\n        }\n        getPlacement($(this));\n        $drop.appendTo(that.options.container);\n        $drop.toggleClass('open', !$(this).hasClass('open'));\n        $drop.append(that.$menu);\n      });\n\n      $(window).on('resize scroll', function () {\n        getPlacement(that.$newElement);\n      });\n\n      this.$element.on('hide.bs.select', function () {\n        that.$menu.data('height', that.$menu.height());\n        $drop.detach();\n      });\n    },\n\n    setSelected: function (index, selected, $lis) {\n      if (!$lis) {\n        var $lis = this.findLis().eq(this.liObj[index]);\n      }\n\n      $lis.toggleClass('selected', selected);\n    },\n\n    setDisabled: function (index, disabled, $lis) {\n      if (!$lis) {\n        var $lis = this.findLis().eq(this.liObj[index]);\n      }\n\n      if (disabled) {\n        $lis.addClass('disabled').children('a').attr('href', '#').attr('tabindex', -1);\n      } else {\n        $lis.removeClass('disabled').children('a').removeAttr('href').attr('tabindex', 0);\n      }\n    },\n\n    isDisabled: function () {\n      return this.$element[0].disabled;\n    },\n\n    checkDisabled: function () {\n      var that = this;\n\n      if (this.isDisabled()) {\n        this.$newElement.addClass('disabled');\n        this.$button.addClass('disabled').attr('tabindex', -1);\n      } else {\n        if (this.$button.hasClass('disabled')) {\n          this.$newElement.removeClass('disabled');\n          this.$button.removeClass('disabled');\n        }\n\n        if (this.$button.attr('tabindex') == -1 && !this.$element.data('tabindex')) {\n          this.$button.removeAttr('tabindex');\n        }\n      }\n\n      this.$button.click(function () {\n        return !that.isDisabled();\n      });\n    },\n\n    tabIndex: function () {\n      if (this.$element.is('[tabindex]')) {\n        this.$element.data('tabindex', this.$element.attr('tabindex'));\n        this.$button.attr('tabindex', this.$element.data('tabindex'));\n      }\n    },\n\n    clickListener: function () {\n      var that = this,\n          $document = $(document);\n\n      this.$newElement.on('touchstart.dropdown', '.dropdown-menu', function (e) {\n        e.stopPropagation();\n      });\n\n      $document.data('spaceSelect', false);\n      \n      this.$button.on('keyup', function (e) {\n        if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {\n            e.preventDefault();\n            $document.data('spaceSelect', false);\n        }\n      });\n\n      this.$newElement.on('click', function () {\n        that.setSize();\n        that.$element.on('shown.bs.select', function () {\n          if (!that.options.liveSearch && !that.multiple) {\n            that.$menu.find('.selected a').focus();\n          } else if (!that.multiple) {\n            var selectedIndex = that.liObj[that.$element[0].selectedIndex];\n\n            if (typeof selectedIndex !== 'number') return;\n            \n            // scroll to selected option\n            var offset = that.$lis.eq(selectedIndex)[0].offsetTop - that.$menuInner[0].offsetTop;\n            offset = offset - that.$menuInner[0].offsetHeight/2 + that.sizeInfo.liHeight/2;\n            that.$menuInner[0].scrollTop = offset;\n          }\n        });\n      });\n\n      this.$menu.on('click', 'li a', function (e) {\n        var $this = $(this),\n            clickedIndex = $this.parent().data('originalIndex'),\n            prevValue = that.$element.val(),\n            prevIndex = that.$element.prop('selectedIndex');\n\n        // Don't close on multi choice menu\n        if (that.multiple) {\n          e.stopPropagation();\n        }\n\n        e.preventDefault();\n\n        //Don't run if we have been disabled\n        if (!that.isDisabled() && !$this.parent().hasClass('disabled')) {\n          var $options = that.$element.find('option'),\n              $option = $options.eq(clickedIndex),\n              state = $option.prop('selected'),\n              $optgroup = $option.parent('optgroup'),\n              maxOptions = that.options.maxOptions,\n              maxOptionsGrp = $optgroup.data('maxOptions') || false;\n\n          if (!that.multiple) { // Deselect all others if not multi select box\n            $options.prop('selected', false);\n            $option.prop('selected', true);\n            that.$menu.find('.selected').removeClass('selected');\n            that.setSelected(clickedIndex, true);\n          } else { // Toggle the one we have chosen if we are multi select.\n            $option.prop('selected', !state);\n            that.setSelected(clickedIndex, !state);\n            $this.blur();\n\n            if (maxOptions !== false || maxOptionsGrp !== false) {\n              var maxReached = maxOptions < $options.filter(':selected').length,\n                  maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length;\n\n              if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {\n                if (maxOptions && maxOptions == 1) {\n                  $options.prop('selected', false);\n                  $option.prop('selected', true);\n                  that.$menu.find('.selected').removeClass('selected');\n                  that.setSelected(clickedIndex, true);\n                } else if (maxOptionsGrp && maxOptionsGrp == 1) {\n                  $optgroup.find('option:selected').prop('selected', false);\n                  $option.prop('selected', true);\n                  var optgroupID = $this.parent().data('optgroup');\n                  that.$menu.find('[data-optgroup=\"' + optgroupID + '\"]').removeClass('selected');\n                  that.setSelected(clickedIndex, true);\n                } else {\n                  var maxOptionsArr = (typeof that.options.maxOptionsText === 'function') ?\n                          that.options.maxOptionsText(maxOptions, maxOptionsGrp) : that.options.maxOptionsText,\n                      maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),\n                      maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),\n                      $notify = $('<div class=\"notify\"></div>');\n                  // If {var} is set in array, replace it\n                  /** @deprecated */\n                  if (maxOptionsArr[2]) {\n                    maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);\n                    maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);\n                  }\n\n                  $option.prop('selected', false);\n\n                  that.$menu.append($notify);\n\n                  if (maxOptions && maxReached) {\n                    $notify.append($('<div>' + maxTxt + '</div>'));\n                    that.$element.trigger('maxReached.bs.select');\n                  }\n\n                  if (maxOptionsGrp && maxReachedGrp) {\n                    $notify.append($('<div>' + maxTxtGrp + '</div>'));\n                    that.$element.trigger('maxReachedGrp.bs.select');\n                  }\n\n                  setTimeout(function () {\n                    that.setSelected(clickedIndex, false);\n                  }, 10);\n\n                  $notify.delay(750).fadeOut(300, function () {\n                    $(this).remove();\n                  });\n                }\n              }\n            }\n          }\n\n          if (!that.multiple) {\n            that.$button.focus();\n          } else if (that.options.liveSearch) {\n            that.$searchbox.focus();\n          }\n\n          // Trigger select 'change'\n          if ((prevValue != that.$element.val() && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) {\n            that.$element.change();\n            // $option.prop('selected') is current option state (selected/unselected). state is previous option state.\n            that.$element.trigger('changed.bs.select', [clickedIndex, $option.prop('selected'), state]);\n          }\n        }\n      });\n\n      this.$menu.on('click', 'li.disabled a, .popover-title, .popover-title :not(.close)', function (e) {\n        if (e.currentTarget == this) {\n          e.preventDefault();\n          e.stopPropagation();\n          if (that.options.liveSearch && !$(e.target).hasClass('close')) {\n            that.$searchbox.focus();\n          } else {\n            that.$button.focus();\n          }\n        }\n      });\n\n      this.$menu.on('click', 'li.divider, li.dropdown-header', function (e) {\n        e.preventDefault();\n        e.stopPropagation();\n        if (that.options.liveSearch) {\n          that.$searchbox.focus();\n        } else {\n          that.$button.focus();\n        }\n      });\n\n      this.$menu.on('click', '.popover-title .close', function () {\n        that.$button.click();\n      });\n\n      this.$searchbox.on('click', function (e) {\n        e.stopPropagation();\n      });\n\n      this.$menu.on('click', '.actions-btn', function (e) {\n        if (that.options.liveSearch) {\n          that.$searchbox.focus();\n        } else {\n          that.$button.focus();\n        }\n\n        e.preventDefault();\n        e.stopPropagation();\n\n        if ($(this).hasClass('bs-select-all')) {\n          that.selectAll();\n        } else {\n          that.deselectAll();\n        }\n        that.$element.change();\n      });\n\n      this.$element.change(function () {\n        that.render(false);\n      });\n    },\n\n    liveSearchListener: function () {\n      var that = this,\n          $no_results = $('<li class=\"no-results\"></li>');\n\n      this.$newElement.on('click.dropdown.data-api touchstart.dropdown.data-api', function () {\n        that.$menuInner.find('.active').removeClass('active');\n        if (!!that.$searchbox.val()) {\n          that.$searchbox.val('');\n          that.$lis.not('.is-hidden').removeClass('hidden');\n          if (!!$no_results.parent().length) $no_results.remove();\n        }\n        if (!that.multiple) that.$menuInner.find('.selected').addClass('active');\n        setTimeout(function () {\n          that.$searchbox.focus();\n        }, 10);\n      });\n\n      this.$searchbox.on('click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api', function (e) {\n        e.stopPropagation();\n      });\n\n      this.$searchbox.on('input propertychange', function () {\n        if (that.$searchbox.val()) {\n          var $searchBase = that.$lis.not('.is-hidden').removeClass('hidden').children('a');\n          if (that.options.liveSearchNormalize) {\n            $searchBase = $searchBase.not(':a' + that._searchStyle() + '(' + normalizeToBase(that.$searchbox.val()) + ')');\n          } else {\n            $searchBase = $searchBase.not(':' + that._searchStyle() + '(' + that.$searchbox.val() + ')');\n          }\n          $searchBase.parent().addClass('hidden');\n\n          that.$lis.filter('.dropdown-header').each(function () {\n            var $this = $(this),\n                optgroup = $this.data('optgroup');\n\n            if (that.$lis.filter('[data-optgroup=' + optgroup + ']').not($this).not('.hidden').length === 0) {\n              $this.addClass('hidden');\n              that.$lis.filter('[data-optgroup=' + optgroup + 'div]').addClass('hidden');\n            }\n          });\n\n          var $lisVisible = that.$lis.not('.hidden');\n\n          // hide divider if first or last visible, or if followed by another divider\n          $lisVisible.each(function (index) {\n            var $this = $(this);\n\n            if ($this.hasClass('divider') && (\n              $this.index() === $lisVisible.eq(0).index() ||\n              $this.index() === $lisVisible.last().index() ||\n              $lisVisible.eq(index + 1).hasClass('divider'))) {\n              $this.addClass('hidden');\n            }\n          });\n\n          if (!that.$lis.not('.hidden, .no-results').length) {\n            if (!!$no_results.parent().length) {\n              $no_results.remove();\n            }\n            $no_results.html(that.options.noneResultsText.replace('{0}', '\"' + htmlEscape(that.$searchbox.val()) + '\"')).show();\n            that.$menuInner.append($no_results);\n          } else if (!!$no_results.parent().length) {\n            $no_results.remove();\n          }\n\n        } else {\n          that.$lis.not('.is-hidden').removeClass('hidden');\n          if (!!$no_results.parent().length) {\n            $no_results.remove();\n          }\n        }\n\n        that.$lis.filter('.active').removeClass('active');\n        that.$lis.not('.hidden, .divider, .dropdown-header').eq(0).addClass('active').children('a').focus();\n        $(this).focus();\n      });\n    },\n\n    _searchStyle: function () {\n      var style = 'icontains';\n      switch (this.options.liveSearchStyle) {\n        case 'begins':\n        case 'startsWith':\n          style = 'ibegins';\n          break;\n        case 'contains':\n        default:\n          break; //no need to change the default\n      }\n\n      return style;\n    },\n\n    val: function (value) {\n      if (typeof value !== 'undefined') {\n        this.$element.val(value);\n        this.render();\n\n        return this.$element;\n      } else {\n        return this.$element.val();\n      }\n    },\n\n    selectAll: function () {\n      this.findLis();\n      this.$element.find('option:enabled').not('[data-divider], [data-hidden]').prop('selected', true);\n      this.$lis.not('.divider, .dropdown-header, .disabled, .hidden').addClass('selected');\n      this.render(false);\n    },\n\n    deselectAll: function () {\n      this.findLis();\n      this.$element.find('option:enabled').not('[data-divider], [data-hidden]').prop('selected', false);\n      this.$lis.not('.divider, .dropdown-header, .disabled, .hidden').removeClass('selected');\n      this.render(false);\n    },\n\n    keydown: function (e) {\n      var $this = $(this),\n          $parent = $this.is('input') ? $this.parent().parent() : $this.parent(),\n          $items,\n          that = $parent.data('this'),\n          index,\n          next,\n          first,\n          last,\n          prev,\n          nextPrev,\n          prevIndex,\n          isActive,\n          selector = ':not(.disabled, .hidden, .dropdown-header, .divider)',\n          keyCodeMap = {\n            32: ' ',\n            48: '0',\n            49: '1',\n            50: '2',\n            51: '3',\n            52: '4',\n            53: '5',\n            54: '6',\n            55: '7',\n            56: '8',\n            57: '9',\n            59: ';',\n            65: 'a',\n            66: 'b',\n            67: 'c',\n            68: 'd',\n            69: 'e',\n            70: 'f',\n            71: 'g',\n            72: 'h',\n            73: 'i',\n            74: 'j',\n            75: 'k',\n            76: 'l',\n            77: 'm',\n            78: 'n',\n            79: 'o',\n            80: 'p',\n            81: 'q',\n            82: 'r',\n            83: 's',\n            84: 't',\n            85: 'u',\n            86: 'v',\n            87: 'w',\n            88: 'x',\n            89: 'y',\n            90: 'z',\n            96: '0',\n            97: '1',\n            98: '2',\n            99: '3',\n            100: '4',\n            101: '5',\n            102: '6',\n            103: '7',\n            104: '8',\n            105: '9'\n          };\n\n      if (that.options.liveSearch) $parent = $this.parent().parent();\n\n      if (that.options.container) $parent = that.$menu;\n\n      $items = $('[role=menu] li a', $parent);\n\n      isActive = that.$menu.parent().hasClass('open');\n\n      if (!isActive && (e.keyCode >= 48 && e.keyCode <= 57 || event.keyCode >= 65 && event.keyCode <= 90)) {\n        if (!that.options.container) {\n          that.setSize();\n          that.$menu.parent().addClass('open');\n          isActive = true;\n        } else {\n          that.$newElement.trigger('click');\n        }\n        that.$searchbox.focus();\n      }\n\n      if (that.options.liveSearch) {\n        if (/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && that.$menu.find('.active').length === 0) {\n          e.preventDefault();\n          that.$menu.parent().removeClass('open');\n          if (that.options.container) that.$newElement.removeClass('open');\n          that.$button.focus();\n        }\n        // $items contains li elements when liveSearch is enabled\n        $items = $('[role=menu] li:not(.disabled, .hidden, .dropdown-header, .divider)', $parent);\n        if (!$this.val() && !/(38|40)/.test(e.keyCode.toString(10))) {\n          if ($items.filter('.active').length === 0) {\n            $items = that.$newElement.find('li');\n            if (that.options.liveSearchNormalize) {\n              $items = $items.filter(':a' + that._searchStyle() + '(' + normalizeToBase(keyCodeMap[e.keyCode]) + ')');\n            } else {\n              $items = $items.filter(':' + that._searchStyle() + '(' + keyCodeMap[e.keyCode] + ')');\n            }\n          }\n        }\n      }\n\n      if (!$items.length) return;\n\n      if (/(38|40)/.test(e.keyCode.toString(10))) {\n        index = $items.index($items.filter(':focus'));\n        first = $items.parent(selector).first().data('originalIndex');\n        last = $items.parent(selector).last().data('originalIndex');\n        next = $items.eq(index).parent().nextAll(selector).eq(0).data('originalIndex');\n        prev = $items.eq(index).parent().prevAll(selector).eq(0).data('originalIndex');\n        nextPrev = $items.eq(next).parent().prevAll(selector).eq(0).data('originalIndex');\n\n        if (that.options.liveSearch) {\n          $items.each(function (i) {\n            if (!$(this).hasClass('disabled')) {\n              $(this).data('index', i);\n            }\n          });\n          index = $items.index($items.filter('.active'));\n          first = $items.first().data('index');\n          last = $items.last().data('index');\n          next = $items.eq(index).nextAll().eq(0).data('index');\n          prev = $items.eq(index).prevAll().eq(0).data('index');\n          nextPrev = $items.eq(next).prevAll().eq(0).data('index');\n        }\n\n        prevIndex = $this.data('prevIndex');\n\n        if (e.keyCode == 38) {\n          if (that.options.liveSearch) index -= 1;\n          if (index != nextPrev && index > prev) index = prev;\n          if (index < first) index = first;\n          if (index == prevIndex) index = last;\n        } else if (e.keyCode == 40) {\n          if (that.options.liveSearch) index += 1;\n          if (index == -1) index = 0;\n          if (index != nextPrev && index < next) index = next;\n          if (index > last) index = last;\n          if (index == prevIndex) index = first;\n        }\n\n        $this.data('prevIndex', index);\n\n        if (!that.options.liveSearch) {\n          $items.eq(index).focus();\n        } else {\n          e.preventDefault();\n          if (!$this.hasClass('dropdown-toggle')) {\n            $items.removeClass('active').eq(index).addClass('active').children('a').focus();\n            $this.focus();\n          }\n        }\n\n      } else if (!$this.is('input')) {\n        var keyIndex = [],\n            count,\n            prevKey;\n\n        $items.each(function () {\n          if (!$(this).parent().hasClass('disabled')) {\n            if ($.trim($(this).text().toLowerCase()).substring(0, 1) == keyCodeMap[e.keyCode]) {\n              keyIndex.push($(this).parent().index());\n            }\n          }\n        });\n\n        count = $(document).data('keycount');\n        count++;\n        $(document).data('keycount', count);\n\n        prevKey = $.trim($(':focus').text().toLowerCase()).substring(0, 1);\n\n        if (prevKey != keyCodeMap[e.keyCode]) {\n          count = 1;\n          $(document).data('keycount', count);\n        } else if (count >= keyIndex.length) {\n          $(document).data('keycount', 0);\n          if (count > keyIndex.length) count = 1;\n        }\n\n        $items.eq(keyIndex[count - 1]).focus();\n      }\n\n      // Select focused option if \"Enter\", \"Spacebar\" or \"Tab\" (when selectOnTab is true) are pressed inside the menu.\n      if ((/(13|32)/.test(e.keyCode.toString(10)) || (/(^9$)/.test(e.keyCode.toString(10)) && that.options.selectOnTab)) && isActive) {\n        if (!/(32)/.test(e.keyCode.toString(10))) e.preventDefault();\n        if (!that.options.liveSearch) {\n          var elem = $(':focus');\n          elem.click();\n          // Bring back focus for multiselects\n          elem.focus();\n          // Prevent screen from scrolling if the user hit the spacebar\n          e.preventDefault();\n          // Fixes spacebar selection of dropdown items in FF & IE\n          $(document).data('spaceSelect', true);\n        } else if (!/(32)/.test(e.keyCode.toString(10))) {\n          that.$menu.find('.active a').click();\n          $this.focus();\n        }\n        $(document).data('keycount', 0);\n      }\n\n      if ((/(^9$|27)/.test(e.keyCode.toString(10)) && isActive && (that.multiple || that.options.liveSearch)) || (/(27)/.test(e.keyCode.toString(10)) && !isActive)) {\n        that.$menu.parent().removeClass('open');\n        if (that.options.container) that.$newElement.removeClass('open');\n        that.$button.focus();\n      }\n    },\n\n    mobile: function () {\n      this.$element.addClass('mobile-device').appendTo(this.$newElement);\n      if (this.options.container) this.$menu.hide();\n    },\n\n    refresh: function () {\n      this.$lis = null;\n      this.reloadLi();\n      this.render();\n      this.checkDisabled();\n      this.liHeight(true);\n      this.setStyle();\n      this.setWidth();\n      if (this.$lis) this.$searchbox.trigger('propertychange');\n\n      this.$element.trigger('refreshed.bs.select');\n    },\n\n    hide: function () {\n      this.$newElement.hide();\n    },\n\n    show: function () {\n      this.$newElement.show();\n    },\n\n    remove: function () {\n      this.$newElement.remove();\n      this.$element.remove();\n    }\n  };\n\n  // SELECTPICKER PLUGIN DEFINITION\n  // ==============================\n  function Plugin(option, event) {\n    // get the args of the outer function..\n    var args = arguments;\n    // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them\n    // to get lost/corrupted in android 2.3 and IE9 #715 #775\n    var _option = option,\n        _event = event;\n    [].shift.apply(args);\n\n    var value;\n    var chain = this.each(function () {\n      var $this = $(this);\n      if ($this.is('select')) {\n        var data = $this.data('selectpicker'),\n            options = typeof _option == 'object' && _option;\n\n        if (!data) {\n          var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, $this.data(), options);\n          $this.data('selectpicker', (data = new Selectpicker(this, config, _event)));\n        } else if (options) {\n          for (var i in options) {\n            if (options.hasOwnProperty(i)) {\n              data.options[i] = options[i];\n            }\n          }\n        }\n\n        if (typeof _option == 'string') {\n          if (data[_option] instanceof Function) {\n            value = data[_option].apply(data, args);\n          } else {\n            value = data.options[_option];\n          }\n        }\n      }\n    });\n\n    if (typeof value !== 'undefined') {\n      //noinspection JSUnusedAssignment\n      return value;\n    } else {\n      return chain;\n    }\n  }\n\n  var old = $.fn.selectpicker;\n  $.fn.selectpicker = Plugin;\n  $.fn.selectpicker.Constructor = Selectpicker;\n\n  // SELECTPICKER NO CONFLICT\n  // ========================\n  $.fn.selectpicker.noConflict = function () {\n    $.fn.selectpicker = old;\n    return this;\n  };\n\n  $(document)\n      .data('keycount', 0)\n      .on('keydown', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=\"menu\"], .bs-searchbox input', Selectpicker.prototype.keydown)\n      .on('focusin.modal', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=\"menu\"], .bs-searchbox input', function (e) {\n        e.stopPropagation();\n      });\n\n  // SELECTPICKER DATA-API\n  // =====================\n  $(window).on('load.bs.select.data-api', function () {\n    $('.selectpicker').each(function () {\n      var $selectpicker = $(this);\n      Plugin.call($selectpicker, $selectpicker.data());\n    })\n  });\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-bg_BG.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Нищо избрано',\n    noneResultsText: 'Няма резултат за {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      return (numSelected == 1) ? \"{0} избран елемент\" : \"{0} избрани елемента\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        (numAll == 1) ? 'Лимита е достигнат ({n} елемент максимум)' : 'Лимита е достигнат ({n} елемента максимум)',\n        (numGroup == 1) ? 'Груповия лимит е достигнат ({n} елемент максимум)' : 'Груповия лимит е достигнат ({n} елемента максимум)'\n      ];\n    },\n    selectAllText: 'Избери всички',\n    deselectAllText: 'Размаркирай всички',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-cs_CZ.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Nic není vybráno',\n    noneResultsText: 'Žádné výsledky {0}',\n    countSelectedText: 'Označeno {0} z {1}',\n    maxOptionsText: ['Limit překročen ({n} {var} max)', 'Limit skupiny překročen ({n} {var} max)', ['položek', 'položka']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-da_DK.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Intet valgt',\n    noneResultsText: 'Ingen resultater fundet {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      return (numSelected == 1) ? \"{0} valgt\" : \"{0} valgt\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        (numAll == 1) ? 'Begrænsning nået (max {n} valgt)' : 'Begrænsning nået (max {n} valgte)',\n        (numGroup == 1) ? 'Gruppe-begrænsning nået (max {n} valgt)' : 'Gruppe-begrænsning nået (max {n} valgte)'\n      ];\n    },\n    selectAllText: 'Markér alle',\n    deselectAllText: 'Afmarkér alle',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-de_DE.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Bitte wählen...',\n    noneResultsText: 'Keine Ergebnisse für {0}',\n    countSelectedText: '{0} von {1} ausgewählt',\n    maxOptionsText: ['Limit erreicht ({n} {var} max.)', 'Gruppen-Limit erreicht ({n} {var} max.)', ['Eintrag', 'Einträge']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-en_US.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Nothing selected',\n    noneResultsText: 'No results match {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      return (numSelected == 1) ? \"{0} item selected\" : \"{0} items selected\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',\n        (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'\n      ];\n    },\n    selectAllText: 'Select All',\n    deselectAllText: 'Deselect All',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-es_CL.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'No hay selección',\n    noneResultsText: 'No hay resultados {0}',\n    countSelectedText: 'Seleccionados {0} de {1}',\n    maxOptionsText: ['Límite alcanzado ({n} {var} max)', 'Límite del grupo alcanzado({n} {var} max)', ['elementos', 'element']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-eu.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Hautapenik ez',\n    noneResultsText: 'Emaitzarik ez {0}',\n    countSelectedText: '{1}(e)tik {0} hautatuta',\n    maxOptionsText: ['Mugara iritsita ({n} {var} gehienez)', 'Taldearen mugara iritsita ({n} {var} gehienez)', ['elementu', 'elementu']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-fa_IR.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n    $.fn.selectpicker.defaults = {\n        noneSelectedText: 'چیزی انتخاب نشده است',\n        noneResultsText: 'هیج مشابهی برای {0} پیدا نشد',\n        countSelectedText: \"{0} از {1} مورد انتخاب شده\",\n        maxOptionsText: ['بیشتر ممکن نیست {حداکثر {n} عدد}', 'بیشتر ممکن نیست {حداکثر {n} عدد}'],\n        selectAllText: 'انتخاب همه',\n        deselectAllText: 'انتخاب هیچ کدام',\n        multipleSeparator: ', '\n    };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-fr_FR.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Aucune s&eacute;lection',\n    noneResultsText: 'Aucun r&eacute;sultat pour {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      return (numSelected > 1) ? \"{0} &eacute;l&eacute;ments s&eacute;lectionn&eacute;s\" : \"{0} &eacute;l&eacute;ment s&eacute;lectionn&eacute;\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        (numAll > 1) ? 'Limite atteinte ({n} &eacute;l&eacute;ments max)' : 'Limite atteinte ({n} &eacute;l&eacute;ment max)',\n        (numGroup > 1) ? 'Limite du groupe atteinte ({n} &eacute;l&eacute;ments max)' : 'Limite du groupe atteinte ({n} &eacute;l&eacute;ment max)'\n      ];\n    },\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-hu_HU.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Válasszon!',\n    noneResultsText: 'Nincs találat {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      return '{n} elem kiválasztva';\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        'Legfeljebb {n} elem választható',\n        'A csoportban legfeljebb {n} elem választható'\n      ];\n    },\n    selectAllText: 'Mind',\n    deselectAllText: 'Egyik sem',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-it_IT.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Nessuna selezione',\n    noneResultsText: 'Nessun risultato per {0}',\n    countSelectedText: 'Selezionati {0} di {1}',\n    maxOptionsText: ['Limite raggiunto ({n} {var} max)', 'Limite del gruppo raggiunto ({n} {var} max)', ['elementi', 'elemento']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-ko_KR.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: '항목을 선택해주세요',\n    noneResultsText: '{0} 검색 결과가 없습니다',\n    countSelectedText: function (numSelected, numTotal) {\n      return \"{0}개를 선택하였습니다\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        '{n}개까지 선택 가능합니다',\n        '해당 그룹은 {n}개까지 선택 가능합니다'\n      ];\n    },\n    selectAllText: '전체선택',\n    deselectAllText: '전체해제',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-nl_NL.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Niets geselecteerd',\n    noneResultsText: 'Geen resultaten gevonden voor {0}',\n    countSelectedText: '{0} van {1} geselecteerd',\n    maxOptionsText: ['Limiet bereikt ({n} {var} max)', 'Groep limiet bereikt ({n} {var} max)', ['items', 'item']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-pl_PL.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Nic nie zaznaczono',\n    noneResultsText: 'Brak wyników wyszukiwania {0}',\n    countSelectedText: 'Zaznaczono {0} z {1}',\n    maxOptionsText: ['Osiągnięto limit ({n} {var} max)', 'Limit grupy osiągnięty ({n} {var} max)', ['elementy', 'element']],\n    selectAll: 'Zaznacz wszystkie',\n    deselectAll: 'Odznacz wszystkie',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-pt_BR.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Nada selecionado',\n    noneResultsText: 'Nada encontrado contendo {0}',\n    countSelectedText: 'Selecionado {0} de {1}',\n    maxOptionsText: ['Limite excedido (máx. {n} {var})', 'Limite do grupo excedido (máx. {n} {var})', ['itens', 'item']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-pt_PT.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n$.fn.selectpicker.defaults = {\nnoneSelectedText: 'Nenhum seleccionado',\nnoneResultsText: 'Sem resultados contendo {0}',\ncountSelectedText: 'Selecionado {0} de {1}',\nmaxOptionsText: ['Limite ultrapassado (máx. {n} {var})', 'Limite de seleções ultrapassado (máx. {n} {var})', ['itens', 'item']],\nmultipleSeparator: ', '\n};\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-ro_RO.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Nu a fost selectat nimic',\n    noneResultsText: 'Nu exista niciun rezultat {0}',\n    countSelectedText: '{0} din {1} selectat(e)',\n    maxOptionsText: ['Limita a fost atinsa ({n} {var} max)', 'Limita de grup a fost atinsa ({n} {var} max)', ['iteme', 'item']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-ru_RU.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Ничего не выбрано',\n    noneResultsText: 'Совпадений не найдено {0}',\n    countSelectedText: 'Выбрано {0} из {1}',\n    maxOptionsText: ['Достигнут предел ({n} {var} максимум)', 'Достигнут предел в группе ({n} {var} максимум)', ['items', 'item']],\n    doneButtonText: 'Закрыть',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-sk_SK.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Vyberte zo zoznamu',\n    noneResultsText: 'Pre výraz {0} neboli nájdené žiadne výsledky',\n    countSelectedText: 'Vybrané {0} z {1}',\n    maxOptionsText: ['Limit prekročený ({n} {var} max)', 'Limit skupiny prekročený ({n} {var} max)', ['položiek', 'položka']],\n    selectAllText: 'Vybrať všetky',\n    deselectAllText: 'Zrušiť výber',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-sl_SI.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Nič izbranega',\n    noneResultsText: 'Ni zadetkov za {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      \"Število izbranih: {0}\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        'Omejitev dosežena (max. izbranih: {n})',\n        'Omejitev skupine dosežena (max. izbranih: {n})'\n      ];\n    },\n    selectAllText: 'Izberi vse',\n    deselectAllText: 'Počisti izbor',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-sv_SE.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Inget valt',\n    noneResultsText: 'Inget sökresultat matchar {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      return (numSelected === 1) ? \"{0} alternativ valt\" : \"{0} alternativ valda\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        'Gräns uppnåd (max {n} alternativ)',\n        'Gräns uppnåd (max {n} gruppalternativ)'\n      ];\n    },\n    selectAllText: 'Markera alla',\n    deselectAllText: 'Avmarkera alla',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-tr_TR.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Hiçbiri seçilmedi',\n    noneResultsText: 'Hiçbir sonuç bulunamadı {0}',\n    countSelectedText: function (numSelected, numTotal) {\n      return (numSelected == 1) ? \"{0} öğe seçildi\" : \"{0} öğe seçildi\";\n    },\n    maxOptionsText: function (numAll, numGroup) {\n      return [\n        (numAll == 1) ? 'Limit aşıldı (maksimum {n} sayıda öğe )' : 'Limit aşıldı (maksimum {n} sayıda öğe)',\n        (numGroup == 1) ? 'Grup limiti aşıldı (maksimum {n} sayıda öğe)' : 'Grup limiti aşıldı (maksimum {n} sayıda öğe)'\n      ];\n    },\n    selectAllText: 'Tümünü Seç',\n    deselectAllText: 'Seçiniz',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-ua_UA.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: 'Нічого не вибрано',\n    noneResultsText: 'Збігів не знайдено {0}',\n    countSelectedText: 'Вибрано {0} із {1}',\n    maxOptionsText: ['Досягнута межа ({n} {var} максимум)', 'Досягнута межа в групі ({n} {var} максимум)', ['items', 'item']],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-zh_CN.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: '没有选中任何项',\n    noneResultsText: '没有找到匹配项',\n    countSelectedText: '选中{1}中的{0}项',\n    maxOptionsText: ['超出限制 (最多选择{n}项)', '组选择超出限制(最多选择{n}组)'],\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-select/1.7.2/js/i18n/defaults-zh_TW.js",
    "content": "/*!\n * Bootstrap-select v1.7.2 (http://silviomoreto.github.io/bootstrap-select)\n *\n * Copyright 2013-2015 bootstrap-select\n * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)\n */\n\n(function (root, factory) {\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module unless amdModuleId is set\n    define([\"jquery\"], function (a0) {\n      return (factory(a0));\n    });\n  } else if (typeof exports === 'object') {\n    // Node. Does not work with strict CommonJS, but\n    // only CommonJS-like environments that support module.exports,\n    // like Node.\n    module.exports = factory(require(\"jquery\"));\n  } else {\n    factory(jQuery);\n  }\n}(this, function () {\n\n(function ($) {\n  $.fn.selectpicker.defaults = {\n    noneSelectedText: '沒有選取任何項目',\n    noneResultsText: '沒有找到符合的結果',\n    countSelectedText: '已經選取{0}個項目',\n    maxOptionsText: ['超過限制 (最多選擇{n}項)', '超過限制(最多選擇{n}組)'],\n    selectAllText: '選取全部',\n    deselectAllText: '全部取消',\n    multipleSeparator: ', '\n  };\n})(jQuery);\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert-animations.less",
    "content": "@-webkit-keyframes showSweetAlert {\n  0% {\n    transform: scale(0.7);\n    -webkit-transform: scale(0.7); }\n  45% {\n    transform: scale(1.05);\n    -webkit-transform: scale(1.05); }\n  80% {\n    transform: scale(0.95);\n    -webkit-tranform: scale(0.95); }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1); } }\n@keyframes showSweetAlert {\n  0% {\n    transform: scale(0.7);\n    -webkit-transform: scale(0.7); }\n  45% {\n    transform: scale(1.05);\n    -webkit-transform: scale(1.05); }\n  80% {\n    transform: scale(0.95);\n    -webkit-tranform: scale(0.95); }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1); } }\n@-webkit-keyframes hideSweetAlert {\n  0% {\n    transform: scale(1);\n    -webkit-transform: scale(1); }\n  100% {\n    transform: scale(0.5);\n    -webkit-transform: scale(0.5); } }\n@keyframes hideSweetAlert {\n  0% {\n    transform: scale(1);\n    -webkit-transform: scale(1); }\n  100% {\n    transform: scale(0.5);\n    -webkit-transform: scale(0.5); } }\n.showSweetAlert {\n  -webkit-animation: showSweetAlert 0.3s;\n  animation: showSweetAlert 0.3s; }\n\n.hideSweetAlert {\n  -webkit-animation: hideSweetAlert 0.2s;\n  animation: hideSweetAlert 0.2s; }\n\n@-webkit-keyframes animateSuccessTip {\n  0% {\n    width: 0;\n    left: 1px;\n    top: 19px; }\n  54% {\n    width: 0;\n    left: 1px;\n    top: 19px; }\n  70% {\n    width: 50px;\n    left: -8px;\n    top: 37px; }\n  84% {\n    width: 17px;\n    left: 21px;\n    top: 48px; }\n  100% {\n    width: 25px;\n    left: 14px;\n    top: 45px; } }\n@keyframes animateSuccessTip {\n  0% {\n    width: 0;\n    left: 1px;\n    top: 19px; }\n  54% {\n    width: 0;\n    left: 1px;\n    top: 19px; }\n  70% {\n    width: 50px;\n    left: -8px;\n    top: 37px; }\n  84% {\n    width: 17px;\n    left: 21px;\n    top: 48px; }\n  100% {\n    width: 25px;\n    left: 14px;\n    top: 45px; } }\n@-webkit-keyframes animateSuccessLong {\n  0% {\n    width: 0;\n    right: 46px;\n    top: 54px; }\n  65% {\n    width: 0;\n    right: 46px;\n    top: 54px; }\n  84% {\n    width: 55px;\n    right: 0px;\n    top: 35px; }\n  100% {\n    width: 47px;\n    right: 8px;\n    top: 38px; } }\n@keyframes animateSuccessLong {\n  0% {\n    width: 0;\n    right: 46px;\n    top: 54px; }\n  65% {\n    width: 0;\n    right: 46px;\n    top: 54px; }\n  84% {\n    width: 55px;\n    right: 0px;\n    top: 35px; }\n  100% {\n    width: 47px;\n    right: 8px;\n    top: 38px; } }\n@-webkit-keyframes rotatePlaceholder {\n  0% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg); }\n  5% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg); }\n  12% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg); }\n  100% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg); } }\n@keyframes rotatePlaceholder {\n  0% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg); }\n  5% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg); }\n  12% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg); }\n  100% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg); } }\n.animateSuccessTip {\n  -webkit-animation: animateSuccessTip 0.75s;\n  animation: animateSuccessTip 0.75s; }\n\n.animateSuccessLong {\n  -webkit-animation: animateSuccessLong 0.75s;\n  animation: animateSuccessLong 0.75s; }\n\n.icon.success.animate::after {\n  -webkit-animation: rotatePlaceholder 4.25s ease-in;\n  animation: rotatePlaceholder 4.25s ease-in; }\n\n@-webkit-keyframes animateErrorIcon {\n  0% {\n    transform: rotateX(100deg);\n    -webkit-transform: rotateX(100deg);\n    opacity: 0; }\n  100% {\n    transform: rotateX(0deg);\n    -webkit-transform: rotateX(0deg);\n    opacity: 1; } }\n@keyframes animateErrorIcon {\n  0% {\n    transform: rotateX(100deg);\n    -webkit-transform: rotateX(100deg);\n    opacity: 0; }\n  100% {\n    transform: rotateX(0deg);\n    -webkit-transform: rotateX(0deg);\n    opacity: 1; } }\n.animateErrorIcon {\n  -webkit-animation: animateErrorIcon 0.5s;\n  animation: animateErrorIcon 0.5s; }\n\n@-webkit-keyframes animateXMark {\n  0% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0; }\n  50% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0; }\n  80% {\n    transform: scale(1.15);\n    -webkit-transform: scale(1.15);\n    margin-top: -6px; }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n    margin-top: 0;\n    opacity: 1; } }\n@keyframes animateXMark {\n  0% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0; }\n  50% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0; }\n  80% {\n    transform: scale(1.15);\n    -webkit-transform: scale(1.15);\n    margin-top: -6px; }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n    margin-top: 0;\n    opacity: 1; } }\n.animateXMark {\n  -webkit-animation: animateXMark 0.5s;\n  animation: animateXMark 0.5s; }\n\n@-webkit-keyframes pulseWarning {\n  0% {\n    border-color: #F8D486; }\n  100% {\n    border-color: #F8BB86; } }\n@keyframes pulseWarning {\n  0% {\n    border-color: #F8D486; }\n  100% {\n    border-color: #F8BB86; } }\n.pulseWarning {\n  -webkit-animation: pulseWarning 0.75s infinite alternate;\n  animation: pulseWarning 0.75s infinite alternate; }\n\n@-webkit-keyframes pulseWarningIns {\n  0% {\n    background-color: #F8D486; }\n  100% {\n    background-color: #F8BB86; } }\n@keyframes pulseWarningIns {\n  0% {\n    background-color: #F8D486; }\n  100% {\n    background-color: #F8BB86; } }\n.pulseWarningIns {\n  -webkit-animation: pulseWarningIns 0.75s infinite alternate;\n  animation: pulseWarningIns 0.75s infinite alternate; }\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert-combine.less",
    "content": "@import \"../bootstrap/variables\";\n@import \"../bootstrap/mixins\";\n@import \"sweet-alert\";\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert.css",
    "content": "@-webkit-keyframes showSweetAlert {\n  0% {\n    transform: scale(0.7);\n    -webkit-transform: scale(0.7);\n  }\n  45% {\n    transform: scale(1.05);\n    -webkit-transform: scale(1.05);\n  }\n  80% {\n    transform: scale(0.95);\n    -webkit-tranform: scale(0.95);\n  }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n  }\n}\n@keyframes showSweetAlert {\n  0% {\n    transform: scale(0.7);\n    -webkit-transform: scale(0.7);\n  }\n  45% {\n    transform: scale(1.05);\n    -webkit-transform: scale(1.05);\n  }\n  80% {\n    transform: scale(0.95);\n    -webkit-tranform: scale(0.95);\n  }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n  }\n}\n@-webkit-keyframes hideSweetAlert {\n  0% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n  }\n  100% {\n    transform: scale(0.5);\n    -webkit-transform: scale(0.5);\n  }\n}\n@keyframes hideSweetAlert {\n  0% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n  }\n  100% {\n    transform: scale(0.5);\n    -webkit-transform: scale(0.5);\n  }\n}\n.showSweetAlert {\n  -webkit-animation: showSweetAlert 0.3s;\n  animation: showSweetAlert 0.3s;\n}\n.hideSweetAlert {\n  -webkit-animation: hideSweetAlert 0.2s;\n  animation: hideSweetAlert 0.2s;\n}\n@-webkit-keyframes animateSuccessTip {\n  0% {\n    width: 0;\n    left: 1px;\n    top: 19px;\n  }\n  54% {\n    width: 0;\n    left: 1px;\n    top: 19px;\n  }\n  70% {\n    width: 50px;\n    left: -8px;\n    top: 37px;\n  }\n  84% {\n    width: 17px;\n    left: 21px;\n    top: 48px;\n  }\n  100% {\n    width: 25px;\n    left: 14px;\n    top: 45px;\n  }\n}\n@keyframes animateSuccessTip {\n  0% {\n    width: 0;\n    left: 1px;\n    top: 19px;\n  }\n  54% {\n    width: 0;\n    left: 1px;\n    top: 19px;\n  }\n  70% {\n    width: 50px;\n    left: -8px;\n    top: 37px;\n  }\n  84% {\n    width: 17px;\n    left: 21px;\n    top: 48px;\n  }\n  100% {\n    width: 25px;\n    left: 14px;\n    top: 45px;\n  }\n}\n@-webkit-keyframes animateSuccessLong {\n  0% {\n    width: 0;\n    right: 46px;\n    top: 54px;\n  }\n  65% {\n    width: 0;\n    right: 46px;\n    top: 54px;\n  }\n  84% {\n    width: 55px;\n    right: 0px;\n    top: 35px;\n  }\n  100% {\n    width: 47px;\n    right: 8px;\n    top: 38px;\n  }\n}\n@keyframes animateSuccessLong {\n  0% {\n    width: 0;\n    right: 46px;\n    top: 54px;\n  }\n  65% {\n    width: 0;\n    right: 46px;\n    top: 54px;\n  }\n  84% {\n    width: 55px;\n    right: 0px;\n    top: 35px;\n  }\n  100% {\n    width: 47px;\n    right: 8px;\n    top: 38px;\n  }\n}\n@-webkit-keyframes rotatePlaceholder {\n  0% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg);\n  }\n  5% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg);\n  }\n  12% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg);\n  }\n  100% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg);\n  }\n}\n@keyframes rotatePlaceholder {\n  0% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg);\n  }\n  5% {\n    transform: rotate(-45deg);\n    -webkit-transform: rotate(-45deg);\n  }\n  12% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg);\n  }\n  100% {\n    transform: rotate(-405deg);\n    -webkit-transform: rotate(-405deg);\n  }\n}\n.animateSuccessTip {\n  -webkit-animation: animateSuccessTip 0.75s;\n  animation: animateSuccessTip 0.75s;\n}\n.animateSuccessLong {\n  -webkit-animation: animateSuccessLong 0.75s;\n  animation: animateSuccessLong 0.75s;\n}\n.icon.success.animate::after {\n  -webkit-animation: rotatePlaceholder 4.25s ease-in;\n  animation: rotatePlaceholder 4.25s ease-in;\n}\n@-webkit-keyframes animateErrorIcon {\n  0% {\n    transform: rotateX(100deg);\n    -webkit-transform: rotateX(100deg);\n    opacity: 0;\n  }\n  100% {\n    transform: rotateX(0deg);\n    -webkit-transform: rotateX(0deg);\n    opacity: 1;\n  }\n}\n@keyframes animateErrorIcon {\n  0% {\n    transform: rotateX(100deg);\n    -webkit-transform: rotateX(100deg);\n    opacity: 0;\n  }\n  100% {\n    transform: rotateX(0deg);\n    -webkit-transform: rotateX(0deg);\n    opacity: 1;\n  }\n}\n.animateErrorIcon {\n  -webkit-animation: animateErrorIcon 0.5s;\n  animation: animateErrorIcon 0.5s;\n}\n@-webkit-keyframes animateXMark {\n  0% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0;\n  }\n  50% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0;\n  }\n  80% {\n    transform: scale(1.15);\n    -webkit-transform: scale(1.15);\n    margin-top: -6px;\n  }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n    margin-top: 0;\n    opacity: 1;\n  }\n}\n@keyframes animateXMark {\n  0% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0;\n  }\n  50% {\n    transform: scale(0.4);\n    -webkit-transform: scale(0.4);\n    margin-top: 26px;\n    opacity: 0;\n  }\n  80% {\n    transform: scale(1.15);\n    -webkit-transform: scale(1.15);\n    margin-top: -6px;\n  }\n  100% {\n    transform: scale(1);\n    -webkit-transform: scale(1);\n    margin-top: 0;\n    opacity: 1;\n  }\n}\n.animateXMark {\n  -webkit-animation: animateXMark 0.5s;\n  animation: animateXMark 0.5s;\n}\n@-webkit-keyframes pulseWarning {\n  0% {\n    border-color: #F8D486;\n  }\n  100% {\n    border-color: #F8BB86;\n  }\n}\n@keyframes pulseWarning {\n  0% {\n    border-color: #F8D486;\n  }\n  100% {\n    border-color: #F8BB86;\n  }\n}\n.pulseWarning {\n  -webkit-animation: pulseWarning 0.75s infinite alternate;\n  animation: pulseWarning 0.75s infinite alternate;\n}\n@-webkit-keyframes pulseWarningIns {\n  0% {\n    background-color: #F8D486;\n  }\n  100% {\n    background-color: #F8BB86;\n  }\n}\n@keyframes pulseWarningIns {\n  0% {\n    background-color: #F8D486;\n  }\n  100% {\n    background-color: #F8BB86;\n  }\n}\n.pulseWarningIns {\n  -webkit-animation: pulseWarningIns 0.75s infinite alternate;\n  animation: pulseWarningIns 0.75s infinite alternate;\n}\n.sweet-overlay {\n  background-color: rgba(0, 0, 0, 0.4);\n  position: fixed;\n  left: 0;\n  right: 0;\n  top: 0;\n  bottom: 0;\n  display: none;\n  z-index: 1040;\n}\n.sweet-alert {\n  background-color: #ffffff;\n  width: 478px;\n  padding: 17px;\n  border-radius: 5px;\n  text-align: center;\n  position: fixed;\n  left: 50%;\n  top: 50%;\n  margin-left: -256px;\n  margin-top: -200px;\n  overflow: hidden;\n  display: none;\n  z-index: 2000;\n}\n@media all and (max-width: 767px) {\n  .sweet-alert {\n    width: auto;\n    margin-left: 0;\n    margin-right: 0;\n    left: 15px;\n    right: 15px;\n  }\n}\n.sweet-alert .icon {\n  width: 80px;\n  height: 80px;\n  border: 4px solid gray;\n  border-radius: 50%;\n  margin: 20px auto;\n  position: relative;\n  box-sizing: content-box;\n}\n.sweet-alert .icon.error {\n  border-color: #d43f3a;\n}\n.sweet-alert .icon.error .x-mark {\n  position: relative;\n  display: block;\n}\n.sweet-alert .icon.error .line {\n  position: absolute;\n  height: 5px;\n  width: 47px;\n  background-color: #d9534f;\n  display: block;\n  top: 37px;\n  border-radius: 2px;\n}\n.sweet-alert .icon.error .line.left {\n  -webkit-transform: rotate(45deg);\n  transform: rotate(45deg);\n  left: 17px;\n}\n.sweet-alert .icon.error .line.right {\n  -webkit-transform: rotate(-45deg);\n  transform: rotate(-45deg);\n  right: 16px;\n}\n.sweet-alert .icon.warning {\n  border-color: #eea236;\n}\n.sweet-alert .icon.warning .body {\n  position: absolute;\n  width: 5px;\n  height: 47px;\n  left: 50%;\n  top: 10px;\n  border-radius: 2px;\n  margin-left: -2px;\n  background-color: #f0ad4e;\n}\n.sweet-alert .icon.warning .dot {\n  position: absolute;\n  width: 7px;\n  height: 7px;\n  border-radius: 50%;\n  margin-left: -3px;\n  left: 50%;\n  bottom: 10px;\n  background-color: #f0ad4e;\n}\n.sweet-alert .icon.info {\n  border-color: #46b8da;\n}\n.sweet-alert .icon.info::before {\n  content: \"\";\n  position: absolute;\n  width: 5px;\n  height: 29px;\n  left: 50%;\n  bottom: 17px;\n  border-radius: 2px;\n  margin-left: -2px;\n  background-color: #5bc0de;\n}\n.sweet-alert .icon.info::after {\n  content: \"\";\n  position: absolute;\n  width: 7px;\n  height: 7px;\n  border-radius: 50%;\n  margin-left: -3px;\n  top: 19px;\n  background-color: #5bc0de;\n}\n.sweet-alert .icon.success {\n  border-color: #4cae4c;\n}\n.sweet-alert .icon.success::before,\n.sweet-alert .icon.success::after {\n  content: '';\n  border-radius: 50%;\n  position: absolute;\n  width: 60px;\n  height: 120px;\n  background: white;\n  -webkit-transform: rotate(45deg);\n  transform: rotate(45deg);\n}\n.sweet-alert .icon.success::before {\n  border-radius: 120px 0 0 120px;\n  top: -7px;\n  left: -33px;\n  -webkit-transform: rotate(-45deg);\n  transform: rotate(-45deg);\n  -webkit-transform-origin: 60px 60px;\n  transform-origin: 60px 60px;\n}\n.sweet-alert .icon.success::after {\n  border-radius: 0 120px 120px 0;\n  top: -11px;\n  left: 30px;\n  -webkit-transform: rotate(-45deg);\n  transform: rotate(-45deg);\n  -webkit-transform-origin: 0px 60px;\n  transform-origin: 0px 60px;\n}\n.sweet-alert .icon.success .placeholder {\n  width: 80px;\n  height: 80px;\n  border: 4px solid rgba(92, 184, 92, 0.2);\n  border-radius: 50%;\n  box-sizing: content-box;\n  position: absolute;\n  left: -4px;\n  top: -4px;\n  z-index: 2;\n}\n.sweet-alert .icon.success .fix {\n  width: 5px;\n  height: 90px;\n  background-color: #ffffff;\n  position: absolute;\n  left: 28px;\n  top: 8px;\n  z-index: 1;\n  -webkit-transform: rotate(-45deg);\n  transform: rotate(-45deg);\n}\n.sweet-alert .icon.success .line {\n  height: 5px;\n  background-color: #5cb85c;\n  display: block;\n  border-radius: 2px;\n  position: absolute;\n  z-index: 2;\n}\n.sweet-alert .icon.success .line.tip {\n  width: 25px;\n  left: 14px;\n  top: 46px;\n  -webkit-transform: rotate(45deg);\n  transform: rotate(45deg);\n}\n.sweet-alert .icon.success .line.long {\n  width: 47px;\n  right: 8px;\n  top: 38px;\n  -webkit-transform: rotate(-45deg);\n  transform: rotate(-45deg);\n}\n.sweet-alert .icon.custom {\n  background-size: contain;\n  border-radius: 0;\n  border: none;\n  background-position: center center;\n  background-repeat: no-repeat;\n}\n.sweet-alert .btn-default:focus {\n  border-color: #cccccc;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(204, 204, 204, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(204, 204, 204, 0.6);\n}\n.sweet-alert .btn-success:focus {\n  border-color: #4cae4c;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(76, 174, 76, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(76, 174, 76, 0.6);\n}\n.sweet-alert .btn-info:focus {\n  border-color: #46b8da;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(70, 184, 218, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(70, 184, 218, 0.6);\n}\n.sweet-alert .btn-danger:focus {\n  border-color: #d43f3a;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(212, 63, 58, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(212, 63, 58, 0.6);\n}\n.sweet-alert .btn-warning:focus {\n  border-color: #eea236;\n  outline: 0;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(238, 162, 54, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(238, 162, 54, 0.6);\n}\n.sweet-alert button::-moz-focus-inner {\n  border: 0;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert.js",
    "content": "// SweetAlert\n// 2014 (c) - Tristan Edwards\n// github.com/t4t5/sweetalert\n(function(window, document) {\n\n  var modalClass   = '.sweet-alert',\n      overlayClass = '.sweet-overlay',\n      alertTypes   = ['error', 'warning', 'info', 'success'],\n      defaultParams = {\n        title: '',\n        text: '',\n        type: null,\n        allowOutsideClick: false,\n        showCancelButton: false,\n        showConfirmButton: true,\n        closeOnConfirm: true,\n        closeOnCancel: true,\n        confirmButtonText: 'OK',\n        confirmButtonClass: 'btn-primary',\n        cancelButtonText: 'Cancel',\n        cancelButtonClass: 'btn-default',\n        containerClass: '',\n        titleClass: '',\n        textClass: '',\n        imageUrl: null,\n        imageSize: null,\n        timer: null\n      };\n\n\n  /*\n   * Manipulate DOM\n   */\n\n  var getModal = function() {\n      return document.querySelector(modalClass);\n    },\n    getOverlay = function() {\n      return document.querySelector(overlayClass);\n    },\n    hasClass = function(elem, className) {\n      return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');\n    },\n    addClass = function(elem, className) {\n      if (className && !hasClass(elem, className)) {\n        elem.className += ' ' + className;\n      }\n    },\n    removeClass = function(elem, className) {\n      var newClass = ' ' + elem.className.replace(/[\\t\\r\\n]/g, ' ') + ' ';\n      if (hasClass(elem, className)) {\n        while (newClass.indexOf(' ' + className + ' ') >= 0) {\n          newClass = newClass.replace(' ' + className + ' ', ' ');\n        }\n        elem.className = newClass.replace(/^\\s+|\\s+$/g, '');\n      }\n    },\n    escapeHtml = function(str) {\n      var div = document.createElement('div');\n      div.appendChild(document.createTextNode(str));\n      return div.innerHTML;\n    },\n    _show = function(elem) {\n      elem.style.opacity = '';\n      elem.style.display = 'block';\n    },\n    show = function(elems) {\n      if (elems && !elems.length) {\n        return _show(elems);\n      }\n      for (var i = 0; i < elems.length; ++i) {\n        _show(elems[i]);\n      }\n    },\n    _hide = function(elem) {\n      elem.style.opacity = '';\n      elem.style.display = 'none';\n    },\n    hide = function(elems) {\n      if (elems && !elems.length) {\n        return _hide(elems);\n      }\n      for (var i = 0; i < elems.length; ++i) {\n        _hide(elems[i]);\n      }\n    },\n    isDescendant = function(parent, child) {\n      var node = child.parentNode;\n      while (node !== null) {\n        if (node === parent) {\n          return true;\n        }\n        node = node.parentNode;\n      }\n      return false;\n    },\n    getTopMargin = function(elem) {\n      elem.style.left = '-9999px';\n      elem.style.display = 'block';\n\n      var height = elem.clientHeight;\n      var padding = parseInt(getComputedStyle(elem).getPropertyValue('padding'), 10);\n\n      elem.style.left = '';\n      elem.style.display = 'none';\n      return ('-' + parseInt(height / 2 + padding) + 'px');\n    },\n    fadeIn = function(elem, interval) {\n      if(+elem.style.opacity < 1) {\n        interval = interval || 16;\n        elem.style.opacity = 0;\n        elem.style.display = 'block';\n        var last = +new Date();\n        var tick = function() {\n          elem.style.opacity = +elem.style.opacity + (new Date() - last) / 100;\n          last = +new Date();\n\n          if (+elem.style.opacity < 1) {\n            setTimeout(tick, interval);\n          }\n        };\n        tick();\n      }\n    },\n    fadeOut = function(elem, interval) {\n      interval = interval || 16;\n      elem.style.opacity = 1;\n      var last = +new Date();\n      var tick = function() {\n        elem.style.opacity = +elem.style.opacity - (new Date() - last) / 100;\n        last = +new Date();\n\n        if (+elem.style.opacity > 0) {\n          setTimeout(tick, interval);\n        } else {\n          elem.style.display = 'none';\n        }\n      };\n      tick();\n    },\n    fireClick = function(node) {\n      // Taken from http://www.nonobtrusive.com/2011/11/29/programatically-fire-crossbrowser-click-event-with-javascript/\n      // Then fixed for today's Chrome browser.\n      if (MouseEvent) {\n        // Up-to-date approach\n        var mevt = new MouseEvent('click', {\n          view: window,\n          bubbles: false,\n          cancelable: true\n        });\n        node.dispatchEvent(mevt);\n      } else if ( document.createEvent ) {\n        // Fallback\n        var evt = document.createEvent('MouseEvents');\n        evt.initEvent('click', false, false);\n        node.dispatchEvent(evt);\n      } else if( document.createEventObject ) {\n        node.fireEvent('onclick') ;\n      } else if (typeof node.onclick === 'function' ) {\n        node.onclick();\n      }\n    },\n    stopEventPropagation = function(e) {\n      // In particular, make sure the space bar doesn't scroll the main window.\n      if (typeof e.stopPropagation === 'function') {\n        e.stopPropagation();\n        e.preventDefault();\n      } else if (window.event && window.event.hasOwnProperty('cancelBubble')) {\n        window.event.cancelBubble = true;\n      }\n    };\n\n  // Remember state in cases where opening and handling a modal will fiddle with it.\n  var previousActiveElement,\n      previousDocumentClick,\n      previousWindowKeyDown,\n      lastFocusedButton;\n\n  /*\n   * Add modal + overlay to DOM\n   */\n\n  window.sweetAlertInitialize = function() {\n    var sweetHTML = '<div class=\"sweet-overlay\" tabIndex=\"-1\"></div><div class=\"sweet-alert\" tabIndex=\"-1\"><div class=\"icon error\"><span class=\"x-mark\"><span class=\"line left\"></span><span class=\"line right\"></span></span></div><div class=\"icon warning\"> <span class=\"body\"></span> <span class=\"dot\"></span> </div> <div class=\"icon info\"></div> <div class=\"icon success\"> <span class=\"line tip\"></span> <span class=\"line long\"></span> <div class=\"placeholder\"></div> <div class=\"fix\"></div> </div> <div class=\"icon custom\"></div> <h2>Title</h2><p class=\"lead text-muted\">Text</p><p><button class=\"cancel btn btn-lg\" tabIndex=\"2\">Cancel</button> <button class=\"confirm btn btn-lg\" tabIndex=\"1\">OK</button></p></div>',\n        sweetWrap = document.createElement('div');\n\n    sweetWrap.innerHTML = sweetHTML;\n\n    // For readability: check sweet-alert.html\n    document.body.appendChild(sweetWrap);\n\n    // For development use only!\n    /*jQuery.ajax({\n      url: '../lib/sweet-alert.html', // Change path depending on file location\n      dataType: 'html'\n    })\n    .done(function(html) {\n      jQuery('body').append(html);\n    });*/\n  }\n\n  /*\n   * Global sweetAlert function\n   */\n\n  window.sweetAlert = window.swal = function() {\n    if (arguments[0] === undefined) {\n      window.console.error('sweetAlert expects at least 1 attribute!');\n      return false;\n    }\n\n    var params = extend({}, defaultParams);\n\n    switch (typeof arguments[0]) {\n\n      case 'string':\n        params.title = arguments[0];\n        params.text  = arguments[1] || '';\n        params.type  = arguments[2] || '';\n\n        break;\n\n      case 'object':\n        if (arguments[0].title === undefined) {\n          window.console.error('Missing \"title\" argument!');\n          return false;\n        }\n\n        params.title              = arguments[0].title;\n        params.text               = arguments[0].text || defaultParams.text;\n        params.type               = arguments[0].type || defaultParams.type;\n        params.allowOutsideClick  = arguments[0].allowOutsideClick || defaultParams.allowOutsideClick;\n        params.showCancelButton   = arguments[0].showCancelButton !== undefined ? arguments[0].showCancelButton : defaultParams.showCancelButton;\n        params.showConfirmButton  = arguments[0].showConfirmButton !== undefined ? arguments[0].showConfirmButton : defaultParams.showConfirmButton;\n        params.closeOnConfirm     = arguments[0].closeOnConfirm !== undefined ? arguments[0].closeOnConfirm : defaultParams.closeOnConfirm;\n        params.closeOnCancel      = arguments[0].closeOnCancel !== undefined ? arguments[0].closeOnCancel : defaultParams.closeOnCancel;\n        params.timer              = arguments[0].timer || defaultParams.timer;\n\n        // Show \"Confirm\" instead of \"OK\" if cancel button is visible\n        params.confirmButtonText  = (defaultParams.showCancelButton) ? 'Confirm' : defaultParams.confirmButtonText;\n        params.confirmButtonText  = arguments[0].confirmButtonText || defaultParams.confirmButtonText;\n        params.confirmButtonClass = arguments[0].confirmButtonClass || (arguments[0].type ? 'btn-' + arguments[0].type : null) || defaultParams.confirmButtonClass;\n        params.cancelButtonText   = arguments[0].cancelButtonText || defaultParams.cancelButtonText;\n        params.cancelButtonClass  = arguments[0].cancelButtonClass || defaultParams.cancelButtonClass;\n        params.containerClass     = arguments[0].containerClass || defaultParams.containerClass;\n        params.titleClass         = arguments[0].titleClass || defaultParams.titleClass;\n        params.textClass          = arguments[0].textClass || defaultParams.textClass;\n        params.imageUrl           = arguments[0].imageUrl || defaultParams.imageUrl;\n        params.imageSize          = arguments[0].imageSize || defaultParams.imageSize;\n        params.doneFunction       = arguments[1] || null;\n\n        break;\n\n      default:\n        window.console.error('Unexpected type of argument! Expected \"string\" or \"object\", got ' + typeof arguments[0]);\n        return false;\n\n    }\n\n    setParameters(params);\n    fixVerticalPosition();\n    openModal();\n\n\n    // Modal interactions\n    var modal = getModal();\n\n    // Mouse interactions\n    var onButtonEvent = function(e) {\n\n      var target = e.target || e.srcElement,\n          targetedConfirm    = (target.className.indexOf('confirm') > -1),\n          modalIsVisible     = hasClass(modal, 'visible'),\n          doneFunctionExists = (params.doneFunction && modal.getAttribute('data-has-done-function') === 'true');\n\n      switch (e.type) {\n        case (\"click\"):\n          if (targetedConfirm && doneFunctionExists && modalIsVisible) { // Clicked \"confirm\"\n\n            params.doneFunction(true);\n\n            if (params.closeOnConfirm) {\n              closeModal();\n            }\n          } else if (doneFunctionExists && modalIsVisible) { // Clicked \"cancel\"\n\n            // Check if callback function expects a parameter (to track cancel actions)\n            var functionAsStr          = String(params.doneFunction).replace(/\\s/g, '');\n            var functionHandlesCancel  = functionAsStr.substring(0, 9) === \"function(\" && functionAsStr.substring(9, 10) !== \")\";\n\n            if (functionHandlesCancel) {\n              params.doneFunction(false);\n            }\n\n            if (params.closeOnCancel) {\n              closeModal();\n            }\n          } else {\n            closeModal();\n          }\n\n          break;\n      }\n    };\n\n    var $buttons = modal.querySelectorAll('button');\n    for (var i = 0; i < $buttons.length; i++) {\n      $buttons[i].onclick     = onButtonEvent;\n    }\n\n    // Remember the current document.onclick event.\n    previousDocumentClick = document.onclick;\n    document.onclick = function(e) {\n      var target = e.target || e.srcElement;\n\n      var clickedOnModal = (modal === target),\n          clickedOnModalChild = isDescendant(modal, e.target),\n          modalIsVisible = hasClass(modal, 'visible'),\n          outsideClickIsAllowed = modal.getAttribute('data-allow-ouside-click') === 'true';\n\n      if (!clickedOnModal && !clickedOnModalChild && modalIsVisible && outsideClickIsAllowed) {\n        closeModal();\n      }\n    };\n\n\n    // Keyboard interactions\n    var $okButton = modal.querySelector('button.confirm'),\n        $cancelButton = modal.querySelector('button.cancel'),\n        $modalButtons = modal.querySelectorAll('button:not([type=hidden])');\n\n\n    function handleKeyDown(e) {\n      var keyCode = e.keyCode || e.which;\n\n      if ([9,13,32,27].indexOf(keyCode) === -1) {\n        // Don't do work on keys we don't care about.\n        return;\n      }\n\n      var $targetElement = e.target || e.srcElement;\n\n      var btnIndex = -1; // Find the button - note, this is a nodelist, not an array.\n      for (var i = 0; i < $modalButtons.length; i++) {\n        if ($targetElement === $modalButtons[i]) {\n          btnIndex = i;\n          break;\n        }\n      }\n\n      if (keyCode === 9) {\n        // TAB\n        if (btnIndex === -1) {\n          // No button focused. Jump to the confirm button.\n          $targetElement = $okButton;\n        } else {\n          // Cycle to the next button\n          if (btnIndex === $modalButtons.length - 1) {\n            $targetElement = $modalButtons[0];\n          } else {\n            $targetElement = $modalButtons[btnIndex + 1];\n          }\n        }\n\n        stopEventPropagation(e);\n        $targetElement.focus();\n\n      } else {\n        if (keyCode === 13 || keyCode === 32) {\n            if (btnIndex === -1) {\n              // ENTER/SPACE clicked outside of a button.\n              $targetElement = $okButton;\n            } else {\n              // Do nothing - let the browser handle it.\n              $targetElement = undefined;\n            }\n        } else if (keyCode === 27 && !($cancelButton.hidden || $cancelButton.style.display === 'none')) {\n          // ESC to cancel only if there's a cancel button displayed (like the alert() window).\n          $targetElement = $cancelButton;\n        } else {\n          // Fallback - let the browser handle it.\n          $targetElement = undefined;\n        }\n\n        if ($targetElement !== undefined) {\n          fireClick($targetElement, e);\n        }\n      }\n    }\n\n    previousWindowKeyDown = window.onkeydown;\n    window.onkeydown = handleKeyDown;\n\n    function handleOnBlur(e) {\n      var $targetElement = e.target || e.srcElement,\n          $focusElement = e.relatedTarget,\n          modalIsVisible = hasClass(modal, 'visible');\n\n      if (modalIsVisible) {\n        var btnIndex = -1; // Find the button - note, this is a nodelist, not an array.\n\n        if ($focusElement !== null) {\n          // If we picked something in the DOM to focus to, let's see if it was a button.\n          for (var i = 0; i < $modalButtons.length; i++) {\n            if ($focusElement === $modalButtons[i]) {\n              btnIndex = i;\n              break;\n            }\n          }\n\n          if (btnIndex === -1) {\n            // Something in the dom, but not a visible button. Focus back on the button.\n            $targetElement.focus();\n          }\n        } else {\n          // Exiting the DOM (e.g. clicked in the URL bar);\n          lastFocusedButton = $targetElement;\n        }\n      }\n    }\n\n    $okButton.onblur = handleOnBlur;\n    $cancelButton.onblur = handleOnBlur;\n\n    window.onfocus = function() {\n      // When the user has focused away and focused back from the whole window.\n      window.setTimeout(function() {\n        // Put in a timeout to jump out of the event sequence. Calling focus() in the event\n        // sequence confuses things.\n        if (lastFocusedButton !== undefined) {\n          lastFocusedButton.focus();\n          lastFocusedButton = undefined;\n        }\n      }, 0);\n    };\n  };\n\n  /**\n   * Set default params for each popup\n   * @param {Object} userParams\n   */\n  window.swal.setDefaults = function(userParams) {\n    if (!userParams) {\n      throw new Error('userParams is required');\n    }\n    if (typeof userParams !== 'object') {\n      throw new Error('userParams has to be a object');\n    }\n\n    extend(defaultParams, userParams);\n  };\n\n  /**\n   * Closes the current modal\n   */\n  window.swal.close = function() {\n    closeModal();\n  }\n\n  /*\n   * Set type, text and actions on modal\n   */\n\n  function setParameters(params) {\n    var modal = getModal();\n\n    var $title = modal.querySelector('h2'),\n        $text = modal.querySelector('p'),\n        $cancelBtn = modal.querySelector('button.cancel'),\n        $confirmBtn = modal.querySelector('button.confirm');\n\n    // Title\n    $title.innerHTML = escapeHtml(params.title).split(\"\\n\").join(\"<br>\");\n\n    // Text\n    $text.innerHTML = escapeHtml(params.text || '').split(\"\\n\").join(\"<br>\");\n    if (params.text) {\n      show($text);\n    }\n\n    // Icon\n    hide(modal.querySelectorAll('.icon'));\n    if (params.type) {\n      var validType = false;\n      for (var i = 0; i < alertTypes.length; i++) {\n        if (params.type === alertTypes[i]) {\n          validType = true;\n          break;\n        }\n      }\n      if (!validType) {\n        window.console.error('Unknown alert type: ' + params.type);\n        return false;\n      }\n      var $icon = modal.querySelector('.icon.' + params.type);\n      show($icon);\n\n      // Animate icon\n      switch (params.type) {\n        case \"success\":\n          addClass($icon, 'animate');\n          addClass($icon.querySelector('.tip'), 'animateSuccessTip');\n          addClass($icon.querySelector('.long'), 'animateSuccessLong');\n          break;\n        case \"error\":\n          addClass($icon, 'animateErrorIcon');\n          addClass($icon.querySelector('.x-mark'), 'animateXMark');\n          break;\n        case \"warning\":\n          addClass($icon, 'pulseWarning');\n          addClass($icon.querySelector('.body'), 'pulseWarningIns');\n          addClass($icon.querySelector('.dot'), 'pulseWarningIns');\n          break;\n      }\n\n    }\n\n    // Custom image\n    if (params.imageUrl) {\n      var $customIcon = modal.querySelector('.icon.custom');\n\n      $customIcon.style.backgroundImage = 'url(' + params.imageUrl + ')';\n      show($customIcon);\n\n      var _imgWidth  = 80,\n          _imgHeight = 80;\n\n      if (params.imageSize) {\n        var imgWidth  = params.imageSize.split('x')[0];\n        var imgHeight = params.imageSize.split('x')[1];\n\n        if (!imgWidth || !imgHeight) {\n          window.console.error(\"Parameter imageSize expects value with format WIDTHxHEIGHT, got \" + params.imageSize);\n        } else {\n          _imgWidth  = imgWidth;\n          _imgHeight = imgHeight;\n\n          $customIcon.css({\n            'width': imgWidth + 'px',\n            'height': imgHeight + 'px'\n          });\n        }\n      }\n      $customIcon.setAttribute('style', $customIcon.getAttribute('style') + 'width:' + _imgWidth + 'px; height:' + _imgHeight + 'px');\n    }\n\n    // Cancel button\n    modal.setAttribute('data-has-cancel-button', params.showCancelButton);\n    if (params.showCancelButton) {\n      $cancelBtn.style.display = 'inline-block';\n    } else {\n      hide($cancelBtn);\n    }\n    \n    //Confirm button\n    modal.setAttribute('data-has-confirm-button', params.showConfirmButton);\n    if (params.showConfirmButton) {\n      $confirmBtn.style.display = 'inline-block';\n    } else {\n      hide($confirmBtn);\n    }\n    \n\n    // Edit text on cancel and confirm buttons\n    if (params.cancelButtonText) {\n      $cancelBtn.innerHTML = escapeHtml(params.cancelButtonText);\n    }\n    if (params.confirmButtonText) {\n      $confirmBtn.innerHTML = escapeHtml(params.confirmButtonText);\n    }\n\n    // Reset confirm buttons to default class (Ugly fix)\n    $confirmBtn.className = 'confirm btn btn-lg';\n\n    // Attach selected class to the sweet alert modal\n    addClass(modal, params.containerClass);\n\n    // Set confirm button to selected class\n    addClass($confirmBtn, params.confirmButtonClass);\n\n    // Set cancel button to selected class\n    addClass($cancelBtn, params.cancelButtonClass);\n\n    // Set title to selected class\n    addClass($title, params.titleClass);\n\n    // Set text to selected class\n    addClass($text, params.textClass);\n\n    // Allow outside click?\n    modal.setAttribute('data-allow-ouside-click', params.allowOutsideClick);\n\n    // Done-function\n    var hasDoneFunction = (params.doneFunction) ? true : false;\n    modal.setAttribute('data-has-done-function', hasDoneFunction);\n\n    // Close timer\n    modal.setAttribute('data-timer', params.timer);\n  }\n\n\n  /*\n   * Set hover, active and focus-states for buttons (source: http://www.sitepoint.com/javascript-generate-lighter-darker-color)\n   */\n\n  function colorLuminance(hex, lum) {\n    // Validate hex string\n    hex = String(hex).replace(/[^0-9a-f]/gi, '');\n    if (hex.length < 6) {\n      hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];\n    }\n    lum = lum || 0;\n\n    // Convert to decimal and change luminosity\n    var rgb = \"#\", c, i;\n    for (i = 0; i < 3; i++) {\n      c = parseInt(hex.substr(i*2,2), 16);\n      c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);\n      rgb += (\"00\"+c).substr(c.length);\n    }\n\n    return rgb;\n  }\n\n  function extend(a, b){\n    for (var key in b) {\n      if (b.hasOwnProperty(key)) {\n        a[key] = b[key];\n      }\n    }\n\n    return a;\n  }\n\n  function hexToRgb(hex) {\n    var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n    return result ? parseInt(result[1], 16) + ', ' + parseInt(result[2], 16) + ', ' + parseInt(result[3], 16) : null;\n  }\n\n  // Add box-shadow style to button (depending on its chosen bg-color)\n  function setFocusStyle($button, bgColor) {\n    var rgbColor = hexToRgb(bgColor);\n    $button.style.boxShadow = '0 0 2px rgba(' + rgbColor +', 0.8), inset 0 0 0 1px rgba(0, 0, 0, 0.05)';\n  }\n\n\n  /*\n   * Animations\n   */\n\n  function openModal() {\n    var modal = getModal();\n    fadeIn(getOverlay(), 10);\n    show(modal);\n    addClass(modal, 'showSweetAlert');\n    removeClass(modal, 'hideSweetAlert');\n\n    previousActiveElement = document.activeElement;\n    var $okButton = modal.querySelector('button.confirm');\n    $okButton.focus();\n\n    setTimeout(function() {\n      addClass(modal, 'visible');\n    }, 500);\n\n    var timer = modal.getAttribute('data-timer');\n    if (timer !== \"null\" && timer !== \"\") {\n      setTimeout(function() {\n        closeModal();\n      }, timer);\n    }\n  }\n\n  function closeModal() {\n    var modal = getModal();\n    fadeOut(getOverlay(), 5);\n    fadeOut(modal, 5);\n    removeClass(modal, 'showSweetAlert');\n    addClass(modal, 'hideSweetAlert');\n    removeClass(modal, 'visible');\n\n\n    // Reset icon animations\n\n    var $successIcon = modal.querySelector('.icon.success');\n    removeClass($successIcon, 'animate');\n    removeClass($successIcon.querySelector('.tip'), 'animateSuccessTip');\n    removeClass($successIcon.querySelector('.long'), 'animateSuccessLong');\n\n    var $errorIcon = modal.querySelector('.icon.error');\n    removeClass($errorIcon, 'animateErrorIcon');\n    removeClass($errorIcon.querySelector('.x-mark'), 'animateXMark');\n\n    var $warningIcon = modal.querySelector('.icon.warning');\n    removeClass($warningIcon, 'pulseWarning');\n    removeClass($warningIcon.querySelector('.body'), 'pulseWarningIns');\n    removeClass($warningIcon.querySelector('.dot'), 'pulseWarningIns');\n\n\n    // Reset the page to its previous state\n    window.onkeydown = previousWindowKeyDown;\n    document.onclick = previousDocumentClick;\n    if (previousActiveElement) {\n      previousActiveElement.focus();\n    }\n    lastFocusedButton = undefined;\n  }\n\n\n  /*\n   * Set \"margin-top\"-property on modal based on its computed height\n   */\n\n  function fixVerticalPosition() {\n    var modal = getModal();\n    modal.style.marginTop = getTopMargin(getModal());\n  }\n\n\n  /*\n   * If library is injected after page has loaded\n   */\n\n  (function () {\n    if (document.readyState === \"complete\" || document.readyState === \"interactive\" && document.body) {\n      sweetAlertInitialize();\n    } else {\n      if (document.addEventListener) {\n        document.addEventListener('DOMContentLoaded', function handler() {\n          document.removeEventListener('DOMContentLoaded', handler, false);\n          sweetAlertInitialize();\n        }, false);\n      } else if (document.attachEvent) {\n        document.attachEvent('onreadystatechange', function handler() {\n          if (document.readyState === 'complete') {\n            document.detachEvent('onreadystatechange', handler);\n            sweetAlertInitialize();\n          }\n        });\n      }\n    }\n  })();\n\n})(window, document);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/bootstrap-sweetalert/lib/sweet-alert.less",
    "content": "// SweetAlert\n// 2014 (c) - Tristan Edwards\n// github.com/t4t5/sweetalert\n\n@import \"sweet-alert-animations\";\n\n.sweet-overlay {\n  background-color: fade(#000, 40%);\n\n  position: fixed;\n  left: 0;\n  right: 0;\n  top: 0;\n  bottom: 0;\n\n  display: none;\n  z-index: @zindex-modal;\n}\n\n.sweet-alert {\n  @width: 478px;\n  @padding: 17px;\n\n  background-color: @body-bg;\n  width: @width;\n  padding: @padding;\n  border-radius: 5px;\n  text-align: center;\n\n  position: fixed;\n  left: 50%;\n  top: 50%;\n  margin-left: -(@width / 2 + @padding);\n  margin-top: -200px;\n\n  overflow: hidden;\n  display: none;\n  z-index: 2000;\n\n  @media all and (max-width: @screen-xs-max) {\n    width: auto;\n    margin-left: 0;\n    margin-right: 0;\n\n    left: (@grid-gutter-width / 2);\n    right: (@grid-gutter-width / 2);\n  }\n\n  .icon {\n    width: 80px;\n    height: 80px;\n    border: 4px solid gray;\n    border-radius: 50%;\n    margin: 20px auto;\n    position: relative;\n    box-sizing: content-box;\n\n    &.error {\n      border-color: @btn-danger-border;\n\n      .x-mark {\n        position: relative;\n        display: block;\n      }\n\n      .line {\n        position: absolute;\n        height: 5px;\n        width: 47px;\n        background-color: @btn-danger-bg;\n        display: block;\n        top: 37px;\n        border-radius: 2px;\n\n        &.left {\n          -webkit-transform: rotate(45deg);\n          transform: rotate(45deg);\n          left: 17px;\n        }\n        &.right {\n          -webkit-transform: rotate(-45deg);\n          transform: rotate(-45deg);\n          right: 16px;\n        }\n      }\n    }\n    &.warning {\n      border-color: @btn-warning-border;\n\n      .body { // Exclamation mark body\n        position: absolute;\n        width: 5px;\n        height: 47px;\n        left: 50%;\n        top: 10px;\n        border-radius: 2px;\n        margin-left: -2px;\n        background-color: @btn-warning-bg;\n      }\n      .dot { // Exclamation mark dot\n        position: absolute;\n        width: 7px;\n        height: 7px;\n        border-radius: 50%;\n        margin-left: -3px;\n        left: 50%;\n        bottom: 10px;\n        background-color: @btn-warning-bg;\n      }\n    }\n    &.info {\n      border-color: @btn-info-border;\n\n      &::before { // i-letter body\n        content: \"\";\n        position: absolute;\n        width: 5px;\n        height: 29px;\n        left: 50%;\n        bottom: 17px;\n        border-radius: 2px;\n        margin-left: -2px;\n        background-color: @btn-info-bg;\n      }\n      &::after { // i-letter dot\n        content: \"\";\n        position: absolute;\n        width: 7px;\n        height: 7px;\n        border-radius: 50%;\n        margin-left: -3px;\n        top: 19px;\n        background-color: @btn-info-bg;\n      }\n    }\n    &.success {\n      border-color: @btn-success-border;\n\n      &::before, &::after { // Emulate moving circular line\n        content: '';\n        border-radius: 50%;\n        position: absolute;\n        width: 60px;\n        height: 120px;\n        background: white;\n        -webkit-transform: rotate(45deg);\n                transform: rotate(45deg);\n      }\n      &::before {\n        border-radius: 120px 0 0 120px;\n        top: -7px;\n        left: -33px;\n\n        -webkit-transform: rotate(-45deg);\n                transform: rotate(-45deg);\n        -webkit-transform-origin: 60px 60px;\n                transform-origin: 60px 60px;\n      }\n      &::after {\n        border-radius: 0 120px 120px 0;\n        top: -11px;\n        left: 30px;\n\n        -webkit-transform: rotate(-45deg);\n                transform: rotate(-45deg);\n        -webkit-transform-origin: 0px 60px;\n                transform-origin: 0px 60px;\n      }\n\n      .placeholder { // Ring\n        width: 80px;\n        height: 80px;\n        border: 4px solid fade(@brand-success, 20%);\n        border-radius: 50%;\n        box-sizing: content-box;\n\n        position: absolute;\n        left: -4px;\n        top: -4px;\n        z-index: 2;\n      }\n\n      .fix {  // Hide corners left from animation\n        width: 5px;\n        height: 90px;\n        background-color: @body-bg;\n\n        position: absolute;\n        left: 28px;\n        top: 8px;\n        z-index: 1;\n\n        -webkit-transform: rotate(-45deg);\n                transform: rotate(-45deg);\n      }\n\n      .line {\n        height: 5px;\n        background-color: @btn-success-bg;\n        display: block;\n        border-radius: 2px;\n\n        position: absolute;\n        z-index: 2;\n\n        &.tip {\n          width: 25px;\n\n          left: 14px;\n          top: 46px;\n\n          -webkit-transform: rotate(45deg);\n                  transform: rotate(45deg);\n        }\n        &.long {\n          width: 47px;\n\n          right: 8px;\n          top: 38px;\n\n          -webkit-transform: rotate(-45deg);\n                  transform: rotate(-45deg);\n        }\n      }\n    }\n    &.custom {\n      background-size: contain;\n      border-radius: 0;\n      border: none;\n      background-position: center center;\n      background-repeat: no-repeat;\n    }\n  }\n\n  .btn-default {\n    .form-control-focus(@btn-default-border);\n  }\n  .btn-success {\n    .form-control-focus(@btn-success-border);\n  }\n  .btn-info {\n    .form-control-focus(@btn-info-border);\n  }\n  .btn-danger {\n    .form-control-focus(@btn-danger-border);\n  }\n  .btn-warning {\n    .form-control-focus(@btn-warning-border);\n  }\n\n  button::-moz-focus-inner {\n    border: 0;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/eonasdan-bootstrap-datetimepicker/4.7.14/css/bootstrap-datetimepicker.css",
    "content": "/*!\n * Datetimepicker for Bootstrap 3\n * ! version : 4.7.14\n * https://github.com/Eonasdan/bootstrap-datetimepicker/\n */\n.bootstrap-datetimepicker-widget {\n  list-style: none;\n}\n.bootstrap-datetimepicker-widget.dropdown-menu {\n  margin: 2px 0;\n  padding: 4px;\n  width: 19em;\n}\n@media (min-width: 768px) {\n  .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs {\n    width: 38em;\n  }\n}\n@media (min-width: 992px) {\n  .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs {\n    width: 38em;\n  }\n}\n@media (min-width: 1200px) {\n  .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs {\n    width: 38em;\n  }\n}\n.bootstrap-datetimepicker-widget.dropdown-menu:before,\n.bootstrap-datetimepicker-widget.dropdown-menu:after {\n  content: '';\n  display: inline-block;\n  position: absolute;\n}\n.bootstrap-datetimepicker-widget.dropdown-menu.bottom:before {\n  border-left: 7px solid transparent;\n  border-right: 7px solid transparent;\n  border-bottom: 7px solid #cccccc;\n  border-bottom-color: rgba(0, 0, 0, 0.2);\n  top: -7px;\n  left: 7px;\n}\n.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after {\n  border-left: 6px solid transparent;\n  border-right: 6px solid transparent;\n  border-bottom: 6px solid white;\n  top: -6px;\n  left: 8px;\n}\n.bootstrap-datetimepicker-widget.dropdown-menu.top:before {\n  border-left: 7px solid transparent;\n  border-right: 7px solid transparent;\n  border-top: 7px solid #cccccc;\n  border-top-color: rgba(0, 0, 0, 0.2);\n  bottom: -7px;\n  left: 6px;\n}\n.bootstrap-datetimepicker-widget.dropdown-menu.top:after {\n  border-left: 6px solid transparent;\n  border-right: 6px solid transparent;\n  border-top: 6px solid white;\n  bottom: -6px;\n  left: 7px;\n}\n.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:before {\n  left: auto;\n  right: 6px;\n}\n.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:after {\n  left: auto;\n  right: 7px;\n}\n.bootstrap-datetimepicker-widget .list-unstyled {\n  margin: 0;\n}\n.bootstrap-datetimepicker-widget a[data-action] {\n  padding: 6px 0;\n}\n.bootstrap-datetimepicker-widget a[data-action]:active {\n  box-shadow: none;\n}\n.bootstrap-datetimepicker-widget .timepicker-hour,\n.bootstrap-datetimepicker-widget .timepicker-minute,\n.bootstrap-datetimepicker-widget .timepicker-second {\n  width: 54px;\n  font-weight: bold;\n  font-size: 1.2em;\n  margin: 0;\n}\n.bootstrap-datetimepicker-widget button[data-action] {\n  padding: 6px;\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"incrementHours\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Increment Hours\";\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"incrementMinutes\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Increment Minutes\";\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"decrementHours\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Decrement Hours\";\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"decrementMinutes\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Decrement Minutes\";\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"showHours\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Show Hours\";\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"showMinutes\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Show Minutes\";\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"togglePeriod\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Toggle AM/PM\";\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"clear\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Clear the picker\";\n}\n.bootstrap-datetimepicker-widget .btn[data-action=\"today\"]::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Set the date to today\";\n}\n.bootstrap-datetimepicker-widget .picker-switch {\n  text-align: center;\n}\n.bootstrap-datetimepicker-widget .picker-switch::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Toggle Date and Time Screens\";\n}\n.bootstrap-datetimepicker-widget .picker-switch td {\n  padding: 0;\n  margin: 0;\n  height: auto;\n  width: auto;\n  line-height: inherit;\n}\n.bootstrap-datetimepicker-widget .picker-switch td span {\n  line-height: 2.5;\n  height: 2.5em;\n  width: 100%;\n}\n.bootstrap-datetimepicker-widget table {\n  width: 100%;\n  margin: 0;\n}\n.bootstrap-datetimepicker-widget table td,\n.bootstrap-datetimepicker-widget table th {\n  text-align: center;\n  border-radius: 4px;\n}\n.bootstrap-datetimepicker-widget table th {\n  height: 20px;\n  line-height: 20px;\n  width: 20px;\n}\n.bootstrap-datetimepicker-widget table th.picker-switch {\n  width: 145px;\n}\n.bootstrap-datetimepicker-widget table th.disabled,\n.bootstrap-datetimepicker-widget table th.disabled:hover {\n  background: none;\n  color: #777777;\n  cursor: not-allowed;\n}\n.bootstrap-datetimepicker-widget table th.prev::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Previous Month\";\n}\n.bootstrap-datetimepicker-widget table th.next::after {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n  content: \"Next Month\";\n}\n.bootstrap-datetimepicker-widget table thead tr:first-child th {\n  cursor: pointer;\n}\n.bootstrap-datetimepicker-widget table thead tr:first-child th:hover {\n  background: #eeeeee;\n}\n.bootstrap-datetimepicker-widget table td {\n  height: 54px;\n  line-height: 54px;\n  width: 54px;\n}\n.bootstrap-datetimepicker-widget table td.cw {\n  font-size: .8em;\n  height: 20px;\n  line-height: 20px;\n  color: #777777;\n}\n.bootstrap-datetimepicker-widget table td.day {\n  height: 20px;\n  line-height: 20px;\n  width: 20px;\n}\n.bootstrap-datetimepicker-widget table td.day:hover,\n.bootstrap-datetimepicker-widget table td.hour:hover,\n.bootstrap-datetimepicker-widget table td.minute:hover,\n.bootstrap-datetimepicker-widget table td.second:hover {\n  background: #eeeeee;\n  cursor: pointer;\n}\n.bootstrap-datetimepicker-widget table td.old,\n.bootstrap-datetimepicker-widget table td.new {\n  color: #777777;\n}\n.bootstrap-datetimepicker-widget table td.today {\n  position: relative;\n}\n.bootstrap-datetimepicker-widget table td.today:before {\n  content: '';\n  display: inline-block;\n  border: 0 0 7px 7px solid transparent;\n  border-bottom-color: #337ab7;\n  border-top-color: rgba(0, 0, 0, 0.2);\n  position: absolute;\n  bottom: 4px;\n  right: 4px;\n}\n.bootstrap-datetimepicker-widget table td.active,\n.bootstrap-datetimepicker-widget table td.active:hover {\n  background-color: #337ab7;\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.bootstrap-datetimepicker-widget table td.active.today:before {\n  border-bottom-color: #fff;\n}\n.bootstrap-datetimepicker-widget table td.disabled,\n.bootstrap-datetimepicker-widget table td.disabled:hover {\n  background: none;\n  color: #777777;\n  cursor: not-allowed;\n}\n.bootstrap-datetimepicker-widget table td span {\n  display: inline-block;\n  width: 54px;\n  height: 54px;\n  line-height: 54px;\n  margin: 2px 1.5px;\n  cursor: pointer;\n  border-radius: 4px;\n}\n.bootstrap-datetimepicker-widget table td span:hover {\n  background: #eeeeee;\n}\n.bootstrap-datetimepicker-widget table td span.active {\n  background-color: #337ab7;\n  color: #ffffff;\n  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.bootstrap-datetimepicker-widget table td span.old {\n  color: #777777;\n}\n.bootstrap-datetimepicker-widget table td span.disabled,\n.bootstrap-datetimepicker-widget table td span.disabled:hover {\n  background: none;\n  color: #777777;\n  cursor: not-allowed;\n}\n.bootstrap-datetimepicker-widget.usetwentyfour td.hour {\n  height: 27px;\n  line-height: 27px;\n}\n.input-group.date .input-group-addon {\n  cursor: pointer;\n}\n.sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/flot/jquery.flot.js",
    "content": "/* Javascript plotting library for jQuery, version 0.8.3.\n\nCopyright (c) 2007-2014 IOLA and Ole Laursen.\nLicensed under the MIT license.\n\n*/\n\n// first an inline dependency, jquery.colorhelpers.js, we inline it here\n// for convenience\n\n/* Plugin for jQuery for working with colors.\n *\n * Version 1.1.\n *\n * Inspiration from jQuery color animation plugin by John Resig.\n *\n * Released under the MIT license by Ole Laursen, October 2009.\n *\n * Examples:\n *\n *   $.color.parse(\"#fff\").scale('rgb', 0.25).add('a', -0.5).toString()\n *   var c = $.color.extract($(\"#mydiv\"), 'background-color');\n *   console.log(c.r, c.g, c.b, c.a);\n *   $.color.make(100, 50, 25, 0.4).toString() // returns \"rgba(100,50,25,0.4)\"\n *\n * Note that .scale() and .add() return the same modified object\n * instead of making a new one.\n *\n * V. 1.1: Fix error handling so e.g. parsing an empty string does\n * produce a color rather than just crashing.\n */\n(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return\"rgb(\"+[o.r,o.g,o.b].join(\",\")+\")\"}else{return\"rgba(\"+[o.r,o.g,o.b,o.a].join(\",\")+\")\"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=\"\"&&c!=\"transparent\")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),\"body\"));if(c==\"rgba(0, 0, 0, 0)\")c=\"transparent\";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*\\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\\(\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]{1,3})\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*\\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\\(\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\%\\s*,\\s*([0-9]+(?:\\.[0-9]+)?)\\s*\\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name==\"transparent\")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);\n\n// the actual Flot code\n(function($) {\n\n\t// Cache the prototype hasOwnProperty for faster access\n\n\tvar hasOwnProperty = Object.prototype.hasOwnProperty;\n\n    // A shim to provide 'detach' to jQuery versions prior to 1.4.  Using a DOM\n    // operation produces the same effect as detach, i.e. removing the element\n    // without touching its jQuery data.\n\n    // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+.\n\n    if (!$.fn.detach) {\n        $.fn.detach = function() {\n            return this.each(function() {\n                if (this.parentNode) {\n                    this.parentNode.removeChild( this );\n                }\n            });\n        };\n    }\n\n\t///////////////////////////////////////////////////////////////////////////\n\t// The Canvas object is a wrapper around an HTML5 <canvas> tag.\n\t//\n\t// @constructor\n\t// @param {string} cls List of classes to apply to the canvas.\n\t// @param {element} container Element onto which to append the canvas.\n\t//\n\t// Requiring a container is a little iffy, but unfortunately canvas\n\t// operations don't work unless the canvas is attached to the DOM.\n\n\tfunction Canvas(cls, container) {\n\n\t\tvar element = container.children(\".\" + cls)[0];\n\n\t\tif (element == null) {\n\n\t\t\telement = document.createElement(\"canvas\");\n\t\t\telement.className = cls;\n\n\t\t\t$(element).css({ direction: \"ltr\", position: \"absolute\", left: 0, top: 0 })\n\t\t\t\t.appendTo(container);\n\n\t\t\t// If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas\n\n\t\t\tif (!element.getContext) {\n\t\t\t\tif (window.G_vmlCanvasManager) {\n\t\t\t\t\telement = window.G_vmlCanvasManager.initElement(element);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(\"Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.element = element;\n\n\t\tvar context = this.context = element.getContext(\"2d\");\n\n\t\t// Determine the screen's ratio of physical to device-independent\n\t\t// pixels.  This is the ratio between the canvas width that the browser\n\t\t// advertises and the number of pixels actually present in that space.\n\n\t\t// The iPhone 4, for example, has a device-independent width of 320px,\n\t\t// but its screen is actually 640px wide.  It therefore has a pixel\n\t\t// ratio of 2, while most normal devices have a ratio of 1.\n\n\t\tvar devicePixelRatio = window.devicePixelRatio || 1,\n\t\t\tbackingStoreRatio =\n\t\t\t\tcontext.webkitBackingStorePixelRatio ||\n\t\t\t\tcontext.mozBackingStorePixelRatio ||\n\t\t\t\tcontext.msBackingStorePixelRatio ||\n\t\t\t\tcontext.oBackingStorePixelRatio ||\n\t\t\t\tcontext.backingStorePixelRatio || 1;\n\n\t\tthis.pixelRatio = devicePixelRatio / backingStoreRatio;\n\n\t\t// Size the canvas to match the internal dimensions of its container\n\n\t\tthis.resize(container.width(), container.height());\n\n\t\t// Collection of HTML div layers for text overlaid onto the canvas\n\n\t\tthis.textContainer = null;\n\t\tthis.text = {};\n\n\t\t// Cache of text fragments and metrics, so we can avoid expensively\n\t\t// re-calculating them when the plot is re-rendered in a loop.\n\n\t\tthis._textCache = {};\n\t}\n\n\t// Resizes the canvas to the given dimensions.\n\t//\n\t// @param {number} width New width of the canvas, in pixels.\n\t// @param {number} width New height of the canvas, in pixels.\n\n\tCanvas.prototype.resize = function(width, height) {\n\n\t\tif (width <= 0 || height <= 0) {\n\t\t\tthrow new Error(\"Invalid dimensions for plot, width = \" + width + \", height = \" + height);\n\t\t}\n\n\t\tvar element = this.element,\n\t\t\tcontext = this.context,\n\t\t\tpixelRatio = this.pixelRatio;\n\n\t\t// Resize the canvas, increasing its density based on the display's\n\t\t// pixel ratio; basically giving it more pixels without increasing the\n\t\t// size of its element, to take advantage of the fact that retina\n\t\t// displays have that many more pixels in the same advertised space.\n\n\t\t// Resizing should reset the state (excanvas seems to be buggy though)\n\n\t\tif (this.width != width) {\n\t\t\telement.width = width * pixelRatio;\n\t\t\telement.style.width = width + \"px\";\n\t\t\tthis.width = width;\n\t\t}\n\n\t\tif (this.height != height) {\n\t\t\telement.height = height * pixelRatio;\n\t\t\telement.style.height = height + \"px\";\n\t\t\tthis.height = height;\n\t\t}\n\n\t\t// Save the context, so we can reset in case we get replotted.  The\n\t\t// restore ensure that we're really back at the initial state, and\n\t\t// should be safe even if we haven't saved the initial state yet.\n\n\t\tcontext.restore();\n\t\tcontext.save();\n\n\t\t// Scale the coordinate space to match the display density; so even though we\n\t\t// may have twice as many pixels, we still want lines and other drawing to\n\t\t// appear at the same size; the extra pixels will just make them crisper.\n\n\t\tcontext.scale(pixelRatio, pixelRatio);\n\t};\n\n\t// Clears the entire canvas area, not including any overlaid HTML text\n\n\tCanvas.prototype.clear = function() {\n\t\tthis.context.clearRect(0, 0, this.width, this.height);\n\t};\n\n\t// Finishes rendering the canvas, including managing the text overlay.\n\n\tCanvas.prototype.render = function() {\n\n\t\tvar cache = this._textCache;\n\n\t\t// For each text layer, add elements marked as active that haven't\n\t\t// already been rendered, and remove those that are no longer active.\n\n\t\tfor (var layerKey in cache) {\n\t\t\tif (hasOwnProperty.call(cache, layerKey)) {\n\n\t\t\t\tvar layer = this.getTextLayer(layerKey),\n\t\t\t\t\tlayerCache = cache[layerKey];\n\n\t\t\t\tlayer.hide();\n\n\t\t\t\tfor (var styleKey in layerCache) {\n\t\t\t\t\tif (hasOwnProperty.call(layerCache, styleKey)) {\n\t\t\t\t\t\tvar styleCache = layerCache[styleKey];\n\t\t\t\t\t\tfor (var key in styleCache) {\n\t\t\t\t\t\t\tif (hasOwnProperty.call(styleCache, key)) {\n\n\t\t\t\t\t\t\t\tvar positions = styleCache[key].positions;\n\n\t\t\t\t\t\t\t\tfor (var i = 0, position; position = positions[i]; i++) {\n\t\t\t\t\t\t\t\t\tif (position.active) {\n\t\t\t\t\t\t\t\t\t\tif (!position.rendered) {\n\t\t\t\t\t\t\t\t\t\t\tlayer.append(position.element);\n\t\t\t\t\t\t\t\t\t\t\tposition.rendered = true;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tpositions.splice(i--, 1);\n\t\t\t\t\t\t\t\t\t\tif (position.rendered) {\n\t\t\t\t\t\t\t\t\t\t\tposition.element.detach();\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (positions.length == 0) {\n\t\t\t\t\t\t\t\t\tdelete styleCache[key];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlayer.show();\n\t\t\t}\n\t\t}\n\t};\n\n\t// Creates (if necessary) and returns the text overlay container.\n\t//\n\t// @param {string} classes String of space-separated CSS classes used to\n\t//     uniquely identify the text layer.\n\t// @return {object} The jQuery-wrapped text-layer div.\n\n\tCanvas.prototype.getTextLayer = function(classes) {\n\n\t\tvar layer = this.text[classes];\n\n\t\t// Create the text layer if it doesn't exist\n\n\t\tif (layer == null) {\n\n\t\t\t// Create the text layer container, if it doesn't exist\n\n\t\t\tif (this.textContainer == null) {\n\t\t\t\tthis.textContainer = $(\"<div class='flot-text'></div>\")\n\t\t\t\t\t.css({\n\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\ttop: 0,\n\t\t\t\t\t\tleft: 0,\n\t\t\t\t\t\tbottom: 0,\n\t\t\t\t\t\tright: 0,\n\t\t\t\t\t\t'font-size': \"smaller\",\n\t\t\t\t\t\tcolor: \"#545454\"\n\t\t\t\t\t})\n\t\t\t\t\t.insertAfter(this.element);\n\t\t\t}\n\n\t\t\tlayer = this.text[classes] = $(\"<div></div>\")\n\t\t\t\t.addClass(classes)\n\t\t\t\t.css({\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\ttop: 0,\n\t\t\t\t\tleft: 0,\n\t\t\t\t\tbottom: 0,\n\t\t\t\t\tright: 0\n\t\t\t\t})\n\t\t\t\t.appendTo(this.textContainer);\n\t\t}\n\n\t\treturn layer;\n\t};\n\n\t// Creates (if necessary) and returns a text info object.\n\t//\n\t// The object looks like this:\n\t//\n\t// {\n\t//     width: Width of the text's wrapper div.\n\t//     height: Height of the text's wrapper div.\n\t//     element: The jQuery-wrapped HTML div containing the text.\n\t//     positions: Array of positions at which this text is drawn.\n\t// }\n\t//\n\t// The positions array contains objects that look like this:\n\t//\n\t// {\n\t//     active: Flag indicating whether the text should be visible.\n\t//     rendered: Flag indicating whether the text is currently visible.\n\t//     element: The jQuery-wrapped HTML div containing the text.\n\t//     x: X coordinate at which to draw the text.\n\t//     y: Y coordinate at which to draw the text.\n\t// }\n\t//\n\t// Each position after the first receives a clone of the original element.\n\t//\n\t// The idea is that that the width, height, and general 'identity' of the\n\t// text is constant no matter where it is placed; the placements are a\n\t// secondary property.\n\t//\n\t// Canvas maintains a cache of recently-used text info objects; getTextInfo\n\t// either returns the cached element or creates a new entry.\n\t//\n\t// @param {string} layer A string of space-separated CSS classes uniquely\n\t//     identifying the layer containing this text.\n\t// @param {string} text Text string to retrieve info for.\n\t// @param {(string|object)=} font Either a string of space-separated CSS\n\t//     classes or a font-spec object, defining the text's font and style.\n\t// @param {number=} angle Angle at which to rotate the text, in degrees.\n\t//     Angle is currently unused, it will be implemented in the future.\n\t// @param {number=} width Maximum width of the text before it wraps.\n\t// @return {object} a text info object.\n\n\tCanvas.prototype.getTextInfo = function(layer, text, font, angle, width) {\n\n\t\tvar textStyle, layerCache, styleCache, info;\n\n\t\t// Cast the value to a string, in case we were given a number or such\n\n\t\ttext = \"\" + text;\n\n\t\t// If the font is a font-spec object, generate a CSS font definition\n\n\t\tif (typeof font === \"object\") {\n\t\t\ttextStyle = font.style + \" \" + font.variant + \" \" + font.weight + \" \" + font.size + \"px/\" + font.lineHeight + \"px \" + font.family;\n\t\t} else {\n\t\t\ttextStyle = font;\n\t\t}\n\n\t\t// Retrieve (or create) the cache for the text's layer and styles\n\n\t\tlayerCache = this._textCache[layer];\n\n\t\tif (layerCache == null) {\n\t\t\tlayerCache = this._textCache[layer] = {};\n\t\t}\n\n\t\tstyleCache = layerCache[textStyle];\n\n\t\tif (styleCache == null) {\n\t\t\tstyleCache = layerCache[textStyle] = {};\n\t\t}\n\n\t\tinfo = styleCache[text];\n\n\t\t// If we can't find a matching element in our cache, create a new one\n\n\t\tif (info == null) {\n\n\t\t\tvar element = $(\"<div></div>\").html(text)\n\t\t\t\t.css({\n\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t'max-width': width,\n\t\t\t\t\ttop: -9999\n\t\t\t\t})\n\t\t\t\t.appendTo(this.getTextLayer(layer));\n\n\t\t\tif (typeof font === \"object\") {\n\t\t\t\telement.css({\n\t\t\t\t\tfont: textStyle,\n\t\t\t\t\tcolor: font.color\n\t\t\t\t});\n\t\t\t} else if (typeof font === \"string\") {\n\t\t\t\telement.addClass(font);\n\t\t\t}\n\n\t\t\tinfo = styleCache[text] = {\n\t\t\t\twidth: element.outerWidth(true),\n\t\t\t\theight: element.outerHeight(true),\n\t\t\t\telement: element,\n\t\t\t\tpositions: []\n\t\t\t};\n\n\t\t\telement.detach();\n\t\t}\n\n\t\treturn info;\n\t};\n\n\t// Adds a text string to the canvas text overlay.\n\t//\n\t// The text isn't drawn immediately; it is marked as rendering, which will\n\t// result in its addition to the canvas on the next render pass.\n\t//\n\t// @param {string} layer A string of space-separated CSS classes uniquely\n\t//     identifying the layer containing this text.\n\t// @param {number} x X coordinate at which to draw the text.\n\t// @param {number} y Y coordinate at which to draw the text.\n\t// @param {string} text Text string to draw.\n\t// @param {(string|object)=} font Either a string of space-separated CSS\n\t//     classes or a font-spec object, defining the text's font and style.\n\t// @param {number=} angle Angle at which to rotate the text, in degrees.\n\t//     Angle is currently unused, it will be implemented in the future.\n\t// @param {number=} width Maximum width of the text before it wraps.\n\t// @param {string=} halign Horizontal alignment of the text; either \"left\",\n\t//     \"center\" or \"right\".\n\t// @param {string=} valign Vertical alignment of the text; either \"top\",\n\t//     \"middle\" or \"bottom\".\n\n\tCanvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) {\n\n\t\tvar info = this.getTextInfo(layer, text, font, angle, width),\n\t\t\tpositions = info.positions;\n\n\t\t// Tweak the div's position to match the text's alignment\n\n\t\tif (halign == \"center\") {\n\t\t\tx -= info.width / 2;\n\t\t} else if (halign == \"right\") {\n\t\t\tx -= info.width;\n\t\t}\n\n\t\tif (valign == \"middle\") {\n\t\t\ty -= info.height / 2;\n\t\t} else if (valign == \"bottom\") {\n\t\t\ty -= info.height;\n\t\t}\n\n\t\t// Determine whether this text already exists at this position.\n\t\t// If so, mark it for inclusion in the next render pass.\n\n\t\tfor (var i = 0, position; position = positions[i]; i++) {\n\t\t\tif (position.x == x && position.y == y) {\n\t\t\t\tposition.active = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// If the text doesn't exist at this position, create a new entry\n\n\t\t// For the very first position we'll re-use the original element,\n\t\t// while for subsequent ones we'll clone it.\n\n\t\tposition = {\n\t\t\tactive: true,\n\t\t\trendered: false,\n\t\t\telement: positions.length ? info.element.clone() : info.element,\n\t\t\tx: x,\n\t\t\ty: y\n\t\t};\n\n\t\tpositions.push(position);\n\n\t\t// Move the element to its final position within the container\n\n\t\tposition.element.css({\n\t\t\ttop: Math.round(y),\n\t\t\tleft: Math.round(x),\n\t\t\t'text-align': halign\t// In case the text wraps\n\t\t});\n\t};\n\n\t// Removes one or more text strings from the canvas text overlay.\n\t//\n\t// If no parameters are given, all text within the layer is removed.\n\t//\n\t// Note that the text is not immediately removed; it is simply marked as\n\t// inactive, which will result in its removal on the next render pass.\n\t// This avoids the performance penalty for 'clear and redraw' behavior,\n\t// where we potentially get rid of all text on a layer, but will likely\n\t// add back most or all of it later, as when redrawing axes, for example.\n\t//\n\t// @param {string} layer A string of space-separated CSS classes uniquely\n\t//     identifying the layer containing this text.\n\t// @param {number=} x X coordinate of the text.\n\t// @param {number=} y Y coordinate of the text.\n\t// @param {string=} text Text string to remove.\n\t// @param {(string|object)=} font Either a string of space-separated CSS\n\t//     classes or a font-spec object, defining the text's font and style.\n\t// @param {number=} angle Angle at which the text is rotated, in degrees.\n\t//     Angle is currently unused, it will be implemented in the future.\n\n\tCanvas.prototype.removeText = function(layer, x, y, text, font, angle) {\n\t\tif (text == null) {\n\t\t\tvar layerCache = this._textCache[layer];\n\t\t\tif (layerCache != null) {\n\t\t\t\tfor (var styleKey in layerCache) {\n\t\t\t\t\tif (hasOwnProperty.call(layerCache, styleKey)) {\n\t\t\t\t\t\tvar styleCache = layerCache[styleKey];\n\t\t\t\t\t\tfor (var key in styleCache) {\n\t\t\t\t\t\t\tif (hasOwnProperty.call(styleCache, key)) {\n\t\t\t\t\t\t\t\tvar positions = styleCache[key].positions;\n\t\t\t\t\t\t\t\tfor (var i = 0, position; position = positions[i]; i++) {\n\t\t\t\t\t\t\t\t\tposition.active = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tvar positions = this.getTextInfo(layer, text, font, angle).positions;\n\t\t\tfor (var i = 0, position; position = positions[i]; i++) {\n\t\t\t\tif (position.x == x && position.y == y) {\n\t\t\t\t\tposition.active = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\t///////////////////////////////////////////////////////////////////////////\n\t// The top-level container for the entire plot.\n\n    function Plot(placeholder, data_, options_, plugins) {\n        // data is on the form:\n        //   [ series1, series2 ... ]\n        // where series is either just the data as [ [x1, y1], [x2, y2], ... ]\n        // or { data: [ [x1, y1], [x2, y2], ... ], label: \"some label\", ... }\n\n        var series = [],\n            options = {\n                // the color theme used for graphs\n                colors: [\"#edc240\", \"#afd8f8\", \"#cb4b4b\", \"#4da74d\", \"#9440ed\"],\n                legend: {\n                    show: true,\n                    noColumns: 1, // number of colums in legend table\n                    labelFormatter: null, // fn: string -> string\n                    labelBoxBorderColor: \"#ccc\", // border color for the little label boxes\n                    container: null, // container (as jQuery object) to put legend in, null means default on top of graph\n                    position: \"ne\", // position of default legend container within plot\n                    margin: 5, // distance from grid edge to default legend container within plot\n                    backgroundColor: null, // null means auto-detect\n                    backgroundOpacity: 0.85, // set to 0 to avoid background\n                    sorted: null    // default to no legend sorting\n                },\n                xaxis: {\n                    show: null, // null = auto-detect, true = always, false = never\n                    position: \"bottom\", // or \"top\"\n                    mode: null, // null or \"time\"\n                    font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: \"italic\", weight: \"bold\", family: \"sans-serif\", variant: \"small-caps\" }\n                    color: null, // base color, labels, ticks\n                    tickColor: null, // possibly different color of ticks, e.g. \"rgba(0,0,0,0.15)\"\n                    transform: null, // null or f: number -> number to transform axis\n                    inverseTransform: null, // if transform is set, this should be the inverse function\n                    min: null, // min. value to show, null means set automatically\n                    max: null, // max. value to show, null means set automatically\n                    autoscaleMargin: null, // margin in % to add if auto-setting min/max\n                    ticks: null, // either [1, 3] or [[1, \"a\"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks\n                    tickFormatter: null, // fn: number -> string\n                    labelWidth: null, // size of tick labels in pixels\n                    labelHeight: null,\n                    reserveSpace: null, // whether to reserve space even if axis isn't shown\n                    tickLength: null, // size in pixels of ticks, or \"full\" for whole line\n                    alignTicksWithAxis: null, // axis number or null for no sync\n                    tickDecimals: null, // no. of decimals, null means auto\n                    tickSize: null, // number or [number, \"unit\"]\n                    minTickSize: null // number or [number, \"unit\"]\n                },\n                yaxis: {\n                    autoscaleMargin: 0.02,\n                    position: \"left\" // or \"right\"\n                },\n                xaxes: [],\n                yaxes: [],\n                series: {\n                    points: {\n                        show: false,\n                        radius: 3,\n                        lineWidth: 2, // in pixels\n                        fill: true,\n                        fillColor: \"#ffffff\",\n                        symbol: \"circle\" // or callback\n                    },\n                    lines: {\n                        // we don't put in show: false so we can see\n                        // whether lines were actively disabled\n                        lineWidth: 2, // in pixels\n                        fill: false,\n                        fillColor: null,\n                        steps: false\n                        // Omit 'zero', so we can later default its value to\n                        // match that of the 'fill' option.\n                    },\n                    bars: {\n                        show: false,\n                        lineWidth: 2, // in pixels\n                        barWidth: 1, // in units of the x axis\n                        fill: true,\n                        fillColor: null,\n                        align: \"left\", // \"left\", \"right\", or \"center\"\n                        horizontal: false,\n                        zero: true\n                    },\n                    shadowSize: 3,\n                    highlightColor: null\n                },\n                grid: {\n                    show: true,\n                    aboveData: false,\n                    color: \"#545454\", // primary color used for outline and labels\n                    backgroundColor: null, // null for transparent, else color\n                    borderColor: null, // set if different from the grid color\n                    tickColor: null, // color for the ticks, e.g. \"rgba(0,0,0,0.15)\"\n                    margin: 0, // distance from the canvas edge to the grid\n                    labelMargin: 5, // in pixels\n                    axisMargin: 8, // in pixels\n                    borderWidth: 2, // in pixels\n                    minBorderMargin: null, // in pixels, null means taken from points radius\n                    markings: null, // array of ranges or fn: axes -> array of ranges\n                    markingsColor: \"#f4f4f4\",\n                    markingsLineWidth: 2,\n                    // interactive stuff\n                    clickable: false,\n                    hoverable: false,\n                    autoHighlight: true, // highlight in case mouse is near\n                    mouseActiveRadius: 10 // how far the mouse can be away to activate an item\n                },\n                interaction: {\n                    redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow\n                },\n                hooks: {}\n            },\n        surface = null,     // the canvas for the plot itself\n        overlay = null,     // canvas for interactive stuff on top of plot\n        eventHolder = null, // jQuery object that events should be bound to\n        ctx = null, octx = null,\n        xaxes = [], yaxes = [],\n        plotOffset = { left: 0, right: 0, top: 0, bottom: 0},\n        plotWidth = 0, plotHeight = 0,\n        hooks = {\n            processOptions: [],\n            processRawData: [],\n            processDatapoints: [],\n            processOffset: [],\n            drawBackground: [],\n            drawSeries: [],\n            draw: [],\n            bindEvents: [],\n            drawOverlay: [],\n            shutdown: []\n        },\n        plot = this;\n\n        // public functions\n        plot.setData = setData;\n        plot.setupGrid = setupGrid;\n        plot.draw = draw;\n        plot.getPlaceholder = function() { return placeholder; };\n        plot.getCanvas = function() { return surface.element; };\n        plot.getPlotOffset = function() { return plotOffset; };\n        plot.width = function () { return plotWidth; };\n        plot.height = function () { return plotHeight; };\n        plot.offset = function () {\n            var o = eventHolder.offset();\n            o.left += plotOffset.left;\n            o.top += plotOffset.top;\n            return o;\n        };\n        plot.getData = function () { return series; };\n        plot.getAxes = function () {\n            var res = {}, i;\n            $.each(xaxes.concat(yaxes), function (_, axis) {\n                if (axis)\n                    res[axis.direction + (axis.n != 1 ? axis.n : \"\") + \"axis\"] = axis;\n            });\n            return res;\n        };\n        plot.getXAxes = function () { return xaxes; };\n        plot.getYAxes = function () { return yaxes; };\n        plot.c2p = canvasToAxisCoords;\n        plot.p2c = axisToCanvasCoords;\n        plot.getOptions = function () { return options; };\n        plot.highlight = highlight;\n        plot.unhighlight = unhighlight;\n        plot.triggerRedrawOverlay = triggerRedrawOverlay;\n        plot.pointOffset = function(point) {\n            return {\n                left: parseInt(xaxes[axisNumber(point, \"x\") - 1].p2c(+point.x) + plotOffset.left, 10),\n                top: parseInt(yaxes[axisNumber(point, \"y\") - 1].p2c(+point.y) + plotOffset.top, 10)\n            };\n        };\n        plot.shutdown = shutdown;\n        plot.destroy = function () {\n            shutdown();\n            placeholder.removeData(\"plot\").empty();\n\n            series = [];\n            options = null;\n            surface = null;\n            overlay = null;\n            eventHolder = null;\n            ctx = null;\n            octx = null;\n            xaxes = [];\n            yaxes = [];\n            hooks = null;\n            highlights = [];\n            plot = null;\n        };\n        plot.resize = function () {\n        \tvar width = placeholder.width(),\n        \t\theight = placeholder.height();\n            surface.resize(width, height);\n            overlay.resize(width, height);\n        };\n\n        // public attributes\n        plot.hooks = hooks;\n\n        // initialize\n        initPlugins(plot);\n        parseOptions(options_);\n        setupCanvases();\n        setData(data_);\n        setupGrid();\n        draw();\n        bindEvents();\n\n\n        function executeHooks(hook, args) {\n            args = [plot].concat(args);\n            for (var i = 0; i < hook.length; ++i)\n                hook[i].apply(this, args);\n        }\n\n        function initPlugins() {\n\n            // References to key classes, allowing plugins to modify them\n\n            var classes = {\n                Canvas: Canvas\n            };\n\n            for (var i = 0; i < plugins.length; ++i) {\n                var p = plugins[i];\n                p.init(plot, classes);\n                if (p.options)\n                    $.extend(true, options, p.options);\n            }\n        }\n\n        function parseOptions(opts) {\n\n            $.extend(true, options, opts);\n\n            // $.extend merges arrays, rather than replacing them.  When less\n            // colors are provided than the size of the default palette, we\n            // end up with those colors plus the remaining defaults, which is\n            // not expected behavior; avoid it by replacing them here.\n\n            if (opts && opts.colors) {\n            \toptions.colors = opts.colors;\n            }\n\n            if (options.xaxis.color == null)\n                options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();\n            if (options.yaxis.color == null)\n                options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();\n\n            if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility\n                options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color;\n            if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility\n                options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color;\n\n            if (options.grid.borderColor == null)\n                options.grid.borderColor = options.grid.color;\n            if (options.grid.tickColor == null)\n                options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();\n\n            // Fill in defaults for axis options, including any unspecified\n            // font-spec fields, if a font-spec was provided.\n\n            // If no x/y axis options were provided, create one of each anyway,\n            // since the rest of the code assumes that they exist.\n\n            var i, axisOptions, axisCount,\n                fontSize = placeholder.css(\"font-size\"),\n                fontSizeDefault = fontSize ? +fontSize.replace(\"px\", \"\") : 13,\n                fontDefaults = {\n                    style: placeholder.css(\"font-style\"),\n                    size: Math.round(0.8 * fontSizeDefault),\n                    variant: placeholder.css(\"font-variant\"),\n                    weight: placeholder.css(\"font-weight\"),\n                    family: placeholder.css(\"font-family\")\n                };\n\n            axisCount = options.xaxes.length || 1;\n            for (i = 0; i < axisCount; ++i) {\n\n                axisOptions = options.xaxes[i];\n                if (axisOptions && !axisOptions.tickColor) {\n                    axisOptions.tickColor = axisOptions.color;\n                }\n\n                axisOptions = $.extend(true, {}, options.xaxis, axisOptions);\n                options.xaxes[i] = axisOptions;\n\n                if (axisOptions.font) {\n                    axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);\n                    if (!axisOptions.font.color) {\n                        axisOptions.font.color = axisOptions.color;\n                    }\n                    if (!axisOptions.font.lineHeight) {\n                        axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);\n                    }\n                }\n            }\n\n            axisCount = options.yaxes.length || 1;\n            for (i = 0; i < axisCount; ++i) {\n\n                axisOptions = options.yaxes[i];\n                if (axisOptions && !axisOptions.tickColor) {\n                    axisOptions.tickColor = axisOptions.color;\n                }\n\n                axisOptions = $.extend(true, {}, options.yaxis, axisOptions);\n                options.yaxes[i] = axisOptions;\n\n                if (axisOptions.font) {\n                    axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);\n                    if (!axisOptions.font.color) {\n                        axisOptions.font.color = axisOptions.color;\n                    }\n                    if (!axisOptions.font.lineHeight) {\n                        axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);\n                    }\n                }\n            }\n\n            // backwards compatibility, to be removed in future\n            if (options.xaxis.noTicks && options.xaxis.ticks == null)\n                options.xaxis.ticks = options.xaxis.noTicks;\n            if (options.yaxis.noTicks && options.yaxis.ticks == null)\n                options.yaxis.ticks = options.yaxis.noTicks;\n            if (options.x2axis) {\n                options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);\n                options.xaxes[1].position = \"top\";\n                // Override the inherit to allow the axis to auto-scale\n                if (options.x2axis.min == null) {\n                    options.xaxes[1].min = null;\n                }\n                if (options.x2axis.max == null) {\n                    options.xaxes[1].max = null;\n                }\n            }\n            if (options.y2axis) {\n                options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);\n                options.yaxes[1].position = \"right\";\n                // Override the inherit to allow the axis to auto-scale\n                if (options.y2axis.min == null) {\n                    options.yaxes[1].min = null;\n                }\n                if (options.y2axis.max == null) {\n                    options.yaxes[1].max = null;\n                }\n            }\n            if (options.grid.coloredAreas)\n                options.grid.markings = options.grid.coloredAreas;\n            if (options.grid.coloredAreasColor)\n                options.grid.markingsColor = options.grid.coloredAreasColor;\n            if (options.lines)\n                $.extend(true, options.series.lines, options.lines);\n            if (options.points)\n                $.extend(true, options.series.points, options.points);\n            if (options.bars)\n                $.extend(true, options.series.bars, options.bars);\n            if (options.shadowSize != null)\n                options.series.shadowSize = options.shadowSize;\n            if (options.highlightColor != null)\n                options.series.highlightColor = options.highlightColor;\n\n            // save options on axes for future reference\n            for (i = 0; i < options.xaxes.length; ++i)\n                getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];\n            for (i = 0; i < options.yaxes.length; ++i)\n                getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];\n\n            // add hooks from options\n            for (var n in hooks)\n                if (options.hooks[n] && options.hooks[n].length)\n                    hooks[n] = hooks[n].concat(options.hooks[n]);\n\n            executeHooks(hooks.processOptions, [options]);\n        }\n\n        function setData(d) {\n            series = parseData(d);\n            fillInSeriesOptions();\n            processData();\n        }\n\n        function parseData(d) {\n            var res = [];\n            for (var i = 0; i < d.length; ++i) {\n                var s = $.extend(true, {}, options.series);\n\n                if (d[i].data != null) {\n                    s.data = d[i].data; // move the data instead of deep-copy\n                    delete d[i].data;\n\n                    $.extend(true, s, d[i]);\n\n                    d[i].data = s.data;\n                }\n                else\n                    s.data = d[i];\n                res.push(s);\n            }\n\n            return res;\n        }\n\n        function axisNumber(obj, coord) {\n            var a = obj[coord + \"axis\"];\n            if (typeof a == \"object\") // if we got a real axis, extract number\n                a = a.n;\n            if (typeof a != \"number\")\n                a = 1; // default to first axis\n            return a;\n        }\n\n        function allAxes() {\n            // return flat array without annoying null entries\n            return $.grep(xaxes.concat(yaxes), function (a) { return a; });\n        }\n\n        function canvasToAxisCoords(pos) {\n            // return an object with x/y corresponding to all used axes\n            var res = {}, i, axis;\n            for (i = 0; i < xaxes.length; ++i) {\n                axis = xaxes[i];\n                if (axis && axis.used)\n                    res[\"x\" + axis.n] = axis.c2p(pos.left);\n            }\n\n            for (i = 0; i < yaxes.length; ++i) {\n                axis = yaxes[i];\n                if (axis && axis.used)\n                    res[\"y\" + axis.n] = axis.c2p(pos.top);\n            }\n\n            if (res.x1 !== undefined)\n                res.x = res.x1;\n            if (res.y1 !== undefined)\n                res.y = res.y1;\n\n            return res;\n        }\n\n        function axisToCanvasCoords(pos) {\n            // get canvas coords from the first pair of x/y found in pos\n            var res = {}, i, axis, key;\n\n            for (i = 0; i < xaxes.length; ++i) {\n                axis = xaxes[i];\n                if (axis && axis.used) {\n                    key = \"x\" + axis.n;\n                    if (pos[key] == null && axis.n == 1)\n                        key = \"x\";\n\n                    if (pos[key] != null) {\n                        res.left = axis.p2c(pos[key]);\n                        break;\n                    }\n                }\n            }\n\n            for (i = 0; i < yaxes.length; ++i) {\n                axis = yaxes[i];\n                if (axis && axis.used) {\n                    key = \"y\" + axis.n;\n                    if (pos[key] == null && axis.n == 1)\n                        key = \"y\";\n\n                    if (pos[key] != null) {\n                        res.top = axis.p2c(pos[key]);\n                        break;\n                    }\n                }\n            }\n\n            return res;\n        }\n\n        function getOrCreateAxis(axes, number) {\n            if (!axes[number - 1])\n                axes[number - 1] = {\n                    n: number, // save the number for future reference\n                    direction: axes == xaxes ? \"x\" : \"y\",\n                    options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)\n                };\n\n            return axes[number - 1];\n        }\n\n        function fillInSeriesOptions() {\n\n            var neededColors = series.length, maxIndex = -1, i;\n\n            // Subtract the number of series that already have fixed colors or\n            // color indexes from the number that we still need to generate.\n\n            for (i = 0; i < series.length; ++i) {\n                var sc = series[i].color;\n                if (sc != null) {\n                    neededColors--;\n                    if (typeof sc == \"number\" && sc > maxIndex) {\n                        maxIndex = sc;\n                    }\n                }\n            }\n\n            // If any of the series have fixed color indexes, then we need to\n            // generate at least as many colors as the highest index.\n\n            if (neededColors <= maxIndex) {\n                neededColors = maxIndex + 1;\n            }\n\n            // Generate all the colors, using first the option colors and then\n            // variations on those colors once they're exhausted.\n\n            var c, colors = [], colorPool = options.colors,\n                colorPoolSize = colorPool.length, variation = 0;\n\n            for (i = 0; i < neededColors; i++) {\n\n                c = $.color.parse(colorPool[i % colorPoolSize] || \"#666\");\n\n                // Each time we exhaust the colors in the pool we adjust\n                // a scaling factor used to produce more variations on\n                // those colors. The factor alternates negative/positive\n                // to produce lighter/darker colors.\n\n                // Reset the variation after every few cycles, or else\n                // it will end up producing only white or black colors.\n\n                if (i % colorPoolSize == 0 && i) {\n                    if (variation >= 0) {\n                        if (variation < 0.5) {\n                            variation = -variation - 0.2;\n                        } else variation = 0;\n                    } else variation = -variation;\n                }\n\n                colors[i] = c.scale('rgb', 1 + variation);\n            }\n\n            // Finalize the series options, filling in their colors\n\n            var colori = 0, s;\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n\n                // assign colors\n                if (s.color == null) {\n                    s.color = colors[colori].toString();\n                    ++colori;\n                }\n                else if (typeof s.color == \"number\")\n                    s.color = colors[s.color].toString();\n\n                // turn on lines automatically in case nothing is set\n                if (s.lines.show == null) {\n                    var v, show = true;\n                    for (v in s)\n                        if (s[v] && s[v].show) {\n                            show = false;\n                            break;\n                        }\n                    if (show)\n                        s.lines.show = true;\n                }\n\n                // If nothing was provided for lines.zero, default it to match\n                // lines.fill, since areas by default should extend to zero.\n\n                if (s.lines.zero == null) {\n                    s.lines.zero = !!s.lines.fill;\n                }\n\n                // setup axes\n                s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, \"x\"));\n                s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, \"y\"));\n            }\n        }\n\n        function processData() {\n            var topSentry = Number.POSITIVE_INFINITY,\n                bottomSentry = Number.NEGATIVE_INFINITY,\n                fakeInfinity = Number.MAX_VALUE,\n                i, j, k, m, length,\n                s, points, ps, x, y, axis, val, f, p,\n                data, format;\n\n            function updateAxis(axis, min, max) {\n                if (min < axis.datamin && min != -fakeInfinity)\n                    axis.datamin = min;\n                if (max > axis.datamax && max != fakeInfinity)\n                    axis.datamax = max;\n            }\n\n            $.each(allAxes(), function (_, axis) {\n                // init axis\n                axis.datamin = topSentry;\n                axis.datamax = bottomSentry;\n                axis.used = false;\n            });\n\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n                s.datapoints = { points: [] };\n\n                executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);\n            }\n\n            // first pass: clean and copy data\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n\n                data = s.data;\n                format = s.datapoints.format;\n\n                if (!format) {\n                    format = [];\n                    // find out how to copy\n                    format.push({ x: true, number: true, required: true });\n                    format.push({ y: true, number: true, required: true });\n\n                    if (s.bars.show || (s.lines.show && s.lines.fill)) {\n                        var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero));\n                        format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale });\n                        if (s.bars.horizontal) {\n                            delete format[format.length - 1].y;\n                            format[format.length - 1].x = true;\n                        }\n                    }\n\n                    s.datapoints.format = format;\n                }\n\n                if (s.datapoints.pointsize != null)\n                    continue; // already filled in\n\n                s.datapoints.pointsize = format.length;\n\n                ps = s.datapoints.pointsize;\n                points = s.datapoints.points;\n\n                var insertSteps = s.lines.show && s.lines.steps;\n                s.xaxis.used = s.yaxis.used = true;\n\n                for (j = k = 0; j < data.length; ++j, k += ps) {\n                    p = data[j];\n\n                    var nullify = p == null;\n                    if (!nullify) {\n                        for (m = 0; m < ps; ++m) {\n                            val = p[m];\n                            f = format[m];\n\n                            if (f) {\n                                if (f.number && val != null) {\n                                    val = +val; // convert to number\n                                    if (isNaN(val))\n                                        val = null;\n                                    else if (val == Infinity)\n                                        val = fakeInfinity;\n                                    else if (val == -Infinity)\n                                        val = -fakeInfinity;\n                                }\n\n                                if (val == null) {\n                                    if (f.required)\n                                        nullify = true;\n\n                                    if (f.defaultValue != null)\n                                        val = f.defaultValue;\n                                }\n                            }\n\n                            points[k + m] = val;\n                        }\n                    }\n\n                    if (nullify) {\n                        for (m = 0; m < ps; ++m) {\n                            val = points[k + m];\n                            if (val != null) {\n                                f = format[m];\n                                // extract min/max info\n                                if (f.autoscale !== false) {\n                                    if (f.x) {\n                                        updateAxis(s.xaxis, val, val);\n                                    }\n                                    if (f.y) {\n                                        updateAxis(s.yaxis, val, val);\n                                    }\n                                }\n                            }\n                            points[k + m] = null;\n                        }\n                    }\n                    else {\n                        // a little bit of line specific stuff that\n                        // perhaps shouldn't be here, but lacking\n                        // better means...\n                        if (insertSteps && k > 0\n                            && points[k - ps] != null\n                            && points[k - ps] != points[k]\n                            && points[k - ps + 1] != points[k + 1]) {\n                            // copy the point to make room for a middle point\n                            for (m = 0; m < ps; ++m)\n                                points[k + ps + m] = points[k + m];\n\n                            // middle point has same y\n                            points[k + 1] = points[k - ps + 1];\n\n                            // we've added a point, better reflect that\n                            k += ps;\n                        }\n                    }\n                }\n            }\n\n            // give the hooks a chance to run\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n\n                executeHooks(hooks.processDatapoints, [ s, s.datapoints]);\n            }\n\n            // second pass: find datamax/datamin for auto-scaling\n            for (i = 0; i < series.length; ++i) {\n                s = series[i];\n                points = s.datapoints.points;\n                ps = s.datapoints.pointsize;\n                format = s.datapoints.format;\n\n                var xmin = topSentry, ymin = topSentry,\n                    xmax = bottomSentry, ymax = bottomSentry;\n\n                for (j = 0; j < points.length; j += ps) {\n                    if (points[j] == null)\n                        continue;\n\n                    for (m = 0; m < ps; ++m) {\n                        val = points[j + m];\n                        f = format[m];\n                        if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity)\n                            continue;\n\n                        if (f.x) {\n                            if (val < xmin)\n                                xmin = val;\n                            if (val > xmax)\n                                xmax = val;\n                        }\n                        if (f.y) {\n                            if (val < ymin)\n                                ymin = val;\n                            if (val > ymax)\n                                ymax = val;\n                        }\n                    }\n                }\n\n                if (s.bars.show) {\n                    // make sure we got room for the bar on the dancing floor\n                    var delta;\n\n                    switch (s.bars.align) {\n                        case \"left\":\n                            delta = 0;\n                            break;\n                        case \"right\":\n                            delta = -s.bars.barWidth;\n                            break;\n                        default:\n                            delta = -s.bars.barWidth / 2;\n                    }\n\n                    if (s.bars.horizontal) {\n                        ymin += delta;\n                        ymax += delta + s.bars.barWidth;\n                    }\n                    else {\n                        xmin += delta;\n                        xmax += delta + s.bars.barWidth;\n                    }\n                }\n\n                updateAxis(s.xaxis, xmin, xmax);\n                updateAxis(s.yaxis, ymin, ymax);\n            }\n\n            $.each(allAxes(), function (_, axis) {\n                if (axis.datamin == topSentry)\n                    axis.datamin = null;\n                if (axis.datamax == bottomSentry)\n                    axis.datamax = null;\n            });\n        }\n\n        function setupCanvases() {\n\n            // Make sure the placeholder is clear of everything except canvases\n            // from a previous plot in this container that we'll try to re-use.\n\n            placeholder.css(\"padding\", 0) // padding messes up the positioning\n                .children().filter(function(){\n                    return !$(this).hasClass(\"flot-overlay\") && !$(this).hasClass('flot-base');\n                }).remove();\n\n            if (placeholder.css(\"position\") == 'static')\n                placeholder.css(\"position\", \"relative\"); // for positioning labels and overlay\n\n            surface = new Canvas(\"flot-base\", placeholder);\n            overlay = new Canvas(\"flot-overlay\", placeholder); // overlay canvas for interactive features\n\n            ctx = surface.context;\n            octx = overlay.context;\n\n            // define which element we're listening for events on\n            eventHolder = $(overlay.element).unbind();\n\n            // If we're re-using a plot object, shut down the old one\n\n            var existing = placeholder.data(\"plot\");\n\n            if (existing) {\n                existing.shutdown();\n                overlay.clear();\n            }\n\n            // save in case we get replotted\n            placeholder.data(\"plot\", plot);\n        }\n\n        function bindEvents() {\n            // bind events\n            if (options.grid.hoverable) {\n                eventHolder.mousemove(onMouseMove);\n\n                // Use bind, rather than .mouseleave, because we officially\n                // still support jQuery 1.2.6, which doesn't define a shortcut\n                // for mouseenter or mouseleave.  This was a bug/oversight that\n                // was fixed somewhere around 1.3.x.  We can return to using\n                // .mouseleave when we drop support for 1.2.6.\n\n                eventHolder.bind(\"mouseleave\", onMouseLeave);\n            }\n\n            if (options.grid.clickable)\n                eventHolder.click(onClick);\n\n            executeHooks(hooks.bindEvents, [eventHolder]);\n        }\n\n        function shutdown() {\n            if (redrawTimeout)\n                clearTimeout(redrawTimeout);\n\n            eventHolder.unbind(\"mousemove\", onMouseMove);\n            eventHolder.unbind(\"mouseleave\", onMouseLeave);\n            eventHolder.unbind(\"click\", onClick);\n\n            executeHooks(hooks.shutdown, [eventHolder]);\n        }\n\n        function setTransformationHelpers(axis) {\n            // set helper functions on the axis, assumes plot area\n            // has been computed already\n\n            function identity(x) { return x; }\n\n            var s, m, t = axis.options.transform || identity,\n                it = axis.options.inverseTransform;\n\n            // precompute how much the axis is scaling a point\n            // in canvas space\n            if (axis.direction == \"x\") {\n                s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));\n                m = Math.min(t(axis.max), t(axis.min));\n            }\n            else {\n                s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));\n                s = -s;\n                m = Math.max(t(axis.max), t(axis.min));\n            }\n\n            // data point to canvas coordinate\n            if (t == identity) // slight optimization\n                axis.p2c = function (p) { return (p - m) * s; };\n            else\n                axis.p2c = function (p) { return (t(p) - m) * s; };\n            // canvas coordinate to data point\n            if (!it)\n                axis.c2p = function (c) { return m + c / s; };\n            else\n                axis.c2p = function (c) { return it(m + c / s); };\n        }\n\n        function measureTickLabels(axis) {\n\n            var opts = axis.options,\n                ticks = axis.ticks || [],\n                labelWidth = opts.labelWidth || 0,\n                labelHeight = opts.labelHeight || 0,\n                maxWidth = labelWidth || (axis.direction == \"x\" ? Math.floor(surface.width / (ticks.length || 1)) : null),\n                legacyStyles = axis.direction + \"Axis \" + axis.direction + axis.n + \"Axis\",\n                layer = \"flot-\" + axis.direction + \"-axis flot-\" + axis.direction + axis.n + \"-axis \" + legacyStyles,\n                font = opts.font || \"flot-tick-label tickLabel\";\n\n            for (var i = 0; i < ticks.length; ++i) {\n\n                var t = ticks[i];\n\n                if (!t.label)\n                    continue;\n\n                var info = surface.getTextInfo(layer, t.label, font, null, maxWidth);\n\n                labelWidth = Math.max(labelWidth, info.width);\n                labelHeight = Math.max(labelHeight, info.height);\n            }\n\n            axis.labelWidth = opts.labelWidth || labelWidth;\n            axis.labelHeight = opts.labelHeight || labelHeight;\n        }\n\n        function allocateAxisBoxFirstPhase(axis) {\n            // find the bounding box of the axis by looking at label\n            // widths/heights and ticks, make room by diminishing the\n            // plotOffset; this first phase only looks at one\n            // dimension per axis, the other dimension depends on the\n            // other axes so will have to wait\n\n            var lw = axis.labelWidth,\n                lh = axis.labelHeight,\n                pos = axis.options.position,\n                isXAxis = axis.direction === \"x\",\n                tickLength = axis.options.tickLength,\n                axisMargin = options.grid.axisMargin,\n                padding = options.grid.labelMargin,\n                innermost = true,\n                outermost = true,\n                first = true,\n                found = false;\n\n            // Determine the axis's position in its direction and on its side\n\n            $.each(isXAxis ? xaxes : yaxes, function(i, a) {\n                if (a && (a.show || a.reserveSpace)) {\n                    if (a === axis) {\n                        found = true;\n                    } else if (a.options.position === pos) {\n                        if (found) {\n                            outermost = false;\n                        } else {\n                            innermost = false;\n                        }\n                    }\n                    if (!found) {\n                        first = false;\n                    }\n                }\n            });\n\n            // The outermost axis on each side has no margin\n\n            if (outermost) {\n                axisMargin = 0;\n            }\n\n            // The ticks for the first axis in each direction stretch across\n\n            if (tickLength == null) {\n                tickLength = first ? \"full\" : 5;\n            }\n\n            if (!isNaN(+tickLength))\n                padding += +tickLength;\n\n            if (isXAxis) {\n                lh += padding;\n\n                if (pos == \"bottom\") {\n                    plotOffset.bottom += lh + axisMargin;\n                    axis.box = { top: surface.height - plotOffset.bottom, height: lh };\n                }\n                else {\n                    axis.box = { top: plotOffset.top + axisMargin, height: lh };\n                    plotOffset.top += lh + axisMargin;\n                }\n            }\n            else {\n                lw += padding;\n\n                if (pos == \"left\") {\n                    axis.box = { left: plotOffset.left + axisMargin, width: lw };\n                    plotOffset.left += lw + axisMargin;\n                }\n                else {\n                    plotOffset.right += lw + axisMargin;\n                    axis.box = { left: surface.width - plotOffset.right, width: lw };\n                }\n            }\n\n             // save for future reference\n            axis.position = pos;\n            axis.tickLength = tickLength;\n            axis.box.padding = padding;\n            axis.innermost = innermost;\n        }\n\n        function allocateAxisBoxSecondPhase(axis) {\n            // now that all axis boxes have been placed in one\n            // dimension, we can set the remaining dimension coordinates\n            if (axis.direction == \"x\") {\n                axis.box.left = plotOffset.left - axis.labelWidth / 2;\n                axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth;\n            }\n            else {\n                axis.box.top = plotOffset.top - axis.labelHeight / 2;\n                axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight;\n            }\n        }\n\n        function adjustLayoutForThingsStickingOut() {\n            // possibly adjust plot offset to ensure everything stays\n            // inside the canvas and isn't clipped off\n\n            var minMargin = options.grid.minBorderMargin,\n                axis, i;\n\n            // check stuff from the plot (FIXME: this should just read\n            // a value from the series, otherwise it's impossible to\n            // customize)\n            if (minMargin == null) {\n                minMargin = 0;\n                for (i = 0; i < series.length; ++i)\n                    minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2));\n            }\n\n            var margins = {\n                left: minMargin,\n                right: minMargin,\n                top: minMargin,\n                bottom: minMargin\n            };\n\n            // check axis labels, note we don't check the actual\n            // labels but instead use the overall width/height to not\n            // jump as much around with replots\n            $.each(allAxes(), function (_, axis) {\n                if (axis.reserveSpace && axis.ticks && axis.ticks.length) {\n                    if (axis.direction === \"x\") {\n                        margins.left = Math.max(margins.left, axis.labelWidth / 2);\n                        margins.right = Math.max(margins.right, axis.labelWidth / 2);\n                    } else {\n                        margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2);\n                        margins.top = Math.max(margins.top, axis.labelHeight / 2);\n                    }\n                }\n            });\n\n            plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left));\n            plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right));\n            plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top));\n            plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom));\n        }\n\n        function setupGrid() {\n            var i, axes = allAxes(), showGrid = options.grid.show;\n\n            // Initialize the plot's offset from the edge of the canvas\n\n            for (var a in plotOffset) {\n                var margin = options.grid.margin || 0;\n                plotOffset[a] = typeof margin == \"number\" ? margin : margin[a] || 0;\n            }\n\n            executeHooks(hooks.processOffset, [plotOffset]);\n\n            // If the grid is visible, add its border width to the offset\n\n            for (var a in plotOffset) {\n                if(typeof(options.grid.borderWidth) == \"object\") {\n                    plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0;\n                }\n                else {\n                    plotOffset[a] += showGrid ? options.grid.borderWidth : 0;\n                }\n            }\n\n            $.each(axes, function (_, axis) {\n                var axisOpts = axis.options;\n                axis.show = axisOpts.show == null ? axis.used : axisOpts.show;\n                axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace;\n                setRange(axis);\n            });\n\n            if (showGrid) {\n\n                var allocatedAxes = $.grep(axes, function (axis) {\n                    return axis.show || axis.reserveSpace;\n                });\n\n                $.each(allocatedAxes, function (_, axis) {\n                    // make the ticks\n                    setupTickGeneration(axis);\n                    setTicks(axis);\n                    snapRangeToTicks(axis, axis.ticks);\n                    // find labelWidth/Height for axis\n                    measureTickLabels(axis);\n                });\n\n                // with all dimensions calculated, we can compute the\n                // axis bounding boxes, start from the outside\n                // (reverse order)\n                for (i = allocatedAxes.length - 1; i >= 0; --i)\n                    allocateAxisBoxFirstPhase(allocatedAxes[i]);\n\n                // make sure we've got enough space for things that\n                // might stick out\n                adjustLayoutForThingsStickingOut();\n\n                $.each(allocatedAxes, function (_, axis) {\n                    allocateAxisBoxSecondPhase(axis);\n                });\n            }\n\n            plotWidth = surface.width - plotOffset.left - plotOffset.right;\n            plotHeight = surface.height - plotOffset.bottom - plotOffset.top;\n\n            // now we got the proper plot dimensions, we can compute the scaling\n            $.each(axes, function (_, axis) {\n                setTransformationHelpers(axis);\n            });\n\n            if (showGrid) {\n                drawAxisLabels();\n            }\n\n            insertLegend();\n        }\n\n        function setRange(axis) {\n            var opts = axis.options,\n                min = +(opts.min != null ? opts.min : axis.datamin),\n                max = +(opts.max != null ? opts.max : axis.datamax),\n                delta = max - min;\n\n            if (delta == 0.0) {\n                // degenerate case\n                var widen = max == 0 ? 1 : 0.01;\n\n                if (opts.min == null)\n                    min -= widen;\n                // always widen max if we couldn't widen min to ensure we\n                // don't fall into min == max which doesn't work\n                if (opts.max == null || opts.min != null)\n                    max += widen;\n            }\n            else {\n                // consider autoscaling\n                var margin = opts.autoscaleMargin;\n                if (margin != null) {\n                    if (opts.min == null) {\n                        min -= delta * margin;\n                        // make sure we don't go below zero if all values\n                        // are positive\n                        if (min < 0 && axis.datamin != null && axis.datamin >= 0)\n                            min = 0;\n                    }\n                    if (opts.max == null) {\n                        max += delta * margin;\n                        if (max > 0 && axis.datamax != null && axis.datamax <= 0)\n                            max = 0;\n                    }\n                }\n            }\n            axis.min = min;\n            axis.max = max;\n        }\n\n        function setupTickGeneration(axis) {\n            var opts = axis.options;\n\n            // estimate number of ticks\n            var noTicks;\n            if (typeof opts.ticks == \"number\" && opts.ticks > 0)\n                noTicks = opts.ticks;\n            else\n                // heuristic based on the model a*sqrt(x) fitted to\n                // some data points that seemed reasonable\n                noTicks = 0.3 * Math.sqrt(axis.direction == \"x\" ? surface.width : surface.height);\n\n            var delta = (axis.max - axis.min) / noTicks,\n                dec = -Math.floor(Math.log(delta) / Math.LN10),\n                maxDec = opts.tickDecimals;\n\n            if (maxDec != null && dec > maxDec) {\n                dec = maxDec;\n            }\n\n            var magn = Math.pow(10, -dec),\n                norm = delta / magn, // norm is between 1.0 and 10.0\n                size;\n\n            if (norm < 1.5) {\n                size = 1;\n            } else if (norm < 3) {\n                size = 2;\n                // special case for 2.5, requires an extra decimal\n                if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {\n                    size = 2.5;\n                    ++dec;\n                }\n            } else if (norm < 7.5) {\n                size = 5;\n            } else {\n                size = 10;\n            }\n\n            size *= magn;\n\n            if (opts.minTickSize != null && size < opts.minTickSize) {\n                size = opts.minTickSize;\n            }\n\n            axis.delta = delta;\n            axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);\n            axis.tickSize = opts.tickSize || size;\n\n            // Time mode was moved to a plug-in in 0.8, and since so many people use it\n            // we'll add an especially friendly reminder to make sure they included it.\n\n            if (opts.mode == \"time\" && !axis.tickGenerator) {\n                throw new Error(\"Time mode requires the flot.time plugin.\");\n            }\n\n            // Flot supports base-10 axes; any other mode else is handled by a plug-in,\n            // like flot.time.js.\n\n            if (!axis.tickGenerator) {\n\n                axis.tickGenerator = function (axis) {\n\n                    var ticks = [],\n                        start = floorInBase(axis.min, axis.tickSize),\n                        i = 0,\n                        v = Number.NaN,\n                        prev;\n\n                    do {\n                        prev = v;\n                        v = start + i * axis.tickSize;\n                        ticks.push(v);\n                        ++i;\n                    } while (v < axis.max && v != prev);\n                    return ticks;\n                };\n\n\t\t\t\taxis.tickFormatter = function (value, axis) {\n\n\t\t\t\t\tvar factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1;\n\t\t\t\t\tvar formatted = \"\" + Math.round(value * factor) / factor;\n\n\t\t\t\t\t// If tickDecimals was specified, ensure that we have exactly that\n\t\t\t\t\t// much precision; otherwise default to the value's own precision.\n\n\t\t\t\t\tif (axis.tickDecimals != null) {\n\t\t\t\t\t\tvar decimal = formatted.indexOf(\".\");\n\t\t\t\t\t\tvar precision = decimal == -1 ? 0 : formatted.length - decimal - 1;\n\t\t\t\t\t\tif (precision < axis.tickDecimals) {\n\t\t\t\t\t\t\treturn (precision ? formatted : formatted + \".\") + (\"\" + factor).substr(1, axis.tickDecimals - precision);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n                    return formatted;\n                };\n            }\n\n            if ($.isFunction(opts.tickFormatter))\n                axis.tickFormatter = function (v, axis) { return \"\" + opts.tickFormatter(v, axis); };\n\n            if (opts.alignTicksWithAxis != null) {\n                var otherAxis = (axis.direction == \"x\" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];\n                if (otherAxis && otherAxis.used && otherAxis != axis) {\n                    // consider snapping min/max to outermost nice ticks\n                    var niceTicks = axis.tickGenerator(axis);\n                    if (niceTicks.length > 0) {\n                        if (opts.min == null)\n                            axis.min = Math.min(axis.min, niceTicks[0]);\n                        if (opts.max == null && niceTicks.length > 1)\n                            axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);\n                    }\n\n                    axis.tickGenerator = function (axis) {\n                        // copy ticks, scaled to this axis\n                        var ticks = [], v, i;\n                        for (i = 0; i < otherAxis.ticks.length; ++i) {\n                            v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);\n                            v = axis.min + v * (axis.max - axis.min);\n                            ticks.push(v);\n                        }\n                        return ticks;\n                    };\n\n                    // we might need an extra decimal since forced\n                    // ticks don't necessarily fit naturally\n                    if (!axis.mode && opts.tickDecimals == null) {\n                        var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),\n                            ts = axis.tickGenerator(axis);\n\n                        // only proceed if the tick interval rounded\n                        // with an extra decimal doesn't give us a\n                        // zero at end\n                        if (!(ts.length > 1 && /\\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))\n                            axis.tickDecimals = extraDec;\n                    }\n                }\n            }\n        }\n\n        function setTicks(axis) {\n            var oticks = axis.options.ticks, ticks = [];\n            if (oticks == null || (typeof oticks == \"number\" && oticks > 0))\n                ticks = axis.tickGenerator(axis);\n            else if (oticks) {\n                if ($.isFunction(oticks))\n                    // generate the ticks\n                    ticks = oticks(axis);\n                else\n                    ticks = oticks;\n            }\n\n            // clean up/labelify the supplied ticks, copy them over\n            var i, v;\n            axis.ticks = [];\n            for (i = 0; i < ticks.length; ++i) {\n                var label = null;\n                var t = ticks[i];\n                if (typeof t == \"object\") {\n                    v = +t[0];\n                    if (t.length > 1)\n                        label = t[1];\n                }\n                else\n                    v = +t;\n                if (label == null)\n                    label = axis.tickFormatter(v, axis);\n                if (!isNaN(v))\n                    axis.ticks.push({ v: v, label: label });\n            }\n        }\n\n        function snapRangeToTicks(axis, ticks) {\n            if (axis.options.autoscaleMargin && ticks.length > 0) {\n                // snap to ticks\n                if (axis.options.min == null)\n                    axis.min = Math.min(axis.min, ticks[0].v);\n                if (axis.options.max == null && ticks.length > 1)\n                    axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);\n            }\n        }\n\n        function draw() {\n\n            surface.clear();\n\n            executeHooks(hooks.drawBackground, [ctx]);\n\n            var grid = options.grid;\n\n            // draw background, if any\n            if (grid.show && grid.backgroundColor)\n                drawBackground();\n\n            if (grid.show && !grid.aboveData) {\n                drawGrid();\n            }\n\n            for (var i = 0; i < series.length; ++i) {\n                executeHooks(hooks.drawSeries, [ctx, series[i]]);\n                drawSeries(series[i]);\n            }\n\n            executeHooks(hooks.draw, [ctx]);\n\n            if (grid.show && grid.aboveData) {\n                drawGrid();\n            }\n\n            surface.render();\n\n            // A draw implies that either the axes or data have changed, so we\n            // should probably update the overlay highlights as well.\n\n            triggerRedrawOverlay();\n        }\n\n        function extractRange(ranges, coord) {\n            var axis, from, to, key, axes = allAxes();\n\n            for (var i = 0; i < axes.length; ++i) {\n                axis = axes[i];\n                if (axis.direction == coord) {\n                    key = coord + axis.n + \"axis\";\n                    if (!ranges[key] && axis.n == 1)\n                        key = coord + \"axis\"; // support x1axis as xaxis\n                    if (ranges[key]) {\n                        from = ranges[key].from;\n                        to = ranges[key].to;\n                        break;\n                    }\n                }\n            }\n\n            // backwards-compat stuff - to be removed in future\n            if (!ranges[key]) {\n                axis = coord == \"x\" ? xaxes[0] : yaxes[0];\n                from = ranges[coord + \"1\"];\n                to = ranges[coord + \"2\"];\n            }\n\n            // auto-reverse as an added bonus\n            if (from != null && to != null && from > to) {\n                var tmp = from;\n                from = to;\n                to = tmp;\n            }\n\n            return { from: from, to: to, axis: axis };\n        }\n\n        function drawBackground() {\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n\n            ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, \"rgba(255, 255, 255, 0)\");\n            ctx.fillRect(0, 0, plotWidth, plotHeight);\n            ctx.restore();\n        }\n\n        function drawGrid() {\n            var i, axes, bw, bc;\n\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n\n            // draw markings\n            var markings = options.grid.markings;\n            if (markings) {\n                if ($.isFunction(markings)) {\n                    axes = plot.getAxes();\n                    // xmin etc. is backwards compatibility, to be\n                    // removed in the future\n                    axes.xmin = axes.xaxis.min;\n                    axes.xmax = axes.xaxis.max;\n                    axes.ymin = axes.yaxis.min;\n                    axes.ymax = axes.yaxis.max;\n\n                    markings = markings(axes);\n                }\n\n                for (i = 0; i < markings.length; ++i) {\n                    var m = markings[i],\n                        xrange = extractRange(m, \"x\"),\n                        yrange = extractRange(m, \"y\");\n\n                    // fill in missing\n                    if (xrange.from == null)\n                        xrange.from = xrange.axis.min;\n                    if (xrange.to == null)\n                        xrange.to = xrange.axis.max;\n                    if (yrange.from == null)\n                        yrange.from = yrange.axis.min;\n                    if (yrange.to == null)\n                        yrange.to = yrange.axis.max;\n\n                    // clip\n                    if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||\n                        yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)\n                        continue;\n\n                    xrange.from = Math.max(xrange.from, xrange.axis.min);\n                    xrange.to = Math.min(xrange.to, xrange.axis.max);\n                    yrange.from = Math.max(yrange.from, yrange.axis.min);\n                    yrange.to = Math.min(yrange.to, yrange.axis.max);\n\n                    var xequal = xrange.from === xrange.to,\n                        yequal = yrange.from === yrange.to;\n\n                    if (xequal && yequal) {\n                        continue;\n                    }\n\n                    // then draw\n                    xrange.from = Math.floor(xrange.axis.p2c(xrange.from));\n                    xrange.to = Math.floor(xrange.axis.p2c(xrange.to));\n                    yrange.from = Math.floor(yrange.axis.p2c(yrange.from));\n                    yrange.to = Math.floor(yrange.axis.p2c(yrange.to));\n\n                    if (xequal || yequal) {\n                        var lineWidth = m.lineWidth || options.grid.markingsLineWidth,\n                            subPixel = lineWidth % 2 ? 0.5 : 0;\n                        ctx.beginPath();\n                        ctx.strokeStyle = m.color || options.grid.markingsColor;\n                        ctx.lineWidth = lineWidth;\n                        if (xequal) {\n                            ctx.moveTo(xrange.to + subPixel, yrange.from);\n                            ctx.lineTo(xrange.to + subPixel, yrange.to);\n                        } else {\n                            ctx.moveTo(xrange.from, yrange.to + subPixel);\n                            ctx.lineTo(xrange.to, yrange.to + subPixel);                            \n                        }\n                        ctx.stroke();\n                    } else {\n                        ctx.fillStyle = m.color || options.grid.markingsColor;\n                        ctx.fillRect(xrange.from, yrange.to,\n                                     xrange.to - xrange.from,\n                                     yrange.from - yrange.to);\n                    }\n                }\n            }\n\n            // draw the ticks\n            axes = allAxes();\n            bw = options.grid.borderWidth;\n\n            for (var j = 0; j < axes.length; ++j) {\n                var axis = axes[j], box = axis.box,\n                    t = axis.tickLength, x, y, xoff, yoff;\n                if (!axis.show || axis.ticks.length == 0)\n                    continue;\n\n                ctx.lineWidth = 1;\n\n                // find the edges\n                if (axis.direction == \"x\") {\n                    x = 0;\n                    if (t == \"full\")\n                        y = (axis.position == \"top\" ? 0 : plotHeight);\n                    else\n                        y = box.top - plotOffset.top + (axis.position == \"top\" ? box.height : 0);\n                }\n                else {\n                    y = 0;\n                    if (t == \"full\")\n                        x = (axis.position == \"left\" ? 0 : plotWidth);\n                    else\n                        x = box.left - plotOffset.left + (axis.position == \"left\" ? box.width : 0);\n                }\n\n                // draw tick bar\n                if (!axis.innermost) {\n                    ctx.strokeStyle = axis.options.color;\n                    ctx.beginPath();\n                    xoff = yoff = 0;\n                    if (axis.direction == \"x\")\n                        xoff = plotWidth + 1;\n                    else\n                        yoff = plotHeight + 1;\n\n                    if (ctx.lineWidth == 1) {\n                        if (axis.direction == \"x\") {\n                            y = Math.floor(y) + 0.5;\n                        } else {\n                            x = Math.floor(x) + 0.5;\n                        }\n                    }\n\n                    ctx.moveTo(x, y);\n                    ctx.lineTo(x + xoff, y + yoff);\n                    ctx.stroke();\n                }\n\n                // draw ticks\n\n                ctx.strokeStyle = axis.options.tickColor;\n\n                ctx.beginPath();\n                for (i = 0; i < axis.ticks.length; ++i) {\n                    var v = axis.ticks[i].v;\n\n                    xoff = yoff = 0;\n\n                    if (isNaN(v) || v < axis.min || v > axis.max\n                        // skip those lying on the axes if we got a border\n                        || (t == \"full\"\n                            && ((typeof bw == \"object\" && bw[axis.position] > 0) || bw > 0)\n                            && (v == axis.min || v == axis.max)))\n                        continue;\n\n                    if (axis.direction == \"x\") {\n                        x = axis.p2c(v);\n                        yoff = t == \"full\" ? -plotHeight : t;\n\n                        if (axis.position == \"top\")\n                            yoff = -yoff;\n                    }\n                    else {\n                        y = axis.p2c(v);\n                        xoff = t == \"full\" ? -plotWidth : t;\n\n                        if (axis.position == \"left\")\n                            xoff = -xoff;\n                    }\n\n                    if (ctx.lineWidth == 1) {\n                        if (axis.direction == \"x\")\n                            x = Math.floor(x) + 0.5;\n                        else\n                            y = Math.floor(y) + 0.5;\n                    }\n\n                    ctx.moveTo(x, y);\n                    ctx.lineTo(x + xoff, y + yoff);\n                }\n\n                ctx.stroke();\n            }\n\n\n            // draw border\n            if (bw) {\n                // If either borderWidth or borderColor is an object, then draw the border\n                // line by line instead of as one rectangle\n                bc = options.grid.borderColor;\n                if(typeof bw == \"object\" || typeof bc == \"object\") {\n                    if (typeof bw !== \"object\") {\n                        bw = {top: bw, right: bw, bottom: bw, left: bw};\n                    }\n                    if (typeof bc !== \"object\") {\n                        bc = {top: bc, right: bc, bottom: bc, left: bc};\n                    }\n\n                    if (bw.top > 0) {\n                        ctx.strokeStyle = bc.top;\n                        ctx.lineWidth = bw.top;\n                        ctx.beginPath();\n                        ctx.moveTo(0 - bw.left, 0 - bw.top/2);\n                        ctx.lineTo(plotWidth, 0 - bw.top/2);\n                        ctx.stroke();\n                    }\n\n                    if (bw.right > 0) {\n                        ctx.strokeStyle = bc.right;\n                        ctx.lineWidth = bw.right;\n                        ctx.beginPath();\n                        ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top);\n                        ctx.lineTo(plotWidth + bw.right / 2, plotHeight);\n                        ctx.stroke();\n                    }\n\n                    if (bw.bottom > 0) {\n                        ctx.strokeStyle = bc.bottom;\n                        ctx.lineWidth = bw.bottom;\n                        ctx.beginPath();\n                        ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2);\n                        ctx.lineTo(0, plotHeight + bw.bottom / 2);\n                        ctx.stroke();\n                    }\n\n                    if (bw.left > 0) {\n                        ctx.strokeStyle = bc.left;\n                        ctx.lineWidth = bw.left;\n                        ctx.beginPath();\n                        ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom);\n                        ctx.lineTo(0- bw.left/2, 0);\n                        ctx.stroke();\n                    }\n                }\n                else {\n                    ctx.lineWidth = bw;\n                    ctx.strokeStyle = options.grid.borderColor;\n                    ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);\n                }\n            }\n\n            ctx.restore();\n        }\n\n        function drawAxisLabels() {\n\n            $.each(allAxes(), function (_, axis) {\n                var box = axis.box,\n                    legacyStyles = axis.direction + \"Axis \" + axis.direction + axis.n + \"Axis\",\n                    layer = \"flot-\" + axis.direction + \"-axis flot-\" + axis.direction + axis.n + \"-axis \" + legacyStyles,\n                    font = axis.options.font || \"flot-tick-label tickLabel\",\n                    tick, x, y, halign, valign;\n\n                // Remove text before checking for axis.show and ticks.length;\n                // otherwise plugins, like flot-tickrotor, that draw their own\n                // tick labels will end up with both theirs and the defaults.\n\n                surface.removeText(layer);\n\n                if (!axis.show || axis.ticks.length == 0)\n                    return;\n\n                for (var i = 0; i < axis.ticks.length; ++i) {\n\n                    tick = axis.ticks[i];\n                    if (!tick.label || tick.v < axis.min || tick.v > axis.max)\n                        continue;\n\n                    if (axis.direction == \"x\") {\n                        halign = \"center\";\n                        x = plotOffset.left + axis.p2c(tick.v);\n                        if (axis.position == \"bottom\") {\n                            y = box.top + box.padding;\n                        } else {\n                            y = box.top + box.height - box.padding;\n                            valign = \"bottom\";\n                        }\n                    } else {\n                        valign = \"middle\";\n                        y = plotOffset.top + axis.p2c(tick.v);\n                        if (axis.position == \"left\") {\n                            x = box.left + box.width - box.padding;\n                            halign = \"right\";\n                        } else {\n                            x = box.left + box.padding;\n                        }\n                    }\n\n                    surface.addText(layer, x, y, tick.label, font, null, null, halign, valign);\n                }\n            });\n        }\n\n        function drawSeries(series) {\n            if (series.lines.show)\n                drawSeriesLines(series);\n            if (series.bars.show)\n                drawSeriesBars(series);\n            if (series.points.show)\n                drawSeriesPoints(series);\n        }\n\n        function drawSeriesLines(series) {\n            function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {\n                var points = datapoints.points,\n                    ps = datapoints.pointsize,\n                    prevx = null, prevy = null;\n\n                ctx.beginPath();\n                for (var i = ps; i < points.length; i += ps) {\n                    var x1 = points[i - ps], y1 = points[i - ps + 1],\n                        x2 = points[i], y2 = points[i + 1];\n\n                    if (x1 == null || x2 == null)\n                        continue;\n\n                    // clip with ymin\n                    if (y1 <= y2 && y1 < axisy.min) {\n                        if (y2 < axisy.min)\n                            continue;   // line segment is outside\n                        // compute new intersection point\n                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y1 = axisy.min;\n                    }\n                    else if (y2 <= y1 && y2 < axisy.min) {\n                        if (y1 < axisy.min)\n                            continue;\n                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y2 = axisy.min;\n                    }\n\n                    // clip with ymax\n                    if (y1 >= y2 && y1 > axisy.max) {\n                        if (y2 > axisy.max)\n                            continue;\n                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y1 = axisy.max;\n                    }\n                    else if (y2 >= y1 && y2 > axisy.max) {\n                        if (y1 > axisy.max)\n                            continue;\n                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y2 = axisy.max;\n                    }\n\n                    // clip with xmin\n                    if (x1 <= x2 && x1 < axisx.min) {\n                        if (x2 < axisx.min)\n                            continue;\n                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x1 = axisx.min;\n                    }\n                    else if (x2 <= x1 && x2 < axisx.min) {\n                        if (x1 < axisx.min)\n                            continue;\n                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x2 = axisx.min;\n                    }\n\n                    // clip with xmax\n                    if (x1 >= x2 && x1 > axisx.max) {\n                        if (x2 > axisx.max)\n                            continue;\n                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x1 = axisx.max;\n                    }\n                    else if (x2 >= x1 && x2 > axisx.max) {\n                        if (x1 > axisx.max)\n                            continue;\n                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x2 = axisx.max;\n                    }\n\n                    if (x1 != prevx || y1 != prevy)\n                        ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);\n\n                    prevx = x2;\n                    prevy = y2;\n                    ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);\n                }\n                ctx.stroke();\n            }\n\n            function plotLineArea(datapoints, axisx, axisy) {\n                var points = datapoints.points,\n                    ps = datapoints.pointsize,\n                    bottom = Math.min(Math.max(0, axisy.min), axisy.max),\n                    i = 0, top, areaOpen = false,\n                    ypos = 1, segmentStart = 0, segmentEnd = 0;\n\n                // we process each segment in two turns, first forward\n                // direction to sketch out top, then once we hit the\n                // end we go backwards to sketch the bottom\n                while (true) {\n                    if (ps > 0 && i > points.length + ps)\n                        break;\n\n                    i += ps; // ps is negative if going backwards\n\n                    var x1 = points[i - ps],\n                        y1 = points[i - ps + ypos],\n                        x2 = points[i], y2 = points[i + ypos];\n\n                    if (areaOpen) {\n                        if (ps > 0 && x1 != null && x2 == null) {\n                            // at turning point\n                            segmentEnd = i;\n                            ps = -ps;\n                            ypos = 2;\n                            continue;\n                        }\n\n                        if (ps < 0 && i == segmentStart + ps) {\n                            // done with the reverse sweep\n                            ctx.fill();\n                            areaOpen = false;\n                            ps = -ps;\n                            ypos = 1;\n                            i = segmentStart = segmentEnd + ps;\n                            continue;\n                        }\n                    }\n\n                    if (x1 == null || x2 == null)\n                        continue;\n\n                    // clip x values\n\n                    // clip with xmin\n                    if (x1 <= x2 && x1 < axisx.min) {\n                        if (x2 < axisx.min)\n                            continue;\n                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x1 = axisx.min;\n                    }\n                    else if (x2 <= x1 && x2 < axisx.min) {\n                        if (x1 < axisx.min)\n                            continue;\n                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x2 = axisx.min;\n                    }\n\n                    // clip with xmax\n                    if (x1 >= x2 && x1 > axisx.max) {\n                        if (x2 > axisx.max)\n                            continue;\n                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x1 = axisx.max;\n                    }\n                    else if (x2 >= x1 && x2 > axisx.max) {\n                        if (x1 > axisx.max)\n                            continue;\n                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;\n                        x2 = axisx.max;\n                    }\n\n                    if (!areaOpen) {\n                        // open area\n                        ctx.beginPath();\n                        ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));\n                        areaOpen = true;\n                    }\n\n                    // now first check the case where both is outside\n                    if (y1 >= axisy.max && y2 >= axisy.max) {\n                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));\n                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));\n                        continue;\n                    }\n                    else if (y1 <= axisy.min && y2 <= axisy.min) {\n                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));\n                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));\n                        continue;\n                    }\n\n                    // else it's a bit more complicated, there might\n                    // be a flat maxed out rectangle first, then a\n                    // triangular cutout or reverse; to find these\n                    // keep track of the current x values\n                    var x1old = x1, x2old = x2;\n\n                    // clip the y values, without shortcutting, we\n                    // go through all cases in turn\n\n                    // clip with ymin\n                    if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {\n                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y1 = axisy.min;\n                    }\n                    else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {\n                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y2 = axisy.min;\n                    }\n\n                    // clip with ymax\n                    if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {\n                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y1 = axisy.max;\n                    }\n                    else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {\n                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;\n                        y2 = axisy.max;\n                    }\n\n                    // if the x value was changed we got a rectangle\n                    // to fill\n                    if (x1 != x1old) {\n                        ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));\n                        // it goes to (x1, y1), but we fill that below\n                    }\n\n                    // fill triangular section, this sometimes result\n                    // in redundant points if (x1, y1) hasn't changed\n                    // from previous line to, but we just ignore that\n                    ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));\n                    ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));\n\n                    // fill the other rectangle if it's there\n                    if (x2 != x2old) {\n                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));\n                        ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));\n                    }\n                }\n            }\n\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n            ctx.lineJoin = \"round\";\n\n            var lw = series.lines.lineWidth,\n                sw = series.shadowSize;\n            // FIXME: consider another form of shadow when filling is turned on\n            if (lw > 0 && sw > 0) {\n                // draw shadow as a thick and thin line with transparency\n                ctx.lineWidth = sw;\n                ctx.strokeStyle = \"rgba(0,0,0,0.1)\";\n                // position shadow at angle from the mid of line\n                var angle = Math.PI/18;\n                plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis);\n                ctx.lineWidth = sw/2;\n                plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis);\n            }\n\n            ctx.lineWidth = lw;\n            ctx.strokeStyle = series.color;\n            var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);\n            if (fillStyle) {\n                ctx.fillStyle = fillStyle;\n                plotLineArea(series.datapoints, series.xaxis, series.yaxis);\n            }\n\n            if (lw > 0)\n                plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);\n            ctx.restore();\n        }\n\n        function drawSeriesPoints(series) {\n            function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {\n                var points = datapoints.points, ps = datapoints.pointsize;\n\n                for (var i = 0; i < points.length; i += ps) {\n                    var x = points[i], y = points[i + 1];\n                    if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)\n                        continue;\n\n                    ctx.beginPath();\n                    x = axisx.p2c(x);\n                    y = axisy.p2c(y) + offset;\n                    if (symbol == \"circle\")\n                        ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);\n                    else\n                        symbol(ctx, x, y, radius, shadow);\n                    ctx.closePath();\n\n                    if (fillStyle) {\n                        ctx.fillStyle = fillStyle;\n                        ctx.fill();\n                    }\n                    ctx.stroke();\n                }\n            }\n\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n\n            var lw = series.points.lineWidth,\n                sw = series.shadowSize,\n                radius = series.points.radius,\n                symbol = series.points.symbol;\n\n            // If the user sets the line width to 0, we change it to a very \n            // small value. A line width of 0 seems to force the default of 1.\n            // Doing the conditional here allows the shadow setting to still be \n            // optional even with a lineWidth of 0.\n\n            if( lw == 0 )\n                lw = 0.0001;\n\n            if (lw > 0 && sw > 0) {\n                // draw shadow in two steps\n                var w = sw / 2;\n                ctx.lineWidth = w;\n                ctx.strokeStyle = \"rgba(0,0,0,0.1)\";\n                plotPoints(series.datapoints, radius, null, w + w/2, true,\n                           series.xaxis, series.yaxis, symbol);\n\n                ctx.strokeStyle = \"rgba(0,0,0,0.2)\";\n                plotPoints(series.datapoints, radius, null, w/2, true,\n                           series.xaxis, series.yaxis, symbol);\n            }\n\n            ctx.lineWidth = lw;\n            ctx.strokeStyle = series.color;\n            plotPoints(series.datapoints, radius,\n                       getFillStyle(series.points, series.color), 0, false,\n                       series.xaxis, series.yaxis, symbol);\n            ctx.restore();\n        }\n\n        function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {\n            var left, right, bottom, top,\n                drawLeft, drawRight, drawTop, drawBottom,\n                tmp;\n\n            // in horizontal mode, we start the bar from the left\n            // instead of from the bottom so it appears to be\n            // horizontal rather than vertical\n            if (horizontal) {\n                drawBottom = drawRight = drawTop = true;\n                drawLeft = false;\n                left = b;\n                right = x;\n                top = y + barLeft;\n                bottom = y + barRight;\n\n                // account for negative bars\n                if (right < left) {\n                    tmp = right;\n                    right = left;\n                    left = tmp;\n                    drawLeft = true;\n                    drawRight = false;\n                }\n            }\n            else {\n                drawLeft = drawRight = drawTop = true;\n                drawBottom = false;\n                left = x + barLeft;\n                right = x + barRight;\n                bottom = b;\n                top = y;\n\n                // account for negative bars\n                if (top < bottom) {\n                    tmp = top;\n                    top = bottom;\n                    bottom = tmp;\n                    drawBottom = true;\n                    drawTop = false;\n                }\n            }\n\n            // clip\n            if (right < axisx.min || left > axisx.max ||\n                top < axisy.min || bottom > axisy.max)\n                return;\n\n            if (left < axisx.min) {\n                left = axisx.min;\n                drawLeft = false;\n            }\n\n            if (right > axisx.max) {\n                right = axisx.max;\n                drawRight = false;\n            }\n\n            if (bottom < axisy.min) {\n                bottom = axisy.min;\n                drawBottom = false;\n            }\n\n            if (top > axisy.max) {\n                top = axisy.max;\n                drawTop = false;\n            }\n\n            left = axisx.p2c(left);\n            bottom = axisy.p2c(bottom);\n            right = axisx.p2c(right);\n            top = axisy.p2c(top);\n\n            // fill the bar\n            if (fillStyleCallback) {\n                c.fillStyle = fillStyleCallback(bottom, top);\n                c.fillRect(left, top, right - left, bottom - top)\n            }\n\n            // draw outline\n            if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {\n                c.beginPath();\n\n                // FIXME: inline moveTo is buggy with excanvas\n                c.moveTo(left, bottom);\n                if (drawLeft)\n                    c.lineTo(left, top);\n                else\n                    c.moveTo(left, top);\n                if (drawTop)\n                    c.lineTo(right, top);\n                else\n                    c.moveTo(right, top);\n                if (drawRight)\n                    c.lineTo(right, bottom);\n                else\n                    c.moveTo(right, bottom);\n                if (drawBottom)\n                    c.lineTo(left, bottom);\n                else\n                    c.moveTo(left, bottom);\n                c.stroke();\n            }\n        }\n\n        function drawSeriesBars(series) {\n            function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {\n                var points = datapoints.points, ps = datapoints.pointsize;\n\n                for (var i = 0; i < points.length; i += ps) {\n                    if (points[i] == null)\n                        continue;\n                    drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);\n                }\n            }\n\n            ctx.save();\n            ctx.translate(plotOffset.left, plotOffset.top);\n\n            // FIXME: figure out a way to add shadows (for instance along the right edge)\n            ctx.lineWidth = series.bars.lineWidth;\n            ctx.strokeStyle = series.color;\n\n            var barLeft;\n\n            switch (series.bars.align) {\n                case \"left\":\n                    barLeft = 0;\n                    break;\n                case \"right\":\n                    barLeft = -series.bars.barWidth;\n                    break;\n                default:\n                    barLeft = -series.bars.barWidth / 2;\n            }\n\n            var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;\n            plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis);\n            ctx.restore();\n        }\n\n        function getFillStyle(filloptions, seriesColor, bottom, top) {\n            var fill = filloptions.fill;\n            if (!fill)\n                return null;\n\n            if (filloptions.fillColor)\n                return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);\n\n            var c = $.color.parse(seriesColor);\n            c.a = typeof fill == \"number\" ? fill : 0.4;\n            c.normalize();\n            return c.toString();\n        }\n\n        function insertLegend() {\n\n            if (options.legend.container != null) {\n                $(options.legend.container).html(\"\");\n            } else {\n                placeholder.find(\".legend\").remove();\n            }\n\n            if (!options.legend.show) {\n                return;\n            }\n\n            var fragments = [], entries = [], rowStarted = false,\n                lf = options.legend.labelFormatter, s, label;\n\n            // Build a list of legend entries, with each having a label and a color\n\n            for (var i = 0; i < series.length; ++i) {\n                s = series[i];\n                if (s.label) {\n                    label = lf ? lf(s.label, s) : s.label;\n                    if (label) {\n                        entries.push({\n                            label: label,\n                            color: s.color\n                        });\n                    }\n                }\n            }\n\n            // Sort the legend using either the default or a custom comparator\n\n            if (options.legend.sorted) {\n                if ($.isFunction(options.legend.sorted)) {\n                    entries.sort(options.legend.sorted);\n                } else if (options.legend.sorted == \"reverse\") {\n                \tentries.reverse();\n                } else {\n                    var ascending = options.legend.sorted != \"descending\";\n                    entries.sort(function(a, b) {\n                        return a.label == b.label ? 0 : (\n                            (a.label < b.label) != ascending ? 1 : -1   // Logical XOR\n                        );\n                    });\n                }\n            }\n\n            // Generate markup for the list of entries, in their final order\n\n            for (var i = 0; i < entries.length; ++i) {\n\n                var entry = entries[i];\n\n                if (i % options.legend.noColumns == 0) {\n                    if (rowStarted)\n                        fragments.push('</tr>');\n                    fragments.push('<tr>');\n                    rowStarted = true;\n                }\n\n                fragments.push(\n                    '<td class=\"legendColorBox\"><div style=\"border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px\"><div style=\"width:4px;height:0;border:5px solid ' + entry.color + ';overflow:hidden\"></div></div></td>' +\n                    '<td class=\"legendLabel\">' + entry.label + '</td>'\n                );\n            }\n\n            if (rowStarted)\n                fragments.push('</tr>');\n\n            if (fragments.length == 0)\n                return;\n\n            var table = '<table style=\"font-size:smaller;color:' + options.grid.color + '\">' + fragments.join(\"\") + '</table>';\n            if (options.legend.container != null)\n                $(options.legend.container).html(table);\n            else {\n                var pos = \"\",\n                    p = options.legend.position,\n                    m = options.legend.margin;\n                if (m[0] == null)\n                    m = [m, m];\n                if (p.charAt(0) == \"n\")\n                    pos += 'top:' + (m[1] + plotOffset.top) + 'px;';\n                else if (p.charAt(0) == \"s\")\n                    pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';\n                if (p.charAt(1) == \"e\")\n                    pos += 'right:' + (m[0] + plotOffset.right) + 'px;';\n                else if (p.charAt(1) == \"w\")\n                    pos += 'left:' + (m[0] + plotOffset.left) + 'px;';\n                var legend = $('<div class=\"legend\">' + table.replace('style=\"', 'style=\"position:absolute;' + pos +';') + '</div>').appendTo(placeholder);\n                if (options.legend.backgroundOpacity != 0.0) {\n                    // put in the transparent background\n                    // separately to avoid blended labels and\n                    // label boxes\n                    var c = options.legend.backgroundColor;\n                    if (c == null) {\n                        c = options.grid.backgroundColor;\n                        if (c && typeof c == \"string\")\n                            c = $.color.parse(c);\n                        else\n                            c = $.color.extract(legend, 'background-color');\n                        c.a = 1;\n                        c = c.toString();\n                    }\n                    var div = legend.children();\n                    $('<div style=\"position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';\"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);\n                }\n            }\n        }\n\n\n        // interactive features\n\n        var highlights = [],\n            redrawTimeout = null;\n\n        // returns the data item the mouse is over, or null if none is found\n        function findNearbyItem(mouseX, mouseY, seriesFilter) {\n            var maxDistance = options.grid.mouseActiveRadius,\n                smallestDistance = maxDistance * maxDistance + 1,\n                item = null, foundPoint = false, i, j, ps;\n\n            for (i = series.length - 1; i >= 0; --i) {\n                if (!seriesFilter(series[i]))\n                    continue;\n\n                var s = series[i],\n                    axisx = s.xaxis,\n                    axisy = s.yaxis,\n                    points = s.datapoints.points,\n                    mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster\n                    my = axisy.c2p(mouseY),\n                    maxx = maxDistance / axisx.scale,\n                    maxy = maxDistance / axisy.scale;\n\n                ps = s.datapoints.pointsize;\n                // with inverse transforms, we can't use the maxx/maxy\n                // optimization, sadly\n                if (axisx.options.inverseTransform)\n                    maxx = Number.MAX_VALUE;\n                if (axisy.options.inverseTransform)\n                    maxy = Number.MAX_VALUE;\n\n                if (s.lines.show || s.points.show) {\n                    for (j = 0; j < points.length; j += ps) {\n                        var x = points[j], y = points[j + 1];\n                        if (x == null)\n                            continue;\n\n                        // For points and lines, the cursor must be within a\n                        // certain distance to the data point\n                        if (x - mx > maxx || x - mx < -maxx ||\n                            y - my > maxy || y - my < -maxy)\n                            continue;\n\n                        // We have to calculate distances in pixels, not in\n                        // data units, because the scales of the axes may be different\n                        var dx = Math.abs(axisx.p2c(x) - mouseX),\n                            dy = Math.abs(axisy.p2c(y) - mouseY),\n                            dist = dx * dx + dy * dy; // we save the sqrt\n\n                        // use <= to ensure last point takes precedence\n                        // (last generally means on top of)\n                        if (dist < smallestDistance) {\n                            smallestDistance = dist;\n                            item = [i, j / ps];\n                        }\n                    }\n                }\n\n                if (s.bars.show && !item) { // no other point can be nearby\n\n                    var barLeft, barRight;\n\n                    switch (s.bars.align) {\n                        case \"left\":\n                            barLeft = 0;\n                            break;\n                        case \"right\":\n                            barLeft = -s.bars.barWidth;\n                            break;\n                        default:\n                            barLeft = -s.bars.barWidth / 2;\n                    }\n\n                    barRight = barLeft + s.bars.barWidth;\n\n                    for (j = 0; j < points.length; j += ps) {\n                        var x = points[j], y = points[j + 1], b = points[j + 2];\n                        if (x == null)\n                            continue;\n\n                        // for a bar graph, the cursor must be inside the bar\n                        if (series[i].bars.horizontal ?\n                            (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&\n                             my >= y + barLeft && my <= y + barRight) :\n                            (mx >= x + barLeft && mx <= x + barRight &&\n                             my >= Math.min(b, y) && my <= Math.max(b, y)))\n                                item = [i, j / ps];\n                    }\n                }\n            }\n\n            if (item) {\n                i = item[0];\n                j = item[1];\n                ps = series[i].datapoints.pointsize;\n\n                return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),\n                         dataIndex: j,\n                         series: series[i],\n                         seriesIndex: i };\n            }\n\n            return null;\n        }\n\n        function onMouseMove(e) {\n            if (options.grid.hoverable)\n                triggerClickHoverEvent(\"plothover\", e,\n                                       function (s) { return s[\"hoverable\"] != false; });\n        }\n\n        function onMouseLeave(e) {\n            if (options.grid.hoverable)\n                triggerClickHoverEvent(\"plothover\", e,\n                                       function (s) { return false; });\n        }\n\n        function onClick(e) {\n            triggerClickHoverEvent(\"plotclick\", e,\n                                   function (s) { return s[\"clickable\"] != false; });\n        }\n\n        // trigger click or hover event (they send the same parameters\n        // so we share their code)\n        function triggerClickHoverEvent(eventname, event, seriesFilter) {\n            var offset = eventHolder.offset(),\n                canvasX = event.pageX - offset.left - plotOffset.left,\n                canvasY = event.pageY - offset.top - plotOffset.top,\n            pos = canvasToAxisCoords({ left: canvasX, top: canvasY });\n\n            pos.pageX = event.pageX;\n            pos.pageY = event.pageY;\n\n            var item = findNearbyItem(canvasX, canvasY, seriesFilter);\n\n            if (item) {\n                // fill in mouse pos for any listeners out there\n                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10);\n                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10);\n            }\n\n            if (options.grid.autoHighlight) {\n                // clear auto-highlights\n                for (var i = 0; i < highlights.length; ++i) {\n                    var h = highlights[i];\n                    if (h.auto == eventname &&\n                        !(item && h.series == item.series &&\n                          h.point[0] == item.datapoint[0] &&\n                          h.point[1] == item.datapoint[1]))\n                        unhighlight(h.series, h.point);\n                }\n\n                if (item)\n                    highlight(item.series, item.datapoint, eventname);\n            }\n\n            placeholder.trigger(eventname, [ pos, item ]);\n        }\n\n        function triggerRedrawOverlay() {\n            var t = options.interaction.redrawOverlayInterval;\n            if (t == -1) {      // skip event queue\n                drawOverlay();\n                return;\n            }\n\n            if (!redrawTimeout)\n                redrawTimeout = setTimeout(drawOverlay, t);\n        }\n\n        function drawOverlay() {\n            redrawTimeout = null;\n\n            // draw highlights\n            octx.save();\n            overlay.clear();\n            octx.translate(plotOffset.left, plotOffset.top);\n\n            var i, hi;\n            for (i = 0; i < highlights.length; ++i) {\n                hi = highlights[i];\n\n                if (hi.series.bars.show)\n                    drawBarHighlight(hi.series, hi.point);\n                else\n                    drawPointHighlight(hi.series, hi.point);\n            }\n            octx.restore();\n\n            executeHooks(hooks.drawOverlay, [octx]);\n        }\n\n        function highlight(s, point, auto) {\n            if (typeof s == \"number\")\n                s = series[s];\n\n            if (typeof point == \"number\") {\n                var ps = s.datapoints.pointsize;\n                point = s.datapoints.points.slice(ps * point, ps * (point + 1));\n            }\n\n            var i = indexOfHighlight(s, point);\n            if (i == -1) {\n                highlights.push({ series: s, point: point, auto: auto });\n\n                triggerRedrawOverlay();\n            }\n            else if (!auto)\n                highlights[i].auto = false;\n        }\n\n        function unhighlight(s, point) {\n            if (s == null && point == null) {\n                highlights = [];\n                triggerRedrawOverlay();\n                return;\n            }\n\n            if (typeof s == \"number\")\n                s = series[s];\n\n            if (typeof point == \"number\") {\n                var ps = s.datapoints.pointsize;\n                point = s.datapoints.points.slice(ps * point, ps * (point + 1));\n            }\n\n            var i = indexOfHighlight(s, point);\n            if (i != -1) {\n                highlights.splice(i, 1);\n\n                triggerRedrawOverlay();\n            }\n        }\n\n        function indexOfHighlight(s, p) {\n            for (var i = 0; i < highlights.length; ++i) {\n                var h = highlights[i];\n                if (h.series == s && h.point[0] == p[0]\n                    && h.point[1] == p[1])\n                    return i;\n            }\n            return -1;\n        }\n\n        function drawPointHighlight(series, point) {\n            var x = point[0], y = point[1],\n                axisx = series.xaxis, axisy = series.yaxis,\n                highlightColor = (typeof series.highlightColor === \"string\") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();\n\n            if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)\n                return;\n\n            var pointRadius = series.points.radius + series.points.lineWidth / 2;\n            octx.lineWidth = pointRadius;\n            octx.strokeStyle = highlightColor;\n            var radius = 1.5 * pointRadius;\n            x = axisx.p2c(x);\n            y = axisy.p2c(y);\n\n            octx.beginPath();\n            if (series.points.symbol == \"circle\")\n                octx.arc(x, y, radius, 0, 2 * Math.PI, false);\n            else\n                series.points.symbol(octx, x, y, radius, false);\n            octx.closePath();\n            octx.stroke();\n        }\n\n        function drawBarHighlight(series, point) {\n            var highlightColor = (typeof series.highlightColor === \"string\") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),\n                fillStyle = highlightColor,\n                barLeft;\n\n            switch (series.bars.align) {\n                case \"left\":\n                    barLeft = 0;\n                    break;\n                case \"right\":\n                    barLeft = -series.bars.barWidth;\n                    break;\n                default:\n                    barLeft = -series.bars.barWidth / 2;\n            }\n\n            octx.lineWidth = series.bars.lineWidth;\n            octx.strokeStyle = highlightColor;\n\n            drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,\n                    function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);\n        }\n\n        function getColorOrGradient(spec, bottom, top, defaultColor) {\n            if (typeof spec == \"string\")\n                return spec;\n            else {\n                // assume this is a gradient spec; IE currently only\n                // supports a simple vertical gradient properly, so that's\n                // what we support too\n                var gradient = ctx.createLinearGradient(0, top, 0, bottom);\n\n                for (var i = 0, l = spec.colors.length; i < l; ++i) {\n                    var c = spec.colors[i];\n                    if (typeof c != \"string\") {\n                        var co = $.color.parse(defaultColor);\n                        if (c.brightness != null)\n                            co = co.scale('rgb', c.brightness);\n                        if (c.opacity != null)\n                            co.a *= c.opacity;\n                        c = co.toString();\n                    }\n                    gradient.addColorStop(i / (l - 1), c);\n                }\n\n                return gradient;\n            }\n        }\n    }\n\n    // Add the plot function to the top level of the jQuery object\n\n    $.plot = function(placeholder, data, options) {\n        //var t0 = new Date();\n        var plot = new Plot($(placeholder), data, options, $.plot.plugins);\n        //(window.console ? console.log : alert)(\"time used (msecs): \" + ((new Date()).getTime() - t0.getTime()));\n        return plot;\n    };\n\n    $.plot.version = \"0.8.3\";\n\n    $.plot.plugins = [];\n\n    // Also add the plot function as a chainable property\n\n    $.fn.plot = function(data, options) {\n        return this.each(function() {\n            $.plot(this, data, options);\n        });\n    };\n\n    // round to nearby lower multiple of base\n    function floorInBase(n, base) {\n        return base * Math.floor(n / base);\n    }\n\n})(jQuery);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/flot/jquery.flot.resize.js",
    "content": "/* Flot plugin for automatically redrawing plots as the placeholder resizes.\n\nCopyright (c) 2007-2014 IOLA and Ole Laursen.\nLicensed under the MIT license.\n\nIt works by listening for changes on the placeholder div (through the jQuery\nresize event plugin) - if the size changes, it will redraw the plot.\n\nThere are no options. If you need to disable the plugin for some plots, you\ncan just fix the size of their placeholders.\n\n*/\n\n/* Inline dependency:\n * jQuery resize event - v1.1 - 3/14/2010\n * http://benalman.com/projects/jquery-resize-plugin/\n *\n * Copyright (c) 2010 \"Cowboy\" Ben Alman\n * Dual licensed under the MIT and GPL licenses.\n * http://benalman.com/about/license/\n */\n(function($,e,t){\"$:nomunge\";var i=[],n=$.resize=$.extend($.resize,{}),a,r=false,s=\"setTimeout\",u=\"resize\",m=u+\"-special-event\",o=\"pendingDelay\",l=\"activeDelay\",f=\"throttleWindow\";n[o]=200;n[l]=20;n[f]=true;$.event.special[u]={setup:function(){if(!n[f]&&this[s]){return false}var e=$(this);i.push(this);e.data(m,{w:e.width(),h:e.height()});if(i.length===1){a=t;h()}},teardown:function(){if(!n[f]&&this[s]){return false}var e=$(this);for(var t=i.length-1;t>=0;t--){if(i[t]==this){i.splice(t,1);break}}e.removeData(m);if(!i.length){if(r){cancelAnimationFrame(a)}else{clearTimeout(a)}a=null}},add:function(e){if(!n[f]&&this[s]){return false}var i;function a(e,n,a){var r=$(this),s=r.data(m)||{};s.w=n!==t?n:r.width();s.h=a!==t?a:r.height();i.apply(this,arguments)}if($.isFunction(e)){i=e;return a}else{i=e.handler;e.handler=a}}};function h(t){if(r===true){r=t||1}for(var s=i.length-1;s>=0;s--){var l=$(i[s]);if(l[0]==e||l.is(\":visible\")){var f=l.width(),c=l.height(),d=l.data(m);if(d&&(f!==d.w||c!==d.h)){l.trigger(u,[d.w=f,d.h=c]);r=t||true}}else{d=l.data(m);d.w=0;d.h=0}}if(a!==null){if(r&&(t==null||t-r<1e3)){a=e.requestAnimationFrame(h)}else{a=setTimeout(h,n[o]);r=false}}}if(!e.requestAnimationFrame){e.requestAnimationFrame=function(){return e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(t,i){return e.setTimeout(function(){t((new Date).getTime())},n[l])}}()}if(!e.cancelAnimationFrame){e.cancelAnimationFrame=function(){return e.webkitCancelRequestAnimationFrame||e.mozCancelRequestAnimationFrame||e.oCancelRequestAnimationFrame||e.msCancelRequestAnimationFrame||clearTimeout}()}})(jQuery,this);\n\n(function ($) {\n    var options = { }; // no options\n\n    function init(plot) {\n        function onResize() {\n            var placeholder = plot.getPlaceholder();\n\n            // somebody might have hidden us and we can't plot\n            // when we don't have the dimensions\n            if (placeholder.width() == 0 || placeholder.height() == 0)\n                return;\n\n            plot.resize();\n            plot.setupGrid();\n            plot.draw();\n        }\n        \n        function bindEvents(plot, eventHolder) {\n            plot.getPlaceholder().resize(onResize);\n        }\n\n        function shutdown(plot, eventHolder) {\n            plot.getPlaceholder().unbind(\"resize\", onResize);\n        }\n        \n        plot.hooks.bindEvents.push(bindEvents);\n        plot.hooks.shutdown.push(shutdown);\n    }\n    \n    $.plot.plugins.push({\n        init: init,\n        options: options,\n        name: 'resize',\n        version: '1.0'\n    });\n})(jQuery);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/flot-orderBars/.bower.json",
    "content": "{\n  \"name\": \"flot-orderBars\",\n  \"homepage\": \"https://github.com/emmerich/flot-orderBars\",\n  \"_release\": \"d44ff4f2fe\",\n  \"_resolution\": {\n    \"type\": \"branch\",\n    \"branch\": \"master\",\n    \"commit\": \"d44ff4f2fec4c8bb1254e59567ee39fa3684372e\"\n  },\n  \"_source\": \"git://github.com/emmerich/flot-orderBars.git\",\n  \"_target\": \"*\",\n  \"_originalSource\": \"emmerich/flot-orderBars\",\n  \"_direct\": true\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/flot-orderBars/README.md",
    "content": "flot-orderBars\n==============\n\nFork of the Flot OrderBars plugin found here: http://www.benjaminbuffet.com/public/js/jquery.flot.orderBars.js\n\nImprovements\n============\n\n### Compatability with Flot Stack Plugin\nThe main improvement I've made is compatability with the [Flot Stack plugin](https://github.com/flot/flot/blob/master/jquery.flot.stack.js).\n\nTo use the 2 together:\n* Ensure that your data is well formed. Each series should contain a bars object with an order integer, like so:\n```javascript\n  var series = [];\n  \n  series.push({\n      data: [], // your raw data\n      bars: {\n          order: 0\n      }\n  });\n  \n  series.push({\n      data: [], // your raw data\n      bars: {\n          order: 1\n      }\n  });\n```\n\n* Ensure that the order bars plugin is loaded __before__ the stack plugin.\n\nSee the example for more information.\n\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/flot-orderBars/js/jquery.flot.orderBars.js",
    "content": "/*\n * Flot plugin to order bars side by side.\n *\n * Released under the MIT license by Benjamin BUFFET, 20-Sep-2010.\n * Modifications made by Steven Hall <github.com/emmerich>, 01-May-2013.\n *\n * This plugin is an alpha version.\n *\n * To activate the plugin you must specify the parameter \"order\" for the specific serie :\n *\n *  $.plot($(\"#placeholder\"), [{ data: [ ... ], bars :{ order = null or integer }])\n *\n * If 2 series have the same order param, they are ordered by the position in the array;\n *\n * The plugin adjust the point by adding a value depanding of the barwidth\n * Exemple for 3 series (barwidth : 0.1) :\n *\n *          first bar décalage : -0.15\n *          second bar décalage : -0.05\n *          third bar décalage : 0.05\n *\n */\n\n// INFO: decalage/decallage is French for gap. It's used to denote the spacing applied to each\n// bar.\n(function($){\n    function init(plot){\n        var orderedBarSeries;\n        var nbOfBarsToOrder;\n        var borderWidth;\n        var borderWidthInXabsWidth;\n        var pixelInXWidthEquivalent = 1;\n        var isHorizontal = false;\n\n        // A mapping of order integers to decallage.\n        var decallageByOrder = {};\n\n        /*\n         * This method add shift to x values\n         */\n        function reOrderBars(plot, serie, datapoints){\n            var shiftedPoints = null;\n\n            if(serieNeedToBeReordered(serie)){\n                checkIfGraphIsHorizontal(serie);\n                calculPixel2XWidthConvert(plot);\n                retrieveBarSeries(plot);\n                calculBorderAndBarWidth(serie);\n\n                if(nbOfBarsToOrder >= 2){\n                    var position = findPosition(serie);\n                    var decallage = 0;\n\n                    var centerBarShift = calculCenterBarShift();\n\n                    // If we haven't already calculated the decallage for this order value, do it.\n                    if(typeof decallageByOrder[serie.bars.order] === 'undefined') {\n                        if (isBarAtLeftOfCenter(position)){\n                            decallageByOrder[serie.bars.order] = -1*(sumWidth(orderedBarSeries,position-1,Math.floor(nbOfBarsToOrder / 2)-1)) - centerBarShift;\n                        }else{\n                            decallageByOrder[serie.bars.order] = sumWidth(orderedBarSeries,Math.ceil(nbOfBarsToOrder / 2),position-2) + centerBarShift + borderWidthInXabsWidth*2;\n                        }\n                    }\n\n                    // Lookup the decallage based on the series' order value.\n                    decallage = decallageByOrder[serie.bars.order];\n\n                    shiftedPoints = shiftPoints(datapoints,serie,decallage);\n                    datapoints.points = shiftedPoints;\n                }\n            }\n            return shiftedPoints;\n        }\n\n        function serieNeedToBeReordered(serie){\n            return serie.bars != null\n                && serie.bars.show\n                && serie.bars.order != null;\n        }\n\n        function calculPixel2XWidthConvert(plot){\n            var gridDimSize = isHorizontal ? plot.getPlaceholder().innerHeight() : plot.getPlaceholder().innerWidth();\n            var minMaxValues = isHorizontal ? getAxeMinMaxValues(plot.getData(),1) : getAxeMinMaxValues(plot.getData(),0);\n            var AxeSize = minMaxValues[1] - minMaxValues[0];\n            pixelInXWidthEquivalent = AxeSize / gridDimSize;\n        }\n\n        function getAxeMinMaxValues(series,AxeIdx){\n            var minMaxValues = new Array();\n            for(var i = 0; i < series.length; i++){\n                minMaxValues[0] = series[i].data[0][AxeIdx];\n                minMaxValues[1] = series[i].data[series[i].data.length - 1][AxeIdx];\n            }\n            return minMaxValues;\n        }\n\n        function retrieveBarSeries(plot){\n            orderedBarSeries = findOthersBarsToReOrders(plot.getData());\n            nbOfBarsToOrder = orderedBarSeries.length;\n        }\n\n        function findOthersBarsToReOrders(series){\n            var retSeries = new Array();\n            var orderValuesSeen = [];\n\n            for(var i = 0; i < series.length; i++){\n                if(series[i].bars.order != null && series[i].bars.show &&\n                    orderValuesSeen.indexOf(series[i].bars.order) < 0){\n\n                    orderValuesSeen.push(series[i].bars.order);\n                    retSeries.push(series[i]);\n                }\n            }\n            return retSeries.sort(sortByOrder);\n        }\n\n        function sortByOrder(serie1,serie2){\n            var x = serie1.bars.order;\n            var y = serie2.bars.order;\n            return ((x < y) ? -1 : ((x > y) ? 1 : 0));\n        }\n\n        function  calculBorderAndBarWidth(serie){\n            borderWidth = typeof serie.bars.lineWidth !== 'undefined' ? serie.bars.lineWidth  : 2;\n            borderWidthInXabsWidth = borderWidth * pixelInXWidthEquivalent;\n        }\n\n        function checkIfGraphIsHorizontal(serie){\n            if(serie.bars.horizontal){\n                isHorizontal = true;\n            }\n        }\n\n        function findPosition(serie){\n            var pos = 0\n            for (var i = 0; i < orderedBarSeries.length; ++i) {\n                if (serie == orderedBarSeries[i]){\n                    pos = i;\n                    break;\n                }\n            }\n\n            return pos+1;\n        }\n\n        function calculCenterBarShift(){\n            var width = 0;\n\n            if(nbOfBarsToOrder%2 != 0)\n                width = (orderedBarSeries[Math.ceil(nbOfBarsToOrder / 2)].bars.barWidth)/2;\n\n            return width;\n        }\n\n        function isBarAtLeftOfCenter(position){\n            return position <= Math.ceil(nbOfBarsToOrder / 2);\n        }\n\n        function sumWidth(series,start,end){\n            var totalWidth = 0;\n\n            for(var i = start; i <= end; i++){\n                totalWidth += series[i].bars.barWidth+borderWidthInXabsWidth*2;\n            }\n\n            return totalWidth;\n        }\n\n        function shiftPoints(datapoints,serie,dx){\n            var ps = datapoints.pointsize;\n            var points = datapoints.points;\n            var j = 0;\n            for(var i = isHorizontal ? 1 : 0;i < points.length; i += ps){\n                points[i] += dx;\n                //Adding the new x value in the serie to be abble to display the right tooltip value,\n                //using the index 3 to not overide the third index.\n                serie.data[j][3] = points[i];\n                j++;\n            }\n\n            return points;\n        }\n\n        plot.hooks.processDatapoints.push(reOrderBars);\n\n    }\n\n    var options = {\n        series : {\n            bars: {order: null} // or number/string\n        }\n    };\n\n    $.plot.plugins.push({\n        init: init,\n        options: options,\n        name: \"orderBars\",\n        version: \"0.2\"\n    });\n\n})(jQuery);"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/flot.curvedlines/curvedLines.js",
    "content": "/* The MIT License\n\n Copyright (c) 2011 by Michael Zinsmaier and nergal.dev\n Copyright (c) 2012 by Thomas Ritou\n\n Permission is hereby granted, free of charge, to any person obtaining a copy\n of this software and associated documentation files (the \"Software\"), to deal\n in the Software without restriction, including without limitation the rights\n to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n copies of the Software, and to permit persons to whom the Software is\n furnished to do so, subject to the following conditions:\n\n The above copyright notice and this permission notice shall be included in\n all copies or substantial portions of the Software.\n\n THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n THE SOFTWARE.\n*/\n\n/*\n____________________________________________________\n\n what it is:\n ____________________________________________________\n\n curvedLines is a plugin for flot, that tries to display lines in a smoother way.\n This is achieved through adding of more data points. The plugin is a data processor and can thus be used\n in combination with standard line / point rendering options.\n\n => 1) with large data sets you may get trouble\n => 2) if you want to display the points too, you have to plot them as 2nd data series over the lines\n => 3) consecutive x data points are not allowed to have the same value\n\n Feel free to further improve the code\n\n ____________________________________________________\n\n how to use it:\n ____________________________________________________\n\n var d1 = [[5,5],[7,3],[9,12]];\n\n var options = { series: { curvedLines: {  active: true }}};\n\n $.plot($(\"#placeholder\"), [{data: d1, lines: { show: true}, curvedLines: {apply: true}}], options);\n\n _____________________________________________________\n\n options:\n _____________________________________________________\n\n active:           bool true => plugin can be used\n apply:            bool true => series will be drawn as curved line\n monotonicFit:\t   bool true => uses monotone cubic interpolation (preserve monotonicity)\n tension:          int          defines the tension parameter of the hermite spline interpolation (no effect if monotonicFit is set)\n nrSplinePoints:   int \t\t\tdefines the number of sample points (of the spline) in between two consecutive points\n\n deprecated options from flot prior to 1.0.0:\n ------------------------------------------------\n legacyOverride\t   bool true => use old default\n    OR\n legacyOverride    optionArray\n {\n \tfit: \t             bool true => forces the max,mins of the curve to be on the datapoints\n \tcurvePointFactor\t int  \t\t  defines how many \"virtual\" points are used per \"real\" data point to\n \t\t\t\t\t\t\t\t\t  emulate the curvedLines (points total = real points * curvePointFactor)\n \tfitPointDist: \t     int  \t\t  defines the x axis distance of the additional two points that are used\n }\t\t\t\t\t\t   \t\t   \t  to enforce the min max condition.\n */\n\n/*\n *  v0.1   initial commit\n *  v0.15  negative values should work now (outcommented a negative -> 0 hook hope it does no harm)\n *  v0.2   added fill option (thanks to monemihir) and multi axis support (thanks to soewono effendi)\n *  v0.3   improved saddle handling and added basic handling of Dates\n *  v0.4   rewritten fill option (thomas ritou) mostly from original flot code (now fill between points rather than to graph bottom), corrected fill Opacity bug\n *  v0.5   rewritten instead of implementing a own draw function CurvedLines is now based on the processDatapoints flot hook (credits go to thomas ritou).\n * \t\t   This change breakes existing code however CurvedLines are now just many tiny straight lines to flot and therefore all flot lines options (like gradient fill,\n * \t       shadow) are now supported out of the box\n *  v0.6   flot 0.8 compatibility and some bug fixes\n *  v0.6.x changed versioning schema\n *\n *  v1.0.0 API Break marked existing implementation/options as deprecated\n *  v1.1.0 added the new curved line calculations based on hermite splines\n *  v1.1.1 added a rough parameter check to make sure the new options are used\n */\n\n(function($) {\n\n\tvar options = {\n\t\tseries : {\n\t\t\tcurvedLines : {\n\t\t\t\tactive : false,\n\t\t\t\tapply : false,\n\t\t\t\tmonotonicFit : false,\n\t\t\t\ttension : 0.5,\n\t\t\t\tnrSplinePoints : 20,\n\t\t\t\tlegacyOverride : undefined\n\t\t\t}\n\t\t}\n\t};\n\n\tfunction init(plot) {\n\n\t\tplot.hooks.processOptions.push(processOptions);\n\n\t\t//if the plugin is active register processDatapoints method\n\t\tfunction processOptions(plot, options) {\n\t\t\tif (options.series.curvedLines.active) {\n\t\t\t\tplot.hooks.processDatapoints.unshift(processDatapoints);\n\t\t\t}\n\t\t}\n\n\t\t//only if the plugin is active\n\t\tfunction processDatapoints(plot, series, datapoints) {\n\t\t\tvar nrPoints = datapoints.points.length / datapoints.pointsize;\n\t\t\tvar EPSILON = 0.005;\n\n\t\t\t//detects missplaced legacy parameters (prior v1.x.x) in the options object\n\t\t\t//this can happen if somebody upgrades to v1.x.x without adjusting the parameters or uses old examples\n            var invalidLegacyOptions = hasInvalidParameters(series.curvedLines);\n\n\t\t\tif (!invalidLegacyOptions && series.curvedLines.apply == true && series.originSeries === undefined && nrPoints > (1 + EPSILON)) {\n\t\t\t\tif (series.lines.fill) {\n\n\t\t\t\t\tvar pointsTop = calculateCurvePoints(datapoints, series.curvedLines, 1);\n\t\t\t\t\tvar pointsBottom = calculateCurvePoints(datapoints, series.curvedLines, 2);\n\t\t\t\t\t//flot makes sure for us that we've got a second y point if fill is true !\n\n\t\t\t\t\t//Merge top and bottom curve\n\t\t\t\t\tdatapoints.pointsize = 3;\n\t\t\t\t\tdatapoints.points = [];\n\t\t\t\t\tvar j = 0;\n\t\t\t\t\tvar k = 0;\n\t\t\t\t\tvar i = 0;\n\t\t\t\t\tvar ps = 2;\n\t\t\t\t\twhile (i < pointsTop.length || j < pointsBottom.length) {\n\t\t\t\t\t\tif (pointsTop[i] == pointsBottom[j]) {\n\t\t\t\t\t\t\tdatapoints.points[k] = pointsTop[i];\n\t\t\t\t\t\t\tdatapoints.points[k + 1] = pointsTop[i + 1];\n\t\t\t\t\t\t\tdatapoints.points[k + 2] = pointsBottom[j + 1];\n\t\t\t\t\t\t\tj += ps;\n\t\t\t\t\t\t\ti += ps;\n\n\t\t\t\t\t\t} else if (pointsTop[i] < pointsBottom[j]) {\n\t\t\t\t\t\t\tdatapoints.points[k] = pointsTop[i];\n\t\t\t\t\t\t\tdatapoints.points[k + 1] = pointsTop[i + 1];\n\t\t\t\t\t\t\tdatapoints.points[k + 2] = k > 0 ? datapoints.points[k - 1] : null;\n\t\t\t\t\t\t\ti += ps;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tdatapoints.points[k] = pointsBottom[j];\n\t\t\t\t\t\t\tdatapoints.points[k + 1] = k > 1 ? datapoints.points[k - 2] : null;\n\t\t\t\t\t\t\tdatapoints.points[k + 2] = pointsBottom[j + 1];\n\t\t\t\t\t\t\tj += ps;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tk += 3;\n\t\t\t\t\t}\n\t\t\t\t} else if (series.lines.lineWidth > 0) {\n\t\t\t\t\tdatapoints.points = calculateCurvePoints(datapoints, series.curvedLines, 1);\n\t\t\t\t\tdatapoints.pointsize = 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfunction calculateCurvePoints(datapoints, curvedLinesOptions, yPos) {\n\t\t\tif ( typeof curvedLinesOptions.legacyOverride != 'undefined' && curvedLinesOptions.legacyOverride != false) {\n\t\t\t\tvar defaultOptions = {\n\t\t\t\t\tfit : false,\n\t\t\t\t\tcurvePointFactor : 20,\n\t\t\t\t\tfitPointDist : undefined\n\t\t\t\t};\n\t\t\t\tvar legacyOptions = jQuery.extend(defaultOptions, curvedLinesOptions.legacyOverride);\n\t\t\t\treturn calculateLegacyCurvePoints(datapoints, legacyOptions, yPos);\n\t\t\t}\n\n\t\t\treturn calculateSplineCurvePoints(datapoints, curvedLinesOptions, yPos);\n\t\t}\n\n\t\tfunction calculateSplineCurvePoints(datapoints, curvedLinesOptions, yPos) {\n\t\t\tvar points = datapoints.points;\n\t\t\tvar ps = datapoints.pointsize;\n\t\t\t\n\t\t\t//create interpolant fuction\n\t\t\tvar splines = createHermiteSplines(datapoints, curvedLinesOptions, yPos);\n\t\t\tvar result = [];\n\n\t\t\t//sample the function\n\t\t\t// (the result is intependent from the input data =>\n\t\t\t//\tit is ok to alter the input after this method)\n\t\t\tvar j = 0;\n\t\t\tfor (var i = 0; i < points.length - ps; i += ps) {\n\t\t\t\tvar curX = i;\n\t\t\t\tvar curY = i + yPos;\t\n\t\t\t\t\n\t\t\t\tvar xStart = points[curX];\n\t\t\t\tvar xEnd = points[curX + ps];\n\t\t\t\tvar xStep = (xEnd - xStart) / Number(curvedLinesOptions.nrSplinePoints);\n\n\t\t\t\t//add point\n\t\t\t\tresult.push(points[curX]);\n\t\t\t\tresult.push(points[curY]);\n\n\t\t\t\t//add curve point\n\t\t\t\tfor (var x = (xStart += xStep); x < xEnd; x += xStep) {\n\t\t\t\t\tresult.push(x);\n\t\t\t\t\tresult.push(splines[j](x));\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tj++;\n\t\t\t}\n\n\t\t\t//add last point\n\t\t\tresult.push(points[points.length - ps]);\n\t\t\tresult.push(points[points.length - ps + yPos]);\n\n\t\t\treturn result;\n\t\t}\n\n\n\n\t\t// Creates an array of splines, one for each segment of the original curve. Algorithm based on the wikipedia articles: \n\t\t//\n\t\t// http://de.wikipedia.org/w/index.php?title=Kubisch_Hermitescher_Spline&oldid=130168003 and \n\t\t// http://en.wikipedia.org/w/index.php?title=Monotone_cubic_interpolation&oldid=622341725 and the description of Fritsch-Carlson from\n\t\t// http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation\n\t\t// for a detailed description see https://github.com/MichaelZinsmaier/CurvedLines/docu\n\t\tfunction createHermiteSplines(datapoints, curvedLinesOptions, yPos) {\n\t\t\tvar points = datapoints.points;\n\t\t\tvar ps = datapoints.pointsize;\n\t\t\t\n\t\t\t// preparation get length (x_{k+1} - x_k) and slope s=(p_{k+1} - p_k) / (x_{k+1} - x_k) of the segments\n\t\t\tvar segmentLengths = [];\n\t\t\tvar segmentSlopes = [];\n\n\t\t\tfor (var i = 0; i < points.length - ps; i += ps) {\n\t\t\t\tvar curX = i;\n\t\t\t\tvar curY = i + yPos;\t\t\t\n\t\t\t\tvar dx = points[curX + ps] - points[curX];\n\t\t\t\tvar dy = points[curY + ps] - points[curY];\n\t\t\t\t\t\t\t\n\t\t\t\tsegmentLengths.push(dx);\n\t\t\t\tsegmentSlopes.push(dy / dx);\n\t\t\t}\n\n\t\t\t//get the values for the desired gradients  m_k for all points k\n\t\t\t//depending on the used method the formula is different\n\t\t\tvar gradients = [segmentSlopes[0]];\t\n\t\t\tif (curvedLinesOptions.monotonicFit) {\n\t\t\t\t// Fritsch Carlson\n\t\t\t\tfor (var i = 1; i < segmentLengths.length; i++) {\n\t\t\t\t\tvar slope = segmentSlopes[i];\n\t\t\t\t\tvar prev_slope = segmentSlopes[i - 1];\n\t\t\t\t\tif (slope * prev_slope <= 0) { // sign(prev_slope) != sign(slpe)\n\t\t\t\t\t\tgradients.push(0);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tvar length = segmentLengths[i];\n\t\t\t\t\t\tvar prev_length = segmentLengths[i - 1];\n\t\t\t\t\t\tvar common = length + prev_length;\n\t\t\t\t\t\t//m = 3 (prev_length + length) / ((2 length + prev_length) / prev_slope + (length + 2 prev_length) / slope)\n\t\t\t\t\t\tgradients.push(3 * common / ((common + length) / prev_slope + (common + prev_length) / slope));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Cardinal spline with t € [0,1]\n\t\t\t\t// Catmull-Rom for t = 0\n\t\t\t\tfor (var i = ps; i < points.length - ps; i += ps) {\n\t\t\t\t\tvar curX = i;\n\t\t\t\t\tvar curY = i + yPos;\t\n\t\t\t\t\tgradients.push(Number(curvedLinesOptions.tension) * (points[curY + ps] - points[curY - ps]) / (points[curX + ps] - points[curX - ps]));\n\t\t\t\t}\n\t\t\t}\n\t\t\tgradients.push(segmentSlopes[segmentSlopes.length - 1]);\n\n\t\t\t//get the two major coefficients (c'_{oef1} and c'_{oef2}) for each segment spline\n\t\t\tvar coefs1 = [];\n\t\t\tvar coefs2 = [];\n\t\t\tfor (i = 0; i < segmentLengths.length; i++) {\n\t\t\t\tvar m_k = gradients[i];\n\t\t\t\tvar m_k_plus = gradients[i + 1];\n\t\t\t\tvar slope = segmentSlopes[i];\n\t\t\t\tvar invLength = 1 / segmentLengths[i];\n\t\t\t\tvar common = m_k + m_k_plus - slope - slope;\n\t\t\t\t\n\t\t\t\tcoefs1.push(common * invLength * invLength);\n\t\t\t\tcoefs2.push((slope - common - m_k) * invLength);\n\t\t\t}\n\n\t\t\t//create functions with from the coefficients and capture the parameters\n\t\t\tvar ret = [];\n\t\t\tfor (var i = 0; i < segmentLengths.length; i ++) {\n\t\t\t\tvar spline = function (x_k, coef1, coef2, coef3, coef4) {\n\t\t\t\t\t// spline for a segment\n\t\t\t\t\treturn function (x) {\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\tvar diff = x - x_k;\n\t\t\t\t\t\tvar diffSq = diff * diff;\n\t\t\t\t\t\treturn coef1 * diff * diffSq + coef2 * diffSq + coef3 * diff + coef4;\n\t\t\t\t\t};\n\t\t\t\t};\t\t\t\n\t\t\n\t\t\t\tret.push(spline(points[i * ps], coefs1[i], coefs2[i], gradients[i], points[i * ps + yPos]));\n\t\t\t}\n\t\t\t\n\t\t\treturn ret;\n\t\t};\n\n\t\t//no real idea whats going on here code mainly from https://code.google.com/p/flot/issues/detail?id=226\n\t\t//if fit option is selected additional datapoints get inserted before the curve calculations in nergal.dev s code.\n\t\tfunction calculateLegacyCurvePoints(datapoints, curvedLinesOptions, yPos) {\n\n\t\t\tvar points = datapoints.points;\n\t\t\tvar ps = datapoints.pointsize;\n\t\t\tvar num = Number(curvedLinesOptions.curvePointFactor) * (points.length / ps);\n\n\t\t\tvar xdata = new Array;\n\t\t\tvar ydata = new Array;\n\n\t\t\tvar curX = -1;\n\t\t\tvar curY = -1;\n\t\t\tvar j = 0;\n\n\t\t\tif (curvedLinesOptions.fit) {\n\t\t\t\t//insert a point before and after the \"real\" data point to force the line\n\t\t\t\t//to have a max,min at the data point.\n\n\t\t\t\tvar fpDist;\n\t\t\t\tif ( typeof curvedLinesOptions.fitPointDist == 'undefined') {\n\t\t\t\t\t//estimate it\n\t\t\t\t\tvar minX = points[0];\n\t\t\t\t\tvar maxX = points[points.length - ps];\n\t\t\t\t\tfpDist = (maxX - minX) / (500 * 100);\n\t\t\t\t\t//x range / (estimated pixel length of placeholder * factor)\n\t\t\t\t} else {\n\t\t\t\t\t//use user defined value\n\t\t\t\t\tfpDist = Number(curvedLinesOptions.fitPointDist);\n\t\t\t\t}\n\n\t\t\t\tfor (var i = 0; i < points.length; i += ps) {\n\n\t\t\t\t\tvar frontX;\n\t\t\t\t\tvar backX;\n\t\t\t\t\tcurX = i;\n\t\t\t\t\tcurY = i + yPos;\n\n\t\t\t\t\t//add point X s\n\t\t\t\t\tfrontX = points[curX] - fpDist;\n\t\t\t\t\tbackX = points[curX] + fpDist;\n\n\t\t\t\t\tvar factor = 2;\n\t\t\t\t\twhile (frontX == points[curX] || backX == points[curX]) {\n\t\t\t\t\t\t//inside the ulp\n\t\t\t\t\t\tfrontX = points[curX] - (fpDist * factor);\n\t\t\t\t\t\tbackX = points[curX] + (fpDist * factor);\n\t\t\t\t\t\tfactor++;\n\t\t\t\t\t}\n\n\t\t\t\t\t//add curve points\n\t\t\t\t\txdata[j] = frontX;\n\t\t\t\t\tydata[j] = points[curY];\n\t\t\t\t\tj++;\n\n\t\t\t\t\txdata[j] = points[curX];\n\t\t\t\t\tydata[j] = points[curY];\n\t\t\t\t\tj++;\n\n\t\t\t\t\txdata[j] = backX;\n\t\t\t\t\tydata[j] = points[curY];\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t//just use the datapoints\n\t\t\t\tfor (var i = 0; i < points.length; i += ps) {\n\t\t\t\t\tcurX = i;\n\t\t\t\t\tcurY = i + yPos;\n\n\t\t\t\t\txdata[j] = points[curX];\n\t\t\t\t\tydata[j] = points[curY];\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar n = xdata.length;\n\n\t\t\tvar y2 = new Array();\n\t\t\tvar delta = new Array();\n\t\t\ty2[0] = 0;\n\t\t\ty2[n - 1] = 0;\n\t\t\tdelta[0] = 0;\n\n\t\t\tfor (var i = 1; i < n - 1; ++i) {\n\t\t\t\tvar d = (xdata[i + 1] - xdata[i - 1]);\n\t\t\t\tif (d == 0) {\n\t\t\t\t\t//point before current point and after current point need some space in between\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\tvar s = (xdata[i] - xdata[i - 1]) / d;\n\t\t\t\tvar p = s * y2[i - 1] + 2;\n\t\t\t\ty2[i] = (s - 1) / p;\n\t\t\t\tdelta[i] = (ydata[i + 1] - ydata[i]) / (xdata[i + 1] - xdata[i]) - (ydata[i] - ydata[i - 1]) / (xdata[i] - xdata[i - 1]);\n\t\t\t\tdelta[i] = (6 * delta[i] / (xdata[i + 1] - xdata[i - 1]) - s * delta[i - 1]) / p;\n\t\t\t}\n\n\t\t\tfor (var j = n - 2; j >= 0; --j) {\n\t\t\t\ty2[j] = y2[j] * y2[j + 1] + delta[j];\n\t\t\t}\n\n\t\t\t//   xmax  - xmin  / #points\n\t\t\tvar step = (xdata[n - 1] - xdata[0]) / (num - 1);\n\n\t\t\tvar xnew = new Array;\n\t\t\tvar ynew = new Array;\n\t\t\tvar result = new Array;\n\n\t\t\txnew[0] = xdata[0];\n\t\t\tynew[0] = ydata[0];\n\n\t\t\tresult.push(xnew[0]);\n\t\t\tresult.push(ynew[0]);\n\n\t\t\tfor ( j = 1; j < num; ++j) {\n\t\t\t\t//new x point (sampling point for the created curve)\n\t\t\t\txnew[j] = xnew[0] + j * step;\n\n\t\t\t\tvar max = n - 1;\n\t\t\t\tvar min = 0;\n\n\t\t\t\twhile (max - min > 1) {\n\t\t\t\t\tvar k = Math.round((max + min) / 2);\n\t\t\t\t\tif (xdata[k] > xnew[j]) {\n\t\t\t\t\t\tmax = k;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmin = k;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t//found point one to the left and one to the right of generated new point\n\t\t\t\tvar h = (xdata[max] - xdata[min]);\n\n\t\t\t\tif (h == 0) {\n\t\t\t\t\t//similar to above two points from original x data need some space between them\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\tvar a = (xdata[max] - xnew[j]) / h;\n\t\t\t\tvar b = (xnew[j] - xdata[min]) / h;\n\n\t\t\t\tynew[j] = a * ydata[min] + b * ydata[max] + ((a * a * a - a) * y2[min] + (b * b * b - b) * y2[max]) * (h * h) / 6;\n\n\t\t\t\tresult.push(xnew[j]);\n\t\t\t\tresult.push(ynew[j]);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\t\t\n\t\tfunction hasInvalidParameters(curvedLinesOptions) {\n\t\t\tif (typeof curvedLinesOptions.fit != 'undefined' ||\n\t\t\t    typeof curvedLinesOptions.curvePointFactor != 'undefined' ||\n\t\t\t    typeof curvedLinesOptions.fitPointDist != 'undefined') {\n\t\t\t    \tthrow new Error(\"CurvedLines detected illegal parameters. The CurvedLines API changed with version 1.0.0 please check the options object.\");\n\t\t\t    \treturn true;\n\t\t\t    }\n\t\t\treturn false;\n\t\t}\n\t\t\n\n\t}//end init\n\n\n\t$.plot.plugins.push({\n\t\tinit : init,\n\t\toptions : options,\n\t\tname : 'curvedLines',\n\t\tversion : '1.1.1'\n\t});\n\n})(jQuery);\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/jquery/2.1.4/jquery.js",
    "content": "/*!\n * jQuery JavaScript Library v2.1.4\n * http://jquery.com/\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n *\n * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2015-04-28T16:01Z\n */\n\n(function( global, factory ) {\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket #14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n}(typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Support: Firefox 18+\n// Can't be in strict mode, several libs including ASP.NET trace\n// the stack via arguments.caller.callee and Firefox dies if\n// you try to trace through \"use strict\" call chains. (#13335)\n//\n\nvar arr = [];\n\nvar slice = arr.slice;\n\nvar concat = arr.concat;\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar support = {};\n\n\n\nvar\n\t// Use the correct document accordingly with window argument (sandbox)\n\tdocument = window.document,\n\n\tversion = \"2.1.4\",\n\n\t// Define a local copy of jQuery\n\tjQuery = function( selector, context ) {\n\t\t// The jQuery object is actually just the init constructor 'enhanced'\n\t\t// Need init if jQuery is called (just allow error to be thrown if not included)\n\t\treturn new jQuery.fn.init( selector, context );\n\t},\n\n\t// Support: Android<4.1\n\t// Make sure we trim BOM and NBSP\n\trtrim = /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g,\n\n\t// Matches dashed string for camelizing\n\trmsPrefix = /^-ms-/,\n\trdashAlpha = /-([\\da-z])/gi,\n\n\t// Used by jQuery.camelCase as callback to replace()\n\tfcamelCase = function( all, letter ) {\n\t\treturn letter.toUpperCase();\n\t};\n\njQuery.fn = jQuery.prototype = {\n\t// The current version of jQuery being used\n\tjquery: version,\n\n\tconstructor: jQuery,\n\n\t// Start with an empty selector\n\tselector: \"\",\n\n\t// The default length of a jQuery object is 0\n\tlength: 0,\n\n\ttoArray: function() {\n\t\treturn slice.call( this );\n\t},\n\n\t// Get the Nth element in the matched element set OR\n\t// Get the whole matched element set as a clean array\n\tget: function( num ) {\n\t\treturn num != null ?\n\n\t\t\t// Return just the one element from the set\n\t\t\t( num < 0 ? this[ num + this.length ] : this[ num ] ) :\n\n\t\t\t// Return all the elements in a clean array\n\t\t\tslice.call( this );\n\t},\n\n\t// Take an array of elements and push it onto the stack\n\t// (returning the new matched element set)\n\tpushStack: function( elems ) {\n\n\t\t// Build a new jQuery matched element set\n\t\tvar ret = jQuery.merge( this.constructor(), elems );\n\n\t\t// Add the old object onto the stack (as a reference)\n\t\tret.prevObject = this;\n\t\tret.context = this.context;\n\n\t\t// Return the newly-formed element set\n\t\treturn ret;\n\t},\n\n\t// Execute a callback for every element in the matched set.\n\t// (You can seed the arguments with an array of args, but this is\n\t// only used internally.)\n\teach: function( callback, args ) {\n\t\treturn jQuery.each( this, callback, args );\n\t},\n\n\tmap: function( callback ) {\n\t\treturn this.pushStack( jQuery.map(this, function( elem, i ) {\n\t\t\treturn callback.call( elem, i, elem );\n\t\t}));\n\t},\n\n\tslice: function() {\n\t\treturn this.pushStack( slice.apply( this, arguments ) );\n\t},\n\n\tfirst: function() {\n\t\treturn this.eq( 0 );\n\t},\n\n\tlast: function() {\n\t\treturn this.eq( -1 );\n\t},\n\n\teq: function( i ) {\n\t\tvar len = this.length,\n\t\t\tj = +i + ( i < 0 ? len : 0 );\n\t\treturn this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );\n\t},\n\n\tend: function() {\n\t\treturn this.prevObject || this.constructor(null);\n\t},\n\n\t// For internal use only.\n\t// Behaves like an Array's method, not like a jQuery method.\n\tpush: push,\n\tsort: arr.sort,\n\tsplice: arr.splice\n};\n\njQuery.extend = jQuery.fn.extend = function() {\n\tvar options, name, src, copy, copyIsArray, clone,\n\t\ttarget = arguments[0] || {},\n\t\ti = 1,\n\t\tlength = arguments.length,\n\t\tdeep = false;\n\n\t// Handle a deep copy situation\n\tif ( typeof target === \"boolean\" ) {\n\t\tdeep = target;\n\n\t\t// Skip the boolean and the target\n\t\ttarget = arguments[ i ] || {};\n\t\ti++;\n\t}\n\n\t// Handle case when target is a string or something (possible in deep copy)\n\tif ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n\t\ttarget = {};\n\t}\n\n\t// Extend jQuery itself if only one argument is passed\n\tif ( i === length ) {\n\t\ttarget = this;\n\t\ti--;\n\t}\n\n\tfor ( ; i < length; i++ ) {\n\t\t// Only deal with non-null/undefined values\n\t\tif ( (options = arguments[ i ]) != null ) {\n\t\t\t// Extend the base object\n\t\t\tfor ( name in options ) {\n\t\t\t\tsrc = target[ name ];\n\t\t\t\tcopy = options[ name ];\n\n\t\t\t\t// Prevent never-ending loop\n\t\t\t\tif ( target === copy ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Recurse if we're merging plain objects or arrays\n\t\t\t\tif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n\t\t\t\t\tif ( copyIsArray ) {\n\t\t\t\t\t\tcopyIsArray = false;\n\t\t\t\t\t\tclone = src && jQuery.isArray(src) ? src : [];\n\n\t\t\t\t\t} else {\n\t\t\t\t\t\tclone = src && jQuery.isPlainObject(src) ? src : {};\n\t\t\t\t\t}\n\n\t\t\t\t\t// Never move original objects, clone them\n\t\t\t\t\ttarget[ name ] = jQuery.extend( deep, clone, copy );\n\n\t\t\t\t// Don't bring in undefined values\n\t\t\t\t} else if ( copy !== undefined ) {\n\t\t\t\t\ttarget[ name ] = copy;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return the modified object\n\treturn target;\n};\n\njQuery.extend({\n\t// Unique for each copy of jQuery on the page\n\texpando: \"jQuery\" + ( version + Math.random() ).replace( /\\D/g, \"\" ),\n\n\t// Assume jQuery is ready without the ready module\n\tisReady: true,\n\n\terror: function( msg ) {\n\t\tthrow new Error( msg );\n\t},\n\n\tnoop: function() {},\n\n\tisFunction: function( obj ) {\n\t\treturn jQuery.type(obj) === \"function\";\n\t},\n\n\tisArray: Array.isArray,\n\n\tisWindow: function( obj ) {\n\t\treturn obj != null && obj === obj.window;\n\t},\n\n\tisNumeric: function( obj ) {\n\t\t// parseFloat NaNs numeric-cast false positives (null|true|false|\"\")\n\t\t// ...but misinterprets leading-number strings, particularly hex literals (\"0x...\")\n\t\t// subtraction forces infinities to NaN\n\t\t// adding 1 corrects loss of precision from parseFloat (#15100)\n\t\treturn !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 0;\n\t},\n\n\tisPlainObject: function( obj ) {\n\t\t// Not plain objects:\n\t\t// - Any object or value whose internal [[Class]] property is not \"[object Object]\"\n\t\t// - DOM nodes\n\t\t// - window\n\t\tif ( jQuery.type( obj ) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ( obj.constructor &&\n\t\t\t\t!hasOwn.call( obj.constructor.prototype, \"isPrototypeOf\" ) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If the function hasn't returned already, we're confident that\n\t\t// |obj| is a plain object, created by {} or constructed with new Object\n\t\treturn true;\n\t},\n\n\tisEmptyObject: function( obj ) {\n\t\tvar name;\n\t\tfor ( name in obj ) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t},\n\n\ttype: function( obj ) {\n\t\tif ( obj == null ) {\n\t\t\treturn obj + \"\";\n\t\t}\n\t\t// Support: Android<4.0, iOS<6 (functionish RegExp)\n\t\treturn typeof obj === \"object\" || typeof obj === \"function\" ?\n\t\t\tclass2type[ toString.call(obj) ] || \"object\" :\n\t\t\ttypeof obj;\n\t},\n\n\t// Evaluates a script in a global context\n\tglobalEval: function( code ) {\n\t\tvar script,\n\t\t\tindirect = eval;\n\n\t\tcode = jQuery.trim( code );\n\n\t\tif ( code ) {\n\t\t\t// If the code includes a valid, prologue position\n\t\t\t// strict mode pragma, execute code by injecting a\n\t\t\t// script tag into the document.\n\t\t\tif ( code.indexOf(\"use strict\") === 1 ) {\n\t\t\t\tscript = document.createElement(\"script\");\n\t\t\t\tscript.text = code;\n\t\t\t\tdocument.head.appendChild( script ).parentNode.removeChild( script );\n\t\t\t} else {\n\t\t\t// Otherwise, avoid the DOM node creation, insertion\n\t\t\t// and removal by using an indirect global eval\n\t\t\t\tindirect( code );\n\t\t\t}\n\t\t}\n\t},\n\n\t// Convert dashed to camelCase; used by the css and data modules\n\t// Support: IE9-11+\n\t// Microsoft forgot to hump their vendor prefix (#9572)\n\tcamelCase: function( string ) {\n\t\treturn string.replace( rmsPrefix, \"ms-\" ).replace( rdashAlpha, fcamelCase );\n\t},\n\n\tnodeName: function( elem, name ) {\n\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();\n\t},\n\n\t// args is for internal usage only\n\teach: function( obj, callback, args ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = obj.length,\n\t\t\tisArray = isArraylike( obj );\n\n\t\tif ( args ) {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.apply( obj[ i ], args );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// A special, fast, case for the most common use of each\n\t\t} else {\n\t\t\tif ( isArray ) {\n\t\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( i in obj ) {\n\t\t\t\t\tvalue = callback.call( obj[ i ], i, obj[ i ] );\n\n\t\t\t\t\tif ( value === false ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn obj;\n\t},\n\n\t// Support: Android<4.1\n\ttrim: function( text ) {\n\t\treturn text == null ?\n\t\t\t\"\" :\n\t\t\t( text + \"\" ).replace( rtrim, \"\" );\n\t},\n\n\t// results is for internal usage only\n\tmakeArray: function( arr, results ) {\n\t\tvar ret = results || [];\n\n\t\tif ( arr != null ) {\n\t\t\tif ( isArraylike( Object(arr) ) ) {\n\t\t\t\tjQuery.merge( ret,\n\t\t\t\t\ttypeof arr === \"string\" ?\n\t\t\t\t\t[ arr ] : arr\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpush.call( ret, arr );\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tinArray: function( elem, arr, i ) {\n\t\treturn arr == null ? -1 : indexOf.call( arr, elem, i );\n\t},\n\n\tmerge: function( first, second ) {\n\t\tvar len = +second.length,\n\t\t\tj = 0,\n\t\t\ti = first.length;\n\n\t\tfor ( ; j < len; j++ ) {\n\t\t\tfirst[ i++ ] = second[ j ];\n\t\t}\n\n\t\tfirst.length = i;\n\n\t\treturn first;\n\t},\n\n\tgrep: function( elems, callback, invert ) {\n\t\tvar callbackInverse,\n\t\t\tmatches = [],\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tcallbackExpect = !invert;\n\n\t\t// Go through the array, only saving the items\n\t\t// that pass the validator function\n\t\tfor ( ; i < length; i++ ) {\n\t\t\tcallbackInverse = !callback( elems[ i ], i );\n\t\t\tif ( callbackInverse !== callbackExpect ) {\n\t\t\t\tmatches.push( elems[ i ] );\n\t\t\t}\n\t\t}\n\n\t\treturn matches;\n\t},\n\n\t// arg is for internal usage only\n\tmap: function( elems, callback, arg ) {\n\t\tvar value,\n\t\t\ti = 0,\n\t\t\tlength = elems.length,\n\t\t\tisArray = isArraylike( elems ),\n\t\t\tret = [];\n\n\t\t// Go through the array, translating each of the items to their new values\n\t\tif ( isArray ) {\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Go through every key on the object,\n\t\t} else {\n\t\t\tfor ( i in elems ) {\n\t\t\t\tvalue = callback( elems[ i ], i, arg );\n\n\t\t\t\tif ( value != null ) {\n\t\t\t\t\tret.push( value );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flatten any nested arrays\n\t\treturn concat.apply( [], ret );\n\t},\n\n\t// A global GUID counter for objects\n\tguid: 1,\n\n\t// Bind a function to a context, optionally partially applying any\n\t// arguments.\n\tproxy: function( fn, context ) {\n\t\tvar tmp, args, proxy;\n\n\t\tif ( typeof context === \"string\" ) {\n\t\t\ttmp = fn[ context ];\n\t\t\tcontext = fn;\n\t\t\tfn = tmp;\n\t\t}\n\n\t\t// Quick check to determine if target is callable, in the spec\n\t\t// this throws a TypeError, but we will just return undefined.\n\t\tif ( !jQuery.isFunction( fn ) ) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Simulated bind\n\t\targs = slice.call( arguments, 2 );\n\t\tproxy = function() {\n\t\t\treturn fn.apply( context || this, args.concat( slice.call( arguments ) ) );\n\t\t};\n\n\t\t// Set the guid of unique handler to the same of original handler, so it can be removed\n\t\tproxy.guid = fn.guid = fn.guid || jQuery.guid++;\n\n\t\treturn proxy;\n\t},\n\n\tnow: Date.now,\n\n\t// jQuery.support is not used in Core but other projects attach their\n\t// properties to it so it needs to exist.\n\tsupport: support\n});\n\n// Populate the class2type map\njQuery.each(\"Boolean Number String Function Array Date RegExp Object Error\".split(\" \"), function(i, name) {\n\tclass2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n});\n\nfunction isArraylike( obj ) {\n\n\t// Support: iOS 8.2 (not reproducible in simulator)\n\t// `in` check used to prevent JIT error (gh-2145)\n\t// hasOwn isn't used here due to false negatives\n\t// regarding Nodelist length in IE\n\tvar length = \"length\" in obj && obj.length,\n\t\ttype = jQuery.type( obj );\n\n\tif ( type === \"function\" || jQuery.isWindow( obj ) ) {\n\t\treturn false;\n\t}\n\n\tif ( obj.nodeType === 1 && length ) {\n\t\treturn true;\n\t}\n\n\treturn type === \"array\" || length === 0 ||\n\t\ttypeof length === \"number\" && length > 0 && ( length - 1 ) in obj;\n}\nvar Sizzle =\n/*!\n * Sizzle CSS Selector Engine v2.2.0-pre\n * http://sizzlejs.com/\n *\n * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors\n * Released under the MIT license\n * http://jquery.org/license\n *\n * Date: 2014-12-16\n */\n(function( window ) {\n\nvar i,\n\tsupport,\n\tExpr,\n\tgetText,\n\tisXML,\n\ttokenize,\n\tcompile,\n\tselect,\n\toutermostContext,\n\tsortInput,\n\thasDuplicate,\n\n\t// Local document vars\n\tsetDocument,\n\tdocument,\n\tdocElem,\n\tdocumentIsHTML,\n\trbuggyQSA,\n\trbuggyMatches,\n\tmatches,\n\tcontains,\n\n\t// Instance-specific data\n\texpando = \"sizzle\" + 1 * new Date(),\n\tpreferredDoc = window.document,\n\tdirruns = 0,\n\tdone = 0,\n\tclassCache = createCache(),\n\ttokenCache = createCache(),\n\tcompilerCache = createCache(),\n\tsortOrder = function( a, b ) {\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t}\n\t\treturn 0;\n\t},\n\n\t// General-purpose constants\n\tMAX_NEGATIVE = 1 << 31,\n\n\t// Instance methods\n\thasOwn = ({}).hasOwnProperty,\n\tarr = [],\n\tpop = arr.pop,\n\tpush_native = arr.push,\n\tpush = arr.push,\n\tslice = arr.slice,\n\t// Use a stripped-down indexOf as it's faster than native\n\t// http://jsperf.com/thor-indexof-vs-for/5\n\tindexOf = function( list, elem ) {\n\t\tvar i = 0,\n\t\t\tlen = list.length;\n\t\tfor ( ; i < len; i++ ) {\n\t\t\tif ( list[i] === elem ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t},\n\n\tbooleans = \"checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped\",\n\n\t// Regular expressions\n\n\t// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace\n\twhitespace = \"[\\\\x20\\\\t\\\\r\\\\n\\\\f]\",\n\t// http://www.w3.org/TR/css3-syntax/#characters\n\tcharacterEncoding = \"(?:\\\\\\\\.|[\\\\w-]|[^\\\\x00-\\\\xa0])+\",\n\n\t// Loosely modeled on CSS identifier characters\n\t// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors\n\t// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier\n\tidentifier = characterEncoding.replace( \"w\", \"w#\" ),\n\n\t// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors\n\tattributes = \"\\\\[\" + whitespace + \"*(\" + characterEncoding + \")(?:\" + whitespace +\n\t\t// Operator (capture 2)\n\t\t\"*([*^$|!~]?=)\" + whitespace +\n\t\t// \"Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]\"\n\t\t\"*(?:'((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\"|(\" + identifier + \"))|)\" + whitespace +\n\t\t\"*\\\\]\",\n\n\tpseudos = \":(\" + characterEncoding + \")(?:\\\\((\" +\n\t\t// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:\n\t\t// 1. quoted (capture 3; capture 4 or capture 5)\n\t\t\"('((?:\\\\\\\\.|[^\\\\\\\\'])*)'|\\\"((?:\\\\\\\\.|[^\\\\\\\\\\\"])*)\\\")|\" +\n\t\t// 2. simple (capture 6)\n\t\t\"((?:\\\\\\\\.|[^\\\\\\\\()[\\\\]]|\" + attributes + \")*)|\" +\n\t\t// 3. anything else (capture 2)\n\t\t\".*\" +\n\t\t\")\\\\)|)\",\n\n\t// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter\n\trwhitespace = new RegExp( whitespace + \"+\", \"g\" ),\n\trtrim = new RegExp( \"^\" + whitespace + \"+|((?:^|[^\\\\\\\\])(?:\\\\\\\\.)*)\" + whitespace + \"+$\", \"g\" ),\n\n\trcomma = new RegExp( \"^\" + whitespace + \"*,\" + whitespace + \"*\" ),\n\trcombinators = new RegExp( \"^\" + whitespace + \"*([>+~]|\" + whitespace + \")\" + whitespace + \"*\" ),\n\n\trattributeQuotes = new RegExp( \"=\" + whitespace + \"*([^\\\\]'\\\"]*?)\" + whitespace + \"*\\\\]\", \"g\" ),\n\n\trpseudo = new RegExp( pseudos ),\n\tridentifier = new RegExp( \"^\" + identifier + \"$\" ),\n\n\tmatchExpr = {\n\t\t\"ID\": new RegExp( \"^#(\" + characterEncoding + \")\" ),\n\t\t\"CLASS\": new RegExp( \"^\\\\.(\" + characterEncoding + \")\" ),\n\t\t\"TAG\": new RegExp( \"^(\" + characterEncoding.replace( \"w\", \"w*\" ) + \")\" ),\n\t\t\"ATTR\": new RegExp( \"^\" + attributes ),\n\t\t\"PSEUDO\": new RegExp( \"^\" + pseudos ),\n\t\t\"CHILD\": new RegExp( \"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\\\(\" + whitespace +\n\t\t\t\"*(even|odd|(([+-]|)(\\\\d*)n|)\" + whitespace + \"*(?:([+-]|)\" + whitespace +\n\t\t\t\"*(\\\\d+)|))\" + whitespace + \"*\\\\)|)\", \"i\" ),\n\t\t\"bool\": new RegExp( \"^(?:\" + booleans + \")$\", \"i\" ),\n\t\t// For use in libraries implementing .is()\n\t\t// We use this for POS matching in `select`\n\t\t\"needsContext\": new RegExp( \"^\" + whitespace + \"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\\\(\" +\n\t\t\twhitespace + \"*((?:-\\\\d)?\\\\d*)\" + whitespace + \"*\\\\)|)(?=[^-]|$)\", \"i\" )\n\t},\n\n\trinputs = /^(?:input|select|textarea|button)$/i,\n\trheader = /^h\\d$/i,\n\n\trnative = /^[^{]+\\{\\s*\\[native \\w/,\n\n\t// Easily-parseable/retrievable ID or TAG or CLASS selectors\n\trquickExpr = /^(?:#([\\w-]+)|(\\w+)|\\.([\\w-]+))$/,\n\n\trsibling = /[+~]/,\n\trescape = /'|\\\\/g,\n\n\t// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters\n\trunescape = new RegExp( \"\\\\\\\\([\\\\da-f]{1,6}\" + whitespace + \"?|(\" + whitespace + \")|.)\", \"ig\" ),\n\tfunescape = function( _, escaped, escapedWhitespace ) {\n\t\tvar high = \"0x\" + escaped - 0x10000;\n\t\t// NaN means non-codepoint\n\t\t// Support: Firefox<24\n\t\t// Workaround erroneous numeric interpretation of +\"0x\"\n\t\treturn high !== high || escapedWhitespace ?\n\t\t\tescaped :\n\t\t\thigh < 0 ?\n\t\t\t\t// BMP codepoint\n\t\t\t\tString.fromCharCode( high + 0x10000 ) :\n\t\t\t\t// Supplemental Plane codepoint (surrogate pair)\n\t\t\t\tString.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );\n\t},\n\n\t// Used for iframes\n\t// See setDocument()\n\t// Removing the function wrapper causes a \"Permission Denied\"\n\t// error in IE\n\tunloadHandler = function() {\n\t\tsetDocument();\n\t};\n\n// Optimize for push.apply( _, NodeList )\ntry {\n\tpush.apply(\n\t\t(arr = slice.call( preferredDoc.childNodes )),\n\t\tpreferredDoc.childNodes\n\t);\n\t// Support: Android<4.0\n\t// Detect silently failing push.apply\n\tarr[ preferredDoc.childNodes.length ].nodeType;\n} catch ( e ) {\n\tpush = { apply: arr.length ?\n\n\t\t// Leverage slice if possible\n\t\tfunction( target, els ) {\n\t\t\tpush_native.apply( target, slice.call(els) );\n\t\t} :\n\n\t\t// Support: IE<9\n\t\t// Otherwise append directly\n\t\tfunction( target, els ) {\n\t\t\tvar j = target.length,\n\t\t\t\ti = 0;\n\t\t\t// Can't trust NodeList.length\n\t\t\twhile ( (target[j++] = els[i++]) ) {}\n\t\t\ttarget.length = j - 1;\n\t\t}\n\t};\n}\n\nfunction Sizzle( selector, context, results, seed ) {\n\tvar match, elem, m, nodeType,\n\t\t// QSA vars\n\t\ti, groups, old, nid, newContext, newSelector;\n\n\tif ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\n\tcontext = context || document;\n\tresults = results || [];\n\tnodeType = context.nodeType;\n\n\tif ( typeof selector !== \"string\" || !selector ||\n\t\tnodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {\n\n\t\treturn results;\n\t}\n\n\tif ( !seed && documentIsHTML ) {\n\n\t\t// Try to shortcut find operations when possible (e.g., not under DocumentFragment)\n\t\tif ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {\n\t\t\t// Speed-up: Sizzle(\"#ID\")\n\t\t\tif ( (m = match[1]) ) {\n\t\t\t\tif ( nodeType === 9 ) {\n\t\t\t\t\telem = context.getElementById( m );\n\t\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t\t// nodes that are no longer in the document (jQuery #6963)\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Handle the case where IE, Opera, and Webkit return items\n\t\t\t\t\t\t// by name instead of ID\n\t\t\t\t\t\tif ( elem.id === m ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\treturn results;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Context is not a document\n\t\t\t\t\tif ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&\n\t\t\t\t\t\tcontains( context, elem ) && elem.id === m ) {\n\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Speed-up: Sizzle(\"TAG\")\n\t\t\t} else if ( match[2] ) {\n\t\t\t\tpush.apply( results, context.getElementsByTagName( selector ) );\n\t\t\t\treturn results;\n\n\t\t\t// Speed-up: Sizzle(\".CLASS\")\n\t\t\t} else if ( (m = match[3]) && support.getElementsByClassName ) {\n\t\t\t\tpush.apply( results, context.getElementsByClassName( m ) );\n\t\t\t\treturn results;\n\t\t\t}\n\t\t}\n\n\t\t// QSA path\n\t\tif ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {\n\t\t\tnid = old = expando;\n\t\t\tnewContext = context;\n\t\t\tnewSelector = nodeType !== 1 && selector;\n\n\t\t\t// qSA works strangely on Element-rooted queries\n\t\t\t// We can work around this by specifying an extra ID on the root\n\t\t\t// and working up from there (Thanks to Andrew Dupont for the technique)\n\t\t\t// IE 8 doesn't work on object elements\n\t\t\tif ( nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n\t\t\t\tgroups = tokenize( selector );\n\n\t\t\t\tif ( (old = context.getAttribute(\"id\")) ) {\n\t\t\t\t\tnid = old.replace( rescape, \"\\\\$&\" );\n\t\t\t\t} else {\n\t\t\t\t\tcontext.setAttribute( \"id\", nid );\n\t\t\t\t}\n\t\t\t\tnid = \"[id='\" + nid + \"'] \";\n\n\t\t\t\ti = groups.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tgroups[i] = nid + toSelector( groups[i] );\n\t\t\t\t}\n\t\t\t\tnewContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;\n\t\t\t\tnewSelector = groups.join(\",\");\n\t\t\t}\n\n\t\t\tif ( newSelector ) {\n\t\t\t\ttry {\n\t\t\t\t\tpush.apply( results,\n\t\t\t\t\t\tnewContext.querySelectorAll( newSelector )\n\t\t\t\t\t);\n\t\t\t\t\treturn results;\n\t\t\t\t} catch(qsaError) {\n\t\t\t\t} finally {\n\t\t\t\t\tif ( !old ) {\n\t\t\t\t\t\tcontext.removeAttribute(\"id\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// All others\n\treturn select( selector.replace( rtrim, \"$1\" ), context, results, seed );\n}\n\n/**\n * Create key-value caches of limited size\n * @returns {Function(string, Object)} Returns the Object data after storing it on itself with\n *\tproperty name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)\n *\tdeleting the oldest entry\n */\nfunction createCache() {\n\tvar keys = [];\n\n\tfunction cache( key, value ) {\n\t\t// Use (key + \" \") to avoid collision with native prototype properties (see Issue #157)\n\t\tif ( keys.push( key + \" \" ) > Expr.cacheLength ) {\n\t\t\t// Only keep the most recent entries\n\t\t\tdelete cache[ keys.shift() ];\n\t\t}\n\t\treturn (cache[ key + \" \" ] = value);\n\t}\n\treturn cache;\n}\n\n/**\n * Mark a function for special use by Sizzle\n * @param {Function} fn The function to mark\n */\nfunction markFunction( fn ) {\n\tfn[ expando ] = true;\n\treturn fn;\n}\n\n/**\n * Support testing using an element\n * @param {Function} fn Passed the created div and expects a boolean result\n */\nfunction assert( fn ) {\n\tvar div = document.createElement(\"div\");\n\n\ttry {\n\t\treturn !!fn( div );\n\t} catch (e) {\n\t\treturn false;\n\t} finally {\n\t\t// Remove from its parent by default\n\t\tif ( div.parentNode ) {\n\t\t\tdiv.parentNode.removeChild( div );\n\t\t}\n\t\t// release memory in IE\n\t\tdiv = null;\n\t}\n}\n\n/**\n * Adds the same handler for all of the specified attrs\n * @param {String} attrs Pipe-separated list of attributes\n * @param {Function} handler The method that will be applied\n */\nfunction addHandle( attrs, handler ) {\n\tvar arr = attrs.split(\"|\"),\n\t\ti = attrs.length;\n\n\twhile ( i-- ) {\n\t\tExpr.attrHandle[ arr[i] ] = handler;\n\t}\n}\n\n/**\n * Checks document order of two siblings\n * @param {Element} a\n * @param {Element} b\n * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b\n */\nfunction siblingCheck( a, b ) {\n\tvar cur = b && a,\n\t\tdiff = cur && a.nodeType === 1 && b.nodeType === 1 &&\n\t\t\t( ~b.sourceIndex || MAX_NEGATIVE ) -\n\t\t\t( ~a.sourceIndex || MAX_NEGATIVE );\n\n\t// Use IE sourceIndex if available on both nodes\n\tif ( diff ) {\n\t\treturn diff;\n\t}\n\n\t// Check if b follows a\n\tif ( cur ) {\n\t\twhile ( (cur = cur.nextSibling) ) {\n\t\t\tif ( cur === b ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn a ? 1 : -1;\n}\n\n/**\n * Returns a function to use in pseudos for input types\n * @param {String} type\n */\nfunction createInputPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn name === \"input\" && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for buttons\n * @param {String} type\n */\nfunction createButtonPseudo( type ) {\n\treturn function( elem ) {\n\t\tvar name = elem.nodeName.toLowerCase();\n\t\treturn (name === \"input\" || name === \"button\") && elem.type === type;\n\t};\n}\n\n/**\n * Returns a function to use in pseudos for positionals\n * @param {Function} fn\n */\nfunction createPositionalPseudo( fn ) {\n\treturn markFunction(function( argument ) {\n\t\targument = +argument;\n\t\treturn markFunction(function( seed, matches ) {\n\t\t\tvar j,\n\t\t\t\tmatchIndexes = fn( [], seed.length, argument ),\n\t\t\t\ti = matchIndexes.length;\n\n\t\t\t// Match elements found at the specified indexes\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( seed[ (j = matchIndexes[i]) ] ) {\n\t\t\t\t\tseed[j] = !(matches[j] = seed[j]);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t});\n}\n\n/**\n * Checks a node for validity as a Sizzle context\n * @param {Element|Object=} context\n * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value\n */\nfunction testContext( context ) {\n\treturn context && typeof context.getElementsByTagName !== \"undefined\" && context;\n}\n\n// Expose support vars for convenience\nsupport = Sizzle.support = {};\n\n/**\n * Detects XML nodes\n * @param {Element|Object} elem An element or a document\n * @returns {Boolean} True iff elem is a non-HTML XML node\n */\nisXML = Sizzle.isXML = function( elem ) {\n\t// documentElement is verified for cases where it doesn't yet exist\n\t// (such as loading iframes in IE - #4833)\n\tvar documentElement = elem && (elem.ownerDocument || elem).documentElement;\n\treturn documentElement ? documentElement.nodeName !== \"HTML\" : false;\n};\n\n/**\n * Sets document-related variables once based on the current document\n * @param {Element|Object} [doc] An element or document object to use to set the document\n * @returns {Object} Returns the current document\n */\nsetDocument = Sizzle.setDocument = function( node ) {\n\tvar hasCompare, parent,\n\t\tdoc = node ? node.ownerDocument || node : preferredDoc;\n\n\t// If no document and documentElement is available, return\n\tif ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {\n\t\treturn document;\n\t}\n\n\t// Set our document\n\tdocument = doc;\n\tdocElem = doc.documentElement;\n\tparent = doc.defaultView;\n\n\t// Support: IE>8\n\t// If iframe document is assigned to \"document\" variable and if iframe has been reloaded,\n\t// IE will throw \"permission denied\" error when accessing \"document\" variable, see jQuery #13936\n\t// IE6-8 do not support the defaultView property so parent will be undefined\n\tif ( parent && parent !== parent.top ) {\n\t\t// IE11 does not have attachEvent, so all must suffer\n\t\tif ( parent.addEventListener ) {\n\t\t\tparent.addEventListener( \"unload\", unloadHandler, false );\n\t\t} else if ( parent.attachEvent ) {\n\t\t\tparent.attachEvent( \"onunload\", unloadHandler );\n\t\t}\n\t}\n\n\t/* Support tests\n\t---------------------------------------------------------------------- */\n\tdocumentIsHTML = !isXML( doc );\n\n\t/* Attributes\n\t---------------------------------------------------------------------- */\n\n\t// Support: IE<8\n\t// Verify that getAttribute really returns attributes and not properties\n\t// (excepting IE8 booleans)\n\tsupport.attributes = assert(function( div ) {\n\t\tdiv.className = \"i\";\n\t\treturn !div.getAttribute(\"className\");\n\t});\n\n\t/* getElement(s)By*\n\t---------------------------------------------------------------------- */\n\n\t// Check if getElementsByTagName(\"*\") returns only elements\n\tsupport.getElementsByTagName = assert(function( div ) {\n\t\tdiv.appendChild( doc.createComment(\"\") );\n\t\treturn !div.getElementsByTagName(\"*\").length;\n\t});\n\n\t// Support: IE<9\n\tsupport.getElementsByClassName = rnative.test( doc.getElementsByClassName );\n\n\t// Support: IE<10\n\t// Check if getElementById returns elements by name\n\t// The broken getElementById methods don't pick up programatically-set names,\n\t// so use a roundabout getElementsByName test\n\tsupport.getById = assert(function( div ) {\n\t\tdocElem.appendChild( div ).id = expando;\n\t\treturn !doc.getElementsByName || !doc.getElementsByName( expando ).length;\n\t});\n\n\t// ID find and filter\n\tif ( support.getById ) {\n\t\tExpr.find[\"ID\"] = function( id, context ) {\n\t\t\tif ( typeof context.getElementById !== \"undefined\" && documentIsHTML ) {\n\t\t\t\tvar m = context.getElementById( id );\n\t\t\t\t// Check parentNode to catch when Blackberry 4.6 returns\n\t\t\t\t// nodes that are no longer in the document #6963\n\t\t\t\treturn m && m.parentNode ? [ m ] : [];\n\t\t\t}\n\t\t};\n\t\tExpr.filter[\"ID\"] = function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn elem.getAttribute(\"id\") === attrId;\n\t\t\t};\n\t\t};\n\t} else {\n\t\t// Support: IE6/7\n\t\t// getElementById is not reliable as a find shortcut\n\t\tdelete Expr.find[\"ID\"];\n\n\t\tExpr.filter[\"ID\"] =  function( id ) {\n\t\t\tvar attrId = id.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\tvar node = typeof elem.getAttributeNode !== \"undefined\" && elem.getAttributeNode(\"id\");\n\t\t\t\treturn node && node.value === attrId;\n\t\t\t};\n\t\t};\n\t}\n\n\t// Tag\n\tExpr.find[\"TAG\"] = support.getElementsByTagName ?\n\t\tfunction( tag, context ) {\n\t\t\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\t\t\treturn context.getElementsByTagName( tag );\n\n\t\t\t// DocumentFragment nodes don't have gEBTN\n\t\t\t} else if ( support.qsa ) {\n\t\t\t\treturn context.querySelectorAll( tag );\n\t\t\t}\n\t\t} :\n\n\t\tfunction( tag, context ) {\n\t\t\tvar elem,\n\t\t\t\ttmp = [],\n\t\t\t\ti = 0,\n\t\t\t\t// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too\n\t\t\t\tresults = context.getElementsByTagName( tag );\n\n\t\t\t// Filter out possible comments\n\t\t\tif ( tag === \"*\" ) {\n\t\t\t\twhile ( (elem = results[i++]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\ttmp.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\treturn results;\n\t\t};\n\n\t// Class\n\tExpr.find[\"CLASS\"] = support.getElementsByClassName && function( className, context ) {\n\t\tif ( documentIsHTML ) {\n\t\t\treturn context.getElementsByClassName( className );\n\t\t}\n\t};\n\n\t/* QSA/matchesSelector\n\t---------------------------------------------------------------------- */\n\n\t// QSA and matchesSelector support\n\n\t// matchesSelector(:active) reports false when true (IE9/Opera 11.5)\n\trbuggyMatches = [];\n\n\t// qSa(:focus) reports false when true (Chrome 21)\n\t// We allow this because of a bug in IE8/9 that throws an error\n\t// whenever `document.activeElement` is accessed on an iframe\n\t// So, we allow :focus to pass through QSA all the time to avoid the IE error\n\t// See http://bugs.jquery.com/ticket/13378\n\trbuggyQSA = [];\n\n\tif ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {\n\t\t// Build QSA regex\n\t\t// Regex strategy adopted from Diego Perini\n\t\tassert(function( div ) {\n\t\t\t// Select is set to empty string on purpose\n\t\t\t// This is to test IE's treatment of not explicitly\n\t\t\t// setting a boolean content attribute,\n\t\t\t// since its presence should be enough\n\t\t\t// http://bugs.jquery.com/ticket/12359\n\t\t\tdocElem.appendChild( div ).innerHTML = \"<a id='\" + expando + \"'></a>\" +\n\t\t\t\t\"<select id='\" + expando + \"-\\f]' msallowcapture=''>\" +\n\t\t\t\t\"<option selected=''></option></select>\";\n\n\t\t\t// Support: IE8, Opera 11-12.16\n\t\t\t// Nothing should be selected when empty strings follow ^= or $= or *=\n\t\t\t// The test attribute must be unknown in Opera but \"safe\" for WinRT\n\t\t\t// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section\n\t\t\tif ( div.querySelectorAll(\"[msallowcapture^='']\").length ) {\n\t\t\t\trbuggyQSA.push( \"[*^$]=\" + whitespace + \"*(?:''|\\\"\\\")\" );\n\t\t\t}\n\n\t\t\t// Support: IE8\n\t\t\t// Boolean attributes and \"value\" are not treated correctly\n\t\t\tif ( !div.querySelectorAll(\"[selected]\").length ) {\n\t\t\t\trbuggyQSA.push( \"\\\\[\" + whitespace + \"*(?:value|\" + booleans + \")\" );\n\t\t\t}\n\n\t\t\t// Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+\n\t\t\tif ( !div.querySelectorAll( \"[id~=\" + expando + \"-]\" ).length ) {\n\t\t\t\trbuggyQSA.push(\"~=\");\n\t\t\t}\n\n\t\t\t// Webkit/Opera - :checked should return selected option elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":checked\").length ) {\n\t\t\t\trbuggyQSA.push(\":checked\");\n\t\t\t}\n\n\t\t\t// Support: Safari 8+, iOS 8+\n\t\t\t// https://bugs.webkit.org/show_bug.cgi?id=136851\n\t\t\t// In-page `selector#id sibing-combinator selector` fails\n\t\t\tif ( !div.querySelectorAll( \"a#\" + expando + \"+*\" ).length ) {\n\t\t\t\trbuggyQSA.push(\".#.+[+~]\");\n\t\t\t}\n\t\t});\n\n\t\tassert(function( div ) {\n\t\t\t// Support: Windows 8 Native Apps\n\t\t\t// The type and name attributes are restricted during .innerHTML assignment\n\t\t\tvar input = doc.createElement(\"input\");\n\t\t\tinput.setAttribute( \"type\", \"hidden\" );\n\t\t\tdiv.appendChild( input ).setAttribute( \"name\", \"D\" );\n\n\t\t\t// Support: IE8\n\t\t\t// Enforce case-sensitivity of name attribute\n\t\t\tif ( div.querySelectorAll(\"[name=d]\").length ) {\n\t\t\t\trbuggyQSA.push( \"name\" + whitespace + \"*[*^$|!~]?=\" );\n\t\t\t}\n\n\t\t\t// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)\n\t\t\t// IE8 throws error here and will not see later tests\n\t\t\tif ( !div.querySelectorAll(\":enabled\").length ) {\n\t\t\t\trbuggyQSA.push( \":enabled\", \":disabled\" );\n\t\t\t}\n\n\t\t\t// Opera 10-11 does not throw on post-comma invalid pseudos\n\t\t\tdiv.querySelectorAll(\"*,:x\");\n\t\t\trbuggyQSA.push(\",.*:\");\n\t\t});\n\t}\n\n\tif ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||\n\t\tdocElem.webkitMatchesSelector ||\n\t\tdocElem.mozMatchesSelector ||\n\t\tdocElem.oMatchesSelector ||\n\t\tdocElem.msMatchesSelector) )) ) {\n\n\t\tassert(function( div ) {\n\t\t\t// Check to see if it's possible to do matchesSelector\n\t\t\t// on a disconnected node (IE 9)\n\t\t\tsupport.disconnectedMatch = matches.call( div, \"div\" );\n\n\t\t\t// This should fail with an exception\n\t\t\t// Gecko does not error, returns false instead\n\t\t\tmatches.call( div, \"[s!='']:x\" );\n\t\t\trbuggyMatches.push( \"!=\", pseudos );\n\t\t});\n\t}\n\n\trbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join(\"|\") );\n\trbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join(\"|\") );\n\n\t/* Contains\n\t---------------------------------------------------------------------- */\n\thasCompare = rnative.test( docElem.compareDocumentPosition );\n\n\t// Element contains another\n\t// Purposefully does not implement inclusive descendent\n\t// As in, an element does not contain itself\n\tcontains = hasCompare || rnative.test( docElem.contains ) ?\n\t\tfunction( a, b ) {\n\t\t\tvar adown = a.nodeType === 9 ? a.documentElement : a,\n\t\t\t\tbup = b && b.parentNode;\n\t\t\treturn a === bup || !!( bup && bup.nodeType === 1 && (\n\t\t\t\tadown.contains ?\n\t\t\t\t\tadown.contains( bup ) :\n\t\t\t\t\ta.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16\n\t\t\t));\n\t\t} :\n\t\tfunction( a, b ) {\n\t\t\tif ( b ) {\n\t\t\t\twhile ( (b = b.parentNode) ) {\n\t\t\t\t\tif ( b === a ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t/* Sorting\n\t---------------------------------------------------------------------- */\n\n\t// Document order sorting\n\tsortOrder = hasCompare ?\n\tfunction( a, b ) {\n\n\t\t// Flag for duplicate removal\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Sort on method existence if only one input has compareDocumentPosition\n\t\tvar compare = !a.compareDocumentPosition - !b.compareDocumentPosition;\n\t\tif ( compare ) {\n\t\t\treturn compare;\n\t\t}\n\n\t\t// Calculate position if both inputs belong to the same document\n\t\tcompare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?\n\t\t\ta.compareDocumentPosition( b ) :\n\n\t\t\t// Otherwise we know they are disconnected\n\t\t\t1;\n\n\t\t// Disconnected nodes\n\t\tif ( compare & 1 ||\n\t\t\t(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {\n\n\t\t\t// Choose the first element that is related to our preferred document\n\t\t\tif ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// Maintain original order\n\t\t\treturn sortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\t\t}\n\n\t\treturn compare & 4 ? -1 : 1;\n\t} :\n\tfunction( a, b ) {\n\t\t// Exit early if the nodes are identical\n\t\tif ( a === b ) {\n\t\t\thasDuplicate = true;\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\taup = a.parentNode,\n\t\t\tbup = b.parentNode,\n\t\t\tap = [ a ],\n\t\t\tbp = [ b ];\n\n\t\t// Parentless nodes are either documents or disconnected\n\t\tif ( !aup || !bup ) {\n\t\t\treturn a === doc ? -1 :\n\t\t\t\tb === doc ? 1 :\n\t\t\t\taup ? -1 :\n\t\t\t\tbup ? 1 :\n\t\t\t\tsortInput ?\n\t\t\t\t( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :\n\t\t\t\t0;\n\n\t\t// If the nodes are siblings, we can do a quick check\n\t\t} else if ( aup === bup ) {\n\t\t\treturn siblingCheck( a, b );\n\t\t}\n\n\t\t// Otherwise we need full lists of their ancestors for comparison\n\t\tcur = a;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tap.unshift( cur );\n\t\t}\n\t\tcur = b;\n\t\twhile ( (cur = cur.parentNode) ) {\n\t\t\tbp.unshift( cur );\n\t\t}\n\n\t\t// Walk down the tree looking for a discrepancy\n\t\twhile ( ap[i] === bp[i] ) {\n\t\t\ti++;\n\t\t}\n\n\t\treturn i ?\n\t\t\t// Do a sibling check if the nodes have a common ancestor\n\t\t\tsiblingCheck( ap[i], bp[i] ) :\n\n\t\t\t// Otherwise nodes in our document sort first\n\t\t\tap[i] === preferredDoc ? -1 :\n\t\t\tbp[i] === preferredDoc ? 1 :\n\t\t\t0;\n\t};\n\n\treturn doc;\n};\n\nSizzle.matches = function( expr, elements ) {\n\treturn Sizzle( expr, null, null, elements );\n};\n\nSizzle.matchesSelector = function( elem, expr ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\t// Make sure that attribute selectors are quoted\n\texpr = expr.replace( rattributeQuotes, \"='$1']\" );\n\n\tif ( support.matchesSelector && documentIsHTML &&\n\t\t( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&\n\t\t( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {\n\n\t\ttry {\n\t\t\tvar ret = matches.call( elem, expr );\n\n\t\t\t// IE 9's matchesSelector returns false on disconnected nodes\n\t\t\tif ( ret || support.disconnectedMatch ||\n\t\t\t\t\t// As well, disconnected nodes are said to be in a document\n\t\t\t\t\t// fragment in IE 9\n\t\t\t\t\telem.document && elem.document.nodeType !== 11 ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t} catch (e) {}\n\t}\n\n\treturn Sizzle( expr, document, null, [ elem ] ).length > 0;\n};\n\nSizzle.contains = function( context, elem ) {\n\t// Set document vars if needed\n\tif ( ( context.ownerDocument || context ) !== document ) {\n\t\tsetDocument( context );\n\t}\n\treturn contains( context, elem );\n};\n\nSizzle.attr = function( elem, name ) {\n\t// Set document vars if needed\n\tif ( ( elem.ownerDocument || elem ) !== document ) {\n\t\tsetDocument( elem );\n\t}\n\n\tvar fn = Expr.attrHandle[ name.toLowerCase() ],\n\t\t// Don't get fooled by Object.prototype properties (jQuery #13807)\n\t\tval = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?\n\t\t\tfn( elem, name, !documentIsHTML ) :\n\t\t\tundefined;\n\n\treturn val !== undefined ?\n\t\tval :\n\t\tsupport.attributes || !documentIsHTML ?\n\t\t\telem.getAttribute( name ) :\n\t\t\t(val = elem.getAttributeNode(name)) && val.specified ?\n\t\t\t\tval.value :\n\t\t\t\tnull;\n};\n\nSizzle.error = function( msg ) {\n\tthrow new Error( \"Syntax error, unrecognized expression: \" + msg );\n};\n\n/**\n * Document sorting and removing duplicates\n * @param {ArrayLike} results\n */\nSizzle.uniqueSort = function( results ) {\n\tvar elem,\n\t\tduplicates = [],\n\t\tj = 0,\n\t\ti = 0;\n\n\t// Unless we *know* we can detect duplicates, assume their presence\n\thasDuplicate = !support.detectDuplicates;\n\tsortInput = !support.sortStable && results.slice( 0 );\n\tresults.sort( sortOrder );\n\n\tif ( hasDuplicate ) {\n\t\twhile ( (elem = results[i++]) ) {\n\t\t\tif ( elem === results[ i ] ) {\n\t\t\t\tj = duplicates.push( i );\n\t\t\t}\n\t\t}\n\t\twhile ( j-- ) {\n\t\t\tresults.splice( duplicates[ j ], 1 );\n\t\t}\n\t}\n\n\t// Clear input after sorting to release objects\n\t// See https://github.com/jquery/sizzle/pull/225\n\tsortInput = null;\n\n\treturn results;\n};\n\n/**\n * Utility function for retrieving the text value of an array of DOM nodes\n * @param {Array|Element} elem\n */\ngetText = Sizzle.getText = function( elem ) {\n\tvar node,\n\t\tret = \"\",\n\t\ti = 0,\n\t\tnodeType = elem.nodeType;\n\n\tif ( !nodeType ) {\n\t\t// If no nodeType, this is expected to be an array\n\t\twhile ( (node = elem[i++]) ) {\n\t\t\t// Do not traverse comment nodes\n\t\t\tret += getText( node );\n\t\t}\n\t} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {\n\t\t// Use textContent for elements\n\t\t// innerText usage removed for consistency of new lines (jQuery #11153)\n\t\tif ( typeof elem.textContent === \"string\" ) {\n\t\t\treturn elem.textContent;\n\t\t} else {\n\t\t\t// Traverse its children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tret += getText( elem );\n\t\t\t}\n\t\t}\n\t} else if ( nodeType === 3 || nodeType === 4 ) {\n\t\treturn elem.nodeValue;\n\t}\n\t// Do not include comment or processing instruction nodes\n\n\treturn ret;\n};\n\nExpr = Sizzle.selectors = {\n\n\t// Can be adjusted by the user\n\tcacheLength: 50,\n\n\tcreatePseudo: markFunction,\n\n\tmatch: matchExpr,\n\n\tattrHandle: {},\n\n\tfind: {},\n\n\trelative: {\n\t\t\">\": { dir: \"parentNode\", first: true },\n\t\t\" \": { dir: \"parentNode\" },\n\t\t\"+\": { dir: \"previousSibling\", first: true },\n\t\t\"~\": { dir: \"previousSibling\" }\n\t},\n\n\tpreFilter: {\n\t\t\"ATTR\": function( match ) {\n\t\t\tmatch[1] = match[1].replace( runescape, funescape );\n\n\t\t\t// Move the given value to match[3] whether quoted or unquoted\n\t\t\tmatch[3] = ( match[3] || match[4] || match[5] || \"\" ).replace( runescape, funescape );\n\n\t\t\tif ( match[2] === \"~=\" ) {\n\t\t\t\tmatch[3] = \" \" + match[3] + \" \";\n\t\t\t}\n\n\t\t\treturn match.slice( 0, 4 );\n\t\t},\n\n\t\t\"CHILD\": function( match ) {\n\t\t\t/* matches from matchExpr[\"CHILD\"]\n\t\t\t\t1 type (only|nth|...)\n\t\t\t\t2 what (child|of-type)\n\t\t\t\t3 argument (even|odd|\\d*|\\d*n([+-]\\d+)?|...)\n\t\t\t\t4 xn-component of xn+y argument ([+-]?\\d*n|)\n\t\t\t\t5 sign of xn-component\n\t\t\t\t6 x of xn-component\n\t\t\t\t7 sign of y-component\n\t\t\t\t8 y of y-component\n\t\t\t*/\n\t\t\tmatch[1] = match[1].toLowerCase();\n\n\t\t\tif ( match[1].slice( 0, 3 ) === \"nth\" ) {\n\t\t\t\t// nth-* requires argument\n\t\t\t\tif ( !match[3] ) {\n\t\t\t\t\tSizzle.error( match[0] );\n\t\t\t\t}\n\n\t\t\t\t// numeric x and y parameters for Expr.filter.CHILD\n\t\t\t\t// remember that false/true cast respectively to 0/1\n\t\t\t\tmatch[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === \"even\" || match[3] === \"odd\" ) );\n\t\t\t\tmatch[5] = +( ( match[7] + match[8] ) || match[3] === \"odd\" );\n\n\t\t\t// other types prohibit arguments\n\t\t\t} else if ( match[3] ) {\n\t\t\t\tSizzle.error( match[0] );\n\t\t\t}\n\n\t\t\treturn match;\n\t\t},\n\n\t\t\"PSEUDO\": function( match ) {\n\t\t\tvar excess,\n\t\t\t\tunquoted = !match[6] && match[2];\n\n\t\t\tif ( matchExpr[\"CHILD\"].test( match[0] ) ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Accept quoted arguments as-is\n\t\t\tif ( match[3] ) {\n\t\t\t\tmatch[2] = match[4] || match[5] || \"\";\n\n\t\t\t// Strip excess characters from unquoted arguments\n\t\t\t} else if ( unquoted && rpseudo.test( unquoted ) &&\n\t\t\t\t// Get excess from tokenize (recursively)\n\t\t\t\t(excess = tokenize( unquoted, true )) &&\n\t\t\t\t// advance to the next closing parenthesis\n\t\t\t\t(excess = unquoted.indexOf( \")\", unquoted.length - excess ) - unquoted.length) ) {\n\n\t\t\t\t// excess is a negative index\n\t\t\t\tmatch[0] = match[0].slice( 0, excess );\n\t\t\t\tmatch[2] = unquoted.slice( 0, excess );\n\t\t\t}\n\n\t\t\t// Return only captures needed by the pseudo filter method (type and argument)\n\t\t\treturn match.slice( 0, 3 );\n\t\t}\n\t},\n\n\tfilter: {\n\n\t\t\"TAG\": function( nodeNameSelector ) {\n\t\t\tvar nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn nodeNameSelector === \"*\" ?\n\t\t\t\tfunction() { return true; } :\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn elem.nodeName && elem.nodeName.toLowerCase() === nodeName;\n\t\t\t\t};\n\t\t},\n\n\t\t\"CLASS\": function( className ) {\n\t\t\tvar pattern = classCache[ className + \" \" ];\n\n\t\t\treturn pattern ||\n\t\t\t\t(pattern = new RegExp( \"(^|\" + whitespace + \")\" + className + \"(\" + whitespace + \"|$)\" )) &&\n\t\t\t\tclassCache( className, function( elem ) {\n\t\t\t\t\treturn pattern.test( typeof elem.className === \"string\" && elem.className || typeof elem.getAttribute !== \"undefined\" && elem.getAttribute(\"class\") || \"\" );\n\t\t\t\t});\n\t\t},\n\n\t\t\"ATTR\": function( name, operator, check ) {\n\t\t\treturn function( elem ) {\n\t\t\t\tvar result = Sizzle.attr( elem, name );\n\n\t\t\t\tif ( result == null ) {\n\t\t\t\t\treturn operator === \"!=\";\n\t\t\t\t}\n\t\t\t\tif ( !operator ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tresult += \"\";\n\n\t\t\t\treturn operator === \"=\" ? result === check :\n\t\t\t\t\toperator === \"!=\" ? result !== check :\n\t\t\t\t\toperator === \"^=\" ? check && result.indexOf( check ) === 0 :\n\t\t\t\t\toperator === \"*=\" ? check && result.indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"$=\" ? check && result.slice( -check.length ) === check :\n\t\t\t\t\toperator === \"~=\" ? ( \" \" + result.replace( rwhitespace, \" \" ) + \" \" ).indexOf( check ) > -1 :\n\t\t\t\t\toperator === \"|=\" ? result === check || result.slice( 0, check.length + 1 ) === check + \"-\" :\n\t\t\t\t\tfalse;\n\t\t\t};\n\t\t},\n\n\t\t\"CHILD\": function( type, what, argument, first, last ) {\n\t\t\tvar simple = type.slice( 0, 3 ) !== \"nth\",\n\t\t\t\tforward = type.slice( -4 ) !== \"last\",\n\t\t\t\tofType = what === \"of-type\";\n\n\t\t\treturn first === 1 && last === 0 ?\n\n\t\t\t\t// Shortcut for :nth-*(n)\n\t\t\t\tfunction( elem ) {\n\t\t\t\t\treturn !!elem.parentNode;\n\t\t\t\t} :\n\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tvar cache, outerCache, node, diff, nodeIndex, start,\n\t\t\t\t\t\tdir = simple !== forward ? \"nextSibling\" : \"previousSibling\",\n\t\t\t\t\t\tparent = elem.parentNode,\n\t\t\t\t\t\tname = ofType && elem.nodeName.toLowerCase(),\n\t\t\t\t\t\tuseCache = !xml && !ofType;\n\n\t\t\t\t\tif ( parent ) {\n\n\t\t\t\t\t\t// :(first|last|only)-(child|of-type)\n\t\t\t\t\t\tif ( simple ) {\n\t\t\t\t\t\t\twhile ( dir ) {\n\t\t\t\t\t\t\t\tnode = elem;\n\t\t\t\t\t\t\t\twhile ( (node = node[ dir ]) ) {\n\t\t\t\t\t\t\t\t\tif ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {\n\t\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t// Reverse direction for :only-* (if we haven't yet done so)\n\t\t\t\t\t\t\t\tstart = dir = type === \"only\" && !start && \"nextSibling\";\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tstart = [ forward ? parent.firstChild : parent.lastChild ];\n\n\t\t\t\t\t\t// non-xml :nth-child(...) stores cache data on `parent`\n\t\t\t\t\t\tif ( forward && useCache ) {\n\t\t\t\t\t\t\t// Seek `elem` from a previously-cached index\n\t\t\t\t\t\t\touterCache = parent[ expando ] || (parent[ expando ] = {});\n\t\t\t\t\t\t\tcache = outerCache[ type ] || [];\n\t\t\t\t\t\t\tnodeIndex = cache[0] === dirruns && cache[1];\n\t\t\t\t\t\t\tdiff = cache[0] === dirruns && cache[2];\n\t\t\t\t\t\t\tnode = nodeIndex && parent.childNodes[ nodeIndex ];\n\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\n\t\t\t\t\t\t\t\t// Fallback to seeking `elem` from the start\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\t// When found, cache indexes on `parent` and break\n\t\t\t\t\t\t\t\tif ( node.nodeType === 1 && ++diff && node === elem ) {\n\t\t\t\t\t\t\t\t\touterCache[ type ] = [ dirruns, nodeIndex, diff ];\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Use previously-cached element index if available\n\t\t\t\t\t\t} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {\n\t\t\t\t\t\t\tdiff = cache[1];\n\n\t\t\t\t\t\t// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Use the same loop as above to seek `elem` from the start\n\t\t\t\t\t\t\twhile ( (node = ++nodeIndex && node && node[ dir ] ||\n\t\t\t\t\t\t\t\t(diff = nodeIndex = 0) || start.pop()) ) {\n\n\t\t\t\t\t\t\t\tif ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {\n\t\t\t\t\t\t\t\t\t// Cache the index of each encountered element\n\t\t\t\t\t\t\t\t\tif ( useCache ) {\n\t\t\t\t\t\t\t\t\t\t(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif ( node === elem ) {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Incorporate the offset, then check against cycle size\n\t\t\t\t\t\tdiff -= last;\n\t\t\t\t\t\treturn diff === first || ( diff % first === 0 && diff / first >= 0 );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t},\n\n\t\t\"PSEUDO\": function( pseudo, argument ) {\n\t\t\t// pseudo-class names are case-insensitive\n\t\t\t// http://www.w3.org/TR/selectors/#pseudo-classes\n\t\t\t// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters\n\t\t\t// Remember that setFilters inherits from pseudos\n\t\t\tvar args,\n\t\t\t\tfn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||\n\t\t\t\t\tSizzle.error( \"unsupported pseudo: \" + pseudo );\n\n\t\t\t// The user may use createPseudo to indicate that\n\t\t\t// arguments are needed to create the filter function\n\t\t\t// just as Sizzle does\n\t\t\tif ( fn[ expando ] ) {\n\t\t\t\treturn fn( argument );\n\t\t\t}\n\n\t\t\t// But maintain support for old signatures\n\t\t\tif ( fn.length > 1 ) {\n\t\t\t\targs = [ pseudo, pseudo, \"\", argument ];\n\t\t\t\treturn Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?\n\t\t\t\t\tmarkFunction(function( seed, matches ) {\n\t\t\t\t\t\tvar idx,\n\t\t\t\t\t\t\tmatched = fn( seed, argument ),\n\t\t\t\t\t\t\ti = matched.length;\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tidx = indexOf( seed, matched[i] );\n\t\t\t\t\t\t\tseed[ idx ] = !( matches[ idx ] = matched[i] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}) :\n\t\t\t\t\tfunction( elem ) {\n\t\t\t\t\t\treturn fn( elem, 0, args );\n\t\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn fn;\n\t\t}\n\t},\n\n\tpseudos: {\n\t\t// Potentially complex pseudos\n\t\t\"not\": markFunction(function( selector ) {\n\t\t\t// Trim the selector passed to compile\n\t\t\t// to avoid treating leading and trailing\n\t\t\t// spaces as combinators\n\t\t\tvar input = [],\n\t\t\t\tresults = [],\n\t\t\t\tmatcher = compile( selector.replace( rtrim, \"$1\" ) );\n\n\t\t\treturn matcher[ expando ] ?\n\t\t\t\tmarkFunction(function( seed, matches, context, xml ) {\n\t\t\t\t\tvar elem,\n\t\t\t\t\t\tunmatched = matcher( seed, null, xml, [] ),\n\t\t\t\t\t\ti = seed.length;\n\n\t\t\t\t\t// Match elements unmatched by `matcher`\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = unmatched[i]) ) {\n\t\t\t\t\t\t\tseed[i] = !(matches[i] = elem);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}) :\n\t\t\t\tfunction( elem, context, xml ) {\n\t\t\t\t\tinput[0] = elem;\n\t\t\t\t\tmatcher( input, null, xml, results );\n\t\t\t\t\t// Don't keep the element (issue #299)\n\t\t\t\t\tinput[0] = null;\n\t\t\t\t\treturn !results.pop();\n\t\t\t\t};\n\t\t}),\n\n\t\t\"has\": markFunction(function( selector ) {\n\t\t\treturn function( elem ) {\n\t\t\t\treturn Sizzle( selector, elem ).length > 0;\n\t\t\t};\n\t\t}),\n\n\t\t\"contains\": markFunction(function( text ) {\n\t\t\ttext = text.replace( runescape, funescape );\n\t\t\treturn function( elem ) {\n\t\t\t\treturn ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;\n\t\t\t};\n\t\t}),\n\n\t\t// \"Whether an element is represented by a :lang() selector\n\t\t// is based solely on the element's language value\n\t\t// being equal to the identifier C,\n\t\t// or beginning with the identifier C immediately followed by \"-\".\n\t\t// The matching of C against the element's language value is performed case-insensitively.\n\t\t// The identifier C does not have to be a valid language name.\"\n\t\t// http://www.w3.org/TR/selectors/#lang-pseudo\n\t\t\"lang\": markFunction( function( lang ) {\n\t\t\t// lang value must be a valid identifier\n\t\t\tif ( !ridentifier.test(lang || \"\") ) {\n\t\t\t\tSizzle.error( \"unsupported lang: \" + lang );\n\t\t\t}\n\t\t\tlang = lang.replace( runescape, funescape ).toLowerCase();\n\t\t\treturn function( elem ) {\n\t\t\t\tvar elemLang;\n\t\t\t\tdo {\n\t\t\t\t\tif ( (elemLang = documentIsHTML ?\n\t\t\t\t\t\telem.lang :\n\t\t\t\t\t\telem.getAttribute(\"xml:lang\") || elem.getAttribute(\"lang\")) ) {\n\n\t\t\t\t\t\telemLang = elemLang.toLowerCase();\n\t\t\t\t\t\treturn elemLang === lang || elemLang.indexOf( lang + \"-\" ) === 0;\n\t\t\t\t\t}\n\t\t\t\t} while ( (elem = elem.parentNode) && elem.nodeType === 1 );\n\t\t\t\treturn false;\n\t\t\t};\n\t\t}),\n\n\t\t// Miscellaneous\n\t\t\"target\": function( elem ) {\n\t\t\tvar hash = window.location && window.location.hash;\n\t\t\treturn hash && hash.slice( 1 ) === elem.id;\n\t\t},\n\n\t\t\"root\": function( elem ) {\n\t\t\treturn elem === docElem;\n\t\t},\n\n\t\t\"focus\": function( elem ) {\n\t\t\treturn elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);\n\t\t},\n\n\t\t// Boolean properties\n\t\t\"enabled\": function( elem ) {\n\t\t\treturn elem.disabled === false;\n\t\t},\n\n\t\t\"disabled\": function( elem ) {\n\t\t\treturn elem.disabled === true;\n\t\t},\n\n\t\t\"checked\": function( elem ) {\n\t\t\t// In CSS3, :checked should return both checked and selected elements\n\t\t\t// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked\n\t\t\tvar nodeName = elem.nodeName.toLowerCase();\n\t\t\treturn (nodeName === \"input\" && !!elem.checked) || (nodeName === \"option\" && !!elem.selected);\n\t\t},\n\n\t\t\"selected\": function( elem ) {\n\t\t\t// Accessing this property makes selected-by-default\n\t\t\t// options in Safari work properly\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\telem.parentNode.selectedIndex;\n\t\t\t}\n\n\t\t\treturn elem.selected === true;\n\t\t},\n\n\t\t// Contents\n\t\t\"empty\": function( elem ) {\n\t\t\t// http://www.w3.org/TR/selectors/#empty-pseudo\n\t\t\t// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),\n\t\t\t//   but not by others (comment: 8; processing instruction: 7; etc.)\n\t\t\t// nodeType < 6 works because attributes (2) do not appear as children\n\t\t\tfor ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {\n\t\t\t\tif ( elem.nodeType < 6 ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t\"parent\": function( elem ) {\n\t\t\treturn !Expr.pseudos[\"empty\"]( elem );\n\t\t},\n\n\t\t// Element/input types\n\t\t\"header\": function( elem ) {\n\t\t\treturn rheader.test( elem.nodeName );\n\t\t},\n\n\t\t\"input\": function( elem ) {\n\t\t\treturn rinputs.test( elem.nodeName );\n\t\t},\n\n\t\t\"button\": function( elem ) {\n\t\t\tvar name = elem.nodeName.toLowerCase();\n\t\t\treturn name === \"input\" && elem.type === \"button\" || name === \"button\";\n\t\t},\n\n\t\t\"text\": function( elem ) {\n\t\t\tvar attr;\n\t\t\treturn elem.nodeName.toLowerCase() === \"input\" &&\n\t\t\t\telem.type === \"text\" &&\n\n\t\t\t\t// Support: IE<8\n\t\t\t\t// New HTML5 attribute values (e.g., \"search\") appear with elem.type === \"text\"\n\t\t\t\t( (attr = elem.getAttribute(\"type\")) == null || attr.toLowerCase() === \"text\" );\n\t\t},\n\n\t\t// Position-in-collection\n\t\t\"first\": createPositionalPseudo(function() {\n\t\t\treturn [ 0 ];\n\t\t}),\n\n\t\t\"last\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\treturn [ length - 1 ];\n\t\t}),\n\n\t\t\"eq\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\treturn [ argument < 0 ? argument + length : argument ];\n\t\t}),\n\n\t\t\"even\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"odd\": createPositionalPseudo(function( matchIndexes, length ) {\n\t\t\tvar i = 1;\n\t\t\tfor ( ; i < length; i += 2 ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"lt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; --i >= 0; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t}),\n\n\t\t\"gt\": createPositionalPseudo(function( matchIndexes, length, argument ) {\n\t\t\tvar i = argument < 0 ? argument + length : argument;\n\t\t\tfor ( ; ++i < length; ) {\n\t\t\t\tmatchIndexes.push( i );\n\t\t\t}\n\t\t\treturn matchIndexes;\n\t\t})\n\t}\n};\n\nExpr.pseudos[\"nth\"] = Expr.pseudos[\"eq\"];\n\n// Add button/input type pseudos\nfor ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {\n\tExpr.pseudos[ i ] = createInputPseudo( i );\n}\nfor ( i in { submit: true, reset: true } ) {\n\tExpr.pseudos[ i ] = createButtonPseudo( i );\n}\n\n// Easy API for creating new setFilters\nfunction setFilters() {}\nsetFilters.prototype = Expr.filters = Expr.pseudos;\nExpr.setFilters = new setFilters();\n\ntokenize = Sizzle.tokenize = function( selector, parseOnly ) {\n\tvar matched, match, tokens, type,\n\t\tsoFar, groups, preFilters,\n\t\tcached = tokenCache[ selector + \" \" ];\n\n\tif ( cached ) {\n\t\treturn parseOnly ? 0 : cached.slice( 0 );\n\t}\n\n\tsoFar = selector;\n\tgroups = [];\n\tpreFilters = Expr.preFilter;\n\n\twhile ( soFar ) {\n\n\t\t// Comma and first run\n\t\tif ( !matched || (match = rcomma.exec( soFar )) ) {\n\t\t\tif ( match ) {\n\t\t\t\t// Don't consume trailing commas as valid\n\t\t\t\tsoFar = soFar.slice( match[0].length ) || soFar;\n\t\t\t}\n\t\t\tgroups.push( (tokens = []) );\n\t\t}\n\n\t\tmatched = false;\n\n\t\t// Combinators\n\t\tif ( (match = rcombinators.exec( soFar )) ) {\n\t\t\tmatched = match.shift();\n\t\t\ttokens.push({\n\t\t\t\tvalue: matched,\n\t\t\t\t// Cast descendant combinators to space\n\t\t\t\ttype: match[0].replace( rtrim, \" \" )\n\t\t\t});\n\t\t\tsoFar = soFar.slice( matched.length );\n\t\t}\n\n\t\t// Filters\n\t\tfor ( type in Expr.filter ) {\n\t\t\tif ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||\n\t\t\t\t(match = preFilters[ type ]( match ))) ) {\n\t\t\t\tmatched = match.shift();\n\t\t\t\ttokens.push({\n\t\t\t\t\tvalue: matched,\n\t\t\t\t\ttype: type,\n\t\t\t\t\tmatches: match\n\t\t\t\t});\n\t\t\t\tsoFar = soFar.slice( matched.length );\n\t\t\t}\n\t\t}\n\n\t\tif ( !matched ) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Return the length of the invalid excess\n\t// if we're just parsing\n\t// Otherwise, throw an error or return tokens\n\treturn parseOnly ?\n\t\tsoFar.length :\n\t\tsoFar ?\n\t\t\tSizzle.error( selector ) :\n\t\t\t// Cache the tokens\n\t\t\ttokenCache( selector, groups ).slice( 0 );\n};\n\nfunction toSelector( tokens ) {\n\tvar i = 0,\n\t\tlen = tokens.length,\n\t\tselector = \"\";\n\tfor ( ; i < len; i++ ) {\n\t\tselector += tokens[i].value;\n\t}\n\treturn selector;\n}\n\nfunction addCombinator( matcher, combinator, base ) {\n\tvar dir = combinator.dir,\n\t\tcheckNonElements = base && dir === \"parentNode\",\n\t\tdoneName = done++;\n\n\treturn combinator.first ?\n\t\t// Check against closest ancestor/preceding element\n\t\tfunction( elem, context, xml ) {\n\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\treturn matcher( elem, context, xml );\n\t\t\t\t}\n\t\t\t}\n\t\t} :\n\n\t\t// Check against all ancestor/preceding elements\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar oldCache, outerCache,\n\t\t\t\tnewCache = [ dirruns, doneName ];\n\n\t\t\t// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching\n\t\t\tif ( xml ) {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twhile ( (elem = elem[ dir ]) ) {\n\t\t\t\t\tif ( elem.nodeType === 1 || checkNonElements ) {\n\t\t\t\t\t\touterCache = elem[ expando ] || (elem[ expando ] = {});\n\t\t\t\t\t\tif ( (oldCache = outerCache[ dir ]) &&\n\t\t\t\t\t\t\toldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {\n\n\t\t\t\t\t\t\t// Assign to newCache so results back-propagate to previous elements\n\t\t\t\t\t\t\treturn (newCache[ 2 ] = oldCache[ 2 ]);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Reuse newcache so results back-propagate to previous elements\n\t\t\t\t\t\t\touterCache[ dir ] = newCache;\n\n\t\t\t\t\t\t\t// A match means we're done; a fail means we have to keep checking\n\t\t\t\t\t\t\tif ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n}\n\nfunction elementMatcher( matchers ) {\n\treturn matchers.length > 1 ?\n\t\tfunction( elem, context, xml ) {\n\t\t\tvar i = matchers.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( !matchers[i]( elem, context, xml ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t} :\n\t\tmatchers[0];\n}\n\nfunction multipleContexts( selector, contexts, results ) {\n\tvar i = 0,\n\t\tlen = contexts.length;\n\tfor ( ; i < len; i++ ) {\n\t\tSizzle( selector, contexts[i], results );\n\t}\n\treturn results;\n}\n\nfunction condense( unmatched, map, filter, context, xml ) {\n\tvar elem,\n\t\tnewUnmatched = [],\n\t\ti = 0,\n\t\tlen = unmatched.length,\n\t\tmapped = map != null;\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (elem = unmatched[i]) ) {\n\t\t\tif ( !filter || filter( elem, context, xml ) ) {\n\t\t\t\tnewUnmatched.push( elem );\n\t\t\t\tif ( mapped ) {\n\t\t\t\t\tmap.push( i );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newUnmatched;\n}\n\nfunction setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {\n\tif ( postFilter && !postFilter[ expando ] ) {\n\t\tpostFilter = setMatcher( postFilter );\n\t}\n\tif ( postFinder && !postFinder[ expando ] ) {\n\t\tpostFinder = setMatcher( postFinder, postSelector );\n\t}\n\treturn markFunction(function( seed, results, context, xml ) {\n\t\tvar temp, i, elem,\n\t\t\tpreMap = [],\n\t\t\tpostMap = [],\n\t\t\tpreexisting = results.length,\n\n\t\t\t// Get initial elements from seed or context\n\t\t\telems = seed || multipleContexts( selector || \"*\", context.nodeType ? [ context ] : context, [] ),\n\n\t\t\t// Prefilter to get matcher input, preserving a map for seed-results synchronization\n\t\t\tmatcherIn = preFilter && ( seed || !selector ) ?\n\t\t\t\tcondense( elems, preMap, preFilter, context, xml ) :\n\t\t\t\telems,\n\n\t\t\tmatcherOut = matcher ?\n\t\t\t\t// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,\n\t\t\t\tpostFinder || ( seed ? preFilter : preexisting || postFilter ) ?\n\n\t\t\t\t\t// ...intermediate processing is necessary\n\t\t\t\t\t[] :\n\n\t\t\t\t\t// ...otherwise use results directly\n\t\t\t\t\tresults :\n\t\t\t\tmatcherIn;\n\n\t\t// Find primary matches\n\t\tif ( matcher ) {\n\t\t\tmatcher( matcherIn, matcherOut, context, xml );\n\t\t}\n\n\t\t// Apply postFilter\n\t\tif ( postFilter ) {\n\t\t\ttemp = condense( matcherOut, postMap );\n\t\t\tpostFilter( temp, [], context, xml );\n\n\t\t\t// Un-match failing elements by moving them back to matcherIn\n\t\t\ti = temp.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tif ( (elem = temp[i]) ) {\n\t\t\t\t\tmatcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( seed ) {\n\t\t\tif ( postFinder || preFilter ) {\n\t\t\t\tif ( postFinder ) {\n\t\t\t\t\t// Get the final matcherOut by condensing this intermediate into postFinder contexts\n\t\t\t\t\ttemp = [];\n\t\t\t\t\ti = matcherOut.length;\n\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\tif ( (elem = matcherOut[i]) ) {\n\t\t\t\t\t\t\t// Restore matcherIn since elem is not yet a final match\n\t\t\t\t\t\t\ttemp.push( (matcherIn[i] = elem) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpostFinder( null, (matcherOut = []), temp, xml );\n\t\t\t\t}\n\n\t\t\t\t// Move matched elements from seed to results to keep them synchronized\n\t\t\t\ti = matcherOut.length;\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\tif ( (elem = matcherOut[i]) &&\n\t\t\t\t\t\t(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {\n\n\t\t\t\t\t\tseed[temp] = !(results[temp] = elem);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Add elements to results, through postFinder if defined\n\t\t} else {\n\t\t\tmatcherOut = condense(\n\t\t\t\tmatcherOut === results ?\n\t\t\t\t\tmatcherOut.splice( preexisting, matcherOut.length ) :\n\t\t\t\t\tmatcherOut\n\t\t\t);\n\t\t\tif ( postFinder ) {\n\t\t\t\tpostFinder( null, results, matcherOut, xml );\n\t\t\t} else {\n\t\t\t\tpush.apply( results, matcherOut );\n\t\t\t}\n\t\t}\n\t});\n}\n\nfunction matcherFromTokens( tokens ) {\n\tvar checkContext, matcher, j,\n\t\tlen = tokens.length,\n\t\tleadingRelative = Expr.relative[ tokens[0].type ],\n\t\timplicitRelative = leadingRelative || Expr.relative[\" \"],\n\t\ti = leadingRelative ? 1 : 0,\n\n\t\t// The foundational matcher ensures that elements are reachable from top-level context(s)\n\t\tmatchContext = addCombinator( function( elem ) {\n\t\t\treturn elem === checkContext;\n\t\t}, implicitRelative, true ),\n\t\tmatchAnyContext = addCombinator( function( elem ) {\n\t\t\treturn indexOf( checkContext, elem ) > -1;\n\t\t}, implicitRelative, true ),\n\t\tmatchers = [ function( elem, context, xml ) {\n\t\t\tvar ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (\n\t\t\t\t(checkContext = context).nodeType ?\n\t\t\t\t\tmatchContext( elem, context, xml ) :\n\t\t\t\t\tmatchAnyContext( elem, context, xml ) );\n\t\t\t// Avoid hanging onto element (issue #299)\n\t\t\tcheckContext = null;\n\t\t\treturn ret;\n\t\t} ];\n\n\tfor ( ; i < len; i++ ) {\n\t\tif ( (matcher = Expr.relative[ tokens[i].type ]) ) {\n\t\t\tmatchers = [ addCombinator(elementMatcher( matchers ), matcher) ];\n\t\t} else {\n\t\t\tmatcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );\n\n\t\t\t// Return special upon seeing a positional matcher\n\t\t\tif ( matcher[ expando ] ) {\n\t\t\t\t// Find the next relative operator (if any) for proper handling\n\t\t\t\tj = ++i;\n\t\t\t\tfor ( ; j < len; j++ ) {\n\t\t\t\t\tif ( Expr.relative[ tokens[j].type ] ) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn setMatcher(\n\t\t\t\t\ti > 1 && elementMatcher( matchers ),\n\t\t\t\t\ti > 1 && toSelector(\n\t\t\t\t\t\t// If the preceding token was a descendant combinator, insert an implicit any-element `*`\n\t\t\t\t\t\ttokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === \" \" ? \"*\" : \"\" })\n\t\t\t\t\t).replace( rtrim, \"$1\" ),\n\t\t\t\t\tmatcher,\n\t\t\t\t\ti < j && matcherFromTokens( tokens.slice( i, j ) ),\n\t\t\t\t\tj < len && matcherFromTokens( (tokens = tokens.slice( j )) ),\n\t\t\t\t\tj < len && toSelector( tokens )\n\t\t\t\t);\n\t\t\t}\n\t\t\tmatchers.push( matcher );\n\t\t}\n\t}\n\n\treturn elementMatcher( matchers );\n}\n\nfunction matcherFromGroupMatchers( elementMatchers, setMatchers ) {\n\tvar bySet = setMatchers.length > 0,\n\t\tbyElement = elementMatchers.length > 0,\n\t\tsuperMatcher = function( seed, context, xml, results, outermost ) {\n\t\t\tvar elem, j, matcher,\n\t\t\t\tmatchedCount = 0,\n\t\t\t\ti = \"0\",\n\t\t\t\tunmatched = seed && [],\n\t\t\t\tsetMatched = [],\n\t\t\t\tcontextBackup = outermostContext,\n\t\t\t\t// We must always have either seed elements or outermost context\n\t\t\t\telems = seed || byElement && Expr.find[\"TAG\"]( \"*\", outermost ),\n\t\t\t\t// Use integer dirruns iff this is the outermost matcher\n\t\t\t\tdirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),\n\t\t\t\tlen = elems.length;\n\n\t\t\tif ( outermost ) {\n\t\t\t\toutermostContext = context !== document && context;\n\t\t\t}\n\n\t\t\t// Add elements passing elementMatchers directly to results\n\t\t\t// Keep `i` a string if there are no elements so `matchedCount` will be \"00\" below\n\t\t\t// Support: IE<9, Safari\n\t\t\t// Tolerate NodeList properties (IE: \"length\"; Safari: <number>) matching elements by id\n\t\t\tfor ( ; i !== len && (elem = elems[i]) != null; i++ ) {\n\t\t\t\tif ( byElement && elem ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (matcher = elementMatchers[j++]) ) {\n\t\t\t\t\t\tif ( matcher( elem, context, xml ) ) {\n\t\t\t\t\t\t\tresults.push( elem );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( outermost ) {\n\t\t\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Track unmatched elements for set filters\n\t\t\t\tif ( bySet ) {\n\t\t\t\t\t// They will have gone through all possible matchers\n\t\t\t\t\tif ( (elem = !matcher && elem) ) {\n\t\t\t\t\t\tmatchedCount--;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Lengthen the array for every element, matched or not\n\t\t\t\t\tif ( seed ) {\n\t\t\t\t\t\tunmatched.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Apply set filters to unmatched elements\n\t\t\tmatchedCount += i;\n\t\t\tif ( bySet && i !== matchedCount ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (matcher = setMatchers[j++]) ) {\n\t\t\t\t\tmatcher( unmatched, setMatched, context, xml );\n\t\t\t\t}\n\n\t\t\t\tif ( seed ) {\n\t\t\t\t\t// Reintegrate element matches to eliminate the need for sorting\n\t\t\t\t\tif ( matchedCount > 0 ) {\n\t\t\t\t\t\twhile ( i-- ) {\n\t\t\t\t\t\t\tif ( !(unmatched[i] || setMatched[i]) ) {\n\t\t\t\t\t\t\t\tsetMatched[i] = pop.call( results );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Discard index placeholder values to get only actual matches\n\t\t\t\t\tsetMatched = condense( setMatched );\n\t\t\t\t}\n\n\t\t\t\t// Add matches to results\n\t\t\t\tpush.apply( results, setMatched );\n\n\t\t\t\t// Seedless set matches succeeding multiple successful matchers stipulate sorting\n\t\t\t\tif ( outermost && !seed && setMatched.length > 0 &&\n\t\t\t\t\t( matchedCount + setMatchers.length ) > 1 ) {\n\n\t\t\t\t\tSizzle.uniqueSort( results );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Override manipulation of globals by nested matchers\n\t\t\tif ( outermost ) {\n\t\t\t\tdirruns = dirrunsUnique;\n\t\t\t\toutermostContext = contextBackup;\n\t\t\t}\n\n\t\t\treturn unmatched;\n\t\t};\n\n\treturn bySet ?\n\t\tmarkFunction( superMatcher ) :\n\t\tsuperMatcher;\n}\n\ncompile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {\n\tvar i,\n\t\tsetMatchers = [],\n\t\telementMatchers = [],\n\t\tcached = compilerCache[ selector + \" \" ];\n\n\tif ( !cached ) {\n\t\t// Generate a function of recursive functions that can be used to check each element\n\t\tif ( !match ) {\n\t\t\tmatch = tokenize( selector );\n\t\t}\n\t\ti = match.length;\n\t\twhile ( i-- ) {\n\t\t\tcached = matcherFromTokens( match[i] );\n\t\t\tif ( cached[ expando ] ) {\n\t\t\t\tsetMatchers.push( cached );\n\t\t\t} else {\n\t\t\t\telementMatchers.push( cached );\n\t\t\t}\n\t\t}\n\n\t\t// Cache the compiled function\n\t\tcached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );\n\n\t\t// Save selector and tokenization\n\t\tcached.selector = selector;\n\t}\n\treturn cached;\n};\n\n/**\n * A low-level selection function that works with Sizzle's compiled\n *  selector functions\n * @param {String|Function} selector A selector or a pre-compiled\n *  selector function built with Sizzle.compile\n * @param {Element} context\n * @param {Array} [results]\n * @param {Array} [seed] A set of elements to match against\n */\nselect = Sizzle.select = function( selector, context, results, seed ) {\n\tvar i, tokens, token, type, find,\n\t\tcompiled = typeof selector === \"function\" && selector,\n\t\tmatch = !seed && tokenize( (selector = compiled.selector || selector) );\n\n\tresults = results || [];\n\n\t// Try to minimize operations if there is no seed and only one group\n\tif ( match.length === 1 ) {\n\n\t\t// Take a shortcut and set the context if the root selector is an ID\n\t\ttokens = match[0] = match[0].slice( 0 );\n\t\tif ( tokens.length > 2 && (token = tokens[0]).type === \"ID\" &&\n\t\t\t\tsupport.getById && context.nodeType === 9 && documentIsHTML &&\n\t\t\t\tExpr.relative[ tokens[1].type ] ) {\n\n\t\t\tcontext = ( Expr.find[\"ID\"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];\n\t\t\tif ( !context ) {\n\t\t\t\treturn results;\n\n\t\t\t// Precompiled matchers will still verify ancestry, so step up a level\n\t\t\t} else if ( compiled ) {\n\t\t\t\tcontext = context.parentNode;\n\t\t\t}\n\n\t\t\tselector = selector.slice( tokens.shift().value.length );\n\t\t}\n\n\t\t// Fetch a seed set for right-to-left matching\n\t\ti = matchExpr[\"needsContext\"].test( selector ) ? 0 : tokens.length;\n\t\twhile ( i-- ) {\n\t\t\ttoken = tokens[i];\n\n\t\t\t// Abort if we hit a combinator\n\t\t\tif ( Expr.relative[ (type = token.type) ] ) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( (find = Expr.find[ type ]) ) {\n\t\t\t\t// Search, expanding context for leading sibling combinators\n\t\t\t\tif ( (seed = find(\n\t\t\t\t\ttoken.matches[0].replace( runescape, funescape ),\n\t\t\t\t\trsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context\n\t\t\t\t)) ) {\n\n\t\t\t\t\t// If seed is empty or no tokens remain, we can return early\n\t\t\t\t\ttokens.splice( i, 1 );\n\t\t\t\t\tselector = seed.length && toSelector( tokens );\n\t\t\t\t\tif ( !selector ) {\n\t\t\t\t\t\tpush.apply( results, seed );\n\t\t\t\t\t\treturn results;\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Compile and execute a filtering function if one is not provided\n\t// Provide `match` to avoid retokenization if we modified the selector above\n\t( compiled || compile( selector, match ) )(\n\t\tseed,\n\t\tcontext,\n\t\t!documentIsHTML,\n\t\tresults,\n\t\trsibling.test( selector ) && testContext( context.parentNode ) || context\n\t);\n\treturn results;\n};\n\n// One-time assignments\n\n// Sort stability\nsupport.sortStable = expando.split(\"\").sort( sortOrder ).join(\"\") === expando;\n\n// Support: Chrome 14-35+\n// Always assume duplicates if they aren't passed to the comparison function\nsupport.detectDuplicates = !!hasDuplicate;\n\n// Initialize against the default document\nsetDocument();\n\n// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)\n// Detached nodes confoundingly follow *each other*\nsupport.sortDetached = assert(function( div1 ) {\n\t// Should return 1, but returns 4 (following)\n\treturn div1.compareDocumentPosition( document.createElement(\"div\") ) & 1;\n});\n\n// Support: IE<8\n// Prevent attribute/property \"interpolation\"\n// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx\nif ( !assert(function( div ) {\n\tdiv.innerHTML = \"<a href='#'></a>\";\n\treturn div.firstChild.getAttribute(\"href\") === \"#\" ;\n}) ) {\n\taddHandle( \"type|href|height|width\", function( elem, name, isXML ) {\n\t\tif ( !isXML ) {\n\t\t\treturn elem.getAttribute( name, name.toLowerCase() === \"type\" ? 1 : 2 );\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use defaultValue in place of getAttribute(\"value\")\nif ( !support.attributes || !assert(function( div ) {\n\tdiv.innerHTML = \"<input/>\";\n\tdiv.firstChild.setAttribute( \"value\", \"\" );\n\treturn div.firstChild.getAttribute( \"value\" ) === \"\";\n}) ) {\n\taddHandle( \"value\", function( elem, name, isXML ) {\n\t\tif ( !isXML && elem.nodeName.toLowerCase() === \"input\" ) {\n\t\t\treturn elem.defaultValue;\n\t\t}\n\t});\n}\n\n// Support: IE<9\n// Use getAttributeNode to fetch booleans when getAttribute lies\nif ( !assert(function( div ) {\n\treturn div.getAttribute(\"disabled\") == null;\n}) ) {\n\taddHandle( booleans, function( elem, name, isXML ) {\n\t\tvar val;\n\t\tif ( !isXML ) {\n\t\t\treturn elem[ name ] === true ? name.toLowerCase() :\n\t\t\t\t\t(val = elem.getAttributeNode( name )) && val.specified ?\n\t\t\t\t\tval.value :\n\t\t\t\tnull;\n\t\t}\n\t});\n}\n\nreturn Sizzle;\n\n})( window );\n\n\n\njQuery.find = Sizzle;\njQuery.expr = Sizzle.selectors;\njQuery.expr[\":\"] = jQuery.expr.pseudos;\njQuery.unique = Sizzle.uniqueSort;\njQuery.text = Sizzle.getText;\njQuery.isXMLDoc = Sizzle.isXML;\njQuery.contains = Sizzle.contains;\n\n\n\nvar rneedsContext = jQuery.expr.match.needsContext;\n\nvar rsingleTag = (/^<(\\w+)\\s*\\/?>(?:<\\/\\1>|)$/);\n\n\n\nvar risSimple = /^.[^:#\\[\\.,]*$/;\n\n// Implement the identical functionality for filter and not\nfunction winnow( elements, qualifier, not ) {\n\tif ( jQuery.isFunction( qualifier ) ) {\n\t\treturn jQuery.grep( elements, function( elem, i ) {\n\t\t\t/* jshint -W018 */\n\t\t\treturn !!qualifier.call( elem, i, elem ) !== not;\n\t\t});\n\n\t}\n\n\tif ( qualifier.nodeType ) {\n\t\treturn jQuery.grep( elements, function( elem ) {\n\t\t\treturn ( elem === qualifier ) !== not;\n\t\t});\n\n\t}\n\n\tif ( typeof qualifier === \"string\" ) {\n\t\tif ( risSimple.test( qualifier ) ) {\n\t\t\treturn jQuery.filter( qualifier, elements, not );\n\t\t}\n\n\t\tqualifier = jQuery.filter( qualifier, elements );\n\t}\n\n\treturn jQuery.grep( elements, function( elem ) {\n\t\treturn ( indexOf.call( qualifier, elem ) >= 0 ) !== not;\n\t});\n}\n\njQuery.filter = function( expr, elems, not ) {\n\tvar elem = elems[ 0 ];\n\n\tif ( not ) {\n\t\texpr = \":not(\" + expr + \")\";\n\t}\n\n\treturn elems.length === 1 && elem.nodeType === 1 ?\n\t\tjQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :\n\t\tjQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {\n\t\t\treturn elem.nodeType === 1;\n\t\t}));\n};\n\njQuery.fn.extend({\n\tfind: function( selector ) {\n\t\tvar i,\n\t\t\tlen = this.length,\n\t\t\tret = [],\n\t\t\tself = this;\n\n\t\tif ( typeof selector !== \"string\" ) {\n\t\t\treturn this.pushStack( jQuery( selector ).filter(function() {\n\t\t\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\t\t\tif ( jQuery.contains( self[ i ], this ) ) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}) );\n\t\t}\n\n\t\tfor ( i = 0; i < len; i++ ) {\n\t\t\tjQuery.find( selector, self[ i ], ret );\n\t\t}\n\n\t\t// Needed because $( selector, context ) becomes $( context ).find( selector )\n\t\tret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );\n\t\tret.selector = this.selector ? this.selector + \" \" + selector : selector;\n\t\treturn ret;\n\t},\n\tfilter: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector || [], false) );\n\t},\n\tnot: function( selector ) {\n\t\treturn this.pushStack( winnow(this, selector || [], true) );\n\t},\n\tis: function( selector ) {\n\t\treturn !!winnow(\n\t\t\tthis,\n\n\t\t\t// If this is a positional/relative selector, check membership in the returned set\n\t\t\t// so $(\"p:first\").is(\"p:last\") won't return true for a doc with two \"p\".\n\t\t\ttypeof selector === \"string\" && rneedsContext.test( selector ) ?\n\t\t\t\tjQuery( selector ) :\n\t\t\t\tselector || [],\n\t\t\tfalse\n\t\t).length;\n\t}\n});\n\n\n// Initialize a jQuery object\n\n\n// A central reference to the root jQuery(document)\nvar rootjQuery,\n\n\t// A simple way to check for HTML strings\n\t// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)\n\t// Strict HTML recognition (#11290: must start with <)\n\trquickExpr = /^(?:\\s*(<[\\w\\W]+>)[^>]*|#([\\w-]*))$/,\n\n\tinit = jQuery.fn.init = function( selector, context ) {\n\t\tvar match, elem;\n\n\t\t// HANDLE: $(\"\"), $(null), $(undefined), $(false)\n\t\tif ( !selector ) {\n\t\t\treturn this;\n\t\t}\n\n\t\t// Handle HTML strings\n\t\tif ( typeof selector === \"string\" ) {\n\t\t\tif ( selector[0] === \"<\" && selector[ selector.length - 1 ] === \">\" && selector.length >= 3 ) {\n\t\t\t\t// Assume that strings that start and end with <> are HTML and skip the regex check\n\t\t\t\tmatch = [ null, selector, null ];\n\n\t\t\t} else {\n\t\t\t\tmatch = rquickExpr.exec( selector );\n\t\t\t}\n\n\t\t\t// Match html or make sure no context is specified for #id\n\t\t\tif ( match && (match[1] || !context) ) {\n\n\t\t\t\t// HANDLE: $(html) -> $(array)\n\t\t\t\tif ( match[1] ) {\n\t\t\t\t\tcontext = context instanceof jQuery ? context[0] : context;\n\n\t\t\t\t\t// Option to run scripts is true for back-compat\n\t\t\t\t\t// Intentionally let the error be thrown if parseHTML is not present\n\t\t\t\t\tjQuery.merge( this, jQuery.parseHTML(\n\t\t\t\t\t\tmatch[1],\n\t\t\t\t\t\tcontext && context.nodeType ? context.ownerDocument || context : document,\n\t\t\t\t\t\ttrue\n\t\t\t\t\t) );\n\n\t\t\t\t\t// HANDLE: $(html, props)\n\t\t\t\t\tif ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {\n\t\t\t\t\t\tfor ( match in context ) {\n\t\t\t\t\t\t\t// Properties of context are called as methods if possible\n\t\t\t\t\t\t\tif ( jQuery.isFunction( this[ match ] ) ) {\n\t\t\t\t\t\t\t\tthis[ match ]( context[ match ] );\n\n\t\t\t\t\t\t\t// ...and otherwise set as attributes\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.attr( match, context[ match ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this;\n\n\t\t\t\t// HANDLE: $(#id)\n\t\t\t\t} else {\n\t\t\t\t\telem = document.getElementById( match[2] );\n\n\t\t\t\t\t// Support: Blackberry 4.6\n\t\t\t\t\t// gEBID returns nodes no longer in the document (#6963)\n\t\t\t\t\tif ( elem && elem.parentNode ) {\n\t\t\t\t\t\t// Inject the element directly into the jQuery object\n\t\t\t\t\t\tthis.length = 1;\n\t\t\t\t\t\tthis[0] = elem;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.context = document;\n\t\t\t\t\tthis.selector = selector;\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\n\t\t\t// HANDLE: $(expr, $(...))\n\t\t\t} else if ( !context || context.jquery ) {\n\t\t\t\treturn ( context || rootjQuery ).find( selector );\n\n\t\t\t// HANDLE: $(expr, context)\n\t\t\t// (which is just equivalent to: $(context).find(expr)\n\t\t\t} else {\n\t\t\t\treturn this.constructor( context ).find( selector );\n\t\t\t}\n\n\t\t// HANDLE: $(DOMElement)\n\t\t} else if ( selector.nodeType ) {\n\t\t\tthis.context = this[0] = selector;\n\t\t\tthis.length = 1;\n\t\t\treturn this;\n\n\t\t// HANDLE: $(function)\n\t\t// Shortcut for document ready\n\t\t} else if ( jQuery.isFunction( selector ) ) {\n\t\t\treturn typeof rootjQuery.ready !== \"undefined\" ?\n\t\t\t\trootjQuery.ready( selector ) :\n\t\t\t\t// Execute immediately if ready is not present\n\t\t\t\tselector( jQuery );\n\t\t}\n\n\t\tif ( selector.selector !== undefined ) {\n\t\t\tthis.selector = selector.selector;\n\t\t\tthis.context = selector.context;\n\t\t}\n\n\t\treturn jQuery.makeArray( selector, this );\n\t};\n\n// Give the init function the jQuery prototype for later instantiation\ninit.prototype = jQuery.fn;\n\n// Initialize central reference\nrootjQuery = jQuery( document );\n\n\nvar rparentsprev = /^(?:parents|prev(?:Until|All))/,\n\t// Methods guaranteed to produce a unique set when starting from a unique set\n\tguaranteedUnique = {\n\t\tchildren: true,\n\t\tcontents: true,\n\t\tnext: true,\n\t\tprev: true\n\t};\n\njQuery.extend({\n\tdir: function( elem, dir, until ) {\n\t\tvar matched = [],\n\t\t\ttruncate = until !== undefined;\n\n\t\twhile ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\tif ( truncate && jQuery( elem ).is( until ) ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tmatched.push( elem );\n\t\t\t}\n\t\t}\n\t\treturn matched;\n\t},\n\n\tsibling: function( n, elem ) {\n\t\tvar matched = [];\n\n\t\tfor ( ; n; n = n.nextSibling ) {\n\t\t\tif ( n.nodeType === 1 && n !== elem ) {\n\t\t\t\tmatched.push( n );\n\t\t\t}\n\t\t}\n\n\t\treturn matched;\n\t}\n});\n\njQuery.fn.extend({\n\thas: function( target ) {\n\t\tvar targets = jQuery( target, this ),\n\t\t\tl = targets.length;\n\n\t\treturn this.filter(function() {\n\t\t\tvar i = 0;\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tif ( jQuery.contains( this, targets[i] ) ) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t},\n\n\tclosest: function( selectors, context ) {\n\t\tvar cur,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tmatched = [],\n\t\t\tpos = rneedsContext.test( selectors ) || typeof selectors !== \"string\" ?\n\t\t\t\tjQuery( selectors, context || this.context ) :\n\t\t\t\t0;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tfor ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {\n\t\t\t\t// Always skip document fragments\n\t\t\t\tif ( cur.nodeType < 11 && (pos ?\n\t\t\t\t\tpos.index(cur) > -1 :\n\n\t\t\t\t\t// Don't pass non-elements to Sizzle\n\t\t\t\t\tcur.nodeType === 1 &&\n\t\t\t\t\t\tjQuery.find.matchesSelector(cur, selectors)) ) {\n\n\t\t\t\t\tmatched.push( cur );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );\n\t},\n\n\t// Determine the position of an element within the set\n\tindex: function( elem ) {\n\n\t\t// No argument, return index in parent\n\t\tif ( !elem ) {\n\t\t\treturn ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;\n\t\t}\n\n\t\t// Index in selector\n\t\tif ( typeof elem === \"string\" ) {\n\t\t\treturn indexOf.call( jQuery( elem ), this[ 0 ] );\n\t\t}\n\n\t\t// Locate the position of the desired element\n\t\treturn indexOf.call( this,\n\n\t\t\t// If it receives a jQuery object, the first element is used\n\t\t\telem.jquery ? elem[ 0 ] : elem\n\t\t);\n\t},\n\n\tadd: function( selector, context ) {\n\t\treturn this.pushStack(\n\t\t\tjQuery.unique(\n\t\t\t\tjQuery.merge( this.get(), jQuery( selector, context ) )\n\t\t\t)\n\t\t);\n\t},\n\n\taddBack: function( selector ) {\n\t\treturn this.add( selector == null ?\n\t\t\tthis.prevObject : this.prevObject.filter(selector)\n\t\t);\n\t}\n});\n\nfunction sibling( cur, dir ) {\n\twhile ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}\n\treturn cur;\n}\n\njQuery.each({\n\tparent: function( elem ) {\n\t\tvar parent = elem.parentNode;\n\t\treturn parent && parent.nodeType !== 11 ? parent : null;\n\t},\n\tparents: function( elem ) {\n\t\treturn jQuery.dir( elem, \"parentNode\" );\n\t},\n\tparentsUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"parentNode\", until );\n\t},\n\tnext: function( elem ) {\n\t\treturn sibling( elem, \"nextSibling\" );\n\t},\n\tprev: function( elem ) {\n\t\treturn sibling( elem, \"previousSibling\" );\n\t},\n\tnextAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\" );\n\t},\n\tprevAll: function( elem ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\" );\n\t},\n\tnextUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"nextSibling\", until );\n\t},\n\tprevUntil: function( elem, i, until ) {\n\t\treturn jQuery.dir( elem, \"previousSibling\", until );\n\t},\n\tsiblings: function( elem ) {\n\t\treturn jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );\n\t},\n\tchildren: function( elem ) {\n\t\treturn jQuery.sibling( elem.firstChild );\n\t},\n\tcontents: function( elem ) {\n\t\treturn elem.contentDocument || jQuery.merge( [], elem.childNodes );\n\t}\n}, function( name, fn ) {\n\tjQuery.fn[ name ] = function( until, selector ) {\n\t\tvar matched = jQuery.map( this, fn, until );\n\n\t\tif ( name.slice( -5 ) !== \"Until\" ) {\n\t\t\tselector = until;\n\t\t}\n\n\t\tif ( selector && typeof selector === \"string\" ) {\n\t\t\tmatched = jQuery.filter( selector, matched );\n\t\t}\n\n\t\tif ( this.length > 1 ) {\n\t\t\t// Remove duplicates\n\t\t\tif ( !guaranteedUnique[ name ] ) {\n\t\t\t\tjQuery.unique( matched );\n\t\t\t}\n\n\t\t\t// Reverse order for parents* and prev-derivatives\n\t\t\tif ( rparentsprev.test( name ) ) {\n\t\t\t\tmatched.reverse();\n\t\t\t}\n\t\t}\n\n\t\treturn this.pushStack( matched );\n\t};\n});\nvar rnotwhite = (/\\S+/g);\n\n\n\n// String to Object options format cache\nvar optionsCache = {};\n\n// Convert String-formatted options into Object-formatted ones and store in cache\nfunction createOptions( options ) {\n\tvar object = optionsCache[ options ] = {};\n\tjQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {\n\t\tobject[ flag ] = true;\n\t});\n\treturn object;\n}\n\n/*\n * Create a callback list using the following parameters:\n *\n *\toptions: an optional list of space-separated options that will change how\n *\t\t\tthe callback list behaves or a more traditional option object\n *\n * By default a callback list will act like an event callback list and can be\n * \"fired\" multiple times.\n *\n * Possible options:\n *\n *\tonce:\t\t\twill ensure the callback list can only be fired once (like a Deferred)\n *\n *\tmemory:\t\t\twill keep track of previous values and will call any callback added\n *\t\t\t\t\tafter the list has been fired right away with the latest \"memorized\"\n *\t\t\t\t\tvalues (like a Deferred)\n *\n *\tunique:\t\t\twill ensure a callback can only be added once (no duplicate in the list)\n *\n *\tstopOnFalse:\tinterrupt callings when a callback returns false\n *\n */\njQuery.Callbacks = function( options ) {\n\n\t// Convert options from String-formatted to Object-formatted if needed\n\t// (we check in cache first)\n\toptions = typeof options === \"string\" ?\n\t\t( optionsCache[ options ] || createOptions( options ) ) :\n\t\tjQuery.extend( {}, options );\n\n\tvar // Last fire value (for non-forgettable lists)\n\t\tmemory,\n\t\t// Flag to know if list was already fired\n\t\tfired,\n\t\t// Flag to know if list is currently firing\n\t\tfiring,\n\t\t// First callback to fire (used internally by add and fireWith)\n\t\tfiringStart,\n\t\t// End of the loop when firing\n\t\tfiringLength,\n\t\t// Index of currently firing callback (modified by remove if needed)\n\t\tfiringIndex,\n\t\t// Actual callback list\n\t\tlist = [],\n\t\t// Stack of fire calls for repeatable lists\n\t\tstack = !options.once && [],\n\t\t// Fire callbacks\n\t\tfire = function( data ) {\n\t\t\tmemory = options.memory && data;\n\t\t\tfired = true;\n\t\t\tfiringIndex = firingStart || 0;\n\t\t\tfiringStart = 0;\n\t\t\tfiringLength = list.length;\n\t\t\tfiring = true;\n\t\t\tfor ( ; list && firingIndex < firingLength; firingIndex++ ) {\n\t\t\t\tif ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {\n\t\t\t\t\tmemory = false; // To prevent further calls using add\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tfiring = false;\n\t\t\tif ( list ) {\n\t\t\t\tif ( stack ) {\n\t\t\t\t\tif ( stack.length ) {\n\t\t\t\t\t\tfire( stack.shift() );\n\t\t\t\t\t}\n\t\t\t\t} else if ( memory ) {\n\t\t\t\t\tlist = [];\n\t\t\t\t} else {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t// Actual Callbacks object\n\t\tself = {\n\t\t\t// Add a callback or a collection of callbacks to the list\n\t\t\tadd: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\t// First, we save the current length\n\t\t\t\t\tvar start = list.length;\n\t\t\t\t\t(function add( args ) {\n\t\t\t\t\t\tjQuery.each( args, function( _, arg ) {\n\t\t\t\t\t\t\tvar type = jQuery.type( arg );\n\t\t\t\t\t\t\tif ( type === \"function\" ) {\n\t\t\t\t\t\t\t\tif ( !options.unique || !self.has( arg ) ) {\n\t\t\t\t\t\t\t\t\tlist.push( arg );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if ( arg && arg.length && type !== \"string\" ) {\n\t\t\t\t\t\t\t\t// Inspect recursively\n\t\t\t\t\t\t\t\tadd( arg );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t})( arguments );\n\t\t\t\t\t// Do we need to add the callbacks to the\n\t\t\t\t\t// current firing batch?\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tfiringLength = list.length;\n\t\t\t\t\t// With memory, if we're not firing then\n\t\t\t\t\t// we should call right away\n\t\t\t\t\t} else if ( memory ) {\n\t\t\t\t\t\tfiringStart = start;\n\t\t\t\t\t\tfire( memory );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Remove a callback from the list\n\t\t\tremove: function() {\n\t\t\t\tif ( list ) {\n\t\t\t\t\tjQuery.each( arguments, function( _, arg ) {\n\t\t\t\t\t\tvar index;\n\t\t\t\t\t\twhile ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {\n\t\t\t\t\t\t\tlist.splice( index, 1 );\n\t\t\t\t\t\t\t// Handle firing indexes\n\t\t\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\t\t\tif ( index <= firingLength ) {\n\t\t\t\t\t\t\t\t\tfiringLength--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif ( index <= firingIndex ) {\n\t\t\t\t\t\t\t\t\tfiringIndex--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Check if a given callback is in the list.\n\t\t\t// If no argument is given, return whether or not list has callbacks attached.\n\t\t\thas: function( fn ) {\n\t\t\t\treturn fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );\n\t\t\t},\n\t\t\t// Remove all callbacks from the list\n\t\t\tempty: function() {\n\t\t\t\tlist = [];\n\t\t\t\tfiringLength = 0;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Have the list do nothing anymore\n\t\t\tdisable: function() {\n\t\t\t\tlist = stack = memory = undefined;\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it disabled?\n\t\t\tdisabled: function() {\n\t\t\t\treturn !list;\n\t\t\t},\n\t\t\t// Lock the list in its current state\n\t\t\tlock: function() {\n\t\t\t\tstack = undefined;\n\t\t\t\tif ( !memory ) {\n\t\t\t\t\tself.disable();\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Is it locked?\n\t\t\tlocked: function() {\n\t\t\t\treturn !stack;\n\t\t\t},\n\t\t\t// Call all callbacks with the given context and arguments\n\t\t\tfireWith: function( context, args ) {\n\t\t\t\tif ( list && ( !fired || stack ) ) {\n\t\t\t\t\targs = args || [];\n\t\t\t\t\targs = [ context, args.slice ? args.slice() : args ];\n\t\t\t\t\tif ( firing ) {\n\t\t\t\t\t\tstack.push( args );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfire( args );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// Call all the callbacks with the given arguments\n\t\t\tfire: function() {\n\t\t\t\tself.fireWith( this, arguments );\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\t// To know if the callbacks have already been called at least once\n\t\t\tfired: function() {\n\t\t\t\treturn !!fired;\n\t\t\t}\n\t\t};\n\n\treturn self;\n};\n\n\njQuery.extend({\n\n\tDeferred: function( func ) {\n\t\tvar tuples = [\n\t\t\t\t// action, add listener, listener list, final state\n\t\t\t\t[ \"resolve\", \"done\", jQuery.Callbacks(\"once memory\"), \"resolved\" ],\n\t\t\t\t[ \"reject\", \"fail\", jQuery.Callbacks(\"once memory\"), \"rejected\" ],\n\t\t\t\t[ \"notify\", \"progress\", jQuery.Callbacks(\"memory\") ]\n\t\t\t],\n\t\t\tstate = \"pending\",\n\t\t\tpromise = {\n\t\t\t\tstate: function() {\n\t\t\t\t\treturn state;\n\t\t\t\t},\n\t\t\t\talways: function() {\n\t\t\t\t\tdeferred.done( arguments ).fail( arguments );\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\t\t\t\tthen: function( /* fnDone, fnFail, fnProgress */ ) {\n\t\t\t\t\tvar fns = arguments;\n\t\t\t\t\treturn jQuery.Deferred(function( newDefer ) {\n\t\t\t\t\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\t\t\t\t\tvar fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];\n\t\t\t\t\t\t\t// deferred[ done | fail | progress ] for forwarding actions to newDefer\n\t\t\t\t\t\t\tdeferred[ tuple[1] ](function() {\n\t\t\t\t\t\t\t\tvar returned = fn && fn.apply( this, arguments );\n\t\t\t\t\t\t\t\tif ( returned && jQuery.isFunction( returned.promise ) ) {\n\t\t\t\t\t\t\t\t\treturned.promise()\n\t\t\t\t\t\t\t\t\t\t.done( newDefer.resolve )\n\t\t\t\t\t\t\t\t\t\t.fail( newDefer.reject )\n\t\t\t\t\t\t\t\t\t\t.progress( newDefer.notify );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tnewDefer[ tuple[ 0 ] + \"With\" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfns = null;\n\t\t\t\t\t}).promise();\n\t\t\t\t},\n\t\t\t\t// Get a promise for this deferred\n\t\t\t\t// If obj is provided, the promise aspect is added to the object\n\t\t\t\tpromise: function( obj ) {\n\t\t\t\t\treturn obj != null ? jQuery.extend( obj, promise ) : promise;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdeferred = {};\n\n\t\t// Keep pipe for back-compat\n\t\tpromise.pipe = promise.then;\n\n\t\t// Add list-specific methods\n\t\tjQuery.each( tuples, function( i, tuple ) {\n\t\t\tvar list = tuple[ 2 ],\n\t\t\t\tstateString = tuple[ 3 ];\n\n\t\t\t// promise[ done | fail | progress ] = list.add\n\t\t\tpromise[ tuple[1] ] = list.add;\n\n\t\t\t// Handle state\n\t\t\tif ( stateString ) {\n\t\t\t\tlist.add(function() {\n\t\t\t\t\t// state = [ resolved | rejected ]\n\t\t\t\t\tstate = stateString;\n\n\t\t\t\t// [ reject_list | resolve_list ].disable; progress_list.lock\n\t\t\t\t}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );\n\t\t\t}\n\n\t\t\t// deferred[ resolve | reject | notify ]\n\t\t\tdeferred[ tuple[0] ] = function() {\n\t\t\t\tdeferred[ tuple[0] + \"With\" ]( this === deferred ? promise : this, arguments );\n\t\t\t\treturn this;\n\t\t\t};\n\t\t\tdeferred[ tuple[0] + \"With\" ] = list.fireWith;\n\t\t});\n\n\t\t// Make the deferred a promise\n\t\tpromise.promise( deferred );\n\n\t\t// Call given func if any\n\t\tif ( func ) {\n\t\t\tfunc.call( deferred, deferred );\n\t\t}\n\n\t\t// All done!\n\t\treturn deferred;\n\t},\n\n\t// Deferred helper\n\twhen: function( subordinate /* , ..., subordinateN */ ) {\n\t\tvar i = 0,\n\t\t\tresolveValues = slice.call( arguments ),\n\t\t\tlength = resolveValues.length,\n\n\t\t\t// the count of uncompleted subordinates\n\t\t\tremaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,\n\n\t\t\t// the master Deferred. If resolveValues consist of only a single Deferred, just use that.\n\t\t\tdeferred = remaining === 1 ? subordinate : jQuery.Deferred(),\n\n\t\t\t// Update function for both resolve and progress values\n\t\t\tupdateFunc = function( i, contexts, values ) {\n\t\t\t\treturn function( value ) {\n\t\t\t\t\tcontexts[ i ] = this;\n\t\t\t\t\tvalues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;\n\t\t\t\t\tif ( values === progressValues ) {\n\t\t\t\t\t\tdeferred.notifyWith( contexts, values );\n\t\t\t\t\t} else if ( !( --remaining ) ) {\n\t\t\t\t\t\tdeferred.resolveWith( contexts, values );\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t},\n\n\t\t\tprogressValues, progressContexts, resolveContexts;\n\n\t\t// Add listeners to Deferred subordinates; treat others as resolved\n\t\tif ( length > 1 ) {\n\t\t\tprogressValues = new Array( length );\n\t\t\tprogressContexts = new Array( length );\n\t\t\tresolveContexts = new Array( length );\n\t\t\tfor ( ; i < length; i++ ) {\n\t\t\t\tif ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {\n\t\t\t\t\tresolveValues[ i ].promise()\n\t\t\t\t\t\t.done( updateFunc( i, resolveContexts, resolveValues ) )\n\t\t\t\t\t\t.fail( deferred.reject )\n\t\t\t\t\t\t.progress( updateFunc( i, progressContexts, progressValues ) );\n\t\t\t\t} else {\n\t\t\t\t\t--remaining;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If we're not waiting on anything, resolve the master\n\t\tif ( !remaining ) {\n\t\t\tdeferred.resolveWith( resolveContexts, resolveValues );\n\t\t}\n\n\t\treturn deferred.promise();\n\t}\n});\n\n\n// The deferred used on DOM ready\nvar readyList;\n\njQuery.fn.ready = function( fn ) {\n\t// Add the callback\n\tjQuery.ready.promise().done( fn );\n\n\treturn this;\n};\n\njQuery.extend({\n\t// Is the DOM ready to be used? Set to true once it occurs.\n\tisReady: false,\n\n\t// A counter to track how many items to wait for before\n\t// the ready event fires. See #6781\n\treadyWait: 1,\n\n\t// Hold (or release) the ready event\n\tholdReady: function( hold ) {\n\t\tif ( hold ) {\n\t\t\tjQuery.readyWait++;\n\t\t} else {\n\t\t\tjQuery.ready( true );\n\t\t}\n\t},\n\n\t// Handle when the DOM is ready\n\tready: function( wait ) {\n\n\t\t// Abort if there are pending holds or we're already ready\n\t\tif ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Remember that the DOM is ready\n\t\tjQuery.isReady = true;\n\n\t\t// If a normal DOM Ready event fired, decrement, and wait if need be\n\t\tif ( wait !== true && --jQuery.readyWait > 0 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If there are functions bound, to execute\n\t\treadyList.resolveWith( document, [ jQuery ] );\n\n\t\t// Trigger any bound ready events\n\t\tif ( jQuery.fn.triggerHandler ) {\n\t\t\tjQuery( document ).triggerHandler( \"ready\" );\n\t\t\tjQuery( document ).off( \"ready\" );\n\t\t}\n\t}\n});\n\n/**\n * The ready event handler and self cleanup method\n */\nfunction completed() {\n\tdocument.removeEventListener( \"DOMContentLoaded\", completed, false );\n\twindow.removeEventListener( \"load\", completed, false );\n\tjQuery.ready();\n}\n\njQuery.ready.promise = function( obj ) {\n\tif ( !readyList ) {\n\n\t\treadyList = jQuery.Deferred();\n\n\t\t// Catch cases where $(document).ready() is called after the browser event has already occurred.\n\t\t// We once tried to use readyState \"interactive\" here, but it caused issues like the one\n\t\t// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15\n\t\tif ( document.readyState === \"complete\" ) {\n\t\t\t// Handle it asynchronously to allow scripts the opportunity to delay ready\n\t\t\tsetTimeout( jQuery.ready );\n\n\t\t} else {\n\n\t\t\t// Use the handy event callback\n\t\t\tdocument.addEventListener( \"DOMContentLoaded\", completed, false );\n\n\t\t\t// A fallback to window.onload, that will always work\n\t\t\twindow.addEventListener( \"load\", completed, false );\n\t\t}\n\t}\n\treturn readyList.promise( obj );\n};\n\n// Kick off the DOM ready check even if the user does not\njQuery.ready.promise();\n\n\n\n\n// Multifunctional method to get and set values of a collection\n// The value/s can optionally be executed if it's a function\nvar access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {\n\tvar i = 0,\n\t\tlen = elems.length,\n\t\tbulk = key == null;\n\n\t// Sets many values\n\tif ( jQuery.type( key ) === \"object\" ) {\n\t\tchainable = true;\n\t\tfor ( i in key ) {\n\t\t\tjQuery.access( elems, fn, i, key[i], true, emptyGet, raw );\n\t\t}\n\n\t// Sets one value\n\t} else if ( value !== undefined ) {\n\t\tchainable = true;\n\n\t\tif ( !jQuery.isFunction( value ) ) {\n\t\t\traw = true;\n\t\t}\n\n\t\tif ( bulk ) {\n\t\t\t// Bulk operations run against the entire set\n\t\t\tif ( raw ) {\n\t\t\t\tfn.call( elems, value );\n\t\t\t\tfn = null;\n\n\t\t\t// ...except when executing function values\n\t\t\t} else {\n\t\t\t\tbulk = fn;\n\t\t\t\tfn = function( elem, key, value ) {\n\t\t\t\t\treturn bulk.call( jQuery( elem ), value );\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif ( fn ) {\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\tfn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn chainable ?\n\t\telems :\n\n\t\t// Gets\n\t\tbulk ?\n\t\t\tfn.call( elems ) :\n\t\t\tlen ? fn( elems[0], key ) : emptyGet;\n};\n\n\n/**\n * Determines whether an object can have data\n */\njQuery.acceptData = function( owner ) {\n\t// Accepts only:\n\t//  - Node\n\t//    - Node.ELEMENT_NODE\n\t//    - Node.DOCUMENT_NODE\n\t//  - Object\n\t//    - Any\n\t/* jshint -W018 */\n\treturn owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );\n};\n\n\nfunction Data() {\n\t// Support: Android<4,\n\t// Old WebKit does not have Object.preventExtensions/freeze method,\n\t// return new empty object instead with no [[set]] accessor\n\tObject.defineProperty( this.cache = {}, 0, {\n\t\tget: function() {\n\t\t\treturn {};\n\t\t}\n\t});\n\n\tthis.expando = jQuery.expando + Data.uid++;\n}\n\nData.uid = 1;\nData.accepts = jQuery.acceptData;\n\nData.prototype = {\n\tkey: function( owner ) {\n\t\t// We can accept data for non-element nodes in modern browsers,\n\t\t// but we should not, see #8335.\n\t\t// Always return the key for a frozen object.\n\t\tif ( !Data.accepts( owner ) ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tvar descriptor = {},\n\t\t\t// Check if the owner object already has a cache key\n\t\t\tunlock = owner[ this.expando ];\n\n\t\t// If not, create one\n\t\tif ( !unlock ) {\n\t\t\tunlock = Data.uid++;\n\n\t\t\t// Secure it in a non-enumerable, non-writable property\n\t\t\ttry {\n\t\t\t\tdescriptor[ this.expando ] = { value: unlock };\n\t\t\t\tObject.defineProperties( owner, descriptor );\n\n\t\t\t// Support: Android<4\n\t\t\t// Fallback to a less secure definition\n\t\t\t} catch ( e ) {\n\t\t\t\tdescriptor[ this.expando ] = unlock;\n\t\t\t\tjQuery.extend( owner, descriptor );\n\t\t\t}\n\t\t}\n\n\t\t// Ensure the cache object\n\t\tif ( !this.cache[ unlock ] ) {\n\t\t\tthis.cache[ unlock ] = {};\n\t\t}\n\n\t\treturn unlock;\n\t},\n\tset: function( owner, data, value ) {\n\t\tvar prop,\n\t\t\t// There may be an unlock assigned to this node,\n\t\t\t// if there is no entry for this \"owner\", create one inline\n\t\t\t// and set the unlock as though an owner entry had always existed\n\t\t\tunlock = this.key( owner ),\n\t\t\tcache = this.cache[ unlock ];\n\n\t\t// Handle: [ owner, key, value ] args\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tcache[ data ] = value;\n\n\t\t// Handle: [ owner, { properties } ] args\n\t\t} else {\n\t\t\t// Fresh assignments by object are shallow copied\n\t\t\tif ( jQuery.isEmptyObject( cache ) ) {\n\t\t\t\tjQuery.extend( this.cache[ unlock ], data );\n\t\t\t// Otherwise, copy the properties one-by-one to the cache object\n\t\t\t} else {\n\t\t\t\tfor ( prop in data ) {\n\t\t\t\t\tcache[ prop ] = data[ prop ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn cache;\n\t},\n\tget: function( owner, key ) {\n\t\t// Either a valid cache is found, or will be created.\n\t\t// New caches will be created and the unlock returned,\n\t\t// allowing direct access to the newly created\n\t\t// empty data object. A valid owner object must be provided.\n\t\tvar cache = this.cache[ this.key( owner ) ];\n\n\t\treturn key === undefined ?\n\t\t\tcache : cache[ key ];\n\t},\n\taccess: function( owner, key, value ) {\n\t\tvar stored;\n\t\t// In cases where either:\n\t\t//\n\t\t//   1. No key was specified\n\t\t//   2. A string key was specified, but no value provided\n\t\t//\n\t\t// Take the \"read\" path and allow the get method to determine\n\t\t// which value to return, respectively either:\n\t\t//\n\t\t//   1. The entire cache object\n\t\t//   2. The data stored at the key\n\t\t//\n\t\tif ( key === undefined ||\n\t\t\t\t((key && typeof key === \"string\") && value === undefined) ) {\n\n\t\t\tstored = this.get( owner, key );\n\n\t\t\treturn stored !== undefined ?\n\t\t\t\tstored : this.get( owner, jQuery.camelCase(key) );\n\t\t}\n\n\t\t// [*]When the key is not a string, or both a key and value\n\t\t// are specified, set or extend (existing objects) with either:\n\t\t//\n\t\t//   1. An object of properties\n\t\t//   2. A key and value\n\t\t//\n\t\tthis.set( owner, key, value );\n\n\t\t// Since the \"set\" path can have two possible entry points\n\t\t// return the expected data based on which path was taken[*]\n\t\treturn value !== undefined ? value : key;\n\t},\n\tremove: function( owner, key ) {\n\t\tvar i, name, camel,\n\t\t\tunlock = this.key( owner ),\n\t\t\tcache = this.cache[ unlock ];\n\n\t\tif ( key === undefined ) {\n\t\t\tthis.cache[ unlock ] = {};\n\n\t\t} else {\n\t\t\t// Support array or space separated string of keys\n\t\t\tif ( jQuery.isArray( key ) ) {\n\t\t\t\t// If \"name\" is an array of keys...\n\t\t\t\t// When data is initially created, via (\"key\", \"val\") signature,\n\t\t\t\t// keys will be converted to camelCase.\n\t\t\t\t// Since there is no way to tell _how_ a key was added, remove\n\t\t\t\t// both plain key and camelCase key. #12786\n\t\t\t\t// This will only penalize the array argument path.\n\t\t\t\tname = key.concat( key.map( jQuery.camelCase ) );\n\t\t\t} else {\n\t\t\t\tcamel = jQuery.camelCase( key );\n\t\t\t\t// Try the string as a key before any manipulation\n\t\t\t\tif ( key in cache ) {\n\t\t\t\t\tname = [ key, camel ];\n\t\t\t\t} else {\n\t\t\t\t\t// If a key with the spaces exists, use it.\n\t\t\t\t\t// Otherwise, create an array by matching non-whitespace\n\t\t\t\t\tname = camel;\n\t\t\t\t\tname = name in cache ?\n\t\t\t\t\t\t[ name ] : ( name.match( rnotwhite ) || [] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ti = name.length;\n\t\t\twhile ( i-- ) {\n\t\t\t\tdelete cache[ name[ i ] ];\n\t\t\t}\n\t\t}\n\t},\n\thasData: function( owner ) {\n\t\treturn !jQuery.isEmptyObject(\n\t\t\tthis.cache[ owner[ this.expando ] ] || {}\n\t\t);\n\t},\n\tdiscard: function( owner ) {\n\t\tif ( owner[ this.expando ] ) {\n\t\t\tdelete this.cache[ owner[ this.expando ] ];\n\t\t}\n\t}\n};\nvar data_priv = new Data();\n\nvar data_user = new Data();\n\n\n\n//\tImplementation Summary\n//\n//\t1. Enforce API surface and semantic compatibility with 1.9.x branch\n//\t2. Improve the module's maintainability by reducing the storage\n//\t\tpaths to a single mechanism.\n//\t3. Use the same single mechanism to support \"private\" and \"user\" data.\n//\t4. _Never_ expose \"private\" data to user code (TODO: Drop _data, _removeData)\n//\t5. Avoid exposing implementation details on user objects (eg. expando properties)\n//\t6. Provide a clear path for implementation upgrade to WeakMap in 2014\n\nvar rbrace = /^(?:\\{[\\w\\W]*\\}|\\[[\\w\\W]*\\])$/,\n\trmultiDash = /([A-Z])/g;\n\nfunction dataAttr( elem, key, data ) {\n\tvar name;\n\n\t// If nothing was found internally, try to fetch any\n\t// data from the HTML5 data-* attribute\n\tif ( data === undefined && elem.nodeType === 1 ) {\n\t\tname = \"data-\" + key.replace( rmultiDash, \"-$1\" ).toLowerCase();\n\t\tdata = elem.getAttribute( name );\n\n\t\tif ( typeof data === \"string\" ) {\n\t\t\ttry {\n\t\t\t\tdata = data === \"true\" ? true :\n\t\t\t\t\tdata === \"false\" ? false :\n\t\t\t\t\tdata === \"null\" ? null :\n\t\t\t\t\t// Only convert to a number if it doesn't change the string\n\t\t\t\t\t+data + \"\" === data ? +data :\n\t\t\t\t\trbrace.test( data ) ? jQuery.parseJSON( data ) :\n\t\t\t\t\tdata;\n\t\t\t} catch( e ) {}\n\n\t\t\t// Make sure we set the data so it isn't changed later\n\t\t\tdata_user.set( elem, key, data );\n\t\t} else {\n\t\t\tdata = undefined;\n\t\t}\n\t}\n\treturn data;\n}\n\njQuery.extend({\n\thasData: function( elem ) {\n\t\treturn data_user.hasData( elem ) || data_priv.hasData( elem );\n\t},\n\n\tdata: function( elem, name, data ) {\n\t\treturn data_user.access( elem, name, data );\n\t},\n\n\tremoveData: function( elem, name ) {\n\t\tdata_user.remove( elem, name );\n\t},\n\n\t// TODO: Now that all calls to _data and _removeData have been replaced\n\t// with direct calls to data_priv methods, these can be deprecated.\n\t_data: function( elem, name, data ) {\n\t\treturn data_priv.access( elem, name, data );\n\t},\n\n\t_removeData: function( elem, name ) {\n\t\tdata_priv.remove( elem, name );\n\t}\n});\n\njQuery.fn.extend({\n\tdata: function( key, value ) {\n\t\tvar i, name, data,\n\t\t\telem = this[ 0 ],\n\t\t\tattrs = elem && elem.attributes;\n\n\t\t// Gets all values\n\t\tif ( key === undefined ) {\n\t\t\tif ( this.length ) {\n\t\t\t\tdata = data_user.get( elem );\n\n\t\t\t\tif ( elem.nodeType === 1 && !data_priv.get( elem, \"hasDataAttrs\" ) ) {\n\t\t\t\t\ti = attrs.length;\n\t\t\t\t\twhile ( i-- ) {\n\n\t\t\t\t\t\t// Support: IE11+\n\t\t\t\t\t\t// The attrs elements can be null (#14894)\n\t\t\t\t\t\tif ( attrs[ i ] ) {\n\t\t\t\t\t\t\tname = attrs[ i ].name;\n\t\t\t\t\t\t\tif ( name.indexOf( \"data-\" ) === 0 ) {\n\t\t\t\t\t\t\t\tname = jQuery.camelCase( name.slice(5) );\n\t\t\t\t\t\t\t\tdataAttr( elem, name, data[ name ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdata_priv.set( elem, \"hasDataAttrs\", true );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn data;\n\t\t}\n\n\t\t// Sets multiple values\n\t\tif ( typeof key === \"object\" ) {\n\t\t\treturn this.each(function() {\n\t\t\t\tdata_user.set( this, key );\n\t\t\t});\n\t\t}\n\n\t\treturn access( this, function( value ) {\n\t\t\tvar data,\n\t\t\t\tcamelKey = jQuery.camelCase( key );\n\n\t\t\t// The calling jQuery object (element matches) is not empty\n\t\t\t// (and therefore has an element appears at this[ 0 ]) and the\n\t\t\t// `value` parameter was not undefined. An empty jQuery object\n\t\t\t// will result in `undefined` for elem = this[ 0 ] which will\n\t\t\t// throw an exception if an attempt to read a data cache is made.\n\t\t\tif ( elem && value === undefined ) {\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key as-is\n\t\t\t\tdata = data_user.get( elem, key );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to get data from the cache\n\t\t\t\t// with the key camelized\n\t\t\t\tdata = data_user.get( elem, camelKey );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// Attempt to \"discover\" the data in\n\t\t\t\t// HTML5 custom data-* attrs\n\t\t\t\tdata = dataAttr( elem, camelKey, undefined );\n\t\t\t\tif ( data !== undefined ) {\n\t\t\t\t\treturn data;\n\t\t\t\t}\n\n\t\t\t\t// We tried really hard, but the data doesn't exist.\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Set the data...\n\t\t\tthis.each(function() {\n\t\t\t\t// First, attempt to store a copy or reference of any\n\t\t\t\t// data that might've been store with a camelCased key.\n\t\t\t\tvar data = data_user.get( this, camelKey );\n\n\t\t\t\t// For HTML5 data-* attribute interop, we have to\n\t\t\t\t// store property names with dashes in a camelCase form.\n\t\t\t\t// This might not apply to all properties...*\n\t\t\t\tdata_user.set( this, camelKey, value );\n\n\t\t\t\t// *... In the case of properties that might _actually_\n\t\t\t\t// have dashes, we need to also store a copy of that\n\t\t\t\t// unchanged property.\n\t\t\t\tif ( key.indexOf(\"-\") !== -1 && data !== undefined ) {\n\t\t\t\t\tdata_user.set( this, key, value );\n\t\t\t\t}\n\t\t\t});\n\t\t}, null, value, arguments.length > 1, null, true );\n\t},\n\n\tremoveData: function( key ) {\n\t\treturn this.each(function() {\n\t\t\tdata_user.remove( this, key );\n\t\t});\n\t}\n});\n\n\njQuery.extend({\n\tqueue: function( elem, type, data ) {\n\t\tvar queue;\n\n\t\tif ( elem ) {\n\t\t\ttype = ( type || \"fx\" ) + \"queue\";\n\t\t\tqueue = data_priv.get( elem, type );\n\n\t\t\t// Speed up dequeue by getting out quickly if this is just a lookup\n\t\t\tif ( data ) {\n\t\t\t\tif ( !queue || jQuery.isArray( data ) ) {\n\t\t\t\t\tqueue = data_priv.access( elem, type, jQuery.makeArray(data) );\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push( data );\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn queue || [];\n\t\t}\n\t},\n\n\tdequeue: function( elem, type ) {\n\t\ttype = type || \"fx\";\n\n\t\tvar queue = jQuery.queue( elem, type ),\n\t\t\tstartLength = queue.length,\n\t\t\tfn = queue.shift(),\n\t\t\thooks = jQuery._queueHooks( elem, type ),\n\t\t\tnext = function() {\n\t\t\t\tjQuery.dequeue( elem, type );\n\t\t\t};\n\n\t\t// If the fx queue is dequeued, always remove the progress sentinel\n\t\tif ( fn === \"inprogress\" ) {\n\t\t\tfn = queue.shift();\n\t\t\tstartLength--;\n\t\t}\n\n\t\tif ( fn ) {\n\n\t\t\t// Add a progress sentinel to prevent the fx queue from being\n\t\t\t// automatically dequeued\n\t\t\tif ( type === \"fx\" ) {\n\t\t\t\tqueue.unshift( \"inprogress\" );\n\t\t\t}\n\n\t\t\t// Clear up the last queue stop function\n\t\t\tdelete hooks.stop;\n\t\t\tfn.call( elem, next, hooks );\n\t\t}\n\n\t\tif ( !startLength && hooks ) {\n\t\t\thooks.empty.fire();\n\t\t}\n\t},\n\n\t// Not public - generate a queueHooks object, or return the current one\n\t_queueHooks: function( elem, type ) {\n\t\tvar key = type + \"queueHooks\";\n\t\treturn data_priv.get( elem, key ) || data_priv.access( elem, key, {\n\t\t\tempty: jQuery.Callbacks(\"once memory\").add(function() {\n\t\t\t\tdata_priv.remove( elem, [ type + \"queue\", key ] );\n\t\t\t})\n\t\t});\n\t}\n});\n\njQuery.fn.extend({\n\tqueue: function( type, data ) {\n\t\tvar setter = 2;\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tdata = type;\n\t\t\ttype = \"fx\";\n\t\t\tsetter--;\n\t\t}\n\n\t\tif ( arguments.length < setter ) {\n\t\t\treturn jQuery.queue( this[0], type );\n\t\t}\n\n\t\treturn data === undefined ?\n\t\t\tthis :\n\t\t\tthis.each(function() {\n\t\t\t\tvar queue = jQuery.queue( this, type, data );\n\n\t\t\t\t// Ensure a hooks for this queue\n\t\t\t\tjQuery._queueHooks( this, type );\n\n\t\t\t\tif ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n\t\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t\t}\n\t\t\t});\n\t},\n\tdequeue: function( type ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.dequeue( this, type );\n\t\t});\n\t},\n\tclearQueue: function( type ) {\n\t\treturn this.queue( type || \"fx\", [] );\n\t},\n\t// Get a promise resolved when queues of a certain type\n\t// are emptied (fx is the type by default)\n\tpromise: function( type, obj ) {\n\t\tvar tmp,\n\t\t\tcount = 1,\n\t\t\tdefer = jQuery.Deferred(),\n\t\t\telements = this,\n\t\t\ti = this.length,\n\t\t\tresolve = function() {\n\t\t\t\tif ( !( --count ) ) {\n\t\t\t\t\tdefer.resolveWith( elements, [ elements ] );\n\t\t\t\t}\n\t\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tobj = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\ttype = type || \"fx\";\n\n\t\twhile ( i-- ) {\n\t\t\ttmp = data_priv.get( elements[ i ], type + \"queueHooks\" );\n\t\t\tif ( tmp && tmp.empty ) {\n\t\t\t\tcount++;\n\t\t\t\ttmp.empty.add( resolve );\n\t\t\t}\n\t\t}\n\t\tresolve();\n\t\treturn defer.promise( obj );\n\t}\n});\nvar pnum = (/[+-]?(?:\\d*\\.|)\\d+(?:[eE][+-]?\\d+|)/).source;\n\nvar cssExpand = [ \"Top\", \"Right\", \"Bottom\", \"Left\" ];\n\nvar isHidden = function( elem, el ) {\n\t\t// isHidden might be called from jQuery#filter function;\n\t\t// in that case, element will be second argument\n\t\telem = el || elem;\n\t\treturn jQuery.css( elem, \"display\" ) === \"none\" || !jQuery.contains( elem.ownerDocument, elem );\n\t};\n\nvar rcheckableType = (/^(?:checkbox|radio)$/i);\n\n\n\n(function() {\n\tvar fragment = document.createDocumentFragment(),\n\t\tdiv = fragment.appendChild( document.createElement( \"div\" ) ),\n\t\tinput = document.createElement( \"input\" );\n\n\t// Support: Safari<=5.1\n\t// Check state lost if the name is set (#11217)\n\t// Support: Windows Web Apps (WWA)\n\t// `name` and `type` must use .setAttribute for WWA (#14901)\n\tinput.setAttribute( \"type\", \"radio\" );\n\tinput.setAttribute( \"checked\", \"checked\" );\n\tinput.setAttribute( \"name\", \"t\" );\n\n\tdiv.appendChild( input );\n\n\t// Support: Safari<=5.1, Android<4.2\n\t// Older WebKit doesn't clone checked state correctly in fragments\n\tsupport.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;\n\n\t// Support: IE<=11+\n\t// Make sure textarea (and checkbox) defaultValue is properly cloned\n\tdiv.innerHTML = \"<textarea>x</textarea>\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n})();\nvar strundefined = typeof undefined;\n\n\n\nsupport.focusinBubbles = \"onfocusin\" in window;\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,\n\trfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)$/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = data_priv.get( elem );\n\n\t\t// Don't attach events to noData or text/comment nodes (but allow plain objects)\n\t\tif ( !elemData ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !(events = elemData.events) ) {\n\t\t\tevents = elemData.events = {};\n\t\t}\n\t\tif ( !(eventHandle = elemData.handle) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend({\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join(\".\")\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !(handlers = events[ type ]) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle, false );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = data_priv.hasData( elem ) && data_priv.get( elem );\n\n\t\tif ( !elemData || !(events = elemData.events) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnotwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[t] ) || [];\n\t\t\ttype = origType = tmp[1];\n\t\t\tnamespaces = ( tmp[2] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[2] && new RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector || selector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdelete elemData.handle;\n\t\t\tdata_priv.remove( elem, \"events\" );\n\t\t}\n\t},\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split(\".\") : [];\n\n\t\tcur = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf(\".\") >= 0 ) {\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split(\".\");\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf(\":\") < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join(\".\");\n\t\tevent.namespace_re = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join(\"\\\\.(?:.*\\\\.|)\") + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === (elem.ownerDocument || document) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {\n\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = ( data_priv.get( cur, \"events\" ) || {} )[ event.type ] && data_priv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && jQuery.acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&\n\t\t\t\tjQuery.acceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\t\t\t\t\telem[ type ]();\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\tdispatch: function( event ) {\n\n\t\t// Make a writable jQuery.Event from the native event object\n\t\tevent = jQuery.event.fix( event );\n\n\t\tvar i, j, ret, matched, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\targs = slice.call( arguments ),\n\t\t\thandlers = ( data_priv.get( this, \"events\" ) || {} )[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[0] = event;\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// Triggered event must either 1) have no namespace, or 2) have namespace(s)\n\t\t\t\t// a subset or equal to those in the bound event (both can have no namespace).\n\t\t\t\tif ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )\n\t\t\t\t\t\t\t.apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( (event.result = ret) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, matches, sel, handleObj,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\t// Black-hole SVG <use> instance trees (#13180)\n\t\t// Avoid non-left-click bubbling in Firefox (#3861)\n\t\tif ( delegateCount && cur.nodeType && (!event.button || event.type !== \"click\") ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.disabled !== true || event.type !== \"click\" ) {\n\t\t\t\t\tmatches = [];\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matches[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatches[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) >= 0 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matches[ sel ] ) {\n\t\t\t\t\t\t\tmatches.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matches.length ) {\n\t\t\t\t\t\thandlerQueue.push({ elem: cur, handlers: matches });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\t// Includes some event props shared by KeyEvent and MouseEvent\n\tprops: \"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which\".split(\" \"),\n\n\tfixHooks: {},\n\n\tkeyHooks: {\n\t\tprops: \"char charCode key keyCode\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\n\t\t\t// Add which for key events\n\t\t\tif ( event.which == null ) {\n\t\t\t\tevent.which = original.charCode != null ? original.charCode : original.keyCode;\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tmouseHooks: {\n\t\tprops: \"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement\".split(\" \"),\n\t\tfilter: function( event, original ) {\n\t\t\tvar eventDoc, doc, body,\n\t\t\t\tbutton = original.button;\n\n\t\t\t// Calculate pageX/Y if missing and clientX/Y available\n\t\t\tif ( event.pageX == null && original.clientX != null ) {\n\t\t\t\teventDoc = event.target.ownerDocument || document;\n\t\t\t\tdoc = eventDoc.documentElement;\n\t\t\t\tbody = eventDoc.body;\n\n\t\t\t\tevent.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );\n\t\t\t\tevent.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );\n\t\t\t}\n\n\t\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\t\t// Note: button is not normalized, so don't use it\n\t\t\tif ( !event.which && button !== undefined ) {\n\t\t\t\tevent.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );\n\t\t\t}\n\n\t\t\treturn event;\n\t\t}\n\t},\n\n\tfix: function( event ) {\n\t\tif ( event[ jQuery.expando ] ) {\n\t\t\treturn event;\n\t\t}\n\n\t\t// Create a writable copy of the event object and normalize some properties\n\t\tvar i, prop, copy,\n\t\t\ttype = event.type,\n\t\t\toriginalEvent = event,\n\t\t\tfixHook = this.fixHooks[ type ];\n\n\t\tif ( !fixHook ) {\n\t\t\tthis.fixHooks[ type ] = fixHook =\n\t\t\t\trmouseEvent.test( type ) ? this.mouseHooks :\n\t\t\t\trkeyEvent.test( type ) ? this.keyHooks :\n\t\t\t\t{};\n\t\t}\n\t\tcopy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;\n\n\t\tevent = new jQuery.Event( originalEvent );\n\n\t\ti = copy.length;\n\t\twhile ( i-- ) {\n\t\t\tprop = copy[ i ];\n\t\t\tevent[ prop ] = originalEvent[ prop ];\n\t\t}\n\n\t\t// Support: Cordova 2.5 (WebKit) (#13255)\n\t\t// All events should have a target; Cordova deviceready doesn't\n\t\tif ( !event.target ) {\n\t\t\tevent.target = document;\n\t\t}\n\n\t\t// Support: Safari 6.0+, Chrome<28\n\t\t// Target should not be a text node (#504, #13143)\n\t\tif ( event.target.nodeType === 3 ) {\n\t\t\tevent.target = event.target.parentNode;\n\t\t}\n\n\t\treturn fixHook.filter ? fixHook.filter( event, originalEvent ) : event;\n\t},\n\n\tspecial: {\n\t\tload: {\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tfocus: {\n\t\t\t// Fire native event if possible so blur/focus sequence is correct\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this !== safeActiveElement() && this.focus ) {\n\t\t\t\t\tthis.focus();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusin\"\n\t\t},\n\t\tblur: {\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this === safeActiveElement() && this.blur ) {\n\t\t\t\t\tthis.blur();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t\tdelegateType: \"focusout\"\n\t\t},\n\t\tclick: {\n\t\t\t// For checkbox, fire native event so checked state will be right\n\t\t\ttrigger: function() {\n\t\t\t\tif ( this.type === \"checkbox\" && this.click && jQuery.nodeName( this, \"input\" ) ) {\n\t\t\t\t\tthis.click();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, don't fire native .click() on links\n\t\t\t_default: function( event ) {\n\t\t\t\treturn jQuery.nodeName( event.target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tsimulate: function( type, elem, event, bubble ) {\n\t\t// Piggyback on a donor event to simulate a different one.\n\t\t// Fake originalEvent to avoid donor's stopPropagation, but if the\n\t\t// simulated event prevents default then we do the same on the donor.\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true,\n\t\t\t\toriginalEvent: {}\n\t\t\t}\n\t\t);\n\t\tif ( bubble ) {\n\t\t\tjQuery.event.trigger( e, null, elem );\n\t\t} else {\n\t\t\tjQuery.event.dispatch.call( elem, e );\n\t\t}\n\t\tif ( e.isDefaultPrevented() ) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n};\n\njQuery.removeEvent = function( elem, type, handle ) {\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle, false );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\t// Allow instantiation without the 'new' keyword\n\tif ( !(this instanceof jQuery.Event) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\t\t\t\t// Support: Android<4.0\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || jQuery.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && e.preventDefault ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && e.stopPropagation ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && e.stopImmediatePropagation ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// Support: Chrome 15+\njQuery.each({\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mousenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || (related !== target && !jQuery.contains( target, related )) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n});\n\n// Support: Firefox, Chrome, Safari\n// Create \"bubbling\" focus and blur events\nif ( !support.focusinBubbles ) {\n\tjQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );\n\t\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = data_priv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdata_priv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this,\n\t\t\t\t\tattaches = data_priv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdata_priv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdata_priv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t});\n}\n\njQuery.fn.extend({\n\n\ton: function( types, selector, data, fn, /*INTERNAL*/ one ) {\n\t\tvar origFn, type;\n\n\t\t// Types can be a map of types/handlers\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-Object, selector, data )\n\t\t\tif ( typeof selector !== \"string\" ) {\n\t\t\t\t// ( types-Object, data )\n\t\t\t\tdata = data || selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.on( type, selector, data, types[ type ], one );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( data == null && fn == null ) {\n\t\t\t// ( types, fn )\n\t\t\tfn = selector;\n\t\t\tdata = selector = undefined;\n\t\t} else if ( fn == null ) {\n\t\t\tif ( typeof selector === \"string\" ) {\n\t\t\t\t// ( types, selector, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = undefined;\n\t\t\t} else {\n\t\t\t\t// ( types, data, fn )\n\t\t\t\tfn = data;\n\t\t\t\tdata = selector;\n\t\t\t\tselector = undefined;\n\t\t\t}\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t} else if ( !fn ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tif ( one === 1 ) {\n\t\t\torigFn = fn;\n\t\t\tfn = function( event ) {\n\t\t\t\t// Can use an empty set, since event contains the info\n\t\t\t\tjQuery().off( event );\n\t\t\t\treturn origFn.apply( this, arguments );\n\t\t\t};\n\t\t\t// Use same guid so caller can remove using origFn\n\t\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.add( this, types, fn, data, selector );\n\t\t});\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn this.on( types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\t\t\t// ( event )  dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ? handleObj.origType + \".\" + handleObj.namespace : handleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t});\n\t},\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t});\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[0];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n});\n\n\nvar\n\trxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/gi,\n\trtagName = /<([\\w:]+)/,\n\trhtml = /<|&#?\\w+;/,\n\trnoInnerhtml = /<(?:script|style|link)/i,\n\t// checked=\"checked\" or checked\n\trchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n\trscriptType = /^$|\\/(?:java|ecma)script/i,\n\trscriptTypeMasked = /^true\\/(.*)/,\n\trcleanScript = /^\\s*<!(?:\\[CDATA\\[|--)|(?:\\]\\]|--)>\\s*$/g,\n\n\t// We have to close these tags to support XHTML (#13200)\n\twrapMap = {\n\n\t\t// Support: IE9\n\t\toption: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n\n\t\tthead: [ 1, \"<table>\", \"</table>\" ],\n\t\tcol: [ 2, \"<table><colgroup>\", \"</colgroup></table>\" ],\n\t\ttr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n\t\ttd: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n\n\t\t_default: [ 0, \"\", \"\" ]\n\t};\n\n// Support: IE9\nwrapMap.optgroup = wrapMap.option;\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// Support: 1.x compatibility\n// Manipulating tables requires a tbody\nfunction manipulationTarget( elem, content ) {\n\treturn jQuery.nodeName( elem, \"table\" ) &&\n\t\tjQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ?\n\n\t\telem.getElementsByTagName(\"tbody\")[0] ||\n\t\t\telem.appendChild( elem.ownerDocument.createElement(\"tbody\") ) :\n\t\telem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = (elem.getAttribute(\"type\") !== null) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tvar match = rscriptTypeMasked.exec( elem.type );\n\n\tif ( match ) {\n\t\telem.type = match[ 1 ];\n\t} else {\n\t\telem.removeAttribute(\"type\");\n\t}\n\n\treturn elem;\n}\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdata_priv.set(\n\t\t\telems[ i ], \"globalEval\", !refElements || data_priv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( data_priv.hasData( src ) ) {\n\t\tpdataOld = data_priv.access( src );\n\t\tpdataCur = data_priv.set( dest, pdataOld );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdelete pdataCur.handle;\n\t\t\tpdataCur.events = {};\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( data_user.hasData( src ) ) {\n\t\tudataOld = data_user.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdata_user.set( dest, udataCur );\n\t}\n}\n\nfunction getAll( context, tag ) {\n\tvar ret = context.getElementsByTagName ? context.getElementsByTagName( tag || \"*\" ) :\n\t\t\tcontext.querySelectorAll ? context.querySelectorAll( tag || \"*\" ) :\n\t\t\t[];\n\n\treturn tag === undefined || tag && jQuery.nodeName( context, tag ) ?\n\t\tjQuery.merge( [ context ], ret ) :\n\t\tret;\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\njQuery.extend({\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tbuildFragment: function( elems, context, scripts, selection ) {\n\t\tvar elem, tmp, tag, wrap, contains, j,\n\t\t\tfragment = context.createDocumentFragment(),\n\t\t\tnodes = [],\n\t\t\ti = 0,\n\t\t\tl = elems.length;\n\n\t\tfor ( ; i < l; i++ ) {\n\t\t\telem = elems[ i ];\n\n\t\t\tif ( elem || elem === 0 ) {\n\n\t\t\t\t// Add nodes directly\n\t\t\t\tif ( jQuery.type( elem ) === \"object\" ) {\n\t\t\t\t\t// Support: QtWebKit, PhantomJS\n\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t\t// Convert non-html into a text node\n\t\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t\t// Convert html into DOM nodes\n\t\t\t\t} else {\n\t\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement(\"div\") );\n\n\t\t\t\t\t// Deserialize a standard representation\n\t\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\t\ttmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, \"<$1></$2>\" ) + wrap[ 2 ];\n\n\t\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\t\tj = wrap[ 0 ];\n\t\t\t\t\twhile ( j-- ) {\n\t\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: QtWebKit, PhantomJS\n\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t\t// Remember the top-level container\n\t\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\t\ttmp.textContent = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Remove wrapper from fragment\n\t\tfragment.textContent = \"\";\n\n\t\ti = 0;\n\t\twhile ( (elem = nodes[ i++ ]) ) {\n\n\t\t\t// #4087 - If origin and destination elements are the same, and this is\n\t\t\t// that element, do not do anything\n\t\t\tif ( selection && jQuery.inArray( elem, selection ) !== -1 ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcontains = jQuery.contains( elem.ownerDocument, elem );\n\n\t\t\t// Append to fragment\n\t\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t\t// Preserve script evaluation history\n\t\t\tif ( contains ) {\n\t\t\t\tsetGlobalEval( tmp );\n\t\t\t}\n\n\t\t\t// Capture executables\n\t\t\tif ( scripts ) {\n\t\t\t\tj = 0;\n\t\t\t\twhile ( (elem = tmp[ j++ ]) ) {\n\t\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\t\tscripts.push( elem );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn fragment;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type, key,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = elems[ i ]) !== undefined; i++ ) {\n\t\t\tif ( jQuery.acceptData( elem ) ) {\n\t\t\t\tkey = elem[ data_priv.expando ];\n\n\t\t\t\tif ( key && (data = data_priv.cache[ key ]) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( data_priv.cache[ key ] ) {\n\t\t\t\t\t\t// Discard any remaining `private` data\n\t\t\t\t\t\tdelete data_priv.cache[ key ];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Discard any remaining `user` data\n\t\t\tdelete data_user.cache[ elem[ data_user.expando ] ];\n\t\t}\n\t}\n});\n\njQuery.fn.extend({\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each(function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t});\n\t},\n\n\tprepend: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t});\n\t},\n\n\tbefore: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t});\n\t},\n\n\tafter: function() {\n\t\treturn this.domManip( arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t});\n\t},\n\n\tremove: function( selector, keepData /* Internal Use Only */ ) {\n\t\tvar elem,\n\t\t\telems = selector ? jQuery.filter( selector, this ) : this,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = elems[i]) != null; i++ ) {\n\t\t\tif ( !keepData && elem.nodeType === 1 ) {\n\t\t\t\tjQuery.cleanData( getAll( elem ) );\n\t\t\t}\n\n\t\t\tif ( elem.parentNode ) {\n\t\t\t\tif ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\t\t\tsetGlobalEval( getAll( elem, \"script\" ) );\n\t\t\t\t}\n\t\t\t\telem.parentNode.removeChild( elem );\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; (elem = this[i]) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map(function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t});\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = value.replace( rxhtmlTag, \"<$1></$2>\" );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar arg = arguments[ 0 ];\n\n\t\t// Make the changes, replacing each context element with the new content\n\t\tthis.domManip( arguments, function( elem ) {\n\t\t\targ = this.parentNode;\n\n\t\t\tjQuery.cleanData( getAll( this ) );\n\n\t\t\tif ( arg ) {\n\t\t\t\targ.replaceChild( elem, this );\n\t\t\t}\n\t\t});\n\n\t\t// Force removal if there was no new content (e.g., from empty arguments)\n\t\treturn arg && (arg.length || arg.nodeType) ? this : this.remove();\n\t},\n\n\tdetach: function( selector ) {\n\t\treturn this.remove( selector, true );\n\t},\n\n\tdomManip: function( args, callback ) {\n\n\t\t// Flatten any nested arrays\n\t\targs = concat.apply( [], args );\n\n\t\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\t\ti = 0,\n\t\t\tl = this.length,\n\t\t\tset = this,\n\t\t\tiNoClone = l - 1,\n\t\t\tvalue = args[ 0 ],\n\t\t\tisFunction = jQuery.isFunction( value );\n\n\t\t// We can't cloneNode fragments that contain checked, in WebKit\n\t\tif ( isFunction ||\n\t\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\t\treturn this.each(function( index ) {\n\t\t\t\tvar self = set.eq( index );\n\t\t\t\tif ( isFunction ) {\n\t\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t\t}\n\t\t\t\tself.domManip( args, callback );\n\t\t\t});\n\t\t}\n\n\t\tif ( l ) {\n\t\t\tfragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );\n\t\t\tfirst = fragment.firstChild;\n\n\t\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\t\tfragment = first;\n\t\t\t}\n\n\t\t\tif ( first ) {\n\t\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\t\thasScripts = scripts.length;\n\n\t\t\t\t// Use the original fragment for the last item instead of the first because it can end up\n\t\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\tnode = fragment;\n\n\t\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\t\t\t// Support: QtWebKit\n\t\t\t\t\t\t\t// jQuery.merge because push.apply(_, arraylike) throws\n\t\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcallback.call( this[ i ], node, i );\n\t\t\t\t}\n\n\t\t\t\tif ( hasScripts ) {\n\t\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t\t// Reenable scripts\n\t\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t\t!data_priv.access( node, \"globalEval\" ) && jQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\t\tif ( node.src ) {\n\t\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\t\tif ( jQuery._evalUrl ) {\n\t\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.globalEval( node.textContent.replace( rcleanScript, \"\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n});\n\njQuery.each({\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: QtWebKit\n\t\t\t// .get() because push.apply(_, arraylike) throws\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n});\n\n\nvar iframe,\n\telemdisplay = {};\n\n/**\n * Retrieve the actual display of a element\n * @param {String} name nodeName of the element\n * @param {Object} doc Document object\n */\n// Called only from within defaultDisplay\nfunction actualDisplay( name, doc ) {\n\tvar style,\n\t\telem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),\n\n\t\t// getDefaultComputedStyle might be reliably used only on attached element\n\t\tdisplay = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?\n\n\t\t\t// Use of this method is a temporary fix (more like optimization) until something better comes along,\n\t\t\t// since it was removed from specification and supported only in FF\n\t\t\tstyle.display : jQuery.css( elem[ 0 ], \"display\" );\n\n\t// We don't have any data stored on the element,\n\t// so use \"detach\" method as fast way to get rid of the element\n\telem.detach();\n\n\treturn display;\n}\n\n/**\n * Try to determine the default display value of an element\n * @param {String} nodeName\n */\nfunction defaultDisplay( nodeName ) {\n\tvar doc = document,\n\t\tdisplay = elemdisplay[ nodeName ];\n\n\tif ( !display ) {\n\t\tdisplay = actualDisplay( nodeName, doc );\n\n\t\t// If the simple way fails, read from inside an iframe\n\t\tif ( display === \"none\" || !display ) {\n\n\t\t\t// Use the already-created iframe if possible\n\t\t\tiframe = (iframe || jQuery( \"<iframe frameborder='0' width='0' height='0'/>\" )).appendTo( doc.documentElement );\n\n\t\t\t// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse\n\t\t\tdoc = iframe[ 0 ].contentDocument;\n\n\t\t\t// Support: IE\n\t\t\tdoc.write();\n\t\t\tdoc.close();\n\n\t\t\tdisplay = actualDisplay( nodeName, doc );\n\t\t\tiframe.detach();\n\t\t}\n\n\t\t// Store the correct default display\n\t\telemdisplay[ nodeName ] = display;\n\t}\n\n\treturn display;\n}\nvar rmargin = (/^margin/);\n\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\t\t// Support: IE<=11+, Firefox<=30+ (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tif ( elem.ownerDocument.defaultView.opener ) {\n\t\t\treturn elem.ownerDocument.defaultView.getComputedStyle( elem, null );\n\t\t}\n\n\t\treturn window.getComputedStyle( elem, null );\n\t};\n\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// Support: IE9\n\t// getPropertyValue is only needed for .css('filter') (#12537)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\t}\n\n\tif ( computed ) {\n\n\t\tif ( ret === \"\" && !jQuery.contains( elem.ownerDocument, elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// Support: iOS < 6\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels\n\t\t// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values\n\t\tif ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\t\t// Support: IE\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn (this.get = hookFn).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\n(function() {\n\tvar pixelPositionVal, boxSizingReliableVal,\n\t\tdocElem = document.documentElement,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE9-11+\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tcontainer.style.cssText = \"border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;\" +\n\t\t\"position:absolute\";\n\tcontainer.appendChild( div );\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computePixelPositionAndBoxSizingReliable() {\n\t\tdiv.style.cssText =\n\t\t\t// Support: Firefox<29, Android 2.3\n\t\t\t// Vendor-prefix box-sizing\n\t\t\t\"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;\" +\n\t\t\t\"box-sizing:border-box;display:block;margin-top:1%;top:1%;\" +\n\t\t\t\"border:1px;padding:1px;width:4px;position:absolute\";\n\t\tdiv.innerHTML = \"\";\n\t\tdocElem.appendChild( container );\n\n\t\tvar divStyle = window.getComputedStyle( div, null );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\t\tboxSizingReliableVal = divStyle.width === \"4px\";\n\n\t\tdocElem.removeChild( container );\n\t}\n\n\t// Support: node.js jsdom\n\t// Don't assume that getComputedStyle is a property of the global object\n\tif ( window.getComputedStyle ) {\n\t\tjQuery.extend( support, {\n\t\t\tpixelPosition: function() {\n\n\t\t\t\t// This test is executed only once but we still do memoizing\n\t\t\t\t// since we can use the boxSizingReliable pre-computing.\n\t\t\t\t// No need to check if the test was already performed, though.\n\t\t\t\tcomputePixelPositionAndBoxSizingReliable();\n\t\t\t\treturn pixelPositionVal;\n\t\t\t},\n\t\t\tboxSizingReliable: function() {\n\t\t\t\tif ( boxSizingReliableVal == null ) {\n\t\t\t\t\tcomputePixelPositionAndBoxSizingReliable();\n\t\t\t\t}\n\t\t\t\treturn boxSizingReliableVal;\n\t\t\t},\n\t\t\treliableMarginRight: function() {\n\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Check if div with explicit width and no margin-right incorrectly\n\t\t\t\t// gets computed margin-right based on width of container. (#3333)\n\t\t\t\t// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n\t\t\t\t// This support function is only executed once so no memoizing is needed.\n\t\t\t\tvar ret,\n\t\t\t\t\tmarginDiv = div.appendChild( document.createElement( \"div\" ) );\n\n\t\t\t\t// Reset CSS: box-sizing; display; margin; border; padding\n\t\t\t\tmarginDiv.style.cssText = div.style.cssText =\n\t\t\t\t\t// Support: Firefox<29, Android 2.3\n\t\t\t\t\t// Vendor-prefix box-sizing\n\t\t\t\t\t\"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;\" +\n\t\t\t\t\t\"box-sizing:content-box;display:block;margin:0;border:0;padding:0\";\n\t\t\t\tmarginDiv.style.marginRight = marginDiv.style.width = \"0\";\n\t\t\t\tdiv.style.width = \"1px\";\n\t\t\t\tdocElem.appendChild( container );\n\n\t\t\t\tret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );\n\n\t\t\t\tdocElem.removeChild( container );\n\t\t\t\tdiv.removeChild( marginDiv );\n\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t});\n\t}\n})();\n\n\n// A method for quickly swapping in/out CSS properties to get correct calculations.\njQuery.swap = function( elem, options, callback, args ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.apply( elem, args || [] );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar\n\t// Swappable if display is none or starts with table except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trnumsplit = new RegExp( \"^(\" + pnum + \")(.*)$\", \"i\" ),\n\trrelNum = new RegExp( \"^([+-])=(\" + pnum + \")\", \"i\" ),\n\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t},\n\n\tcssPrefixes = [ \"Webkit\", \"O\", \"Moz\", \"ms\" ];\n\n// Return a css property mapped to a potentially vendor prefixed property\nfunction vendorPropName( style, name ) {\n\n\t// Shortcut for names that are not vendor prefixed\n\tif ( name in style ) {\n\t\treturn name;\n\t}\n\n\t// Check for vendor prefixed names\n\tvar capName = name[0].toUpperCase() + name.slice(1),\n\t\torigName = name,\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in style ) {\n\t\t\treturn name;\n\t\t}\n\t}\n\n\treturn origName;\n}\n\nfunction setPositiveNumber( elem, value, subtract ) {\n\tvar matches = rnumsplit.exec( value );\n\treturn matches ?\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {\n\tvar i = extra === ( isBorderBox ? \"border\" : \"content\" ) ?\n\t\t// If we already have the right measurement, avoid augmentation\n\t\t4 :\n\t\t// Otherwise initialize for horizontal or vertical properties\n\t\tname === \"width\" ? 1 : 0,\n\n\t\tval = 0;\n\n\tfor ( ; i < 4; i += 2 ) {\n\t\t// Both box models exclude margin, so add it if we want it\n\t\tif ( extra === \"margin\" ) {\n\t\t\tval += jQuery.css( elem, extra + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\tif ( isBorderBox ) {\n\t\t\t// border-box includes padding, so remove it if we want content\n\t\t\tif ( extra === \"content\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// At this point, extra isn't border nor margin, so remove border\n\t\t\tif ( extra !== \"margin\" ) {\n\t\t\t\tval -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t} else {\n\t\t\t// At this point, extra isn't content, so add padding\n\t\t\tval += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// At this point, extra isn't content nor padding, so add border\n\t\t\tif ( extra !== \"padding\" ) {\n\t\t\t\tval += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\treturn val;\n}\n\nfunction getWidthOrHeight( elem, name, extra ) {\n\n\t// Start with offset property, which is equivalent to the border-box value\n\tvar valueIsBorderBox = true,\n\t\tval = name === \"width\" ? elem.offsetWidth : elem.offsetHeight,\n\t\tstyles = getStyles( elem ),\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t// Some non-html elements return undefined for offsetWidth, so check for null/undefined\n\t// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285\n\t// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668\n\tif ( val <= 0 || val == null ) {\n\t\t// Fall back to computed then uncomputed css if necessary\n\t\tval = curCSS( elem, name, styles );\n\t\tif ( val < 0 || val == null ) {\n\t\t\tval = elem.style[ name ];\n\t\t}\n\n\t\t// Computed unit is not pixels. Stop here and return.\n\t\tif ( rnumnonpx.test(val) ) {\n\t\t\treturn val;\n\t\t}\n\n\t\t// Check for style in case a browser which returns unreliable values\n\t\t// for getComputedStyle silently falls back to the reliable elem.style\n\t\tvalueIsBorderBox = isBorderBox &&\n\t\t\t( support.boxSizingReliable() || val === elem.style[ name ] );\n\n\t\t// Normalize \"\", auto, and prepare for extra\n\t\tval = parseFloat( val ) || 0;\n\t}\n\n\t// Use the active box-sizing model to add/subtract irrelevant styles\n\treturn ( val +\n\t\taugmentWidthOrHeight(\n\t\t\telem,\n\t\t\tname,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles\n\t\t)\n\t) + \"px\";\n}\n\nfunction showHide( elements, show ) {\n\tvar display, elem, hidden,\n\t\tvalues = [],\n\t\tindex = 0,\n\t\tlength = elements.length;\n\n\tfor ( ; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvalues[ index ] = data_priv.get( elem, \"olddisplay\" );\n\t\tdisplay = elem.style.display;\n\t\tif ( show ) {\n\t\t\t// Reset the inline display of this element to learn if it is\n\t\t\t// being hidden by cascaded rules or not\n\t\t\tif ( !values[ index ] && display === \"none\" ) {\n\t\t\t\telem.style.display = \"\";\n\t\t\t}\n\n\t\t\t// Set elements which have been overridden with display: none\n\t\t\t// in a stylesheet to whatever the default browser style is\n\t\t\t// for such an element\n\t\t\tif ( elem.style.display === \"\" && isHidden( elem ) ) {\n\t\t\t\tvalues[ index ] = data_priv.access( elem, \"olddisplay\", defaultDisplay(elem.nodeName) );\n\t\t\t}\n\t\t} else {\n\t\t\thidden = isHidden( elem );\n\n\t\t\tif ( display !== \"none\" || !hidden ) {\n\t\t\t\tdata_priv.set( elem, \"olddisplay\", hidden ? display : jQuery.css( elem, \"display\" ) );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the display of most of the elements in a second loop\n\t// to avoid the constant reflow\n\tfor ( index = 0; index < length; index++ ) {\n\t\telem = elements[ index ];\n\t\tif ( !elem.style ) {\n\t\t\tcontinue;\n\t\t}\n\t\tif ( !show || elem.style.display === \"none\" || elem.style.display === \"\" ) {\n\t\t\telem.style.display = show ? values[ index ] || \"\" : \"none\";\n\t\t}\n\t}\n\n\treturn elements;\n}\n\njQuery.extend({\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {\n\t\t\"float\": \"cssFloat\"\n\t},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = jQuery.camelCase( name ),\n\t\t\tstyle = elem.style;\n\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && (ret = rrelNum.exec( value )) ) {\n\t\t\t\tvalue = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number, add 'px' to the (except for certain CSS properties)\n\t\t\tif ( type === \"number\" && !jQuery.cssNumber[ origName ] ) {\n\t\t\t\tvalue += \"px\";\n\t\t\t}\n\n\t\t\t// Support: IE9-11+\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {\n\t\t\t\tstyle[ name ] = value;\n\t\t\t}\n\n\t\t} else {\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = jQuery.camelCase( name );\n\n\t\t// Make sure that we're working with the right name\n\t\tname = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || jQuery.isNumeric( num ) ? num || 0 : val;\n\t\t}\n\t\treturn val;\n\t}\n});\n\njQuery.each([ \"height\", \"width\" ], function( i, name ) {\n\tjQuery.cssHooks[ name ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) && elem.offsetWidth === 0 ?\n\t\t\t\t\tjQuery.swap( elem, cssShow, function() {\n\t\t\t\t\t\treturn getWidthOrHeight( elem, name, extra );\n\t\t\t\t\t}) :\n\t\t\t\t\tgetWidthOrHeight( elem, name, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar styles = extra && getStyles( elem );\n\t\t\treturn setPositiveNumber( elem, value, extra ?\n\t\t\t\taugmentWidthOrHeight(\n\t\t\t\t\telem,\n\t\t\t\t\tname,\n\t\t\t\t\textra,\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\t\tstyles\n\t\t\t\t) : 0\n\t\t\t);\n\t\t}\n\t};\n});\n\n// Support: Android 2.3\njQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn jQuery.swap( elem, { \"display\": \"inline-block\" },\n\t\t\t\tcurCSS, [ elem, \"marginRight\" ] );\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each({\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split(\" \") : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( !rmargin.test( prefix ) ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n});\n\njQuery.fn.extend({\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( jQuery.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t},\n\tshow: function() {\n\t\treturn showHide( this, true );\n\t},\n\thide: function() {\n\t\treturn showHide( this );\n\t},\n\ttoggle: function( state ) {\n\t\tif ( typeof state === \"boolean\" ) {\n\t\t\treturn state ? this.show() : this.hide();\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( isHidden( this ) ) {\n\t\t\t\tjQuery( this ).show();\n\t\t\t} else {\n\t\t\t\tjQuery( this ).hide();\n\t\t\t}\n\t\t});\n\t}\n});\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || \"swing\";\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\tif ( tween.elem[ tween.prop ] != null &&\n\t\t\t\t(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE9\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t}\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back Compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, timerId,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trfxnum = new RegExp( \"^(?:([+-])=|)(\" + pnum + \")([a-z%]*)$\", \"i\" ),\n\trrun = /queueHooks$/,\n\tanimationPrefilters = [ defaultPrefilter ],\n\ttweeners = {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value ),\n\t\t\t\ttarget = tween.cur(),\n\t\t\t\tparts = rfxnum.exec( value ),\n\t\t\t\tunit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" ),\n\n\t\t\t\t// Starting value computation is required for potential unit mismatches\n\t\t\t\tstart = ( jQuery.cssNumber[ prop ] || unit !== \"px\" && +target ) &&\n\t\t\t\t\trfxnum.exec( jQuery.css( tween.elem, prop ) ),\n\t\t\t\tscale = 1,\n\t\t\t\tmaxIterations = 20;\n\n\t\t\tif ( start && start[ 3 ] !== unit ) {\n\t\t\t\t// Trust units reported by jQuery.css\n\t\t\t\tunit = unit || start[ 3 ];\n\n\t\t\t\t// Make sure we update the tween properties later on\n\t\t\t\tparts = parts || [];\n\n\t\t\t\t// Iteratively approximate from a nonzero starting point\n\t\t\t\tstart = +target || 1;\n\n\t\t\t\tdo {\n\t\t\t\t\t// If previous iteration zeroed out, double until we get *something*.\n\t\t\t\t\t// Use string for doubling so we don't accidentally see scale as unchanged below\n\t\t\t\t\tscale = scale || \".5\";\n\n\t\t\t\t\t// Adjust and apply\n\t\t\t\t\tstart = start / scale;\n\t\t\t\t\tjQuery.style( tween.elem, prop, start + unit );\n\n\t\t\t\t// Update scale, tolerating zero or NaN from tween.cur(),\n\t\t\t\t// break the loop if scale is unchanged or perfect, or if we've just had enough\n\t\t\t\t} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );\n\t\t\t}\n\n\t\t\t// Update tween properties\n\t\t\tif ( parts ) {\n\t\t\t\tstart = tween.start = +start || +target || 0;\n\t\t\t\ttween.unit = unit;\n\t\t\t\t// If a +=/-= token was provided, we're doing a relative animation\n\t\t\t\ttween.end = parts[ 1 ] ?\n\t\t\t\t\tstart + ( parts[ 1 ] + 1 ) * parts[ 2 ] :\n\t\t\t\t\t+parts[ 2 ];\n\t\t\t}\n\n\t\t\treturn tween;\n\t\t} ]\n\t};\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\tsetTimeout(function() {\n\t\tfxNow = undefined;\n\t});\n\treturn ( fxNow = jQuery.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4 ; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( tweeners[ prop ] || [] ).concat( tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( (tween = collection[ index ].call( animation, prop, value )) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\t/* jshint validthis: true */\n\tvar prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHidden( elem ),\n\t\tdataShow = data_priv.get( elem, \"fxshow\" );\n\n\t// Handle queue: false promises\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always(function() {\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always(function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t// Height/width overflow pass\n\tif ( elem.nodeType === 1 && ( \"height\" in props || \"width\" in props ) ) {\n\t\t// Make sure that nothing sneaks out\n\t\t// Record all 3 overflow attributes because IE9-10 do not\n\t\t// change the overflow attribute when overflowX and\n\t\t// overflowY are set to the same value\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Set display property to inline-block for height/width\n\t\t// animations on inline elements that are having width/height animated\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\n\t\t// Test default display if display is currently \"none\"\n\t\tcheckDisplay = display === \"none\" ?\n\t\t\tdata_priv.get( elem, \"olddisplay\" ) || defaultDisplay( elem.nodeName ) : display;\n\n\t\tif ( checkDisplay === \"inline\" && jQuery.css( elem, \"float\" ) === \"none\" ) {\n\t\t\tstyle.display = \"inline-block\";\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always(function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t});\n\t}\n\n\t// show/hide pass\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.exec( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\n\t\t// Any non-fx value stops us from restoring the original display value\n\t\t} else {\n\t\t\tdisplay = undefined;\n\t\t}\n\t}\n\n\tif ( !jQuery.isEmptyObject( orig ) ) {\n\t\tif ( dataShow ) {\n\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\thidden = dataShow.hidden;\n\t\t\t}\n\t\t} else {\n\t\t\tdataShow = data_priv.access( elem, \"fxshow\", {} );\n\t\t}\n\n\t\t// Store state if its toggle - enables .stop().toggle() to \"reverse\"\n\t\tif ( toggle ) {\n\t\t\tdataShow.hidden = !hidden;\n\t\t}\n\t\tif ( hidden ) {\n\t\t\tjQuery( elem ).show();\n\t\t} else {\n\t\t\tanim.done(function() {\n\t\t\t\tjQuery( elem ).hide();\n\t\t\t});\n\t\t}\n\t\tanim.done(function() {\n\t\t\tvar prop;\n\n\t\t\tdata_priv.remove( elem, \"fxshow\" );\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t}\n\t\t});\n\t\tfor ( prop in orig ) {\n\t\t\ttween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\n\t\t\tif ( !( prop in dataShow ) ) {\n\t\t\t\tdataShow[ prop ] = tween.start;\n\t\t\t\tif ( hidden ) {\n\t\t\t\t\ttween.end = tween.start;\n\t\t\t\t\ttween.start = prop === \"width\" || prop === \"height\" ? 1 : 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t// If this is a noop like .hide().hide(), restore an overwritten display value\n\t} else if ( (display === \"none\" ? defaultDisplay( elem.nodeName ) : display) === \"inline\" ) {\n\t\tstyle.display = display;\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = jQuery.camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( jQuery.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = animationPrefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t}),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\t\t\t\t// Support: Android 2.3\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ]);\n\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t} else {\n\t\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\t\tanimation = deferred.promise({\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, { specialEasing: {} }, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length ; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t}),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length ; index++ ) {\n\t\tresult = animationPrefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( jQuery.isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t})\n\t);\n\n\t// attach callbacks from options\n\treturn animation.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweener: function( props, callback ) {\n\t\tif ( jQuery.isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.split(\" \");\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length ; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\ttweeners[ prop ] = tweeners[ prop ] || [];\n\t\t\ttweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tanimationPrefilters.unshift( callback );\n\t\t} else {\n\t\t\tanimationPrefilters.push( callback );\n\t\t}\n\t}\n});\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tjQuery.isFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !jQuery.isFunction( easing ) && easing\n\t};\n\n\topt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n\t\topt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( jQuery.isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend({\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHidden ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate({ opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || data_priv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue && type !== false ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = data_priv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t});\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each(function() {\n\t\t\tvar index,\n\t\t\t\tdata = data_priv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t});\n\t}\n});\n\njQuery.each([ \"toggle\", \"show\", \"hide\" ], function( i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n});\n\n// Generate shortcuts for custom animations\njQuery.each({\n\tslideDown: genFx(\"show\"),\n\tslideUp: genFx(\"hide\"),\n\tslideToggle: genFx(\"toggle\"),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n});\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = jQuery.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\t\t// Checks the timer has not already been removed\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tif ( timer() ) {\n\t\tjQuery.fx.start();\n\t} else {\n\t\tjQuery.timers.pop();\n\t}\n};\n\njQuery.fx.interval = 13;\n\njQuery.fx.start = function() {\n\tif ( !timerId ) {\n\t\ttimerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );\n\t}\n};\n\njQuery.fx.stop = function() {\n\tclearInterval( timerId );\n\ttimerId = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\tclearTimeout( timeout );\n\t\t};\n\t});\n};\n\n\n(function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: iOS<=5.1, Android<=4.2+\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE<=11+\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: Android<=2.3\n\t// Options inside disabled selects are incorrectly marked as disabled\n\tselect.disabled = true;\n\tsupport.optDisabled = !opt.disabled;\n\n\t// Support: IE<=11+\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n})();\n\n\nvar nodeHook, boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend({\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tattr: function( elem, name, value ) {\n\t\tvar hooks, ret,\n\t\t\tnType = elem.nodeType;\n\n\t\t// don't get/set attributes on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === strundefined ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// All attributes are lowercase\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\tname = name.toLowerCase();\n\t\t\thooks = jQuery.attrHooks[ name ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\n\t\t\t} else if ( hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {\n\t\t\t\treturn ret;\n\n\t\t\t} else {\n\t\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t} else if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ) {\n\t\t\treturn ret;\n\n\t\t} else {\n\t\t\tret = jQuery.find.attr( elem, name );\n\n\t\t\t// Non-existent attributes return null, we normalize to undefined\n\t\t\treturn ret == null ?\n\t\t\t\tundefined :\n\t\t\t\tret;\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name, propName,\n\t\t\ti = 0,\n\t\t\tattrNames = value && value.match( rnotwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( (name = attrNames[i++]) ) {\n\t\t\t\tpropName = jQuery.propFix[ name ] || name;\n\n\t\t\t\t// Boolean attributes get special treatment (#10870)\n\t\t\t\tif ( jQuery.expr.match.bool.test( name ) ) {\n\t\t\t\t\t// Set corresponding property to false\n\t\t\t\t\telem[ propName ] = false;\n\t\t\t\t}\n\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tjQuery.nodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle;\n\t\tif ( !isXML ) {\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ name ];\n\t\t\tattrHandle[ name ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tname.toLowerCase() :\n\t\t\t\tnull;\n\t\t\tattrHandle[ name ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n});\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i;\n\njQuery.fn.extend({\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each(function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t},\n\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks, notxml,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( !elem || nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tnotxml = nType !== 1 || !jQuery.isXMLDoc( elem );\n\n\t\tif ( notxml ) {\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\treturn hooks && \"set\" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?\n\t\t\t\tret :\n\t\t\t\t( elem[ name ] = value );\n\n\t\t} else {\n\t\t\treturn hooks && \"get\" in hooks && (ret = hooks.get( elem, name )) !== null ?\n\t\t\t\tret :\n\t\t\t\telem[ name ];\n\t\t}\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\t\t\t\treturn elem.hasAttribute( \"tabindex\" ) || rfocusable.test( elem.nodeName ) || elem.href ?\n\t\t\t\t\telem.tabIndex :\n\t\t\t\t\t-1;\n\t\t\t}\n\t\t}\n\t}\n});\n\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\t};\n}\n\njQuery.each([\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n});\n\n\n\n\nvar rclass = /[\\t\\r\\n\\f]/g;\n\njQuery.fn.extend({\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j, finalValue,\n\t\t\tproceed = typeof value === \"string\" && value,\n\t\t\ti = 0,\n\t\t\tlen = this.length;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\n\t\tif ( proceed ) {\n\t\t\t// The disjunction here is for better compressibility (see removeClass)\n\t\t\tclasses = ( value || \"\" ).match( rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\" \"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = jQuery.trim( cur );\n\t\t\t\t\tif ( elem.className !== finalValue ) {\n\t\t\t\t\t\telem.className = finalValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, clazz, j, finalValue,\n\t\t\tproceed = arguments.length === 0 || typeof value === \"string\" && value,\n\t\t\ti = 0,\n\t\t\tlen = this.length;\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, this.className ) );\n\t\t\t});\n\t\t}\n\t\tif ( proceed ) {\n\t\t\tclasses = ( value || \"\" ).match( rnotwhite ) || [];\n\n\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\telem = this[ i ];\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( elem.className ?\n\t\t\t\t\t( \" \" + elem.className + \" \" ).replace( rclass, \" \" ) :\n\t\t\t\t\t\"\"\n\t\t\t\t);\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( (clazz = classes[j++]) ) {\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) >= 0 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = value ? jQuery.trim( cur ) : \"\";\n\t\t\t\t\tif ( elem.className !== finalValue ) {\n\t\t\t\t\t\telem.className = finalValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value;\n\n\t\tif ( typeof stateVal === \"boolean\" && type === \"string\" ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( jQuery.isFunction( value ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tif ( type === \"string\" ) {\n\t\t\t\t// Toggle individual class names\n\t\t\t\tvar className,\n\t\t\t\t\ti = 0,\n\t\t\t\t\tself = jQuery( this ),\n\t\t\t\t\tclassNames = value.match( rnotwhite ) || [];\n\n\t\t\t\twhile ( (className = classNames[ i++ ]) ) {\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( type === strundefined || type === \"boolean\" ) {\n\t\t\t\tif ( this.className ) {\n\t\t\t\t\t// store className if set\n\t\t\t\t\tdata_priv.set( this, \"__className__\", this.className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tthis.className = this.className || value === false ? \"\" : data_priv.get( this, \"__className__\" ) || \"\";\n\t\t\t}\n\t\t});\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className = \" \" + selector + \" \",\n\t\t\ti = 0,\n\t\t\tl = this.length;\n\t\tfor ( ; i < l; i++ ) {\n\t\t\tif ( this[i].nodeType === 1 && (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) >= 0 ) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n});\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend({\n\tval: function( value ) {\n\t\tvar hooks, ret, isFunction,\n\t\t\telem = this[0];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks && \"get\" in hooks && (ret = hooks.get( elem, \"value\" )) !== undefined ) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\treturn typeof ret === \"string\" ?\n\t\t\t\t\t// Handle most common string cases\n\t\t\t\t\tret.replace(rreturn, \"\") :\n\t\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\t\tret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tisFunction = jQuery.isFunction( value );\n\n\t\treturn this.each(function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( jQuery.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t});\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !(\"set\" in hooks) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t});\n\t}\n});\n\njQuery.extend({\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\t\t\t\t\t// Support: IE10-11+\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\tjQuery.trim( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\" || index < 0,\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length,\n\t\t\t\t\ti = index < 0 ?\n\t\t\t\t\t\tmax :\n\t\t\t\t\t\tone ? index : 0;\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// IE6-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t( support.optDisabled ? !option.disabled : option.getAttribute( \"disabled\" ) === null ) &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\t\t\t\t\tif ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n});\n\n// Radios and checkboxes getter/setter\njQuery.each([ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( jQuery.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n\t\t};\n\t}\n});\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\njQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n\t\"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n\t\"change select submit keydown keypress keyup error contextmenu\").split(\" \"), function( i, name ) {\n\n\t// Handle event binding\n\tjQuery.fn[ name ] = function( data, fn ) {\n\t\treturn arguments.length > 0 ?\n\t\t\tthis.on( name, null, data, fn ) :\n\t\t\tthis.trigger( name );\n\t};\n});\n\njQuery.fn.extend({\n\thover: function( fnOver, fnOut ) {\n\t\treturn this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n\t},\n\n\tbind: function( types, data, fn ) {\n\t\treturn this.on( types, null, data, fn );\n\t},\n\tunbind: function( types, fn ) {\n\t\treturn this.off( types, null, fn );\n\t},\n\n\tdelegate: function( selector, types, data, fn ) {\n\t\treturn this.on( types, selector, data, fn );\n\t},\n\tundelegate: function( selector, types, fn ) {\n\t\t// ( namespace ) or ( selector, types [, fn] )\n\t\treturn arguments.length === 1 ? this.off( selector, \"**\" ) : this.off( types, selector || \"**\", fn );\n\t}\n});\n\n\nvar nonce = jQuery.now();\n\nvar rquery = (/\\?/);\n\n\n\n// Support: Android 2.3\n// Workaround failure to string-cast null input\njQuery.parseJSON = function( data ) {\n\treturn JSON.parse( data + \"\" );\n};\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml, tmp;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE9\n\ttry {\n\t\ttmp = new DOMParser();\n\t\txml = tmp.parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trhash = /#.*$/,\n\trts = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\trurl = /^([\\w.+-]+:)(?:\\/\\/(?:[^\\/?#]*@|)([^\\/?#:]*)(?::(\\d+)|)|)/,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t *    - BEFORE asking for a transport\n\t *    - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Document location\n\tajaxLocation = window.location.href,\n\n\t// Segment location into parts\n\tajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];\n\n\t\tif ( jQuery.isFunction( func ) ) {\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( (dataType = dataTypes[i++]) ) {\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[0] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t(structure[ dataType ] = structure[ dataType ] || []).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t});\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader(\"Content-Type\");\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s[ \"throws\" ] ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn { state: \"parsererror\", error: conv ? e : \"No conversion from \" + prev + \" to \" + current };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend({\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: ajaxLocation,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /xml/,\n\t\t\thtml: /html/,\n\t\t\tjson: /json/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": jQuery.parseJSON,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\t\t\t// Cross-domain detection vars\n\t\t\tparts,\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\t\t\t// Loop variable\n\t\t\ti,\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\tjQuery.event,\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks(\"once memory\"),\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\t\t\t// The jqXHR state\n\t\t\tstate = 0,\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( state === 2 ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( (match = rheaders.exec( responseHeadersString )) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match;\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn state === 2 ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tvar lname = name.toLowerCase();\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\tname = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( !state ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\t// Lazy-add the new callback in a way that preserves old ones\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR ).complete = completeDeferred.add;\n\t\tjqXHR.success = jqXHR.done;\n\t\tjqXHR.error = jqXHR.fail;\n\n\t\t// Remove hash character (#7531: and string promotion)\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || ajaxLocation ) + \"\" ).replace( rhash, \"\" )\n\t\t\t.replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().match( rnotwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when we have a protocol:host:port mismatch\n\t\tif ( s.crossDomain == null ) {\n\t\t\tparts = rurl.exec( s.url.toLowerCase() );\n\t\t\ts.crossDomain = !!( parts &&\n\t\t\t\t( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||\n\t\t\t\t\t( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? \"80\" : \"443\" ) ) !==\n\t\t\t\t\t\t( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? \"80\" : \"443\" ) ) )\n\t\t\t);\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( state === 2 ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger(\"ajaxStart\");\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\tcacheURL = s.url;\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// If data is available, append data to url\n\t\t\tif ( s.data ) {\n\t\t\t\tcacheURL = ( s.url += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data );\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add anti-cache in url if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\ts.url = rts.test( cacheURL ) ?\n\n\t\t\t\t\t// If there is already a '_' parameter, set its value\n\t\t\t\t\tcacheURL.replace( rts, \"$1_=\" + nonce++ ) :\n\n\t\t\t\t\t// Otherwise add one to the end\n\t\t\t\t\tcacheURL + ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + nonce++;\n\t\t\t}\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tfor ( i in { success: 1, error: 1, complete: 1 } ) {\n\t\t\tjqXHR[ i ]( s[ i ] );\n\t\t}\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = setTimeout(function() {\n\t\t\t\t\tjqXHR.abort(\"timeout\");\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tstate = 1;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\t\t\t\t// Propagate exception as error if not done\n\t\t\t\tif ( state < 2 ) {\n\t\t\t\t\tdone( -1, e );\n\t\t\t\t// Simply rethrow otherwise\n\t\t\t\t} else {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Called once\n\t\t\tif ( state === 2 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// State is \"done\" now\n\t\t\tstate = 2;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\tclearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"Last-Modified\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader(\"etag\");\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger(\"ajaxStop\");\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n});\n\njQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( jQuery.isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\treturn jQuery.ajax({\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t});\n\t};\n});\n\n\njQuery._evalUrl = function( url ) {\n\treturn jQuery.ajax({\n\t\turl: url,\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tasync: false,\n\t\tglobal: false,\n\t\t\"throws\": true\n\t});\n};\n\n\njQuery.fn.extend({\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).wrapAll( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\tif ( this[ 0 ] ) {\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map(function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t}).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( jQuery.isFunction( html ) ) {\n\t\t\treturn this.each(function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call(this, i) );\n\t\t\t});\n\t\t}\n\n\t\treturn this.each(function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t});\n\t},\n\n\twrap: function( html ) {\n\t\tvar isFunction = jQuery.isFunction( html );\n\n\t\treturn this.each(function( i ) {\n\t\t\tjQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );\n\t\t});\n\t},\n\n\tunwrap: function() {\n\t\treturn this.parent().each(function() {\n\t\t\tif ( !jQuery.nodeName( this, \"body\" ) ) {\n\t\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t\t}\n\t\t}).end();\n\t}\n});\n\n\njQuery.expr.filters.hidden = function( elem ) {\n\t// Support: Opera <= 12.12\n\t// Opera reports offsetWidths and offsetHeights less than zero on some elements\n\treturn elem.offsetWidth <= 0 && elem.offsetHeight <= 0;\n};\njQuery.expr.filters.visible = function( elem ) {\n\treturn !jQuery.expr.filters.hidden( elem );\n};\n\n\n\n\nvar r20 = /%20/g,\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( jQuery.isArray( obj ) ) {\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams( prefix + \"[\" + ( typeof v === \"object\" ? i : \"\" ) + \"]\", v, traditional, add );\n\t\t\t}\n\t\t});\n\n\t} else if ( !traditional && jQuery.type( obj ) === \"object\" ) {\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, value ) {\n\t\t\t// If value is a function, invoke it and return its value\n\t\t\tvalue = jQuery.isFunction( value ) ? value() : ( value == null ? \"\" : value );\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n\t\t};\n\n\t// Set traditional to true for jQuery <= 1.3.2 behavior.\n\tif ( traditional === undefined ) {\n\t\ttraditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t});\n\n\t} else {\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" ).replace( r20, \"+\" );\n};\n\njQuery.fn.extend({\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map(function() {\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t})\n\t\t.filter(function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t})\n\t\t.map(function( i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\treturn val == null ?\n\t\t\t\tnull :\n\t\t\t\tjQuery.isArray( val ) ?\n\t\t\t\t\tjQuery.map( val, function( val ) {\n\t\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t\t}) :\n\t\t\t\t\t{ name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t}).get();\n\t}\n});\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new XMLHttpRequest();\n\t} catch( e ) {}\n};\n\nvar xhrId = 0,\n\txhrCallbacks = {},\n\txhrSuccessStatus = {\n\t\t// file protocol always yields status code 0, assume 200\n\t\t0: 200,\n\t\t// Support: IE9\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\n// Support: IE9\n// Open requests must be manually aborted on unload (#5280)\n// See https://support.microsoft.com/kb/2856746 for more info\nif ( window.attachEvent ) {\n\twindow.attachEvent( \"onunload\", function() {\n\t\tfor ( var key in xhrCallbacks ) {\n\t\t\txhrCallbacks[ key ]();\n\t\t}\n\t});\n}\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport(function( options ) {\n\tvar callback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr(),\n\t\t\t\t\tid = ++xhrId;\n\n\t\t\t\txhr.open( options.type, options.url, options.async, options.username, options.password );\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[\"X-Requested-With\"] ) {\n\t\t\t\t\theaders[\"X-Requested-With\"] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tdelete xhrCallbacks[ id ];\n\t\t\t\t\t\t\tcallback = xhr.onload = xhr.onerror = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\t// file: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\t\t\t\t\t\t\t\t\t// Support: IE9\n\t\t\t\t\t\t\t\t\t// Accessing binary-data responseText throws an exception\n\t\t\t\t\t\t\t\t\t// (#11426)\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText === \"string\" ? {\n\t\t\t\t\t\t\t\t\t\ttext: xhr.responseText\n\t\t\t\t\t\t\t\t\t} : undefined,\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\txhr.onerror = callback(\"error\");\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = xhrCallbacks[ id ] = callback(\"abort\");\n\n\t\t\t\ttry {\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\n// Install script dataType\njQuery.ajaxSetup({\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /(?:java|ecma)script/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n});\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n});\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\t// This transport only deals with cross domain requests\n\tif ( s.crossDomain ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery(\"<script>\").prop({\n\t\t\t\t\tasync: true,\n\t\t\t\t\tcharset: s.scriptCharset,\n\t\t\t\t\tsrc: s.url\n\t\t\t\t}).on(\n\t\t\t\t\t\"load error\",\n\t\t\t\t\tcallback = function( evt ) {\n\t\t\t\t\t\tscript.remove();\n\t\t\t\t\t\tcallback = null;\n\t\t\t\t\t\tif ( evt ) {\n\t\t\t\t\t\t\tcomplete( evt.type === \"error\" ? 404 : 200, evt.type );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tdocument.head.appendChild( script[ 0 ] );\n\t\t\t},\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n});\n\n\n\n\nvar oldCallbacks = [],\n\trjsonp = /(=)\\?(?=&|$)|\\?\\?/;\n\n// Default jsonp settings\njQuery.ajaxSetup({\n\tjsonp: \"callback\",\n\tjsonpCallback: function() {\n\t\tvar callback = oldCallbacks.pop() || ( jQuery.expando + \"_\" + ( nonce++ ) );\n\t\tthis[ callback ] = true;\n\t\treturn callback;\n\t}\n});\n\n// Detect, normalize options and install callbacks for jsonp requests\njQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n\tvar callbackName, overwritten, responseContainer,\n\t\tjsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?\n\t\t\t\"url\" :\n\t\t\ttypeof s.data === \"string\" && !( s.contentType || \"\" ).indexOf(\"application/x-www-form-urlencoded\") && rjsonp.test( s.data ) && \"data\"\n\t\t);\n\n\t// Handle iff the expected data type is \"jsonp\" or we have a parameter to set\n\tif ( jsonProp || s.dataTypes[ 0 ] === \"jsonp\" ) {\n\n\t\t// Get callback name, remembering preexisting value associated with it\n\t\tcallbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?\n\t\t\ts.jsonpCallback() :\n\t\t\ts.jsonpCallback;\n\n\t\t// Insert callback into url or form data\n\t\tif ( jsonProp ) {\n\t\t\ts[ jsonProp ] = s[ jsonProp ].replace( rjsonp, \"$1\" + callbackName );\n\t\t} else if ( s.jsonp !== false ) {\n\t\t\ts.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.jsonp + \"=\" + callbackName;\n\t\t}\n\n\t\t// Use data converter to retrieve json after script execution\n\t\ts.converters[\"script json\"] = function() {\n\t\t\tif ( !responseContainer ) {\n\t\t\t\tjQuery.error( callbackName + \" was not called\" );\n\t\t\t}\n\t\t\treturn responseContainer[ 0 ];\n\t\t};\n\n\t\t// force json dataType\n\t\ts.dataTypes[ 0 ] = \"json\";\n\n\t\t// Install callback\n\t\toverwritten = window[ callbackName ];\n\t\twindow[ callbackName ] = function() {\n\t\t\tresponseContainer = arguments;\n\t\t};\n\n\t\t// Clean-up function (fires after converters)\n\t\tjqXHR.always(function() {\n\t\t\t// Restore preexisting value\n\t\t\twindow[ callbackName ] = overwritten;\n\n\t\t\t// Save back as free\n\t\t\tif ( s[ callbackName ] ) {\n\t\t\t\t// make sure that re-using the options doesn't screw things around\n\t\t\t\ts.jsonpCallback = originalSettings.jsonpCallback;\n\n\t\t\t\t// save the callback name for future use\n\t\t\t\toldCallbacks.push( callbackName );\n\t\t\t}\n\n\t\t\t// Call if it was a function and we have a response\n\t\t\tif ( responseContainer && jQuery.isFunction( overwritten ) ) {\n\t\t\t\toverwritten( responseContainer[ 0 ] );\n\t\t\t}\n\n\t\t\tresponseContainer = overwritten = undefined;\n\t\t});\n\n\t\t// Delegate to script\n\t\treturn \"script\";\n\t}\n});\n\n\n\n\n// data: string of html\n// context (optional): If specified, the fragment will be created in this context, defaults to document\n// keepScripts (optional): If true, will include scripts passed in the html string\njQuery.parseHTML = function( data, context, keepScripts ) {\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\tif ( typeof context === \"boolean\" ) {\n\t\tkeepScripts = context;\n\t\tcontext = false;\n\t}\n\tcontext = context || document;\n\n\tvar parsed = rsingleTag.exec( data ),\n\t\tscripts = !keepScripts && [];\n\n\t// Single tag\n\tif ( parsed ) {\n\t\treturn [ context.createElement( parsed[1] ) ];\n\t}\n\n\tparsed = jQuery.buildFragment( [ data ], context, scripts );\n\n\tif ( scripts && scripts.length ) {\n\t\tjQuery( scripts ).remove();\n\t}\n\n\treturn jQuery.merge( [], parsed.childNodes );\n};\n\n\n// Keep a copy of the old load method\nvar _load = jQuery.fn.load;\n\n/**\n * Load a url into a page\n */\njQuery.fn.load = function( url, params, callback ) {\n\tif ( typeof url !== \"string\" && _load ) {\n\t\treturn _load.apply( this, arguments );\n\t}\n\n\tvar selector, type, response,\n\t\tself = this,\n\t\toff = url.indexOf(\" \");\n\n\tif ( off >= 0 ) {\n\t\tselector = jQuery.trim( url.slice( off ) );\n\t\turl = url.slice( 0, off );\n\t}\n\n\t// If it's a function\n\tif ( jQuery.isFunction( params ) ) {\n\n\t\t// We assume that it's the callback\n\t\tcallback = params;\n\t\tparams = undefined;\n\n\t// Otherwise, build a param string\n\t} else if ( params && typeof params === \"object\" ) {\n\t\ttype = \"POST\";\n\t}\n\n\t// If we have elements to modify, make the request\n\tif ( self.length > 0 ) {\n\t\tjQuery.ajax({\n\t\t\turl: url,\n\n\t\t\t// if \"type\" variable is undefined, then \"GET\" method will be used\n\t\t\ttype: type,\n\t\t\tdataType: \"html\",\n\t\t\tdata: params\n\t\t}).done(function( responseText ) {\n\n\t\t\t// Save response for use in complete callback\n\t\t\tresponse = arguments;\n\n\t\t\tself.html( selector ?\n\n\t\t\t\t// If a selector was specified, locate the right elements in a dummy div\n\t\t\t\t// Exclude scripts to avoid IE 'Permission Denied' errors\n\t\t\t\tjQuery(\"<div>\").append( jQuery.parseHTML( responseText ) ).find( selector ) :\n\n\t\t\t\t// Otherwise use the full result\n\t\t\t\tresponseText );\n\n\t\t}).complete( callback && function( jqXHR, status ) {\n\t\t\tself.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );\n\t\t});\n\t}\n\n\treturn this;\n};\n\n\n\n\n// Attach a bunch of functions for handling common AJAX events\njQuery.each( [ \"ajaxStart\", \"ajaxStop\", \"ajaxComplete\", \"ajaxError\", \"ajaxSuccess\", \"ajaxSend\" ], function( i, type ) {\n\tjQuery.fn[ type ] = function( fn ) {\n\t\treturn this.on( type, fn );\n\t};\n});\n\n\n\n\njQuery.expr.filters.animated = function( elem ) {\n\treturn jQuery.grep(jQuery.timers, function( fn ) {\n\t\treturn elem === fn.elem;\n\t}).length;\n};\n\n\n\n\nvar docElem = window.document.documentElement;\n\n/**\n * Gets a window from an element\n */\nfunction getWindow( elem ) {\n\treturn jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;\n}\n\njQuery.offset = {\n\tsetOffset: function( elem, options, i ) {\n\t\tvar curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,\n\t\t\tposition = jQuery.css( elem, \"position\" ),\n\t\t\tcurElem = jQuery( elem ),\n\t\t\tprops = {};\n\n\t\t// Set position first, in-case top/left are set even on static elem\n\t\tif ( position === \"static\" ) {\n\t\t\telem.style.position = \"relative\";\n\t\t}\n\n\t\tcurOffset = curElem.offset();\n\t\tcurCSSTop = jQuery.css( elem, \"top\" );\n\t\tcurCSSLeft = jQuery.css( elem, \"left\" );\n\t\tcalculatePosition = ( position === \"absolute\" || position === \"fixed\" ) &&\n\t\t\t( curCSSTop + curCSSLeft ).indexOf(\"auto\") > -1;\n\n\t\t// Need to be able to calculate position if either\n\t\t// top or left is auto and position is either absolute or fixed\n\t\tif ( calculatePosition ) {\n\t\t\tcurPosition = curElem.position();\n\t\t\tcurTop = curPosition.top;\n\t\t\tcurLeft = curPosition.left;\n\n\t\t} else {\n\t\t\tcurTop = parseFloat( curCSSTop ) || 0;\n\t\t\tcurLeft = parseFloat( curCSSLeft ) || 0;\n\t\t}\n\n\t\tif ( jQuery.isFunction( options ) ) {\n\t\t\toptions = options.call( elem, i, curOffset );\n\t\t}\n\n\t\tif ( options.top != null ) {\n\t\t\tprops.top = ( options.top - curOffset.top ) + curTop;\n\t\t}\n\t\tif ( options.left != null ) {\n\t\t\tprops.left = ( options.left - curOffset.left ) + curLeft;\n\t\t}\n\n\t\tif ( \"using\" in options ) {\n\t\t\toptions.using.call( elem, props );\n\n\t\t} else {\n\t\t\tcurElem.css( props );\n\t\t}\n\t}\n};\n\njQuery.fn.extend({\n\toffset: function( options ) {\n\t\tif ( arguments.length ) {\n\t\t\treturn options === undefined ?\n\t\t\t\tthis :\n\t\t\t\tthis.each(function( i ) {\n\t\t\t\t\tjQuery.offset.setOffset( this, options, i );\n\t\t\t\t});\n\t\t}\n\n\t\tvar docElem, win,\n\t\t\telem = this[ 0 ],\n\t\t\tbox = { top: 0, left: 0 },\n\t\t\tdoc = elem && elem.ownerDocument;\n\n\t\tif ( !doc ) {\n\t\t\treturn;\n\t\t}\n\n\t\tdocElem = doc.documentElement;\n\n\t\t// Make sure it's not a disconnected DOM node\n\t\tif ( !jQuery.contains( docElem, elem ) ) {\n\t\t\treturn box;\n\t\t}\n\n\t\t// Support: BlackBerry 5, iOS 3 (original iPhone)\n\t\t// If we don't have gBCR, just use 0,0 rather than error\n\t\tif ( typeof elem.getBoundingClientRect !== strundefined ) {\n\t\t\tbox = elem.getBoundingClientRect();\n\t\t}\n\t\twin = getWindow( doc );\n\t\treturn {\n\t\t\ttop: box.top + win.pageYOffset - docElem.clientTop,\n\t\t\tleft: box.left + win.pageXOffset - docElem.clientLeft\n\t\t};\n\t},\n\n\tposition: function() {\n\t\tif ( !this[ 0 ] ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar offsetParent, offset,\n\t\t\telem = this[ 0 ],\n\t\t\tparentOffset = { top: 0, left: 0 };\n\n\t\t// Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent\n\t\tif ( jQuery.css( elem, \"position\" ) === \"fixed\" ) {\n\t\t\t// Assume getBoundingClientRect is there when computed position is fixed\n\t\t\toffset = elem.getBoundingClientRect();\n\n\t\t} else {\n\t\t\t// Get *real* offsetParent\n\t\t\toffsetParent = this.offsetParent();\n\n\t\t\t// Get correct offsets\n\t\t\toffset = this.offset();\n\t\t\tif ( !jQuery.nodeName( offsetParent[ 0 ], \"html\" ) ) {\n\t\t\t\tparentOffset = offsetParent.offset();\n\t\t\t}\n\n\t\t\t// Add offsetParent borders\n\t\t\tparentOffset.top += jQuery.css( offsetParent[ 0 ], \"borderTopWidth\", true );\n\t\t\tparentOffset.left += jQuery.css( offsetParent[ 0 ], \"borderLeftWidth\", true );\n\t\t}\n\n\t\t// Subtract parent offsets and element margins\n\t\treturn {\n\t\t\ttop: offset.top - parentOffset.top - jQuery.css( elem, \"marginTop\", true ),\n\t\t\tleft: offset.left - parentOffset.left - jQuery.css( elem, \"marginLeft\", true )\n\t\t};\n\t},\n\n\toffsetParent: function() {\n\t\treturn this.map(function() {\n\t\t\tvar offsetParent = this.offsetParent || docElem;\n\n\t\t\twhile ( offsetParent && ( !jQuery.nodeName( offsetParent, \"html\" ) && jQuery.css( offsetParent, \"position\" ) === \"static\" ) ) {\n\t\t\t\toffsetParent = offsetParent.offsetParent;\n\t\t\t}\n\n\t\t\treturn offsetParent || docElem;\n\t\t});\n\t}\n});\n\n// Create scrollLeft and scrollTop methods\njQuery.each( { scrollLeft: \"pageXOffset\", scrollTop: \"pageYOffset\" }, function( method, prop ) {\n\tvar top = \"pageYOffset\" === prop;\n\n\tjQuery.fn[ method ] = function( val ) {\n\t\treturn access( this, function( elem, method, val ) {\n\t\t\tvar win = getWindow( elem );\n\n\t\t\tif ( val === undefined ) {\n\t\t\t\treturn win ? win[ prop ] : elem[ method ];\n\t\t\t}\n\n\t\t\tif ( win ) {\n\t\t\t\twin.scrollTo(\n\t\t\t\t\t!top ? val : window.pageXOffset,\n\t\t\t\t\ttop ? val : window.pageYOffset\n\t\t\t\t);\n\n\t\t\t} else {\n\t\t\t\telem[ method ] = val;\n\t\t\t}\n\t\t}, method, val, arguments.length, null );\n\t};\n});\n\n// Support: Safari<7+, Chrome<37+\n// Add the top/left cssHooks using jQuery.fn.position\n// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084\n// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280\n// getComputedStyle returns percent when specified for top/left/bottom/right;\n// rather than make the css module depend on the offset module, just check for it here\njQuery.each( [ \"top\", \"left\" ], function( i, prop ) {\n\tjQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,\n\t\tfunction( elem, computed ) {\n\t\t\tif ( computed ) {\n\t\t\t\tcomputed = curCSS( elem, prop );\n\t\t\t\t// If curCSS returns percentage, fallback to offset\n\t\t\t\treturn rnumnonpx.test( computed ) ?\n\t\t\t\t\tjQuery( elem ).position()[ prop ] + \"px\" :\n\t\t\t\t\tcomputed;\n\t\t\t}\n\t\t}\n\t);\n});\n\n\n// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods\njQuery.each( { Height: \"height\", Width: \"width\" }, function( name, type ) {\n\tjQuery.each( { padding: \"inner\" + name, content: type, \"\": \"outer\" + name }, function( defaultExtra, funcName ) {\n\t\t// Margin is only for outerHeight, outerWidth\n\t\tjQuery.fn[ funcName ] = function( margin, value ) {\n\t\t\tvar chainable = arguments.length && ( defaultExtra || typeof margin !== \"boolean\" ),\n\t\t\t\textra = defaultExtra || ( margin === true || value === true ? \"margin\" : \"border\" );\n\n\t\t\treturn access( this, function( elem, type, value ) {\n\t\t\t\tvar doc;\n\n\t\t\t\tif ( jQuery.isWindow( elem ) ) {\n\t\t\t\t\t// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there\n\t\t\t\t\t// isn't a whole lot we can do. See pull request at this URL for discussion:\n\t\t\t\t\t// https://github.com/jquery/jquery/pull/764\n\t\t\t\t\treturn elem.document.documentElement[ \"client\" + name ];\n\t\t\t\t}\n\n\t\t\t\t// Get document width or height\n\t\t\t\tif ( elem.nodeType === 9 ) {\n\t\t\t\t\tdoc = elem.documentElement;\n\n\t\t\t\t\t// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],\n\t\t\t\t\t// whichever is greatest\n\t\t\t\t\treturn Math.max(\n\t\t\t\t\t\telem.body[ \"scroll\" + name ], doc[ \"scroll\" + name ],\n\t\t\t\t\t\telem.body[ \"offset\" + name ], doc[ \"offset\" + name ],\n\t\t\t\t\t\tdoc[ \"client\" + name ]\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\treturn value === undefined ?\n\t\t\t\t\t// Get width or height on the element, requesting but not forcing parseFloat\n\t\t\t\t\tjQuery.css( elem, type, extra ) :\n\n\t\t\t\t\t// Set width or height on the element\n\t\t\t\t\tjQuery.style( elem, type, value, extra );\n\t\t\t}, type, chainable ? margin : undefined, chainable, null );\n\t\t};\n\t});\n});\n\n\n// The number of elements contained in the matched element set\njQuery.fn.size = function() {\n\treturn this.length;\n};\n\njQuery.fn.andSelf = jQuery.fn.addBack;\n\n\n\n\n// Register as a named AMD module, since jQuery can be concatenated with other\n// files that may use define, but not via a proper concatenation script that\n// understands anonymous AMD modules. A named AMD is safest and most robust\n// way to register. Lowercase jquery is used because AMD module names are\n// derived from file names, and jQuery is normally delivered in a lowercase\n// file name. Do this after creating the global so that if an AMD module wants\n// to call noConflict to hide this version of jQuery, it will work.\n\n// Note that for maximum portability, libraries that are not jQuery should\n// declare themselves as anonymous modules, and avoid setting a global if an\n// AMD loader is present. jQuery is a special case. For more information, see\n// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon\n\nif ( typeof define === \"function\" && define.amd ) {\n\tdefine( \"jquery\", [], function() {\n\t\treturn jQuery;\n\t});\n}\n\n\n\n\nvar\n\t// Map over jQuery in case of overwrite\n\t_jQuery = window.jQuery,\n\n\t// Map over the $ in case of overwrite\n\t_$ = window.$;\n\njQuery.noConflict = function( deep ) {\n\tif ( window.$ === jQuery ) {\n\t\twindow.$ = _$;\n\t}\n\n\tif ( deep && window.jQuery === jQuery ) {\n\t\twindow.jQuery = _jQuery;\n\t}\n\n\treturn jQuery;\n};\n\n// Expose jQuery and $ identifiers, even in AMD\n// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)\n// and CommonJS for browser emulators (#13566)\nif ( typeof noGlobal === strundefined ) {\n\twindow.jQuery = window.$ = jQuery;\n}\n\n\n\n\nreturn jQuery;\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/jquery.easy-pie-chart/2.1.6/jquery.easypiechart.js",
    "content": "/**!\n * easyPieChart\n * Lightweight plugin to render simple, animated and retina optimized pie charts\n *\n * @license \n * @author Robert Fleischmann <rendro87@gmail.com> (http://robert-fleischmann.de)\n * @version 2.1.6\n **/\n\n(function(root, factory) {\n    if(typeof exports === 'object') {\n        module.exports = factory(require('jquery'));\n    }\n    else if(typeof define === 'function' && define.amd) {\n        define(['jquery'], factory);\n    }\n    else {\n        factory(root.jQuery);\n    }\n}(this, function($) {\n\n/**\n * Renderer to render the chart on a canvas object\n * @param {DOMElement} el      DOM element to host the canvas (root of the plugin)\n * @param {object}     options options object of the plugin\n */\nvar CanvasRenderer = function(el, options) {\n\tvar cachedBackground;\n\tvar canvas = document.createElement('canvas');\n\n\tel.appendChild(canvas);\n\n\tif (typeof(G_vmlCanvasManager) !== 'undefined') {\n\t\tG_vmlCanvasManager.initElement(canvas);\n\t}\n\n\tvar ctx = canvas.getContext('2d');\n\n\tcanvas.width = canvas.height = options.size;\n\n\t// canvas on retina devices\n\tvar scaleBy = 1;\n\tif (window.devicePixelRatio > 1) {\n\t\tscaleBy = window.devicePixelRatio;\n\t\tcanvas.style.width = canvas.style.height = [options.size, 'px'].join('');\n\t\tcanvas.width = canvas.height = options.size * scaleBy;\n\t\tctx.scale(scaleBy, scaleBy);\n\t}\n\n\t// move 0,0 coordinates to the center\n\tctx.translate(options.size / 2, options.size / 2);\n\n\t// rotate canvas -90deg\n\tctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI);\n\n\tvar radius = (options.size - options.lineWidth) / 2;\n\tif (options.scaleColor && options.scaleLength) {\n\t\tradius -= options.scaleLength + 2; // 2 is the distance between scale and bar\n\t}\n\n\t// IE polyfill for Date\n\tDate.now = Date.now || function() {\n\t\treturn +(new Date());\n\t};\n\n\t/**\n\t * Draw a circle around the center of the canvas\n\t * @param {strong} color     Valid CSS color string\n\t * @param {number} lineWidth Width of the line in px\n\t * @param {number} percent   Percentage to draw (float between -1 and 1)\n\t */\n\tvar drawCircle = function(color, lineWidth, percent) {\n\t\tpercent = Math.min(Math.max(-1, percent || 0), 1);\n\t\tvar isNegative = percent <= 0 ? true : false;\n\n\t\tctx.beginPath();\n\t\tctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, isNegative);\n\n\t\tctx.strokeStyle = color;\n\t\tctx.lineWidth = lineWidth;\n\n\t\tctx.stroke();\n\t};\n\n\t/**\n\t * Draw the scale of the chart\n\t */\n\tvar drawScale = function() {\n\t\tvar offset;\n\t\tvar length;\n\n\t\tctx.lineWidth = 1;\n\t\tctx.fillStyle = options.scaleColor;\n\n\t\tctx.save();\n\t\tfor (var i = 24; i > 0; --i) {\n\t\t\tif (i % 6 === 0) {\n\t\t\t\tlength = options.scaleLength;\n\t\t\t\toffset = 0;\n\t\t\t} else {\n\t\t\t\tlength = options.scaleLength * 0.6;\n\t\t\t\toffset = options.scaleLength - length;\n\t\t\t}\n\t\t\tctx.fillRect(-options.size/2 + offset, 0, length, 1);\n\t\t\tctx.rotate(Math.PI / 12);\n\t\t}\n\t\tctx.restore();\n\t};\n\n\t/**\n\t * Request animation frame wrapper with polyfill\n\t * @return {function} Request animation frame method or timeout fallback\n\t */\n\tvar reqAnimationFrame = (function() {\n\t\treturn  window.requestAnimationFrame ||\n\t\t\t\twindow.webkitRequestAnimationFrame ||\n\t\t\t\twindow.mozRequestAnimationFrame ||\n\t\t\t\tfunction(callback) {\n\t\t\t\t\twindow.setTimeout(callback, 1000 / 60);\n\t\t\t\t};\n\t}());\n\n\t/**\n\t * Draw the background of the plugin including the scale and the track\n\t */\n\tvar drawBackground = function() {\n\t\tif(options.scaleColor) drawScale();\n\t\tif(options.trackColor) drawCircle(options.trackColor, options.trackWidth || options.lineWidth, 1);\n\t};\n\n  /**\n    * Canvas accessor\n   */\n  this.getCanvas = function() {\n    return canvas;\n  };\n\n  /**\n    * Canvas 2D context 'ctx' accessor\n   */\n  this.getCtx = function() {\n    return ctx;\n  };\n\n\t/**\n\t * Clear the complete canvas\n\t */\n\tthis.clear = function() {\n\t\tctx.clearRect(options.size / -2, options.size / -2, options.size, options.size);\n\t};\n\n\t/**\n\t * Draw the complete chart\n\t * @param {number} percent Percent shown by the chart between -100 and 100\n\t */\n\tthis.draw = function(percent) {\n\t\t// do we need to render a background\n\t\tif (!!options.scaleColor || !!options.trackColor) {\n\t\t\t// getImageData and putImageData are supported\n\t\t\tif (ctx.getImageData && ctx.putImageData) {\n\t\t\t\tif (!cachedBackground) {\n\t\t\t\t\tdrawBackground();\n\t\t\t\t\tcachedBackground = ctx.getImageData(0, 0, options.size * scaleBy, options.size * scaleBy);\n\t\t\t\t} else {\n\t\t\t\t\tctx.putImageData(cachedBackground, 0, 0);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.clear();\n\t\t\t\tdrawBackground();\n\t\t\t}\n\t\t} else {\n\t\t\tthis.clear();\n\t\t}\n\n\t\tctx.lineCap = options.lineCap;\n\n\t\t// if barcolor is a function execute it and pass the percent as a value\n\t\tvar color;\n\t\tif (typeof(options.barColor) === 'function') {\n\t\t\tcolor = options.barColor(percent);\n\t\t} else {\n\t\t\tcolor = options.barColor;\n\t\t}\n\n\t\t// draw bar\n\t\tdrawCircle(color, options.lineWidth, percent / 100);\n\t}.bind(this);\n\n\t/**\n\t * Animate from some percent to some other percentage\n\t * @param {number} from Starting percentage\n\t * @param {number} to   Final percentage\n\t */\n\tthis.animate = function(from, to) {\n\t\tvar startTime = Date.now();\n\t\toptions.onStart(from, to);\n\t\tvar animation = function() {\n\t\t\tvar process = Math.min(Date.now() - startTime, options.animate.duration);\n\t\t\tvar currentValue = options.easing(this, process, from, to - from, options.animate.duration);\n\t\t\tthis.draw(currentValue);\n\t\t\toptions.onStep(from, to, currentValue);\n\t\t\tif (process >= options.animate.duration) {\n\t\t\t\toptions.onStop(from, to);\n\t\t\t} else {\n\t\t\t\treqAnimationFrame(animation);\n\t\t\t}\n\t\t}.bind(this);\n\n\t\treqAnimationFrame(animation);\n\t}.bind(this);\n};\n\nvar EasyPieChart = function(el, opts) {\n\tvar defaultOptions = {\n\t\tbarColor: '#ef1e25',\n\t\ttrackColor: '#f9f9f9',\n\t\tscaleColor: '#dfe0e0',\n\t\tscaleLength: 5,\n\t\tlineCap: 'round',\n\t\tlineWidth: 3,\n\t\ttrackWidth: undefined,\n\t\tsize: 110,\n\t\trotate: 0,\n\t\tanimate: {\n\t\t\tduration: 1000,\n\t\t\tenabled: true\n\t\t},\n\t\teasing: function (x, t, b, c, d) { // more can be found here: http://gsgd.co.uk/sandbox/jquery/easing/\n\t\t\tt = t / (d/2);\n\t\t\tif (t < 1) {\n\t\t\t\treturn c / 2 * t * t + b;\n\t\t\t}\n\t\t\treturn -c/2 * ((--t)*(t-2) - 1) + b;\n\t\t},\n\t\tonStart: function(from, to) {\n\t\t\treturn;\n\t\t},\n\t\tonStep: function(from, to, currentValue) {\n\t\t\treturn;\n\t\t},\n\t\tonStop: function(from, to) {\n\t\t\treturn;\n\t\t}\n\t};\n\n\t// detect present renderer\n\tif (typeof(CanvasRenderer) !== 'undefined') {\n\t\tdefaultOptions.renderer = CanvasRenderer;\n\t} else if (typeof(SVGRenderer) !== 'undefined') {\n\t\tdefaultOptions.renderer = SVGRenderer;\n\t} else {\n\t\tthrow new Error('Please load either the SVG- or the CanvasRenderer');\n\t}\n\n\tvar options = {};\n\tvar currentValue = 0;\n\n\t/**\n\t * Initialize the plugin by creating the options object and initialize rendering\n\t */\n\tvar init = function() {\n\t\tthis.el = el;\n\t\tthis.options = options;\n\n\t\t// merge user options into default options\n\t\tfor (var i in defaultOptions) {\n\t\t\tif (defaultOptions.hasOwnProperty(i)) {\n\t\t\t\toptions[i] = opts && typeof(opts[i]) !== 'undefined' ? opts[i] : defaultOptions[i];\n\t\t\t\tif (typeof(options[i]) === 'function') {\n\t\t\t\t\toptions[i] = options[i].bind(this);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// check for jQuery easing\n\t\tif (typeof(options.easing) === 'string' && typeof(jQuery) !== 'undefined' && jQuery.isFunction(jQuery.easing[options.easing])) {\n\t\t\toptions.easing = jQuery.easing[options.easing];\n\t\t} else {\n\t\t\toptions.easing = defaultOptions.easing;\n\t\t}\n\n\t\t// process earlier animate option to avoid bc breaks\n\t\tif (typeof(options.animate) === 'number') {\n\t\t\toptions.animate = {\n\t\t\t\tduration: options.animate,\n\t\t\t\tenabled: true\n\t\t\t};\n\t\t}\n\n\t\tif (typeof(options.animate) === 'boolean' && !options.animate) {\n\t\t\toptions.animate = {\n\t\t\t\tduration: 1000,\n\t\t\t\tenabled: options.animate\n\t\t\t};\n\t\t}\n\n\t\t// create renderer\n\t\tthis.renderer = new options.renderer(el, options);\n\n\t\t// initial draw\n\t\tthis.renderer.draw(currentValue);\n\n\t\t// initial update\n\t\tif (el.dataset && el.dataset.percent) {\n\t\t\tthis.update(parseFloat(el.dataset.percent));\n\t\t} else if (el.getAttribute && el.getAttribute('data-percent')) {\n\t\t\tthis.update(parseFloat(el.getAttribute('data-percent')));\n\t\t}\n\t}.bind(this);\n\n\t/**\n\t * Update the value of the chart\n\t * @param  {number} newValue Number between 0 and 100\n\t * @return {object}          Instance of the plugin for method chaining\n\t */\n\tthis.update = function(newValue) {\n\t\tnewValue = parseFloat(newValue);\n\t\tif (options.animate.enabled) {\n\t\t\tthis.renderer.animate(currentValue, newValue);\n\t\t} else {\n\t\t\tthis.renderer.draw(newValue);\n\t\t}\n\t\tcurrentValue = newValue;\n\t\treturn this;\n\t}.bind(this);\n\n\t/**\n\t * Disable animation\n\t * @return {object} Instance of the plugin for method chaining\n\t */\n\tthis.disableAnimation = function() {\n\t\toptions.animate.enabled = false;\n\t\treturn this;\n\t};\n\n\t/**\n\t * Enable animation\n\t * @return {object} Instance of the plugin for method chaining\n\t */\n\tthis.enableAnimation = function() {\n\t\toptions.animate.enabled = true;\n\t\treturn this;\n\t};\n\n\tinit();\n};\n\n$.fn.easyPieChart = function(options) {\n\treturn this.each(function() {\n\t\tvar instanceOptions;\n\n\t\tif (!$.data(this, 'easyPieChart')) {\n\t\t\tinstanceOptions = $.extend({}, options, $(this).data());\n\t\t\t$.data(this, 'easyPieChart', new EasyPieChart(this, instanceOptions));\n\t\t}\n\t});\n};\n\n\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.css",
    "content": "/*\n== malihu jquery custom scrollbar plugin ==\nPlugin URI: http://manos.malihu.gr/jquery-custom-content-scroller\n*/\n\n\n\n/*\nCONTENTS: \n\t1. BASIC STYLE - Plugin's basic/essential CSS properties (normally, should not be edited). \n\t2. VERTICAL SCROLLBAR - Positioning and dimensions of vertical scrollbar. \n\t3. HORIZONTAL SCROLLBAR - Positioning and dimensions of horizontal scrollbar.\n\t4. VERTICAL AND HORIZONTAL SCROLLBARS - Positioning and dimensions of 2-axis scrollbars. \n\t5. TRANSITIONS - CSS3 transitions for hover events, auto-expanded and auto-hidden scrollbars. \n\t6. SCROLLBAR COLORS, OPACITY AND BACKGROUNDS \n\t\t6.1 THEMES - Scrollbar colors, opacity, dimensions, backgrounds etc. via ready-to-use themes.\n*/\n\n\n\n/* \n------------------------------------------------------------------------------------------------------------------------\n1. BASIC STYLE  \n------------------------------------------------------------------------------------------------------------------------\n*/\n\n\t.mCustomScrollbar{ -ms-touch-action: pinch-zoom; touch-action: pinch-zoom; /* direct pointer events to js */ }\n\t.mCustomScrollbar.mCS_no_scrollbar, .mCustomScrollbar.mCS_touch_action{ -ms-touch-action: auto; touch-action: auto; }\n\t\n\t.mCustomScrollBox{ /* contains plugin's markup */\n\t\tposition: relative;\n\t\toverflow: hidden;\n\t\theight: 100%;\n\t\tmax-width: 100%;\n\t\toutline: none;\n\t\tdirection: ltr;\n\t}\n\n\t.mCSB_container{ /* contains the original content */\n\t\toverflow: hidden;\n\t\twidth: auto;\n\t\theight: auto;\n\t}\n\n\n\n/* \n------------------------------------------------------------------------------------------------------------------------\n2. VERTICAL SCROLLBAR \ny-axis\n------------------------------------------------------------------------------------------------------------------------\n*/\n\n\t.mCSB_inside > .mCSB_container{ margin-right: 30px; }\n\n\t.mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden{ margin-right: 0; } /* non-visible scrollbar */\n\t\n\t.mCS-dir-rtl > .mCSB_inside > .mCSB_container{ /* RTL direction/left-side scrollbar */\n\t\tmargin-right: 0;\n\t\tmargin-left: 30px;\n\t}\n\t\n\t.mCS-dir-rtl > .mCSB_inside > .mCSB_container.mCS_no_scrollbar_y.mCS_y_hidden{ margin-left: 0; } /* RTL direction/left-side scrollbar */\n\n\t.mCSB_scrollTools{ /* contains scrollbar markup (draggable element, dragger rail, buttons etc.) */\n\t\tposition: absolute;\n\t\twidth: 16px;\n\t\theight: auto;\n\t\tleft: auto;\n\t\ttop: 0;\n\t\tright: 0;\n\t\tbottom: 0;\n\t}\n\n\t.mCSB_outside + .mCSB_scrollTools{ right: -26px; } /* scrollbar position: outside */\n\t\n\t.mCS-dir-rtl > .mCSB_inside > .mCSB_scrollTools, \n\t.mCS-dir-rtl > .mCSB_outside + .mCSB_scrollTools{ /* RTL direction/left-side scrollbar */\n\t\tright: auto;\n\t\tleft: 0;\n\t}\n\t\n\t.mCS-dir-rtl > .mCSB_outside + .mCSB_scrollTools{ left: -26px; } /* RTL direction/left-side scrollbar (scrollbar position: outside) */\n\n\t.mCSB_scrollTools .mCSB_draggerContainer{ /* contains the draggable element and dragger rail markup */\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\tbottom: 0;\n\t\tright: 0; \n\t\theight: auto;\n\t}\n\n\t.mCSB_scrollTools a + .mCSB_draggerContainer{ margin: 20px 0; }\n\n\t.mCSB_scrollTools .mCSB_draggerRail{\n\t\twidth: 2px;\n\t\theight: 100%;\n\t\tmargin: 0 auto;\n\t\t-webkit-border-radius: 16px; -moz-border-radius: 16px; border-radius: 16px;\n\t}\n\n\t.mCSB_scrollTools .mCSB_dragger{ /* the draggable element */\n\t\tcursor: pointer;\n\t\twidth: 100%;\n\t\theight: 30px; /* minimum dragger height */\n\t\tz-index: 1;\n\t}\n\n\t.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ /* the dragger element */\n\t\tposition: relative;\n\t\twidth: 4px;\n\t\theight: 100%;\n\t\tmargin: 0 auto;\n\t\t-webkit-border-radius: 16px; -moz-border-radius: 16px; border-radius: 16px;\n\t\ttext-align: center;\n\t}\n\t\n\t.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar, \n\t.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{ width: 12px; /* auto-expanded scrollbar */ }\n\t\n\t.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{ width: 8px; /* auto-expanded scrollbar */ }\n\n\t.mCSB_scrollTools .mCSB_buttonUp,\n\t.mCSB_scrollTools .mCSB_buttonDown{\n\t\tdisplay: block;\n\t\tposition: absolute;\n\t\theight: 20px;\n\t\twidth: 100%;\n\t\toverflow: hidden;\n\t\tmargin: 0 auto;\n\t\tcursor: pointer;\n\t}\n\n\t.mCSB_scrollTools .mCSB_buttonDown{ bottom: 0; }\n\n\n\n/* \n------------------------------------------------------------------------------------------------------------------------\n3. HORIZONTAL SCROLLBAR \nx-axis\n------------------------------------------------------------------------------------------------------------------------\n*/\n\n\t.mCSB_horizontal.mCSB_inside > .mCSB_container{\n\t\tmargin-right: 0;\n\t\tmargin-bottom: 30px;\n\t}\n\t\n\t.mCSB_horizontal.mCSB_outside > .mCSB_container{ min-height: 100%; }\n\n\t.mCSB_horizontal > .mCSB_container.mCS_no_scrollbar_x.mCS_x_hidden{ margin-bottom: 0; } /* non-visible scrollbar */\n\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal{\n\t\twidth: auto;\n\t\theight: 16px;\n\t\ttop: auto;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\tleft: 0;\n\t}\n\n\t.mCustomScrollBox + .mCSB_scrollTools.mCSB_scrollTools_horizontal,\n\t.mCustomScrollBox + .mCSB_scrollTools + .mCSB_scrollTools.mCSB_scrollTools_horizontal{ bottom: -26px; } /* scrollbar position: outside */\n\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal a + .mCSB_draggerContainer{ margin: 0 20px; }\n\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_draggerRail{\n\t\twidth: 100%;\n\t\theight: 2px;\n\t\tmargin: 7px 0;\n\t}\n\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_dragger{\n\t\twidth: 30px; /* minimum dragger width */\n\t\theight: 100%;\n\t\tleft: 0;\n\t}\n\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 100%;\n\t\theight: 4px;\n\t\tmargin: 6px auto;\n\t}\n\t\n\t.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar, \n\t.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{\n\t\theight: 12px; /* auto-expanded scrollbar */\n\t\tmargin: 2px auto;\n\t}\n\t\n\t.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{\n\t\theight: 8px; /* auto-expanded scrollbar */\n\t\tmargin: 4px 0;\n\t}\n\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonLeft,\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonRight{\n\t\tdisplay: block;\n\t\tposition: absolute;\n\t\twidth: 20px;\n\t\theight: 100%;\n\t\toverflow: hidden;\n\t\tmargin: 0 auto;\n\t\tcursor: pointer;\n\t}\n\t\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonLeft{ left: 0; }\n\n\t.mCSB_scrollTools.mCSB_scrollTools_horizontal .mCSB_buttonRight{ right: 0; }\n\n\n\n/* \n------------------------------------------------------------------------------------------------------------------------\n4. VERTICAL AND HORIZONTAL SCROLLBARS \nyx-axis \n------------------------------------------------------------------------------------------------------------------------\n*/\n\n\t.mCSB_container_wrapper{\n\t\tposition: absolute;\n\t\theight: auto;\n\t\twidth: auto;\n\t\toverflow: hidden;\n\t\ttop: 0;\n\t\tleft: 0;\n\t\tright: 0;\n\t\tbottom: 0;\n\t\tmargin-right: 30px;\n\t\tmargin-bottom: 30px;\n\t}\n\t\n\t.mCSB_container_wrapper > .mCSB_container{\n\t\tpadding-right: 30px;\n\t\tpadding-bottom: 30px;\n\t\t-webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;\n\t}\n\t\n\t.mCSB_vertical_horizontal > .mCSB_scrollTools.mCSB_scrollTools_vertical{ bottom: 20px; }\n\t\n\t.mCSB_vertical_horizontal > .mCSB_scrollTools.mCSB_scrollTools_horizontal{ right: 20px; }\n\t\n\t/* non-visible horizontal scrollbar */\n\t.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden + .mCSB_scrollTools.mCSB_scrollTools_vertical{ bottom: 0; }\n\t\n\t/* non-visible vertical scrollbar/RTL direction/left-side scrollbar */\n\t.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden + .mCSB_scrollTools ~ .mCSB_scrollTools.mCSB_scrollTools_horizontal, \n\t.mCS-dir-rtl > .mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_scrollTools.mCSB_scrollTools_horizontal{ right: 0; }\n\t\n\t/* RTL direction/left-side scrollbar */\n\t.mCS-dir-rtl > .mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_scrollTools.mCSB_scrollTools_horizontal{ left: 20px; }\n\t\n\t/* non-visible scrollbar/RTL direction/left-side scrollbar */\n\t.mCS-dir-rtl > .mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden + .mCSB_scrollTools ~ .mCSB_scrollTools.mCSB_scrollTools_horizontal{ left: 0; }\n\t\n\t.mCS-dir-rtl > .mCSB_inside > .mCSB_container_wrapper{ /* RTL direction/left-side scrollbar */\n\t\tmargin-right: 0;\n\t\tmargin-left: 30px;\n\t}\n\t\n\t.mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden > .mCSB_container{ padding-right: 0; }\n\t\n\t.mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden > .mCSB_container{ padding-bottom: 0; }\n\t\n\t.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_container_wrapper.mCS_no_scrollbar_y.mCS_y_hidden{\n\t\tmargin-right: 0; /* non-visible scrollbar */\n\t\tmargin-left: 0;\n\t}\n\t\n\t/* non-visible horizontal scrollbar */\n\t.mCustomScrollBox.mCSB_vertical_horizontal.mCSB_inside > .mCSB_container_wrapper.mCS_no_scrollbar_x.mCS_x_hidden{ margin-bottom: 0; }\n\n\n\n/* \n------------------------------------------------------------------------------------------------------------------------\n5. TRANSITIONS  \n------------------------------------------------------------------------------------------------------------------------\n*/\n\n\t.mCSB_scrollTools, \n\t.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCSB_scrollTools .mCSB_buttonUp,\n\t.mCSB_scrollTools .mCSB_buttonDown,\n\t.mCSB_scrollTools .mCSB_buttonLeft,\n\t.mCSB_scrollTools .mCSB_buttonRight{\n\t\t-webkit-transition: opacity .2s ease-in-out, background-color .2s ease-in-out;\n\t\t-moz-transition: opacity .2s ease-in-out, background-color .2s ease-in-out;\n\t\t-o-transition: opacity .2s ease-in-out, background-color .2s ease-in-out;\n\t\ttransition: opacity .2s ease-in-out, background-color .2s ease-in-out;\n\t}\n\t\n\t.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger_bar, /* auto-expanded scrollbar */\n\t.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerRail, \n\t.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger_bar, \n\t.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerRail{\n\t\t-webkit-transition: width .2s ease-out .2s, height .2s ease-out .2s, \n\t\t\t\t\tmargin-left .2s ease-out .2s, margin-right .2s ease-out .2s, \n\t\t\t\t\tmargin-top .2s ease-out .2s, margin-bottom .2s ease-out .2s,\n\t\t\t\t\topacity .2s ease-in-out, background-color .2s ease-in-out; \n\t\t-moz-transition: width .2s ease-out .2s, height .2s ease-out .2s, \n\t\t\t\t\tmargin-left .2s ease-out .2s, margin-right .2s ease-out .2s, \n\t\t\t\t\tmargin-top .2s ease-out .2s, margin-bottom .2s ease-out .2s,\n\t\t\t\t\topacity .2s ease-in-out, background-color .2s ease-in-out; \n\t\t-o-transition: width .2s ease-out .2s, height .2s ease-out .2s, \n\t\t\t\t\tmargin-left .2s ease-out .2s, margin-right .2s ease-out .2s, \n\t\t\t\t\tmargin-top .2s ease-out .2s, margin-bottom .2s ease-out .2s,\n\t\t\t\t\topacity .2s ease-in-out, background-color .2s ease-in-out; \n\t\ttransition: width .2s ease-out .2s, height .2s ease-out .2s, \n\t\t\t\t\tmargin-left .2s ease-out .2s, margin-right .2s ease-out .2s, \n\t\t\t\t\tmargin-top .2s ease-out .2s, margin-bottom .2s ease-out .2s,\n\t\t\t\t\topacity .2s ease-in-out, background-color .2s ease-in-out; \n\t}\n\n\n\n/* \n------------------------------------------------------------------------------------------------------------------------\n6. SCROLLBAR COLORS, OPACITY AND BACKGROUNDS  \n------------------------------------------------------------------------------------------------------------------------\n*/\n\n\t/* \n\t----------------------------------------\n\t6.1 THEMES \n\t----------------------------------------\n\t*/\n\t\n\t/* default theme (\"light\") */\n\n\t.mCSB_scrollTools{ opacity: 0.75; filter: \"alpha(opacity=75)\"; -ms-filter: \"alpha(opacity=75)\"; }\n\t\n\t.mCS-autoHide > .mCustomScrollBox > .mCSB_scrollTools,\n\t.mCS-autoHide > .mCustomScrollBox ~ .mCSB_scrollTools{ opacity: 0; filter: \"alpha(opacity=0)\"; -ms-filter: \"alpha(opacity=0)\"; }\n\t\n\t.mCustomScrollbar > .mCustomScrollBox > .mCSB_scrollTools.mCSB_scrollTools_onDrag,\n\t.mCustomScrollbar > .mCustomScrollBox ~ .mCSB_scrollTools.mCSB_scrollTools_onDrag,\n\t.mCustomScrollBox:hover > .mCSB_scrollTools,\n\t.mCustomScrollBox:hover ~ .mCSB_scrollTools,\n\t.mCS-autoHide:hover > .mCustomScrollBox > .mCSB_scrollTools,\n\t.mCS-autoHide:hover > .mCustomScrollBox ~ .mCSB_scrollTools{ opacity: 1; filter: \"alpha(opacity=100)\"; -ms-filter: \"alpha(opacity=100)\"; }\n\n\t.mCSB_scrollTools .mCSB_draggerRail{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.4);\n\t\tfilter: \"alpha(opacity=40)\"; -ms-filter: \"alpha(opacity=40)\"; \n\t}\n\n\t.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.75);\n\t\tfilter: \"alpha(opacity=75)\"; -ms-filter: \"alpha(opacity=75)\"; \n\t}\n\n\t.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.85);\n\t\tfilter: \"alpha(opacity=85)\"; -ms-filter: \"alpha(opacity=85)\"; \n\t}\n\t.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.9);\n\t\tfilter: \"alpha(opacity=90)\"; -ms-filter: \"alpha(opacity=90)\"; \n\t}\n\n\t.mCSB_scrollTools .mCSB_buttonUp,\n\t.mCSB_scrollTools .mCSB_buttonDown,\n\t.mCSB_scrollTools .mCSB_buttonLeft,\n\t.mCSB_scrollTools .mCSB_buttonRight{\n\t\tbackground-image: url(mCSB_buttons.png); /* css sprites */\n\t\tbackground-repeat: no-repeat;\n\t\topacity: 0.4; filter: \"alpha(opacity=40)\"; -ms-filter: \"alpha(opacity=40)\"; \n\t}\n\n\t.mCSB_scrollTools .mCSB_buttonUp{\n\t\tbackground-position: 0 0;\n\t\t/* \n\t\tsprites locations \n\t\tlight: 0 0, -16px 0, -32px 0, -48px 0, 0 -72px, -16px -72px, -32px -72px\n\t\tdark: -80px 0, -96px 0, -112px 0, -128px 0, -80px -72px, -96px -72px, -112px -72px\n\t\t*/\n\t}\n\n\t.mCSB_scrollTools .mCSB_buttonDown{\n\t\tbackground-position: 0 -20px;\n\t\t/* \n\t\tsprites locations\n\t\tlight: 0 -20px, -16px -20px, -32px -20px, -48px -20px, 0 -92px, -16px -92px, -32px -92px\n\t\tdark: -80px -20px, -96px -20px, -112px -20px, -128px -20px, -80px -92px, -96px -92px, -112 -92px\n\t\t*/\n\t}\n\n\t.mCSB_scrollTools .mCSB_buttonLeft{\n\t\tbackground-position: 0 -40px;\n\t\t/* \n\t\tsprites locations \n\t\tlight: 0 -40px, -20px -40px, -40px -40px, -60px -40px, 0 -112px, -20px -112px, -40px -112px\n\t\tdark: -80px -40px, -100px -40px, -120px -40px, -140px -40px, -80px -112px, -100px -112px, -120px -112px\n\t\t*/\n\t}\n\n\t.mCSB_scrollTools .mCSB_buttonRight{\n\t\tbackground-position: 0 -56px;\n\t\t/* \n\t\tsprites locations \n\t\tlight: 0 -56px, -20px -56px, -40px -56px, -60px -56px, 0 -128px, -20px -128px, -40px -128px\n\t\tdark: -80px -56px, -100px -56px, -120px -56px, -140px -56px, -80px -128px, -100px -128px, -120px -128px\n\t\t*/\n\t}\n\n\t.mCSB_scrollTools .mCSB_buttonUp:hover,\n\t.mCSB_scrollTools .mCSB_buttonDown:hover,\n\t.mCSB_scrollTools .mCSB_buttonLeft:hover,\n\t.mCSB_scrollTools .mCSB_buttonRight:hover{ opacity: 0.75; filter: \"alpha(opacity=75)\"; -ms-filter: \"alpha(opacity=75)\"; }\n\n\t.mCSB_scrollTools .mCSB_buttonUp:active,\n\t.mCSB_scrollTools .mCSB_buttonDown:active,\n\t.mCSB_scrollTools .mCSB_buttonLeft:active,\n\t.mCSB_scrollTools .mCSB_buttonRight:active{ opacity: 0.9; filter: \"alpha(opacity=90)\"; -ms-filter: \"alpha(opacity=90)\"; }\n\t\n\n\t/* theme: \"dark\" */\n\n\t.mCS-dark.mCSB_scrollTools .mCSB_draggerRail{ background-color: #000; background-color: rgba(0,0,0,0.15); }\n\n\t.mCS-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.75); }\n\n\t.mCS-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: rgba(0,0,0,0.85); }\n\n\t.mCS-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: rgba(0,0,0,0.9); }\n\n\t.mCS-dark.mCSB_scrollTools .mCSB_buttonUp{ background-position: -80px 0; }\n\n\t.mCS-dark.mCSB_scrollTools .mCSB_buttonDown{ background-position: -80px -20px; }\n\n\t.mCS-dark.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -80px -40px; }\n\n\t.mCS-dark.mCSB_scrollTools .mCSB_buttonRight{ background-position: -80px -56px; }\n\t\n\t/* ---------------------------------------- */\n\t\n\n\n\t/* theme: \"light-2\", \"dark-2\" */\n\n\t.mCS-light-2.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-dark-2.mCSB_scrollTools .mCSB_draggerRail{\n\t\twidth: 4px;\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.1);\n\t\t-webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px;\n\t}\n\n\t.mCS-light-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-dark-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 4px;\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.75);\n\t\t-webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px;\n\t}\n\n\t.mCS-light-2.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-dark-2.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-light-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-dark-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 100%;\n\t\theight: 4px;\n\t\tmargin: 6px auto;\n\t}\n\n\t.mCS-light-2.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #fff; background-color: rgba(255,255,255,0.85); }\n\n\t.mCS-light-2.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-light-2.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #fff; background-color: rgba(255,255,255,0.9); }\n\n\t.mCS-light-2.mCSB_scrollTools .mCSB_buttonUp{ background-position: -32px 0; }\n\n\t.mCS-light-2.mCSB_scrollTools .mCSB_buttonDown{\tbackground-position: -32px -20px; }\n\n\t.mCS-light-2.mCSB_scrollTools .mCSB_buttonLeft{\tbackground-position: -40px -40px; }\n\n\t.mCS-light-2.mCSB_scrollTools .mCSB_buttonRight{ background-position: -40px -56px; }\n\t\n\t\n\t/* theme: \"dark-2\" */\n\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_draggerRail{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.1);\n\t\t-webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px;\n\t}\n\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.75);\n\t\t-webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px;\n\t}\n\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.85); }\n\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.9); }\n\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_buttonUp{ background-position: -112px 0; }\n\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_buttonDown{ background-position: -112px -20px; }\n\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -120px -40px; }\n\n\t.mCS-dark-2.mCSB_scrollTools .mCSB_buttonRight{\tbackground-position: -120px -56px; }\n\t\n\t/* ---------------------------------------- */\n\t\n\n\n\t/* theme: \"light-thick\", \"dark-thick\" */\n\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_draggerRail{\n\t\twidth: 4px;\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.1);\n\t\t-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;\n\t}\n\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 6px;\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.75);\n\t\t-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;\n\t}\n\n\t.mCS-light-thick.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-dark-thick.mCSB_scrollTools_horizontal .mCSB_draggerRail{\n\t\twidth: 100%;\n\t\theight: 4px;\n\t\tmargin: 6px 0;\n\t}\n\n\t.mCS-light-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-dark-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 100%;\n\t\theight: 6px;\n\t\tmargin: 5px auto;\n\t}\n\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #fff; background-color: rgba(255,255,255,0.85); }\n\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #fff; background-color: rgba(255,255,255,0.9); }\n\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_buttonUp{ background-position: -16px 0; }\n\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_buttonDown{\tbackground-position: -16px -20px; }\n\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_buttonLeft{\tbackground-position: -20px -40px; }\n\n\t.mCS-light-thick.mCSB_scrollTools .mCSB_buttonRight{ background-position: -20px -56px; }\n\n\n\t/* theme: \"dark-thick\" */\n\t\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_draggerRail{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.1);\n\t\t-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;\n\t}\n\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.75);\n\t\t-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;\n\t}\n\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.85); }\n\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.9); }\n\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonUp{ background-position: -96px 0; }\n\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonDown{ background-position: -96px -20px; }\n\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -100px -40px; }\n\n\t.mCS-dark-thick.mCSB_scrollTools .mCSB_buttonRight{\tbackground-position: -100px -56px; }\n\t\n\t/* ---------------------------------------- */\n\t\n\n\n\t/* theme: \"light-thin\", \"dark-thin\" */\n\t\n\t.mCS-light-thin.mCSB_scrollTools .mCSB_draggerRail{ background-color: #fff; background-color: rgba(255,255,255,0.1); }\n\n\t.mCS-light-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ width: 2px; }\n\n\t.mCS-light-thin.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-dark-thin.mCSB_scrollTools_horizontal .mCSB_draggerRail{ width: 100%; }\n\n\t.mCS-light-thin.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-dark-thin.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 100%;\n\t\theight: 2px;\n\t\tmargin: 7px auto;\n\t}\n\n\n\t/* theme \"dark-thin\" */\n\t\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_draggerRail{ background-color: #000; background-color: rgba(0,0,0,0.15); }\n\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.75); }\n\t\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.85); }\n\t\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.9); }\n\t\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonUp{\tbackground-position: -80px 0; }\n\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonDown{ background-position: -80px -20px; }\n\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -80px -40px; }\n\n\t.mCS-dark-thin.mCSB_scrollTools .mCSB_buttonRight{ background-position: -80px -56px; }\n\t\n\t/* ---------------------------------------- */\n\t\n\t\n\t\n\t/* theme \"rounded\", \"rounded-dark\", \"rounded-dots\", \"rounded-dots-dark\" */\n\t\n\t.mCS-rounded.mCSB_scrollTools .mCSB_draggerRail{ background-color: #fff; background-color: rgba(255,255,255,0.15); }\n\t\n\t.mCS-rounded.mCSB_scrollTools .mCSB_dragger, \n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger, \n\t.mCS-rounded-dots.mCSB_scrollTools .mCSB_dragger, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger{ height: 14px; }\n\t\n\t.mCS-rounded.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dots.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 14px;\n\t\tmargin: 0 1px;\n\t}\n\t\n\t.mCS-rounded.mCSB_scrollTools_horizontal .mCSB_dragger, \n\t.mCS-rounded-dark.mCSB_scrollTools_horizontal .mCSB_dragger, \n\t.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_dragger, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_dragger{ width: 14px; }\n\t\n\t.mCS-rounded.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\theight: 14px;\n\t\tmargin: 1px 0;\n\t}\n\t\n\t.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar, \n\t.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar, \n\t.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 16px; /* auto-expanded scrollbar */\n\t\theight: 16px;\n\t\tmargin: -1px 0;\n\t}\n\t\n\t.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCS-rounded.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail, \n\t.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCS-rounded-dark.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{ width: 4px; /* auto-expanded scrollbar */ }\n\t\n\t.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar, \n\t.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded .mCSB_dragger_bar, \n\t.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_dragger .mCSB_dragger_bar{\n\t\theight: 16px; /* auto-expanded scrollbar */\n\t\twidth: 16px;\n\t\tmargin: 0 -1px;\n\t}\n\t\n\t.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCS-rounded.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail, \n\t.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCS-rounded-dark.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{\n\t\theight: 4px; /* auto-expanded scrollbar */\n\t\tmargin: 6px 0;\n\t}\n\t\n\t.mCS-rounded.mCSB_scrollTools .mCSB_buttonUp{ background-position: 0 -72px; }\n\t\n\t.mCS-rounded.mCSB_scrollTools .mCSB_buttonDown{ background-position: 0 -92px; }\n\t\n\t.mCS-rounded.mCSB_scrollTools .mCSB_buttonLeft{ background-position: 0 -112px; }\n\t\n\t.mCS-rounded.mCSB_scrollTools .mCSB_buttonRight{ background-position: 0 -128px; }\n\t\n\t\n\t/* theme \"rounded-dark\", \"rounded-dots-dark\" */\n\t\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.75); }\n\t\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_draggerRail{ background-color: #000; background-color: rgba(0,0,0,0.15); }\n\t\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.85); }\n\t\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.9); }\n\t\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonUp{ background-position: -80px -72px; }\n\t\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonDown{ background-position: -80px -92px; }\n\t\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -80px -112px; }\n\t\n\t.mCS-rounded-dark.mCSB_scrollTools .mCSB_buttonRight{ background-position: -80px -128px; }\n\t\n\t\n\t/* theme \"rounded-dots\", \"rounded-dots-dark\" */\n\t\n\t.mCS-rounded-dots.mCSB_scrollTools_vertical .mCSB_draggerRail, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools_vertical .mCSB_draggerRail{ width: 4px; }\n\t\n\t.mCS-rounded-dots.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail{\n\t\tbackground-color: transparent;\n\t\tbackground-position: center;\n\t}\n\t\n\t.mCS-rounded-dots.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail{\n\t\tbackground-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAANElEQVQYV2NkIAAYiVbw//9/Y6DiM1ANJoyMjGdBbLgJQAX/kU0DKgDLkaQAvxW4HEvQFwCRcxIJK1XznAAAAABJRU5ErkJggg==\");\n\t\tbackground-repeat: repeat-y;\n\t\topacity: 0.3;\n\t\tfilter: \"alpha(opacity=30)\"; -ms-filter: \"alpha(opacity=30)\"; \n\t}\n\t\n\t.mCS-rounded-dots.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-rounded-dots-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail{\n\t\theight: 4px;\n\t\tmargin: 6px 0;\n\t\tbackground-repeat: repeat-x;\n\t}\n\t\n\t.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonUp{ background-position: -16px -72px; }\n\t\n\t.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonDown{ background-position: -16px -92px; }\n\t\n\t.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -20px -112px; }\n\t\n\t.mCS-rounded-dots.mCSB_scrollTools .mCSB_buttonRight{ background-position: -20px -128px; }\n\t\n\t\n\t/* theme \"rounded-dots-dark\" */\n\t\n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_draggerRail{\n\t\tbackground-image: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAALElEQVQYV2NkIAAYSVFgDFR8BqrBBEifBbGRTfiPZhpYjiQFBK3A6l6CvgAAE9kGCd1mvgEAAAAASUVORK5CYII=\");\n\t}\n\t\n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonUp{ background-position: -96px -72px; }\n\t\n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonDown{ background-position: -96px -92px; }\n\t\n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -100px -112px; }\n\t\n\t.mCS-rounded-dots-dark.mCSB_scrollTools .mCSB_buttonRight{ background-position: -100px -128px; }\n\t\n\t/* ---------------------------------------- */\n\t\n\t\n\t\n\t/* theme \"3d\", \"3d-dark\", \"3d-thick\", \"3d-thick-dark\" */\n\t\n\t.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\tbackground-repeat: repeat-y;\n\t\tbackground-image: -moz-linear-gradient(left, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 100%);\n\t\tbackground-image: -webkit-gradient(linear, left top, right top, color-stop(0%,rgba(255,255,255,0.5)), color-stop(100%,rgba(255,255,255,0)));\n\t\tbackground-image: -webkit-linear-gradient(left, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0) 100%);\n\t\tbackground-image: -o-linear-gradient(left, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0) 100%);\n\t\tbackground-image: -ms-linear-gradient(left, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0) 100%);\n\t\tbackground-image: linear-gradient(to right, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0) 100%);\n\t}\n\t\n\t.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\tbackground-repeat: repeat-x;\n\t\tbackground-image: -moz-linear-gradient(top, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 100%);\n\t\tbackground-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(255,255,255,0.5)), color-stop(100%,rgba(255,255,255,0)));\n\t\tbackground-image: -webkit-linear-gradient(top, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0) 100%);\n\t\tbackground-image: -o-linear-gradient(top, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0) 100%);\n\t\tbackground-image: -ms-linear-gradient(top, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0) 100%);\n\t\tbackground-image: linear-gradient(to bottom, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0) 100%);\n\t}\n\t\n\t\n\t/* theme \"3d\", \"3d-dark\" */\n\t\n\t.mCS-3d.mCSB_scrollTools_vertical .mCSB_dragger, \n\t.mCS-3d-dark.mCSB_scrollTools_vertical .mCSB_dragger{ height: 70px; }\n\t\n\t.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger, \n\t.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger{ width: 70px; }\n\t\n\t.mCS-3d.mCSB_scrollTools, \n\t.mCS-3d-dark.mCSB_scrollTools{\n\t\topacity: 1;\n\t\tfilter: \"alpha(opacity=30)\"; -ms-filter: \"alpha(opacity=30)\"; \n\t}\n\t\n\t.mCS-3d.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ -webkit-border-radius: 16px; -moz-border-radius: 16px; border-radius: 16px; }\n\t\n\t.mCS-3d.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail{\n\t\twidth: 8px;\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.2);\n\t\tbox-shadow: inset 1px 0 1px rgba(0,0,0,0.5), inset -1px 0 1px rgba(255,255,255,0.2);\n\t}\n\t\n\t.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \t \n\t.mCS-3d.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar, \n\t.mCS-3d.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-3d.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar, \n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar, \n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #555; }\n\n\t.mCS-3d.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ width: 8px; }\n\n\t.mCS-3d.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail{\n\t\twidth: 100%;\n\t\theight: 8px;\n\t\tmargin: 4px 0;\n\t\tbox-shadow: inset 0 1px 1px rgba(0,0,0,0.5), inset 0 -1px 1px rgba(255,255,255,0.2);\n\t}\n\n\t.mCS-3d.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\twidth: 100%;\n\t\theight: 8px;\n\t\tmargin: 4px auto;\n\t}\n\t\n\t.mCS-3d.mCSB_scrollTools .mCSB_buttonUp{ background-position: -32px -72px; }\n\t\n\t.mCS-3d.mCSB_scrollTools .mCSB_buttonDown{ background-position: -32px -92px; }\n\t\n\t.mCS-3d.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -40px -112px; }\n\t\n\t.mCS-3d.mCSB_scrollTools .mCSB_buttonRight{ background-position: -40px -128px; }\n\t\n\t\n\t/* theme \"3d-dark\" */\n\t\n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_draggerRail{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.1);\n\t\tbox-shadow: inset 1px 0 1px rgba(0,0,0,0.1);\n\t}\n\t\n\t.mCS-3d-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail{ box-shadow: inset 0 1px 1px rgba(0,0,0,0.1); }\n\t\n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonUp{ background-position: -112px -72px; }\n\n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonDown{ background-position: -112px -92px; }\n\n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -120px -112px; }\n\n\t.mCS-3d-dark.mCSB_scrollTools .mCSB_buttonRight{\tbackground-position: -120px -128px; }\n\t\n\t/* ---------------------------------------- */\n\t\n\t\n\t\n\t/* theme: \"3d-thick\", \"3d-thick-dark\" */\n\t\n\t.mCS-3d-thick.mCSB_scrollTools, \n\t.mCS-3d-thick-dark.mCSB_scrollTools{\n\t\topacity: 1;\n\t\tfilter: \"alpha(opacity=30)\"; -ms-filter: \"alpha(opacity=30)\"; \n\t}\n\t\n\t.mCS-3d-thick.mCSB_scrollTools, \n\t.mCS-3d-thick-dark.mCSB_scrollTools, \n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerContainer, \n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerContainer{ -webkit-border-radius: 7px; -moz-border-radius: 7px; border-radius: 7px; }\n\t\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; }\n\t\n\t.mCSB_inside + .mCS-3d-thick.mCSB_scrollTools_vertical, \n\t.mCSB_inside + .mCS-3d-thick-dark.mCSB_scrollTools_vertical{ right: 1px; }\n\t\n\t.mCS-3d-thick.mCSB_scrollTools_vertical, \n\t.mCS-3d-thick-dark.mCSB_scrollTools_vertical{ box-shadow: inset 1px 0 1px rgba(0,0,0,0.1), inset 0 0 14px rgba(0,0,0,0.5); }\n\t\n\t.mCS-3d-thick.mCSB_scrollTools_horizontal, \n\t.mCS-3d-thick-dark.mCSB_scrollTools_horizontal{\n\t\tbottom: 1px;\n\t\tbox-shadow: inset 0 1px 1px rgba(0,0,0,0.1), inset 0 0 14px rgba(0,0,0,0.5);\n\t}\n\t\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\tbox-shadow: inset 1px 0 0 rgba(255,255,255,0.4);\n\t\twidth: 12px;\n\t\tmargin: 2px;\n\t\tposition: absolute;\n\t\theight: auto;\n\t\ttop: 0;\n\t\tbottom: 0;\n\t\tleft: 0;\n\t\tright: 0;\n\t}\n\t\n\t.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{ box-shadow: inset 0 1px 0 rgba(255,255,255,0.4); }\n\t\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,  \n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar, \n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #555; }\n\t\n\t.mCS-3d-thick.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\theight: 12px;\n\t\twidth: auto;\n\t}\n\t\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerContainer{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.05);\n\t\tbox-shadow: inset 1px 1px 16px rgba(0,0,0,0.1);\n\t}\n\t\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_draggerRail{ background-color: transparent; }\n\t\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonUp{ background-position: -32px -72px; }\n\t\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonDown{ background-position: -32px -92px; }\n\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -40px -112px; }\n\n\t.mCS-3d-thick.mCSB_scrollTools .mCSB_buttonRight{\tbackground-position: -40px -128px; }\n\t\n\t\n\t/* theme: \"3d-thick-dark\" */\n\t\n\t.mCS-3d-thick-dark.mCSB_scrollTools{ box-shadow: inset 0 0 14px rgba(0,0,0,0.2); }\n\t\n\t.mCS-3d-thick-dark.mCSB_scrollTools_horizontal{ box-shadow: inset 0 1px 1px rgba(0,0,0,0.1), inset 0 0 14px rgba(0,0,0,0.2); }\n\t\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ box-shadow: inset 1px 0 0 rgba(255,255,255,0.4), inset -1px 0 0 rgba(0,0,0,0.2); }\n\t \n\t.mCS-3d-thick-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{ box-shadow: inset 0 1px 0 rgba(255,255,255,0.4), inset 0 -1px 0 rgba(0,0,0,0.2); }\n\t\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar,  \n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar, \n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #777; }\n\t\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerContainer{\n\t\tbackground-color: #fff; background-color: rgba(0,0,0,0.05);\n\t\tbox-shadow: inset 1px 1px 16px rgba(0,0,0,0.1);\n\t}\n\t\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_draggerRail{ background-color: transparent; }\n\t\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonUp{ background-position: -112px -72px; }\n\t\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonDown{ background-position: -112px -92px; }\n\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -120px -112px; }\n\n\t.mCS-3d-thick-dark.mCSB_scrollTools .mCSB_buttonRight{\tbackground-position: -120px -128px; }\n\t\n\t/* ---------------------------------------- */\n\t\n\t\n\t\n\t/* theme: \"minimal\", \"minimal-dark\" */\n\t\n\t.mCSB_outside + .mCS-minimal.mCSB_scrollTools_vertical, \n\t.mCSB_outside + .mCS-minimal-dark.mCSB_scrollTools_vertical{\n\t\tright: 0; \n\t\tmargin: 12px 0; \n\t}\n\t\n\t.mCustomScrollBox.mCS-minimal + .mCSB_scrollTools.mCSB_scrollTools_horizontal, \n\t.mCustomScrollBox.mCS-minimal + .mCSB_scrollTools + .mCSB_scrollTools.mCSB_scrollTools_horizontal, \n\t.mCustomScrollBox.mCS-minimal-dark + .mCSB_scrollTools.mCSB_scrollTools_horizontal, \n\t.mCustomScrollBox.mCS-minimal-dark + .mCSB_scrollTools + .mCSB_scrollTools.mCSB_scrollTools_horizontal{\n\t\tbottom: 0; \n\t\tmargin: 0 12px; \n\t}\n\t\n\t/* RTL direction/left-side scrollbar */\n\t.mCS-dir-rtl > .mCSB_outside + .mCS-minimal.mCSB_scrollTools_vertical, \n\t.mCS-dir-rtl > .mCSB_outside + .mCS-minimal-dark.mCSB_scrollTools_vertical{\n\t\tleft: 0; \n\t\tright: auto;\n\t}\n\t\n\t.mCS-minimal.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-minimal-dark.mCSB_scrollTools .mCSB_draggerRail{ background-color: transparent; }\n\t\n\t.mCS-minimal.mCSB_scrollTools_vertical .mCSB_dragger, \n\t.mCS-minimal-dark.mCSB_scrollTools_vertical .mCSB_dragger{ height: 50px; }\n\t\n\t.mCS-minimal.mCSB_scrollTools_horizontal .mCSB_dragger, \n\t.mCS-minimal-dark.mCSB_scrollTools_horizontal .mCSB_dragger{ width: 50px; }\n\t\n\t.mCS-minimal.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.2);\n\t\tfilter: \"alpha(opacity=20)\"; -ms-filter: \"alpha(opacity=20)\"; \n\t}\n\t\n\t.mCS-minimal.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-minimal.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{\n\t\tbackground-color: #fff; background-color: rgba(255,255,255,0.5);\n\t\tfilter: \"alpha(opacity=50)\"; -ms-filter: \"alpha(opacity=50)\"; \n\t}\n\t\n\t\n\t/* theme: \"minimal-dark\" */\n\t\n\t.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.2);\n\t\tfilter: \"alpha(opacity=20)\"; -ms-filter: \"alpha(opacity=20)\"; \n\t}\n\t\n\t.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-minimal-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.5);\n\t\tfilter: \"alpha(opacity=50)\"; -ms-filter: \"alpha(opacity=50)\"; \n\t}\n\t\n\t/* ---------------------------------------- */\n\t\n\t\n\t\n\t/* theme \"light-3\", \"dark-3\" */\n\t\n\t.mCS-light-3.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-dark-3.mCSB_scrollTools .mCSB_draggerRail{\n\t\twidth: 6px;\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.2);\n\t}\n\n\t.mCS-light-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-dark-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ width: 6px; }\n\n\t.mCS-light-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-dark-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-light-3.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-dark-3.mCSB_scrollTools_horizontal .mCSB_draggerRail{\n\t\twidth: 100%;\n\t\theight: 6px;\n\t\tmargin: 5px 0;\n\t}\n\t\n\t.mCS-light-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCS-light-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail, \n\t.mCS-dark-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCS-dark-3.mCSB_scrollTools_vertical.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{\n\t\twidth: 12px;\n\t}\n\t\n\t.mCS-light-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCS-light-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail, \n\t.mCS-dark-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_dragger.mCSB_dragger_onDrag_expanded + .mCSB_draggerRail, \n\t.mCS-dark-3.mCSB_scrollTools_horizontal.mCSB_scrollTools_onDrag_expand .mCSB_draggerContainer:hover .mCSB_draggerRail{\n\t\theight: 12px;\n\t\tmargin: 2px 0;\n\t}\n\t\n\t.mCS-light-3.mCSB_scrollTools .mCSB_buttonUp{ background-position: -32px -72px; }\n\t\n\t.mCS-light-3.mCSB_scrollTools .mCSB_buttonDown{ background-position: -32px -92px; }\n\t\n\t.mCS-light-3.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -40px -112px; }\n\t\n\t.mCS-light-3.mCSB_scrollTools .mCSB_buttonRight{ background-position: -40px -128px; }\n\t\n\t\n\t/* theme \"dark-3\" */\n\t\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.75); }\n\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.85); }\n\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.9); }\n\t\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_draggerRail{ background-color: #000; background-color: rgba(0,0,0,0.1); }\n\t\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_buttonUp{ background-position: -112px -72px; }\n\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_buttonDown{ background-position: -112px -92px; }\n\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -120px -112px; }\n\n\t.mCS-dark-3.mCSB_scrollTools .mCSB_buttonRight{\tbackground-position: -120px -128px; }\n\t\n\t/* ---------------------------------------- */\n\t\n\t\n\t\n\t/* theme \"inset\", \"inset-dark\", \"inset-2\", \"inset-2-dark\", \"inset-3\", \"inset-3-dark\" */\n\t\n\t.mCS-inset.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-inset-2.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-inset-3.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail{\n\t\twidth: 12px;\n\t\tbackground-color: #000; background-color: rgba(0,0,0,0.2);\n\t}\n\n\t.mCS-inset.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-2.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ \n\t\twidth: 6px;\n\t\tmargin: 3px 5px;\n\t\tposition: absolute;\n\t\theight: auto;\n\t\ttop: 0;\n\t\tbottom: 0;\n\t\tleft: 0;\n\t\tright: 0;\n\t}\n\n\t.mCS-inset.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-2.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-2-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-3.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-3-dark.mCSB_scrollTools_horizontal .mCSB_dragger .mCSB_dragger_bar{\n\t\theight: 6px;\n\t\tmargin: 5px 3px;\n\t\tposition: absolute;\n\t\twidth: auto;\n\t\ttop: 0;\n\t\tbottom: 0;\n\t\tleft: 0;\n\t\tright: 0;\n\t}\n\t\n\t.mCS-inset.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-inset-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-inset-2.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-inset-2-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-inset-3.mCSB_scrollTools_horizontal .mCSB_draggerRail, \n\t.mCS-inset-3-dark.mCSB_scrollTools_horizontal .mCSB_draggerRail{\n\t\twidth: 100%;\n\t\theight: 12px;\n\t\tmargin: 2px 0;\n\t}\n\t\n\t.mCS-inset.mCSB_scrollTools .mCSB_buttonUp, \n\t.mCS-inset-2.mCSB_scrollTools .mCSB_buttonUp, \n\t.mCS-inset-3.mCSB_scrollTools .mCSB_buttonUp{ background-position: -32px -72px; }\n\t\n\t.mCS-inset.mCSB_scrollTools .mCSB_buttonDown, \n\t.mCS-inset-2.mCSB_scrollTools .mCSB_buttonDown, \n\t.mCS-inset-3.mCSB_scrollTools .mCSB_buttonDown{ background-position: -32px -92px; }\n\t\n\t.mCS-inset.mCSB_scrollTools .mCSB_buttonLeft, \n\t.mCS-inset-2.mCSB_scrollTools .mCSB_buttonLeft, \n\t.mCS-inset-3.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -40px -112px; }\n\t\n\t.mCS-inset.mCSB_scrollTools .mCSB_buttonRight, \n\t.mCS-inset-2.mCSB_scrollTools .mCSB_buttonRight, \n\t.mCS-inset-3.mCSB_scrollTools .mCSB_buttonRight{ background-position: -40px -128px; }\n\t\n\t\n\t/* theme \"inset-dark\", \"inset-2-dark\", \"inset-3-dark\" */\n\t\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.75); }\n\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.85); }\n\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.9); }\n\t\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail{ background-color: #000; background-color: rgba(0,0,0,0.1); }\n\t\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonUp, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonUp, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonUp{ background-position: -112px -72px; }\n\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonDown, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonDown, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonDown{ background-position: -112px -92px; }\n\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonLeft, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonLeft, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonLeft{ background-position: -120px -112px; }\n\n\t.mCS-inset-dark.mCSB_scrollTools .mCSB_buttonRight, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_buttonRight, \n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_buttonRight{\tbackground-position: -120px -128px; }\n\t\n\t\n\t/* theme \"inset-2\", \"inset-2-dark\" */\n\t\n\t.mCS-inset-2.mCSB_scrollTools .mCSB_draggerRail, \n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail{\n\t\tbackground-color: transparent;\n\t\tborder-width: 1px;\n\t\tborder-style: solid;\n\t\tborder-color: #fff;\n\t\tborder-color: rgba(255,255,255,0.2);\n\t\t-webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;\n\t}\n\t\n\t.mCS-inset-2-dark.mCSB_scrollTools .mCSB_draggerRail{ border-color: #000; border-color: rgba(0,0,0,0.2); }\n\t\n\t\n\t/* theme \"inset-3\", \"inset-3-dark\" */\n\t\n\t.mCS-inset-3.mCSB_scrollTools .mCSB_draggerRail{ background-color: #fff; background-color: rgba(255,255,255,0.6); }\n\t\n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_draggerRail{ background-color: #000; background-color: rgba(0,0,0,0.6); }\n\t\n\t.mCS-inset-3.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.75); }\n\t\n\t.mCS-inset-3.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.85); }\n\t\n\t.mCS-inset-3.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-inset-3.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #000; background-color: rgba(0,0,0,0.9); }\n\t\n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ background-color: #fff; background-color: rgba(255,255,255,0.75); }\n\t\n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ background-color: #fff; background-color: rgba(255,255,255,0.85); }\n\t\n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,\n\t.mCS-inset-3-dark.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ background-color: #fff; background-color: rgba(255,255,255,0.9); }\n\t\n\t/* ---------------------------------------- */\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.js",
    "content": "/*\n== malihu jquery custom scrollbar plugin == \nVersion: 3.1.0 \nPlugin URI: http://manos.malihu.gr/jquery-custom-content-scroller \nAuthor: malihu\nAuthor URI: http://manos.malihu.gr\nLicense: MIT License (MIT)\n*/\n\n/*\nCopyright 2010 Manos Malihutsakis (email: manos@malihu.gr)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\n/*\nThe code below is fairly long, fully commented and should be normally used in development. \nFor production, use either the minified jquery.mCustomScrollbar.min.js script or \nthe production-ready jquery.mCustomScrollbar.concat.min.js which contains the plugin \nand dependencies (minified). \n*/\n\n(function(factory){\n\tif(typeof module!==\"undefined\" && module.exports){\n\t\tmodule.exports=factory;\n\t}else{\n\t\tfactory(jQuery,window,document);\n\t}\n}(function($){\n(function(init){\n\tvar _rjs=typeof define===\"function\" && define.amd, /* RequireJS */\n\t\t_njs=typeof module !== \"undefined\" && module.exports, /* NodeJS */\n\t\t_dlp=(\"https:\"==document.location.protocol) ? \"https:\" : \"http:\", /* location protocol */\n\t\t_url=\"cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.12/jquery.mousewheel.min.js\";\n\tif(!_rjs){\n\t\tif(_njs){\n\t\t\trequire(\"jquery-mousewheel\")($);\n\t\t}else{\n\t\t\t/* load jquery-mousewheel plugin (via CDN) if it's not present or not loaded via RequireJS \n\t\t\t(works when mCustomScrollbar fn is called on window load) */\n\t\t\t$.event.special.mousewheel || $(\"head\").append(decodeURI(\"%3Cscript src=\"+_dlp+\"//\"+_url+\"%3E%3C/script%3E\"));\n\t\t}\n\t}\n\tinit();\n}(function(){\n\t\n\t/* \n\t----------------------------------------\n\tPLUGIN NAMESPACE, PREFIX, DEFAULT SELECTOR(S) \n\t----------------------------------------\n\t*/\n\t\n\tvar pluginNS=\"mCustomScrollbar\",\n\t\tpluginPfx=\"mCS\",\n\t\tdefaultSelector=\".mCustomScrollbar\",\n\t\n\t\n\t\t\n\t\n\t\n\t/* \n\t----------------------------------------\n\tDEFAULT OPTIONS \n\t----------------------------------------\n\t*/\n\t\n\t\tdefaults={\n\t\t\t/*\n\t\t\tset element/content width/height programmatically \n\t\t\tvalues: boolean, pixels, percentage \n\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t-------------------------------------\n\t\t\t\tsetWidth\t\t\t\t\tfalse\n\t\t\t\tsetHeight\t\t\t\t\tfalse\n\t\t\t*/\n\t\t\t/*\n\t\t\tset the initial css top property of content  \n\t\t\tvalues: string (e.g. \"-100px\", \"10%\" etc.)\n\t\t\t*/\n\t\t\tsetTop:0,\n\t\t\t/*\n\t\t\tset the initial css left property of content  \n\t\t\tvalues: string (e.g. \"-100px\", \"10%\" etc.)\n\t\t\t*/\n\t\t\tsetLeft:0,\n\t\t\t/* \n\t\t\tscrollbar axis (vertical and/or horizontal scrollbars) \n\t\t\tvalues (string): \"y\", \"x\", \"yx\"\n\t\t\t*/\n\t\t\taxis:\"y\",\n\t\t\t/*\n\t\t\tposition of scrollbar relative to content  \n\t\t\tvalues (string): \"inside\", \"outside\" (\"outside\" requires elements with position:relative)\n\t\t\t*/\n\t\t\tscrollbarPosition:\"inside\",\n\t\t\t/*\n\t\t\tscrolling inertia\n\t\t\tvalues: integer (milliseconds)\n\t\t\t*/\n\t\t\tscrollInertia:950,\n\t\t\t/* \n\t\t\tauto-adjust scrollbar dragger length\n\t\t\tvalues: boolean\n\t\t\t*/\n\t\t\tautoDraggerLength:true,\n\t\t\t/*\n\t\t\tauto-hide scrollbar when idle \n\t\t\tvalues: boolean\n\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t-------------------------------------\n\t\t\t\tautoHideScrollbar\t\t\tfalse\n\t\t\t*/\n\t\t\t/*\n\t\t\tauto-expands scrollbar on mouse-over and dragging\n\t\t\tvalues: boolean\n\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t-------------------------------------\n\t\t\t\tautoExpandScrollbar\t\t\tfalse\n\t\t\t*/\n\t\t\t/*\n\t\t\talways show scrollbar, even when there's nothing to scroll \n\t\t\tvalues: integer (0=disable, 1=always show dragger rail and buttons, 2=always show dragger rail, dragger and buttons), boolean\n\t\t\t*/\n\t\t\talwaysShowScrollbar:0,\n\t\t\t/*\n\t\t\tscrolling always snaps to a multiple of this number in pixels\n\t\t\tvalues: integer\n\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t-------------------------------------\n\t\t\t\tsnapAmount\t\t\t\t\tnull\n\t\t\t*/\n\t\t\t/*\n\t\t\twhen snapping, snap with this number in pixels as an offset \n\t\t\tvalues: integer\n\t\t\t*/\n\t\t\tsnapOffset:0,\n\t\t\t/* \n\t\t\tmouse-wheel scrolling\n\t\t\t*/\n\t\t\tmouseWheel:{\n\t\t\t\t/* \n\t\t\t\tenable mouse-wheel scrolling\n\t\t\t\tvalues: boolean\n\t\t\t\t*/\n\t\t\t\tenable:true,\n\t\t\t\t/* \n\t\t\t\tscrolling amount in pixels\n\t\t\t\tvalues: \"auto\", integer \n\t\t\t\t*/\n\t\t\t\tscrollAmount:\"auto\",\n\t\t\t\t/* \n\t\t\t\tmouse-wheel scrolling axis \n\t\t\t\tthe default scrolling direction when both vertical and horizontal scrollbars are present \n\t\t\t\tvalues (string): \"y\", \"x\" \n\t\t\t\t*/\n\t\t\t\taxis:\"y\",\n\t\t\t\t/* \n\t\t\t\tprevent the default behaviour which automatically scrolls the parent element(s) when end of scrolling is reached \n\t\t\t\tvalues: boolean\n\t\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\tpreventDefault\t\t\t\tnull\n\t\t\t\t*/\n\t\t\t\t/*\n\t\t\t\tthe reported mouse-wheel delta value. The number of lines (translated to pixels) one wheel notch scrolls.  \n\t\t\t\tvalues: \"auto\", integer \n\t\t\t\t\"auto\" uses the default OS/browser value \n\t\t\t\t*/\n\t\t\t\tdeltaFactor:\"auto\",\n\t\t\t\t/*\n\t\t\t\tnormalize mouse-wheel delta to -1 or 1 (disables mouse-wheel acceleration) \n\t\t\t\tvalues: boolean\n\t\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\tnormalizeDelta\t\t\t\tnull\n\t\t\t\t*/\n\t\t\t\t/*\n\t\t\t\tinvert mouse-wheel scrolling direction \n\t\t\t\tvalues: boolean\n\t\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\tinvert\t\t\t\t\t\tnull\n\t\t\t\t*/\n\t\t\t\t/*\n\t\t\t\tthe tags that disable mouse-wheel when cursor is over them\n\t\t\t\t*/\n\t\t\t\tdisableOver:[\"select\",\"option\",\"keygen\",\"datalist\",\"textarea\"]\n\t\t\t},\n\t\t\t/* \n\t\t\tscrollbar buttons\n\t\t\t*/\n\t\t\tscrollButtons:{ \n\t\t\t\t/*\n\t\t\t\tenable scrollbar buttons\n\t\t\t\tvalues: boolean\n\t\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\tenable\t\t\t\t\t\tnull\n\t\t\t\t*/\n\t\t\t\t/*\n\t\t\t\tscrollbar buttons scrolling type \n\t\t\t\tvalues (string): \"stepless\", \"stepped\"\n\t\t\t\t*/\n\t\t\t\tscrollType:\"stepless\",\n\t\t\t\t/*\n\t\t\t\tscrolling amount in pixels\n\t\t\t\tvalues: \"auto\", integer \n\t\t\t\t*/\n\t\t\t\tscrollAmount:\"auto\"\n\t\t\t\t/*\n\t\t\t\ttabindex of the scrollbar buttons\n\t\t\t\tvalues: false, integer\n\t\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\ttabindex\t\t\t\t\tnull\n\t\t\t\t*/\n\t\t\t},\n\t\t\t/* \n\t\t\tkeyboard scrolling\n\t\t\t*/\n\t\t\tkeyboard:{ \n\t\t\t\t/*\n\t\t\t\tenable scrolling via keyboard\n\t\t\t\tvalues: boolean\n\t\t\t\t*/\n\t\t\t\tenable:true,\n\t\t\t\t/*\n\t\t\t\tkeyboard scrolling type \n\t\t\t\tvalues (string): \"stepless\", \"stepped\"\n\t\t\t\t*/\n\t\t\t\tscrollType:\"stepless\",\n\t\t\t\t/*\n\t\t\t\tscrolling amount in pixels\n\t\t\t\tvalues: \"auto\", integer \n\t\t\t\t*/\n\t\t\t\tscrollAmount:\"auto\"\n\t\t\t},\n\t\t\t/*\n\t\t\tenable content touch-swipe scrolling \n\t\t\tvalues: boolean, integer, string (number)\n\t\t\tinteger values define the axis-specific minimum amount required for scrolling momentum\n\t\t\t*/\n\t\t\tcontentTouchScroll:25,\n\t\t\t/*\n\t\t\tadvanced option parameters\n\t\t\t*/\n\t\t\tadvanced:{\n\t\t\t\t/*\n\t\t\t\tauto-expand content horizontally (for \"x\" or \"yx\" axis) \n\t\t\t\tvalues: boolean, integer (the value 2 forces the non scrollHeight/scrollWidth method, the value 3 forces the scrollHeight/scrollWidth method)\n\t\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\tautoExpandHorizontalScroll\tnull\n\t\t\t\t*/\n\t\t\t\t/*\n\t\t\t\tauto-scroll to elements with focus\n\t\t\t\t*/\n\t\t\t\tautoScrollOnFocus:\"input,textarea,select,button,datalist,keygen,a[tabindex],area,object,[contenteditable='true']\",\n\t\t\t\t/*\n\t\t\t\tauto-update scrollbars on content, element or viewport resize \n\t\t\t\tshould be true for fluid layouts/elements, adding/removing content dynamically, hiding/showing elements, content with images etc. \n\t\t\t\tvalues: boolean\n\t\t\t\t*/\n\t\t\t\tupdateOnContentResize:true,\n\t\t\t\t/*\n\t\t\t\tauto-update scrollbars each time each image inside the element is fully loaded \n\t\t\t\tvalues: \"auto\", boolean\n\t\t\t\t*/\n\t\t\t\tupdateOnImageLoad:\"auto\",\n\t\t\t\t/*\n\t\t\t\tauto-update scrollbars based on the amount and size changes of specific selectors \n\t\t\t\tuseful when you need to update the scrollbar(s) automatically, each time a type of element is added, removed or changes its size \n\t\t\t\tvalues: boolean, string (e.g. \"ul li\" will auto-update scrollbars each time list-items inside the element are changed) \n\t\t\t\ta value of true (boolean) will auto-update scrollbars each time any element is changed\n\t\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\tupdateOnSelectorChange\t\tnull\n\t\t\t\t*/\n\t\t\t\t/*\n\t\t\t\textra selectors that'll release scrollbar dragging upon mouseup, pointerup, touchend etc. (e.g. \"selector-1, selector-2\")\n\t\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\treleaseDraggableSelectors\tnull\n\t\t\t\t*/\n\t\t\t\t/*\n\t\t\t\tauto-update timeout \n\t\t\t\tvalues: integer (milliseconds)\n\t\t\t\t*/\n\t\t\t\tautoUpdateTimeout:60\n\t\t\t},\n\t\t\t/* \n\t\t\tscrollbar theme \n\t\t\tvalues: string (see CSS/plugin URI for a list of ready-to-use themes)\n\t\t\t*/\n\t\t\ttheme:\"light\",\n\t\t\t/*\n\t\t\tuser defined callback functions\n\t\t\t*/\n\t\t\tcallbacks:{\n\t\t\t\t/*\n\t\t\t\tAvailable callbacks: \n\t\t\t\t\tcallback\t\t\t\t\tdefault\n\t\t\t\t\t-------------------------------------\n\t\t\t\t\tonCreate\t\t\t\t\tnull\n\t\t\t\t\tonInit\t\t\t\t\t\tnull\n\t\t\t\t\tonScrollStart\t\t\t\tnull\n\t\t\t\t\tonScroll\t\t\t\t\tnull\n\t\t\t\t\tonTotalScroll\t\t\t\tnull\n\t\t\t\t\tonTotalScrollBack\t\t\tnull\n\t\t\t\t\twhileScrolling\t\t\t\tnull\n\t\t\t\t\tonOverflowY\t\t\t\t\tnull\n\t\t\t\t\tonOverflowX\t\t\t\t\tnull\n\t\t\t\t\tonOverflowYNone\t\t\t\tnull\n\t\t\t\t\tonOverflowXNone\t\t\t\tnull\n\t\t\t\t\tonImageLoad\t\t\t\t\tnull\n\t\t\t\t\tonSelectorChange\t\t\tnull\n\t\t\t\t\tonBeforeUpdate\t\t\t\tnull\n\t\t\t\t\tonUpdate\t\t\t\t\tnull\n\t\t\t\t*/\n\t\t\t\tonTotalScrollOffset:0,\n\t\t\t\tonTotalScrollBackOffset:0,\n\t\t\t\talwaysTriggerOffsets:true\n\t\t\t}\n\t\t\t/*\n\t\t\tadd scrollbar(s) on all elements matching the current selector, now and in the future \n\t\t\tvalues: boolean, string \n\t\t\tstring values: \"on\" (enable), \"once\" (disable after first invocation), \"off\" (disable)\n\t\t\tliveSelector values: string (selector)\n\t\t\t\toption\t\t\t\t\t\tdefault\n\t\t\t\t-------------------------------------\n\t\t\t\tlive\t\t\t\t\t\tfalse\n\t\t\t\tliveSelector\t\t\t\tnull\n\t\t\t*/\n\t\t},\n\t\n\t\n\t\n\t\n\t\n\t/* \n\t----------------------------------------\n\tVARS, CONSTANTS \n\t----------------------------------------\n\t*/\n\t\n\t\ttotalInstances=0, /* plugin instances amount */\n\t\tliveTimers={}, /* live option timers */\n\t\toldIE=(window.attachEvent && !window.addEventListener) ? 1 : 0, /* detect IE < 9 */\n\t\ttouchActive=false,touchable, /* global touch vars (for touch and pointer events) */\n\t\t/* general plugin classes */\n\t\tclasses=[\n\t\t\t\"mCSB_dragger_onDrag\",\"mCSB_scrollTools_onDrag\",\"mCS_img_loaded\",\"mCS_disabled\",\"mCS_destroyed\",\"mCS_no_scrollbar\",\n\t\t\t\"mCS-autoHide\",\"mCS-dir-rtl\",\"mCS_no_scrollbar_y\",\"mCS_no_scrollbar_x\",\"mCS_y_hidden\",\"mCS_x_hidden\",\"mCSB_draggerContainer\",\n\t\t\t\"mCSB_buttonUp\",\"mCSB_buttonDown\",\"mCSB_buttonLeft\",\"mCSB_buttonRight\"\n\t\t],\n\t\t\n\t\n\t\n\t\n\t\n\t/* \n\t----------------------------------------\n\tMETHODS \n\t----------------------------------------\n\t*/\n\t\n\t\tmethods={\n\t\t\t\n\t\t\t/* \n\t\t\tplugin initialization method \n\t\t\tcreates the scrollbar(s), plugin data object and options\n\t\t\t----------------------------------------\n\t\t\t*/\n\t\t\t\n\t\t\tinit:function(options){\n\t\t\t\t\n\t\t\t\tvar options=$.extend(true,{},defaults,options),\n\t\t\t\t\tselector=_selector.call(this); /* validate selector */\n\t\t\t\t\n\t\t\t\t/* \n\t\t\t\tif live option is enabled, monitor for elements matching the current selector and \n\t\t\t\tapply scrollbar(s) when found (now and in the future) \n\t\t\t\t*/\n\t\t\t\tif(options.live){\n\t\t\t\t\tvar liveSelector=options.liveSelector || this.selector || defaultSelector, /* live selector(s) */\n\t\t\t\t\t\t$liveSelector=$(liveSelector); /* live selector(s) as jquery object */\n\t\t\t\t\tif(options.live===\"off\"){\n\t\t\t\t\t\t/* \n\t\t\t\t\t\tdisable live if requested \n\t\t\t\t\t\tusage: $(selector).mCustomScrollbar({live:\"off\"}); \n\t\t\t\t\t\t*/\n\t\t\t\t\t\tremoveLiveTimers(liveSelector);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tliveTimers[liveSelector]=setTimeout(function(){\n\t\t\t\t\t\t/* call mCustomScrollbar fn on live selector(s) every half-second */\n\t\t\t\t\t\t$liveSelector.mCustomScrollbar(options);\n\t\t\t\t\t\tif(options.live===\"once\" && $liveSelector.length){\n\t\t\t\t\t\t\t/* disable live after first invocation */\n\t\t\t\t\t\t\tremoveLiveTimers(liveSelector);\n\t\t\t\t\t\t}\n\t\t\t\t\t},500);\n\t\t\t\t}else{\n\t\t\t\t\tremoveLiveTimers(liveSelector);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t/* options backward compatibility (for versions < 3.0.0) and normalization */\n\t\t\t\toptions.setWidth=(options.set_width) ? options.set_width : options.setWidth;\n\t\t\t\toptions.setHeight=(options.set_height) ? options.set_height : options.setHeight;\n\t\t\t\toptions.axis=(options.horizontalScroll) ? \"x\" : _findAxis(options.axis);\n\t\t\t\toptions.scrollInertia=options.scrollInertia>0 && options.scrollInertia<17 ? 17 : options.scrollInertia;\n\t\t\t\tif(typeof options.mouseWheel!==\"object\" &&  options.mouseWheel==true){ /* old school mouseWheel option (non-object) */\n\t\t\t\t\toptions.mouseWheel={enable:true,scrollAmount:\"auto\",axis:\"y\",preventDefault:false,deltaFactor:\"auto\",normalizeDelta:false,invert:false}\n\t\t\t\t}\n\t\t\t\toptions.mouseWheel.scrollAmount=!options.mouseWheelPixels ? options.mouseWheel.scrollAmount : options.mouseWheelPixels;\n\t\t\t\toptions.mouseWheel.normalizeDelta=!options.advanced.normalizeMouseWheelDelta ? options.mouseWheel.normalizeDelta : options.advanced.normalizeMouseWheelDelta;\n\t\t\t\toptions.scrollButtons.scrollType=_findScrollButtonsType(options.scrollButtons.scrollType); \n\t\t\t\t\n\t\t\t\t_theme(options); /* theme-specific options */\n\t\t\t\t\n\t\t\t\t/* plugin constructor */\n\t\t\t\treturn $(selector).each(function(){\n\t\t\t\t\t\n\t\t\t\t\tvar $this=$(this);\n\t\t\t\t\t\n\t\t\t\t\tif(!$this.data(pluginPfx)){ /* prevent multiple instantiations */\n\t\t\t\t\t\n\t\t\t\t\t\t/* store options and create objects in jquery data */\n\t\t\t\t\t\t$this.data(pluginPfx,{\n\t\t\t\t\t\t\tidx:++totalInstances, /* instance index */\n\t\t\t\t\t\t\topt:options, /* options */\n\t\t\t\t\t\t\tscrollRatio:{y:null,x:null}, /* scrollbar to content ratio */\n\t\t\t\t\t\t\toverflowed:null, /* overflowed axis */\n\t\t\t\t\t\t\tcontentReset:{y:null,x:null}, /* object to check when content resets */\n\t\t\t\t\t\t\tbindEvents:false, /* object to check if events are bound */\n\t\t\t\t\t\t\ttweenRunning:false, /* object to check if tween is running */\n\t\t\t\t\t\t\tsequential:{}, /* sequential scrolling object */\n\t\t\t\t\t\t\tlangDir:$this.css(\"direction\"), /* detect/store direction (ltr or rtl) */\n\t\t\t\t\t\t\tcbOffsets:null, /* object to check whether callback offsets always trigger */\n\t\t\t\t\t\t\t/* \n\t\t\t\t\t\t\tobject to check how scrolling events where last triggered \n\t\t\t\t\t\t\t\"internal\" (default - triggered by this script), \"external\" (triggered by other scripts, e.g. via scrollTo method) \n\t\t\t\t\t\t\tusage: object.data(\"mCS\").trigger\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\ttrigger:null,\n\t\t\t\t\t\t\t/* \n\t\t\t\t\t\t\tobject to check for changes in elements in order to call the update method automatically \n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\tpoll:{size:{o:0,n:0},img:{o:0,n:0},change:{o:0,n:0}}\n\t\t\t\t\t\t});\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\t\t\t\t/* HTML data attributes */\n\t\t\t\t\t\t\thtmlDataAxis=$this.data(\"mcs-axis\"),htmlDataSbPos=$this.data(\"mcs-scrollbar-position\"),htmlDataTheme=$this.data(\"mcs-theme\");\n\t\t\t\t\t\t \n\t\t\t\t\t\tif(htmlDataAxis){o.axis=htmlDataAxis;} /* usage example: data-mcs-axis=\"y\" */\n\t\t\t\t\t\tif(htmlDataSbPos){o.scrollbarPosition=htmlDataSbPos;} /* usage example: data-mcs-scrollbar-position=\"outside\" */\n\t\t\t\t\t\tif(htmlDataTheme){ /* usage example: data-mcs-theme=\"minimal\" */\n\t\t\t\t\t\t\to.theme=htmlDataTheme;\n\t\t\t\t\t\t\t_theme(o); /* theme-specific options */\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t_pluginMarkup.call(this); /* add plugin markup */\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(d && o.callbacks.onCreate && typeof o.callbacks.onCreate===\"function\"){o.callbacks.onCreate.call(this);} /* callbacks: onCreate */\n\t\t\t\t\t\t\n\t\t\t\t\t\t$(\"#mCSB_\"+d.idx+\"_container img:not(.\"+classes[2]+\")\").addClass(classes[2]); /* flag loaded images */\n\t\t\t\t\t\t\n\t\t\t\t\t\tmethods.update.call(null,$this); /* call the update method */\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t});\n\t\t\t\t\n\t\t\t},\n\t\t\t/* ---------------------------------------- */\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* \n\t\t\tplugin update method \n\t\t\tupdates content and scrollbar(s) values, events and status \n\t\t\t----------------------------------------\n\t\t\tusage: $(selector).mCustomScrollbar(\"update\");\n\t\t\t*/\n\t\t\t\n\t\t\tupdate:function(el,cb){\n\t\t\t\t\n\t\t\t\tvar selector=el || _selector.call(this); /* validate selector */\n\t\t\t\t\n\t\t\t\treturn $(selector).each(function(){\n\t\t\t\t\t\n\t\t\t\t\tvar $this=$(this);\n\t\t\t\t\t\n\t\t\t\t\tif($this.data(pluginPfx)){ /* check if plugin has initialized */\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\t\t\t\tmCSB_dragger=[$(\"#mCSB_\"+d.idx+\"_dragger_vertical\"),$(\"#mCSB_\"+d.idx+\"_dragger_horizontal\")];\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(!mCSB_container.length){return;}\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(d.tweenRunning){_stop($this);} /* stop any running tweens while updating */\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(cb && d && o.callbacks.onBeforeUpdate && typeof o.callbacks.onBeforeUpdate===\"function\"){o.callbacks.onBeforeUpdate.call(this);} /* callbacks: onBeforeUpdate */\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* if element was disabled or destroyed, remove class(es) */\n\t\t\t\t\t\tif($this.hasClass(classes[3])){$this.removeClass(classes[3]);}\n\t\t\t\t\t\tif($this.hasClass(classes[4])){$this.removeClass(classes[4]);}\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* css flexbox fix, detect/set max-height */\n\t\t\t\t\t\tif(mCustomScrollBox.height()!==$this.height()){mCustomScrollBox.css(\"max-height\",$this.height());}\n\t\t\t\t\t\t\n\t\t\t\t\t\t_expandContentHorizontally.call(this); /* expand content horizontally */\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(o.axis!==\"y\" && !o.advanced.autoExpandHorizontalScroll){\n\t\t\t\t\t\t\tmCSB_container.css(\"width\",_contentWidth(mCSB_container));\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\td.overflowed=_overflowed.call(this); /* determine if scrolling is required */\n\t\t\t\t\t\t\n\t\t\t\t\t\t_scrollbarVisibility.call(this); /* show/hide scrollbar(s) */\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* auto-adjust scrollbar dragger length analogous to content */\n\t\t\t\t\t\tif(o.autoDraggerLength){_setDraggerLength.call(this);}\n\t\t\t\t\t\t\n\t\t\t\t\t\t_scrollRatio.call(this); /* calculate and store scrollbar to content ratio */\n\t\t\t\t\t\t\n\t\t\t\t\t\t_bindEvents.call(this); /* bind scrollbar events */\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* reset scrolling position and/or events */\n\t\t\t\t\t\tvar to=[Math.abs(mCSB_container[0].offsetTop),Math.abs(mCSB_container[0].offsetLeft)];\n\t\t\t\t\t\tif(o.axis!==\"x\"){ /* y/yx axis */\n\t\t\t\t\t\t\tif(!d.overflowed[0]){ /* y scrolling is not required */\n\t\t\t\t\t\t\t\t_resetContentPosition.call(this); /* reset content position */\n\t\t\t\t\t\t\t\tif(o.axis===\"y\"){\n\t\t\t\t\t\t\t\t\t_unbindEvents.call(this);\n\t\t\t\t\t\t\t\t}else if(o.axis===\"yx\" && d.overflowed[1]){\n\t\t\t\t\t\t\t\t\t_scrollTo($this,to[1].toString(),{dir:\"x\",dur:0,overwrite:\"none\"});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}else if(mCSB_dragger[0].height()>mCSB_dragger[0].parent().height()){\n\t\t\t\t\t\t\t\t_resetContentPosition.call(this); /* reset content position */\n\t\t\t\t\t\t\t}else{ /* y scrolling is required */\n\t\t\t\t\t\t\t\t_scrollTo($this,to[0].toString(),{dir:\"y\",dur:0,overwrite:\"none\"});\n\t\t\t\t\t\t\t\td.contentReset.y=null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(o.axis!==\"y\"){ /* x/yx axis */\n\t\t\t\t\t\t\tif(!d.overflowed[1]){ /* x scrolling is not required */\n\t\t\t\t\t\t\t\t_resetContentPosition.call(this); /* reset content position */\n\t\t\t\t\t\t\t\tif(o.axis===\"x\"){\n\t\t\t\t\t\t\t\t\t_unbindEvents.call(this);\n\t\t\t\t\t\t\t\t}else if(o.axis===\"yx\" && d.overflowed[0]){\n\t\t\t\t\t\t\t\t\t_scrollTo($this,to[0].toString(),{dir:\"y\",dur:0,overwrite:\"none\"});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}else if(mCSB_dragger[1].width()>mCSB_dragger[1].parent().width()){\n\t\t\t\t\t\t\t\t_resetContentPosition.call(this); /* reset content position */\n\t\t\t\t\t\t\t}else{ /* x scrolling is required */\n\t\t\t\t\t\t\t\t_scrollTo($this,to[1].toString(),{dir:\"x\",dur:0,overwrite:\"none\"});\n\t\t\t\t\t\t\t\td.contentReset.x=null;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* callbacks: onImageLoad, onSelectorChange, onUpdate */\n\t\t\t\t\t\tif(cb && d){\n\t\t\t\t\t\t\tif(cb===2 && o.callbacks.onImageLoad && typeof o.callbacks.onImageLoad===\"function\"){\n\t\t\t\t\t\t\t\to.callbacks.onImageLoad.call(this);\n\t\t\t\t\t\t\t}else if(cb===3 && o.callbacks.onSelectorChange && typeof o.callbacks.onSelectorChange===\"function\"){\n\t\t\t\t\t\t\t\to.callbacks.onSelectorChange.call(this);\n\t\t\t\t\t\t\t}else if(o.callbacks.onUpdate && typeof o.callbacks.onUpdate===\"function\"){\n\t\t\t\t\t\t\t\to.callbacks.onUpdate.call(this);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\t_autoUpdate.call(this); /* initialize automatic updating (for dynamic content, fluid layouts etc.) */\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t});\n\t\t\t\t\n\t\t\t},\n\t\t\t/* ---------------------------------------- */\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/* \n\t\t\tplugin scrollTo method \n\t\t\ttriggers a scrolling event to a specific value\n\t\t\t----------------------------------------\n\t\t\tusage: $(selector).mCustomScrollbar(\"scrollTo\",value,options);\n\t\t\t*/\n\t\t\n\t\t\tscrollTo:function(val,options){\n\t\t\t\t\n\t\t\t\t/* prevent silly things like $(selector).mCustomScrollbar(\"scrollTo\",undefined); */\n\t\t\t\tif(typeof val==\"undefined\" || val==null){return;}\n\t\t\t\t\n\t\t\t\tvar selector=_selector.call(this); /* validate selector */\n\t\t\t\t\n\t\t\t\treturn $(selector).each(function(){\n\t\t\t\t\t\n\t\t\t\t\tvar $this=$(this);\n\t\t\t\t\t\n\t\t\t\t\tif($this.data(pluginPfx)){ /* check if plugin has initialized */\n\t\t\t\t\t\n\t\t\t\t\t\tvar d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\t\t\t\t/* method default options */\n\t\t\t\t\t\t\tmethodDefaults={\n\t\t\t\t\t\t\t\ttrigger:\"external\", /* method is by default triggered externally (e.g. from other scripts) */\n\t\t\t\t\t\t\t\tscrollInertia:o.scrollInertia, /* scrolling inertia (animation duration) */\n\t\t\t\t\t\t\t\tscrollEasing:\"mcsEaseInOut\", /* animation easing */\n\t\t\t\t\t\t\t\tmoveDragger:false, /* move dragger instead of content */\n\t\t\t\t\t\t\t\ttimeout:60, /* scroll-to delay */\n\t\t\t\t\t\t\t\tcallbacks:true, /* enable/disable callbacks */\n\t\t\t\t\t\t\t\tonStart:true,\n\t\t\t\t\t\t\t\tonUpdate:true,\n\t\t\t\t\t\t\t\tonComplete:true\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tmethodOptions=$.extend(true,{},methodDefaults,options),\n\t\t\t\t\t\t\tto=_arr.call(this,val),dur=methodOptions.scrollInertia>0 && methodOptions.scrollInertia<17 ? 17 : methodOptions.scrollInertia;\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* translate yx values to actual scroll-to positions */\n\t\t\t\t\t\tto[0]=_to.call(this,to[0],\"y\");\n\t\t\t\t\t\tto[1]=_to.call(this,to[1],\"x\");\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* \n\t\t\t\t\t\tcheck if scroll-to value moves the dragger instead of content. \n\t\t\t\t\t\tOnly pixel values apply on dragger (e.g. 100, \"100px\", \"-=100\" etc.) \n\t\t\t\t\t\t*/\n\t\t\t\t\t\tif(methodOptions.moveDragger){\n\t\t\t\t\t\t\tto[0]*=d.scrollRatio.y;\n\t\t\t\t\t\t\tto[1]*=d.scrollRatio.x;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t\tmethodOptions.dur=dur;\n\t\t\t\t\t\t\n\t\t\t\t\t\tsetTimeout(function(){ \n\t\t\t\t\t\t\t/* do the scrolling */\n\t\t\t\t\t\t\tif(to[0]!==null && typeof to[0]!==\"undefined\" && o.axis!==\"x\" && d.overflowed[0]){ /* scroll y */\n\t\t\t\t\t\t\t\tmethodOptions.dir=\"y\";\n\t\t\t\t\t\t\t\tmethodOptions.overwrite=\"all\";\n\t\t\t\t\t\t\t\t_scrollTo($this,to[0].toString(),methodOptions);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(to[1]!==null && typeof to[1]!==\"undefined\" && o.axis!==\"y\" && d.overflowed[1]){ /* scroll x */\n\t\t\t\t\t\t\t\tmethodOptions.dir=\"x\";\n\t\t\t\t\t\t\t\tmethodOptions.overwrite=\"none\";\n\t\t\t\t\t\t\t\t_scrollTo($this,to[1].toString(),methodOptions);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},methodOptions.timeout);\n\t\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t});\n\t\t\t\t\n\t\t\t},\n\t\t\t/* ---------------------------------------- */\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/*\n\t\t\tplugin stop method \n\t\t\tstops scrolling animation\n\t\t\t----------------------------------------\n\t\t\tusage: $(selector).mCustomScrollbar(\"stop\");\n\t\t\t*/\n\t\t\tstop:function(){\n\t\t\t\t\n\t\t\t\tvar selector=_selector.call(this); /* validate selector */\n\t\t\t\t\n\t\t\t\treturn $(selector).each(function(){\n\t\t\t\t\t\n\t\t\t\t\tvar $this=$(this);\n\t\t\t\t\t\n\t\t\t\t\tif($this.data(pluginPfx)){ /* check if plugin has initialized */\n\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t_stop($this);\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t});\n\t\t\t\t\n\t\t\t},\n\t\t\t/* ---------------------------------------- */\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/*\n\t\t\tplugin disable method \n\t\t\ttemporarily disables the scrollbar(s) \n\t\t\t----------------------------------------\n\t\t\tusage: $(selector).mCustomScrollbar(\"disable\",reset); \n\t\t\treset (boolean): resets content position to 0 \n\t\t\t*/\n\t\t\tdisable:function(r){\n\t\t\t\t\n\t\t\t\tvar selector=_selector.call(this); /* validate selector */\n\t\t\t\t\n\t\t\t\treturn $(selector).each(function(){\n\t\t\t\t\t\n\t\t\t\t\tvar $this=$(this);\n\t\t\t\t\t\n\t\t\t\t\tif($this.data(pluginPfx)){ /* check if plugin has initialized */\n\t\t\t\t\t\t\n\t\t\t\t\t\tvar d=$this.data(pluginPfx);\n\t\t\t\t\t\t\n\t\t\t\t\t\t_autoUpdate.call(this,\"remove\"); /* remove automatic updating */\n\t\t\t\t\t\t\n\t\t\t\t\t\t_unbindEvents.call(this); /* unbind events */\n\t\t\t\t\t\t\n\t\t\t\t\t\tif(r){_resetContentPosition.call(this);} /* reset content position */\n\t\t\t\t\t\t\n\t\t\t\t\t\t_scrollbarVisibility.call(this,true); /* show/hide scrollbar(s) */\n\t\t\t\t\t\t\n\t\t\t\t\t\t$this.addClass(classes[3]); /* add disable class */\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t});\n\t\t\t\t\n\t\t\t},\n\t\t\t/* ---------------------------------------- */\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t/*\n\t\t\tplugin destroy method \n\t\t\tcompletely removes the scrollbar(s) and returns the element to its original state\n\t\t\t----------------------------------------\n\t\t\tusage: $(selector).mCustomScrollbar(\"destroy\"); \n\t\t\t*/\n\t\t\tdestroy:function(){\n\t\t\t\t\n\t\t\t\tvar selector=_selector.call(this); /* validate selector */\n\t\t\t\t\n\t\t\t\treturn $(selector).each(function(){\n\t\t\t\t\t\n\t\t\t\t\tvar $this=$(this);\n\t\t\t\t\t\n\t\t\t\t\tif($this.data(pluginPfx)){ /* check if plugin has initialized */\n\t\t\t\t\t\n\t\t\t\t\t\tvar d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\t\t\t\tscrollbar=$(\".mCSB_\"+d.idx+\"_scrollbar\");\n\t\t\t\t\t\n\t\t\t\t\t\tif(o.live){removeLiveTimers(o.liveSelector || $(selector).selector);} /* remove live timers */\n\t\t\t\t\t\t\n\t\t\t\t\t\t_autoUpdate.call(this,\"remove\"); /* remove automatic updating */\n\t\t\t\t\t\t\n\t\t\t\t\t\t_unbindEvents.call(this); /* unbind events */\n\t\t\t\t\t\t\n\t\t\t\t\t\t_resetContentPosition.call(this); /* reset content position */\n\t\t\t\t\t\t\n\t\t\t\t\t\t$this.removeData(pluginPfx); /* remove plugin data object */\n\t\t\t\t\t\t\n\t\t\t\t\t\t_delete(this,\"mcs\"); /* delete callbacks object */\n\t\t\t\t\t\t\n\t\t\t\t\t\t/* remove plugin markup */\n\t\t\t\t\t\tscrollbar.remove(); /* remove scrollbar(s) first (those can be either inside or outside plugin's inner wrapper) */\n\t\t\t\t\t\tmCSB_container.find(\"img.\"+classes[2]).removeClass(classes[2]); /* remove loaded images flag */\n\t\t\t\t\t\tmCustomScrollBox.replaceWith(mCSB_container.contents()); /* replace plugin's inner wrapper with the original content */\n\t\t\t\t\t\t/* remove plugin classes from the element and add destroy class */\n\t\t\t\t\t\t$this.removeClass(pluginNS+\" _\"+pluginPfx+\"_\"+d.idx+\" \"+classes[6]+\" \"+classes[7]+\" \"+classes[5]+\" \"+classes[3]).addClass(classes[4]);\n\t\t\t\t\t\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t});\n\t\t\t\t\n\t\t\t}\n\t\t\t/* ---------------------------------------- */\n\t\t\t\n\t\t},\n\t\n\t\n\t\n\t\n\t\t\n\t/* \n\t----------------------------------------\n\tFUNCTIONS\n\t----------------------------------------\n\t*/\n\t\n\t\t/* validates selector (if selector is invalid or undefined uses the default one) */\n\t\t_selector=function(){\n\t\t\treturn (typeof $(this)!==\"object\" || $(this).length<1) ? defaultSelector : this;\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* changes options according to theme */\n\t\t_theme=function(obj){\n\t\t\tvar fixedSizeScrollbarThemes=[\"rounded\",\"rounded-dark\",\"rounded-dots\",\"rounded-dots-dark\"],\n\t\t\t\tnonExpandedScrollbarThemes=[\"rounded-dots\",\"rounded-dots-dark\",\"3d\",\"3d-dark\",\"3d-thick\",\"3d-thick-dark\",\"inset\",\"inset-dark\",\"inset-2\",\"inset-2-dark\",\"inset-3\",\"inset-3-dark\"],\n\t\t\t\tdisabledScrollButtonsThemes=[\"minimal\",\"minimal-dark\"],\n\t\t\t\tenabledAutoHideScrollbarThemes=[\"minimal\",\"minimal-dark\"],\n\t\t\t\tscrollbarPositionOutsideThemes=[\"minimal\",\"minimal-dark\"];\n\t\t\tobj.autoDraggerLength=$.inArray(obj.theme,fixedSizeScrollbarThemes) > -1 ? false : obj.autoDraggerLength;\n\t\t\tobj.autoExpandScrollbar=$.inArray(obj.theme,nonExpandedScrollbarThemes) > -1 ? false : obj.autoExpandScrollbar;\n\t\t\tobj.scrollButtons.enable=$.inArray(obj.theme,disabledScrollButtonsThemes) > -1 ? false : obj.scrollButtons.enable;\n\t\t\tobj.autoHideScrollbar=$.inArray(obj.theme,enabledAutoHideScrollbarThemes) > -1 ? true : obj.autoHideScrollbar;\n\t\t\tobj.scrollbarPosition=$.inArray(obj.theme,scrollbarPositionOutsideThemes) > -1 ? \"outside\" : obj.scrollbarPosition;\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* live option timers removal */\n\t\tremoveLiveTimers=function(selector){\n\t\t\tif(liveTimers[selector]){\n\t\t\t\tclearTimeout(liveTimers[selector]);\n\t\t\t\t_delete(liveTimers,selector);\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* normalizes axis option to valid values: \"y\", \"x\", \"yx\" */\n\t\t_findAxis=function(val){\n\t\t\treturn (val===\"yx\" || val===\"xy\" || val===\"auto\") ? \"yx\" : (val===\"x\" || val===\"horizontal\") ? \"x\" : \"y\";\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* normalizes scrollButtons.scrollType option to valid values: \"stepless\", \"stepped\" */\n\t\t_findScrollButtonsType=function(val){\n\t\t\treturn (val===\"stepped\" || val===\"pixels\" || val===\"step\" || val===\"click\") ? \"stepped\" : \"stepless\";\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* generates plugin markup */\n\t\t_pluginMarkup=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\texpandClass=o.autoExpandScrollbar ? \" \"+classes[1]+\"_expand\" : \"\",\n\t\t\t\tscrollbar=[\"<div id='mCSB_\"+d.idx+\"_scrollbar_vertical' class='mCSB_scrollTools mCSB_\"+d.idx+\"_scrollbar mCS-\"+o.theme+\" mCSB_scrollTools_vertical\"+expandClass+\"'><div class='\"+classes[12]+\"'><div id='mCSB_\"+d.idx+\"_dragger_vertical' class='mCSB_dragger' style='position:absolute;' oncontextmenu='return false;'><div class='mCSB_dragger_bar' /></div><div class='mCSB_draggerRail' /></div></div>\",\"<div id='mCSB_\"+d.idx+\"_scrollbar_horizontal' class='mCSB_scrollTools mCSB_\"+d.idx+\"_scrollbar mCS-\"+o.theme+\" mCSB_scrollTools_horizontal\"+expandClass+\"'><div class='\"+classes[12]+\"'><div id='mCSB_\"+d.idx+\"_dragger_horizontal' class='mCSB_dragger' style='position:absolute;' oncontextmenu='return false;'><div class='mCSB_dragger_bar' /></div><div class='mCSB_draggerRail' /></div></div>\"],\n\t\t\t\twrapperClass=o.axis===\"yx\" ? \"mCSB_vertical_horizontal\" : o.axis===\"x\" ? \"mCSB_horizontal\" : \"mCSB_vertical\",\n\t\t\t\tscrollbars=o.axis===\"yx\" ? scrollbar[0]+scrollbar[1] : o.axis===\"x\" ? scrollbar[1] : scrollbar[0],\n\t\t\t\tcontentWrapper=o.axis===\"yx\" ? \"<div id='mCSB_\"+d.idx+\"_container_wrapper' class='mCSB_container_wrapper' />\" : \"\",\n\t\t\t\tautoHideClass=o.autoHideScrollbar ? \" \"+classes[6] : \"\",\n\t\t\t\tscrollbarDirClass=(o.axis!==\"x\" && d.langDir===\"rtl\") ? \" \"+classes[7] : \"\";\n\t\t\tif(o.setWidth){$this.css(\"width\",o.setWidth);} /* set element width */\n\t\t\tif(o.setHeight){$this.css(\"height\",o.setHeight);} /* set element height */\n\t\t\to.setLeft=(o.axis!==\"y\" && d.langDir===\"rtl\") ? \"989999px\" : o.setLeft; /* adjust left position for rtl direction */\n\t\t\t$this.addClass(pluginNS+\" _\"+pluginPfx+\"_\"+d.idx+autoHideClass+scrollbarDirClass).wrapInner(\"<div id='mCSB_\"+d.idx+\"' class='mCustomScrollBox mCS-\"+o.theme+\" \"+wrapperClass+\"'><div id='mCSB_\"+d.idx+\"_container' class='mCSB_container' style='position:relative; top:\"+o.setTop+\"; left:\"+o.setLeft+\";' dir=\"+d.langDir+\" /></div>\");\n\t\t\tvar mCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\");\n\t\t\tif(o.axis!==\"y\" && !o.advanced.autoExpandHorizontalScroll){\n\t\t\t\tmCSB_container.css(\"width\",_contentWidth(mCSB_container));\n\t\t\t}\n\t\t\tif(o.scrollbarPosition===\"outside\"){\n\t\t\t\tif($this.css(\"position\")===\"static\"){ /* requires elements with non-static position */\n\t\t\t\t\t$this.css(\"position\",\"relative\");\n\t\t\t\t}\n\t\t\t\t$this.css(\"overflow\",\"visible\");\n\t\t\t\tmCustomScrollBox.addClass(\"mCSB_outside\").after(scrollbars);\n\t\t\t}else{\n\t\t\t\tmCustomScrollBox.addClass(\"mCSB_inside\").append(scrollbars);\n\t\t\t\tmCSB_container.wrap(contentWrapper);\n\t\t\t}\n\t\t\t_scrollButtons.call(this); /* add scrollbar buttons */\n\t\t\t/* minimum dragger length */\n\t\t\tvar mCSB_dragger=[$(\"#mCSB_\"+d.idx+\"_dragger_vertical\"),$(\"#mCSB_\"+d.idx+\"_dragger_horizontal\")];\n\t\t\tmCSB_dragger[0].css(\"min-height\",mCSB_dragger[0].height());\n\t\t\tmCSB_dragger[1].css(\"min-width\",mCSB_dragger[1].width());\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* calculates content width */\n\t\t_contentWidth=function(el){\n\t\t\tvar val=[el[0].scrollWidth,Math.max.apply(Math,el.children().map(function(){return $(this).outerWidth(true);}).get())],w=el.parent().width();\n\t\t\treturn val[0]>w ? val[0] : val[1]>w ? val[1] : \"100%\";\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* expands content horizontally */\n\t\t_expandContentHorizontally=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\");\n\t\t\tif(o.advanced.autoExpandHorizontalScroll && o.axis!==\"y\"){\n\t\t\t\t/* calculate scrollWidth */\n\t\t\t\tmCSB_container.css({\"width\":\"auto\",\"min-width\":0,\"overflow-x\":\"scroll\"});\n\t\t\t\tvar w=Math.ceil(mCSB_container[0].scrollWidth);\n\t\t\t\tif(o.advanced.autoExpandHorizontalScroll===3 || (o.advanced.autoExpandHorizontalScroll!==2 && w>mCSB_container.parent().width())){\n\t\t\t\t\tmCSB_container.css({\"width\":w,\"min-width\":\"100%\",\"overflow-x\":\"inherit\"});\n\t\t\t\t}else{\n\t\t\t\t\t/* \n\t\t\t\t\twrap content with an infinite width div and set its position to absolute and width to auto. \n\t\t\t\t\tSetting width to auto before calculating the actual width is important! \n\t\t\t\t\tWe must let the browser set the width as browser zoom values are impossible to calculate.\n\t\t\t\t\t*/\n\t\t\t\t\tmCSB_container.css({\"overflow-x\":\"inherit\",\"position\":\"absolute\"})\n\t\t\t\t\t\t.wrap(\"<div class='mCSB_h_wrapper' style='position:relative; left:0; width:999999px;' />\")\n\t\t\t\t\t\t.css({ /* set actual width, original position and un-wrap */\n\t\t\t\t\t\t\t/* \n\t\t\t\t\t\t\tget the exact width (with decimals) and then round-up. \n\t\t\t\t\t\t\tUsing jquery outerWidth() will round the width value which will mess up with inner elements that have non-integer width\n\t\t\t\t\t\t\t*/\n\t\t\t\t\t\t\t\"width\":(Math.ceil(mCSB_container[0].getBoundingClientRect().right+0.4)-Math.floor(mCSB_container[0].getBoundingClientRect().left)),\n\t\t\t\t\t\t\t\"min-width\":\"100%\",\n\t\t\t\t\t\t\t\"position\":\"relative\"\n\t\t\t\t\t\t}).unwrap();\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* adds scrollbar buttons */\n\t\t_scrollButtons=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tmCSB_scrollTools=$(\".mCSB_\"+d.idx+\"_scrollbar:first\"),\n\t\t\t\ttabindex=!_isNumeric(o.scrollButtons.tabindex) ? \"\" : \"tabindex='\"+o.scrollButtons.tabindex+\"'\",\n\t\t\t\tbtnHTML=[\n\t\t\t\t\t\"<a href='#' class='\"+classes[13]+\"' oncontextmenu='return false;' \"+tabindex+\" />\",\n\t\t\t\t\t\"<a href='#' class='\"+classes[14]+\"' oncontextmenu='return false;' \"+tabindex+\" />\",\n\t\t\t\t\t\"<a href='#' class='\"+classes[15]+\"' oncontextmenu='return false;' \"+tabindex+\" />\",\n\t\t\t\t\t\"<a href='#' class='\"+classes[16]+\"' oncontextmenu='return false;' \"+tabindex+\" />\"\n\t\t\t\t],\n\t\t\t\tbtn=[(o.axis===\"x\" ? btnHTML[2] : btnHTML[0]),(o.axis===\"x\" ? btnHTML[3] : btnHTML[1]),btnHTML[2],btnHTML[3]];\n\t\t\tif(o.scrollButtons.enable){\n\t\t\t\tmCSB_scrollTools.prepend(btn[0]).append(btn[1]).next(\".mCSB_scrollTools\").prepend(btn[2]).append(btn[3]);\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* auto-adjusts scrollbar dragger length */\n\t\t_setDraggerLength=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),\n\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\tmCSB_dragger=[$(\"#mCSB_\"+d.idx+\"_dragger_vertical\"),$(\"#mCSB_\"+d.idx+\"_dragger_horizontal\")],\n\t\t\t\tratio=[mCustomScrollBox.height()/mCSB_container.outerHeight(false),mCustomScrollBox.width()/mCSB_container.outerWidth(false)],\n\t\t\t\tl=[\n\t\t\t\t\tparseInt(mCSB_dragger[0].css(\"min-height\")),Math.round(ratio[0]*mCSB_dragger[0].parent().height()),\n\t\t\t\t\tparseInt(mCSB_dragger[1].css(\"min-width\")),Math.round(ratio[1]*mCSB_dragger[1].parent().width())\n\t\t\t\t],\n\t\t\t\th=oldIE && (l[1]<l[0]) ? l[0] : l[1],w=oldIE && (l[3]<l[2]) ? l[2] : l[3];\n\t\t\tmCSB_dragger[0].css({\n\t\t\t\t\"height\":h,\"max-height\":(mCSB_dragger[0].parent().height()-10)\n\t\t\t}).find(\".mCSB_dragger_bar\").css({\"line-height\":l[0]+\"px\"});\n\t\t\tmCSB_dragger[1].css({\n\t\t\t\t\"width\":w,\"max-width\":(mCSB_dragger[1].parent().width()-10)\n\t\t\t});\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* calculates scrollbar to content ratio */\n\t\t_scrollRatio=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),\n\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\tmCSB_dragger=[$(\"#mCSB_\"+d.idx+\"_dragger_vertical\"),$(\"#mCSB_\"+d.idx+\"_dragger_horizontal\")],\n\t\t\t\tscrollAmount=[mCSB_container.outerHeight(false)-mCustomScrollBox.height(),mCSB_container.outerWidth(false)-mCustomScrollBox.width()],\n\t\t\t\tratio=[\n\t\t\t\t\tscrollAmount[0]/(mCSB_dragger[0].parent().height()-mCSB_dragger[0].height()),\n\t\t\t\t\tscrollAmount[1]/(mCSB_dragger[1].parent().width()-mCSB_dragger[1].width())\n\t\t\t\t];\n\t\t\td.scrollRatio={y:ratio[0],x:ratio[1]};\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* toggles scrolling classes */\n\t\t_onDragClasses=function(el,action,xpnd){\n\t\t\tvar expandClass=xpnd ? classes[0]+\"_expanded\" : \"\",\n\t\t\t\tscrollbar=el.closest(\".mCSB_scrollTools\");\n\t\t\tif(action===\"active\"){\n\t\t\t\tel.toggleClass(classes[0]+\" \"+expandClass); scrollbar.toggleClass(classes[1]); \n\t\t\t\tel[0]._draggable=el[0]._draggable ? 0 : 1;\n\t\t\t}else{\n\t\t\t\tif(!el[0]._draggable){\n\t\t\t\t\tif(action===\"hide\"){\n\t\t\t\t\t\tel.removeClass(classes[0]); scrollbar.removeClass(classes[1]);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tel.addClass(classes[0]); scrollbar.addClass(classes[1]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* checks if content overflows its container to determine if scrolling is required */\n\t\t_overflowed=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),\n\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\tcontentHeight=d.overflowed==null ? mCSB_container.height() : mCSB_container.outerHeight(false),\n\t\t\t\tcontentWidth=d.overflowed==null ? mCSB_container.width() : mCSB_container.outerWidth(false),\n\t\t\t\th=mCSB_container[0].scrollHeight,w=mCSB_container[0].scrollWidth;\n\t\t\tif(h>contentHeight){contentHeight=h;}\n\t\t\tif(w>contentWidth){contentWidth=w;}\n\t\t\treturn [contentHeight>mCustomScrollBox.height(),contentWidth>mCustomScrollBox.width()];\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* resets content position to 0 */\n\t\t_resetContentPosition=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\tmCSB_dragger=[$(\"#mCSB_\"+d.idx+\"_dragger_vertical\"),$(\"#mCSB_\"+d.idx+\"_dragger_horizontal\")];\n\t\t\t_stop($this); /* stop any current scrolling before resetting */\n\t\t\tif((o.axis!==\"x\" && !d.overflowed[0]) || (o.axis===\"y\" && d.overflowed[0])){ /* reset y */\n\t\t\t\tmCSB_dragger[0].add(mCSB_container).css(\"top\",0);\n\t\t\t\t_scrollTo($this,\"_resetY\");\n\t\t\t}\n\t\t\tif((o.axis!==\"y\" && !d.overflowed[1]) || (o.axis===\"x\" && d.overflowed[1])){ /* reset x */\n\t\t\t\tvar cx=dx=0;\n\t\t\t\tif(d.langDir===\"rtl\"){ /* adjust left position for rtl direction */\n\t\t\t\t\tcx=mCustomScrollBox.width()-mCSB_container.outerWidth(false);\n\t\t\t\t\tdx=Math.abs(cx/d.scrollRatio.x);\n\t\t\t\t}\n\t\t\t\tmCSB_container.css(\"left\",cx);\n\t\t\t\tmCSB_dragger[1].css(\"left\",dx);\n\t\t\t\t_scrollTo($this,\"_resetX\");\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* binds scrollbar events */\n\t\t_bindEvents=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt;\n\t\t\tif(!d.bindEvents){ /* check if events are already bound */\n\t\t\t\t_draggable.call(this);\n\t\t\t\tif(o.contentTouchScroll){_contentDraggable.call(this);}\n\t\t\t\t_selectable.call(this);\n\t\t\t\tif(o.mouseWheel.enable){ /* bind mousewheel fn when plugin is available */\n\t\t\t\t\tfunction _mwt(){\n\t\t\t\t\t\tmousewheelTimeout=setTimeout(function(){\n\t\t\t\t\t\t\tif(!$.event.special.mousewheel){\n\t\t\t\t\t\t\t\t_mwt();\n\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\tclearTimeout(mousewheelTimeout);\n\t\t\t\t\t\t\t\t_mousewheel.call($this[0]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},100);\n\t\t\t\t\t}\n\t\t\t\t\tvar mousewheelTimeout;\n\t\t\t\t\t_mwt();\n\t\t\t\t}\n\t\t\t\t_draggerRail.call(this);\n\t\t\t\t_wrapperScroll.call(this);\n\t\t\t\tif(o.advanced.autoScrollOnFocus){_focus.call(this);}\n\t\t\t\tif(o.scrollButtons.enable){_buttons.call(this);}\n\t\t\t\tif(o.keyboard.enable){_keyboard.call(this);}\n\t\t\t\td.bindEvents=true;\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* unbinds scrollbar events */\n\t\t_unbindEvents=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tsb=\".mCSB_\"+d.idx+\"_scrollbar\",\n\t\t\t\tsel=$(\"#mCSB_\"+d.idx+\",#mCSB_\"+d.idx+\"_container,#mCSB_\"+d.idx+\"_container_wrapper,\"+sb+\" .\"+classes[12]+\",#mCSB_\"+d.idx+\"_dragger_vertical,#mCSB_\"+d.idx+\"_dragger_horizontal,\"+sb+\">a\"),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\");\n\t\t\tif(o.advanced.releaseDraggableSelectors){sel.add($(o.advanced.releaseDraggableSelectors));}\n\t\t\tif(d.bindEvents){ /* check if events are bound */\n\t\t\t\t/* unbind namespaced events from document/selectors */\n\t\t\t\t$(document).unbind(\".\"+namespace);\n\t\t\t\tsel.each(function(){\n\t\t\t\t\t$(this).unbind(\".\"+namespace);\n\t\t\t\t});\n\t\t\t\t/* clear and delete timeouts/objects */\n\t\t\t\tclearTimeout($this[0]._focusTimeout); _delete($this[0],\"_focusTimeout\");\n\t\t\t\tclearTimeout(d.sequential.step); _delete(d.sequential,\"step\");\n\t\t\t\tclearTimeout(mCSB_container[0].onCompleteTimeout); _delete(mCSB_container[0],\"onCompleteTimeout\");\n\t\t\t\td.bindEvents=false;\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* toggles scrollbar visibility */\n\t\t_scrollbarVisibility=function(disabled){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tcontentWrapper=$(\"#mCSB_\"+d.idx+\"_container_wrapper\"),\n\t\t\t\tcontent=contentWrapper.length ? contentWrapper : $(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\tscrollbar=[$(\"#mCSB_\"+d.idx+\"_scrollbar_vertical\"),$(\"#mCSB_\"+d.idx+\"_scrollbar_horizontal\")],\n\t\t\t\tmCSB_dragger=[scrollbar[0].find(\".mCSB_dragger\"),scrollbar[1].find(\".mCSB_dragger\")];\n\t\t\tif(o.axis!==\"x\"){\n\t\t\t\tif(d.overflowed[0] && !disabled){\n\t\t\t\t\tscrollbar[0].add(mCSB_dragger[0]).add(scrollbar[0].children(\"a\")).css(\"display\",\"block\");\n\t\t\t\t\tcontent.removeClass(classes[8]+\" \"+classes[10]);\n\t\t\t\t}else{\n\t\t\t\t\tif(o.alwaysShowScrollbar){\n\t\t\t\t\t\tif(o.alwaysShowScrollbar!==2){mCSB_dragger[0].css(\"display\",\"none\");}\n\t\t\t\t\t\tcontent.removeClass(classes[10]);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tscrollbar[0].css(\"display\",\"none\");\n\t\t\t\t\t\tcontent.addClass(classes[10]);\n\t\t\t\t\t}\n\t\t\t\t\tcontent.addClass(classes[8]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(o.axis!==\"y\"){\n\t\t\t\tif(d.overflowed[1] && !disabled){\n\t\t\t\t\tscrollbar[1].add(mCSB_dragger[1]).add(scrollbar[1].children(\"a\")).css(\"display\",\"block\");\n\t\t\t\t\tcontent.removeClass(classes[9]+\" \"+classes[11]);\n\t\t\t\t}else{\n\t\t\t\t\tif(o.alwaysShowScrollbar){\n\t\t\t\t\t\tif(o.alwaysShowScrollbar!==2){mCSB_dragger[1].css(\"display\",\"none\");}\n\t\t\t\t\t\tcontent.removeClass(classes[11]);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tscrollbar[1].css(\"display\",\"none\");\n\t\t\t\t\t\tcontent.addClass(classes[11]);\n\t\t\t\t\t}\n\t\t\t\t\tcontent.addClass(classes[9]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!d.overflowed[0] && !d.overflowed[1]){\n\t\t\t\t$this.addClass(classes[5]);\n\t\t\t}else{\n\t\t\t\t$this.removeClass(classes[5]);\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* returns input coordinates of pointer, touch and mouse events (relative to document) */\n\t\t_coordinates=function(e){\n\t\t\tvar t=e.type;\n\t\t\tswitch(t){\n\t\t\t\tcase \"pointerdown\": case \"MSPointerDown\": case \"pointermove\": case \"MSPointerMove\": case \"pointerup\": case \"MSPointerUp\":\n\t\t\t\t\treturn e.target.ownerDocument!==document ? [e.originalEvent.screenY,e.originalEvent.screenX,false] : [e.originalEvent.pageY,e.originalEvent.pageX,false];\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"touchstart\": case \"touchmove\": case \"touchend\":\n\t\t\t\t\tvar touch=e.originalEvent.touches[0] || e.originalEvent.changedTouches[0],\n\t\t\t\t\t\ttouches=e.originalEvent.touches.length || e.originalEvent.changedTouches.length;\n\t\t\t\t\treturn e.target.ownerDocument!==document ? [touch.screenY,touch.screenX,touches>1] : [touch.pageY,touch.pageX,touches>1];\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn [e.pageY,e.pageX,false];\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tSCROLLBAR DRAG EVENTS\n\t\tscrolls content via scrollbar dragging \n\t\t*/\n\t\t_draggable=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tdraggerId=[\"mCSB_\"+d.idx+\"_dragger_vertical\",\"mCSB_\"+d.idx+\"_dragger_horizontal\"],\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\tmCSB_dragger=$(\"#\"+draggerId[0]+\",#\"+draggerId[1]),\n\t\t\t\tdraggable,dragY,dragX,\n\t\t\t\trds=o.advanced.releaseDraggableSelectors ? mCSB_dragger.add($(o.advanced.releaseDraggableSelectors)) : mCSB_dragger;\n\t\t\tmCSB_dragger.bind(\"mousedown.\"+namespace+\" touchstart.\"+namespace+\" pointerdown.\"+namespace+\" MSPointerDown.\"+namespace,function(e){\n\t\t\t\te.stopImmediatePropagation();\n\t\t\t\te.preventDefault();\n\t\t\t\tif(!_mouseBtnLeft(e)){return;} /* left mouse button only */\n\t\t\t\ttouchActive=true;\n\t\t\t\tif(oldIE){document.onselectstart=function(){return false;}} /* disable text selection for IE < 9 */\n\t\t\t\t_iframe(false); /* enable scrollbar dragging over iframes by disabling their events */\n\t\t\t\t_stop($this);\n\t\t\t\tdraggable=$(this);\n\t\t\t\tvar offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left,\n\t\t\t\t\th=draggable.height()+offset.top,w=draggable.width()+offset.left;\n\t\t\t\tif(y<h && y>0 && x<w && x>0){\n\t\t\t\t\tdragY=y; \n\t\t\t\t\tdragX=x;\n\t\t\t\t}\n\t\t\t\t_onDragClasses(draggable,\"active\",o.autoExpandScrollbar); \n\t\t\t}).bind(\"touchmove.\"+namespace,function(e){\n\t\t\t\te.stopImmediatePropagation();\n\t\t\t\te.preventDefault();\n\t\t\t\tvar offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left;\n\t\t\t\t_drag(dragY,dragX,y,x);\n\t\t\t});\n\t\t\t$(document).bind(\"mousemove.\"+namespace+\" pointermove.\"+namespace+\" MSPointerMove.\"+namespace,function(e){\n\t\t\t\tif(draggable){\n\t\t\t\t\tvar offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left;\n\t\t\t\t\tif(dragY===y){return;} /* has it really moved? */\n\t\t\t\t\t_drag(dragY,dragX,y,x);\n\t\t\t\t}\n\t\t\t}).add(rds).bind(\"mouseup.\"+namespace+\" touchend.\"+namespace+\" pointerup.\"+namespace+\" MSPointerUp.\"+namespace,function(e){\n\t\t\t\tif(draggable){\n\t\t\t\t\t_onDragClasses(draggable,\"active\",o.autoExpandScrollbar); \n\t\t\t\t\tdraggable=null;\n\t\t\t\t}\n\t\t\t\ttouchActive=false;\n\t\t\t\tif(oldIE){document.onselectstart=null;} /* enable text selection for IE < 9 */\n\t\t\t\t_iframe(true); /* enable iframes events */\n\t\t\t});\n\t\t\tfunction _iframe(evt){\n\t\t\t\tvar el=mCSB_container.find(\"iframe\");\n\t\t\t\tif(!el.length){return;} /* check if content contains iframes */\n\t\t\t\tvar val=!evt ? \"none\" : \"auto\";\n\t\t\t\tel.css(\"pointer-events\",val); /* for IE11, iframe's display property should not be \"block\" */\n\t\t\t}\n\t\t\tfunction _drag(dragY,dragX,y,x){\n\t\t\t\tmCSB_container[0].idleTimer=o.scrollInertia<233 ? 250 : 0;\n\t\t\t\tif(draggable.attr(\"id\")===draggerId[1]){\n\t\t\t\t\tvar dir=\"x\",to=((draggable[0].offsetLeft-dragX)+x)*d.scrollRatio.x;\n\t\t\t\t}else{\n\t\t\t\t\tvar dir=\"y\",to=((draggable[0].offsetTop-dragY)+y)*d.scrollRatio.y;\n\t\t\t\t}\n\t\t\t\t_scrollTo($this,to.toString(),{dir:dir,drag:true});\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tTOUCH SWIPE EVENTS\n\t\tscrolls content via touch swipe \n\t\tEmulates the native touch-swipe scrolling with momentum found in iOS, Android and WP devices \n\t\t*/\n\t\t_contentDraggable=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\tmCSB_dragger=[$(\"#mCSB_\"+d.idx+\"_dragger_vertical\"),$(\"#mCSB_\"+d.idx+\"_dragger_horizontal\")],\n\t\t\t\tdraggable,dragY,dragX,touchStartY,touchStartX,touchMoveY=[],touchMoveX=[],startTime,runningTime,endTime,distance,speed,amount,\n\t\t\t\tdurA=0,durB,overwrite=o.axis===\"yx\" ? \"none\" : \"all\",touchIntent=[],touchDrag,docDrag,\n\t\t\t\tiframe=mCSB_container.find(\"iframe\"),\n\t\t\t\tevents=[\n\t\t\t\t\t\"touchstart.\"+namespace+\" pointerdown.\"+namespace+\" MSPointerDown.\"+namespace, //start\n\t\t\t\t\t\"touchmove.\"+namespace+\" pointermove.\"+namespace+\" MSPointerMove.\"+namespace, //move\n\t\t\t\t\t\"touchend.\"+namespace+\" pointerup.\"+namespace+\" MSPointerUp.\"+namespace //end\n\t\t\t\t],\n\t\t\t\ttouchAction=document.body.style.touchAction!==undefined;\n\t\t\tmCSB_container.bind(events[0],function(e){\n\t\t\t\t_onTouchstart(e);\n\t\t\t}).bind(events[1],function(e){\n\t\t\t\t_onTouchmove(e);\n\t\t\t});\n\t\t\tmCustomScrollBox.bind(events[0],function(e){\n\t\t\t\t_onTouchstart2(e);\n\t\t\t}).bind(events[2],function(e){\n\t\t\t\t_onTouchend(e);\n\t\t\t});\n\t\t\tif(iframe.length){\n\t\t\t\tiframe.each(function(){\n\t\t\t\t\t$(this).load(function(){\n\t\t\t\t\t\t/* bind events on accessible iframes */\n\t\t\t\t\t\tif(_canAccessIFrame(this)){\n\t\t\t\t\t\t\t$(this.contentDocument || this.contentWindow.document).bind(events[0],function(e){\n\t\t\t\t\t\t\t\t_onTouchstart(e);\n\t\t\t\t\t\t\t\t_onTouchstart2(e);\n\t\t\t\t\t\t\t}).bind(events[1],function(e){\n\t\t\t\t\t\t\t\t_onTouchmove(e);\n\t\t\t\t\t\t\t}).bind(events[2],function(e){\n\t\t\t\t\t\t\t\t_onTouchend(e);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t\tfunction _onTouchstart(e){\n\t\t\t\tif(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){touchable=0; return;}\n\t\t\t\ttouchable=1; touchDrag=0; docDrag=0; draggable=1;\n\t\t\t\t$this.removeClass(\"mCS_touch_action\");\n\t\t\t\tvar offset=mCSB_container.offset();\n\t\t\t\tdragY=_coordinates(e)[0]-offset.top;\n\t\t\t\tdragX=_coordinates(e)[1]-offset.left;\n\t\t\t\ttouchIntent=[_coordinates(e)[0],_coordinates(e)[1]];\n\t\t\t}\n\t\t\tfunction _onTouchmove(e){\n\t\t\t\tif(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){return;}\n\t\t\t\te.stopImmediatePropagation();\n\t\t\t\tif(docDrag && !touchDrag){return;}\n\t\t\t\tif(draggable){\n\t\t\t\t\trunningTime=_getTime();\n\t\t\t\t\tvar offset=mCustomScrollBox.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left,\n\t\t\t\t\t\teasing=\"mcsLinearOut\";\n\t\t\t\t\ttouchMoveY.push(y);\n\t\t\t\t\ttouchMoveX.push(x);\n\t\t\t\t\ttouchIntent[2]=Math.abs(_coordinates(e)[0]-touchIntent[0]); touchIntent[3]=Math.abs(_coordinates(e)[1]-touchIntent[1]);\n\t\t\t\t\tif(d.overflowed[0]){\n\t\t\t\t\t\tvar limit=mCSB_dragger[0].parent().height()-mCSB_dragger[0].height(),\n\t\t\t\t\t\t\tprevent=((dragY-y)>0 && (y-dragY)>-(limit*d.scrollRatio.y) && (touchIntent[3]*2<touchIntent[2] || o.axis===\"yx\"));\n\t\t\t\t\t}\n\t\t\t\t\tif(d.overflowed[1]){\n\t\t\t\t\t\tvar limitX=mCSB_dragger[1].parent().width()-mCSB_dragger[1].width(),\n\t\t\t\t\t\t\tpreventX=((dragX-x)>0 && (x-dragX)>-(limitX*d.scrollRatio.x) && (touchIntent[2]*2<touchIntent[3] || o.axis===\"yx\"));\n\t\t\t\t\t}\n\t\t\t\t\tif(prevent || preventX){ /* prevent native document scrolling */\n\t\t\t\t\t\tif(!touchAction){e.preventDefault();} \n\t\t\t\t\t\ttouchDrag=1;\n\t\t\t\t\t}else{\n\t\t\t\t\t\tdocDrag=1;\n\t\t\t\t\t\t$this.addClass(\"mCS_touch_action\");\n\t\t\t\t\t}\n\t\t\t\t\tif(touchAction){e.preventDefault();} \n\t\t\t\t\tamount=o.axis===\"yx\" ? [(dragY-y),(dragX-x)] : o.axis===\"x\" ? [null,(dragX-x)] : [(dragY-y),null];\n\t\t\t\t\tmCSB_container[0].idleTimer=250;\n\t\t\t\t\tif(d.overflowed[0]){_drag(amount[0],durA,easing,\"y\",\"all\",true);}\n\t\t\t\t\tif(d.overflowed[1]){_drag(amount[1],durA,easing,\"x\",overwrite,true);}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfunction _onTouchstart2(e){\n\t\t\t\tif(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){touchable=0; return;}\n\t\t\t\ttouchable=1;\n\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t_stop($this);\n\t\t\t\tstartTime=_getTime();\n\t\t\t\tvar offset=mCustomScrollBox.offset();\n\t\t\t\ttouchStartY=_coordinates(e)[0]-offset.top;\n\t\t\t\ttouchStartX=_coordinates(e)[1]-offset.left;\n\t\t\t\ttouchMoveY=[]; touchMoveX=[];\n\t\t\t}\n\t\t\tfunction _onTouchend(e){\n\t\t\t\tif(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){return;}\n\t\t\t\tdraggable=0;\n\t\t\t\te.stopImmediatePropagation();\n\t\t\t\ttouchDrag=0; docDrag=0;\n\t\t\t\tendTime=_getTime();\n\t\t\t\tvar offset=mCustomScrollBox.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left;\n\t\t\t\tif((endTime-runningTime)>30){return;}\n\t\t\t\tspeed=1000/(endTime-startTime);\n\t\t\t\tvar easing=\"mcsEaseOut\",slow=speed<2.5,\n\t\t\t\t\tdiff=slow ? [touchMoveY[touchMoveY.length-2],touchMoveX[touchMoveX.length-2]] : [0,0];\n\t\t\t\tdistance=slow ? [(y-diff[0]),(x-diff[1])] : [y-touchStartY,x-touchStartX];\n\t\t\t\tvar absDistance=[Math.abs(distance[0]),Math.abs(distance[1])];\n\t\t\t\tspeed=slow ? [Math.abs(distance[0]/4),Math.abs(distance[1]/4)] : [speed,speed];\n\t\t\t\tvar a=[\n\t\t\t\t\tMath.abs(mCSB_container[0].offsetTop)-(distance[0]*_m((absDistance[0]/speed[0]),speed[0])),\n\t\t\t\t\tMath.abs(mCSB_container[0].offsetLeft)-(distance[1]*_m((absDistance[1]/speed[1]),speed[1]))\n\t\t\t\t];\n\t\t\t\tamount=o.axis===\"yx\" ? [a[0],a[1]] : o.axis===\"x\" ? [null,a[1]] : [a[0],null];\n\t\t\t\tdurB=[(absDistance[0]*4)+o.scrollInertia,(absDistance[1]*4)+o.scrollInertia];\n\t\t\t\tvar md=parseInt(o.contentTouchScroll) || 0; /* absolute minimum distance required */\n\t\t\t\tamount[0]=absDistance[0]>md ? amount[0] : 0;\n\t\t\t\tamount[1]=absDistance[1]>md ? amount[1] : 0;\n\t\t\t\tif(d.overflowed[0]){_drag(amount[0],durB[0],easing,\"y\",overwrite,false);}\n\t\t\t\tif(d.overflowed[1]){_drag(amount[1],durB[1],easing,\"x\",overwrite,false);}\n\t\t\t}\n\t\t\tfunction _m(ds,s){\n\t\t\t\tvar r=[s*1.5,s*2,s/1.5,s/2];\n\t\t\t\tif(ds>90){\n\t\t\t\t\treturn s>4 ? r[0] : r[3];\n\t\t\t\t}else if(ds>60){\n\t\t\t\t\treturn s>3 ? r[3] : r[2];\n\t\t\t\t}else if(ds>30){\n\t\t\t\t\treturn s>8 ? r[1] : s>6 ? r[0] : s>4 ? s : r[2];\n\t\t\t\t}else{\n\t\t\t\t\treturn s>8 ? s : r[3];\n\t\t\t\t}\n\t\t\t}\n\t\t\tfunction _drag(amount,dur,easing,dir,overwrite,drag){\n\t\t\t\tif(!amount){return;}\n\t\t\t\t_scrollTo($this,amount.toString(),{dur:dur,scrollEasing:easing,dir:dir,overwrite:overwrite,drag:drag});\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tSELECT TEXT EVENTS \n\t\tscrolls content when text is selected \n\t\t*/\n\t\t_selectable=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential,\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\twrapper=mCSB_container.parent(),\n\t\t\t\taction;\n\t\t\tmCSB_container.bind(\"mousedown.\"+namespace,function(e){\n\t\t\t\tif(touchable){return;}\n\t\t\t\tif(!action){action=1; touchActive=true;}\n\t\t\t}).add(document).bind(\"mousemove.\"+namespace,function(e){\n\t\t\t\tif(!touchable && action && _sel()){\n\t\t\t\t\tvar offset=mCSB_container.offset(),\n\t\t\t\t\t\ty=_coordinates(e)[0]-offset.top+mCSB_container[0].offsetTop,x=_coordinates(e)[1]-offset.left+mCSB_container[0].offsetLeft;\n\t\t\t\t\tif(y>0 && y<wrapper.height() && x>0 && x<wrapper.width()){\n\t\t\t\t\t\tif(seq.step){_seq(\"off\",null,\"stepped\");}\n\t\t\t\t\t}else{\n\t\t\t\t\t\tif(o.axis!==\"x\" && d.overflowed[0]){\n\t\t\t\t\t\t\tif(y<0){\n\t\t\t\t\t\t\t\t_seq(\"on\",38);\n\t\t\t\t\t\t\t}else if(y>wrapper.height()){\n\t\t\t\t\t\t\t\t_seq(\"on\",40);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(o.axis!==\"y\" && d.overflowed[1]){\n\t\t\t\t\t\t\tif(x<0){\n\t\t\t\t\t\t\t\t_seq(\"on\",37);\n\t\t\t\t\t\t\t}else if(x>wrapper.width()){\n\t\t\t\t\t\t\t\t_seq(\"on\",39);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}).bind(\"mouseup.\"+namespace+\" dragend.\"+namespace,function(e){\n\t\t\t\tif(touchable){return;}\n\t\t\t\tif(action){action=0; _seq(\"off\",null);}\n\t\t\t\ttouchActive=false;\n\t\t\t});\n\t\t\tfunction _sel(){\n\t\t\t\treturn \twindow.getSelection ? window.getSelection().toString() : \n\t\t\t\t\t\tdocument.selection && document.selection.type!=\"Control\" ? document.selection.createRange().text : 0;\n\t\t\t}\n\t\t\tfunction _seq(a,c,s){\n\t\t\t\tseq.type=s && action ? \"stepped\" : \"stepless\";\n\t\t\t\tseq.scrollAmount=10;\n\t\t\t\t_sequentialScroll($this,a,c,\"mcsLinearOut\",s ? 60 : null);\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tMOUSE WHEEL EVENT\n\t\tscrolls content via mouse-wheel \n\t\tvia mouse-wheel plugin (https://github.com/brandonaaron/jquery-mousewheel)\n\t\t*/\n\t\t_mousewheel=function(){\n\t\t\tif(!$(this).data(pluginPfx)){return;} /* Check if the scrollbar is ready to use mousewheel events (issue: #185) */\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_dragger=[$(\"#mCSB_\"+d.idx+\"_dragger_vertical\"),$(\"#mCSB_\"+d.idx+\"_dragger_horizontal\")],\n\t\t\t\tiframe=$(\"#mCSB_\"+d.idx+\"_container\").find(\"iframe\");\n\t\t\tif(iframe.length){\n\t\t\t\tiframe.each(function(){\n\t\t\t\t\t$(this).load(function(){\n\t\t\t\t\t\t/* bind events on accessible iframes */\n\t\t\t\t\t\tif(_canAccessIFrame(this)){\n\t\t\t\t\t\t\t$(this.contentDocument || this.contentWindow.document).bind(\"mousewheel.\"+namespace,function(e,delta){\n\t\t\t\t\t\t\t\t_onMousewheel(e,delta);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t\tmCustomScrollBox.bind(\"mousewheel.\"+namespace,function(e,delta){\n\t\t\t\t_onMousewheel(e,delta);\n\t\t\t});\n\t\t\tfunction _onMousewheel(e,delta){\n\t\t\t\t_stop($this);\n\t\t\t\tif(_disableMousewheel($this,e.target)){return;} /* disables mouse-wheel when hovering specific elements */\n\t\t\t\tvar deltaFactor=o.mouseWheel.deltaFactor!==\"auto\" ? parseInt(o.mouseWheel.deltaFactor) : (oldIE && e.deltaFactor<100) ? 100 : e.deltaFactor || 100;\n\t\t\t\tif(o.axis===\"x\" || o.mouseWheel.axis===\"x\"){\n\t\t\t\t\tvar dir=\"x\",\n\t\t\t\t\t\tpx=[Math.round(deltaFactor*d.scrollRatio.x),parseInt(o.mouseWheel.scrollAmount)],\n\t\t\t\t\t\tamount=o.mouseWheel.scrollAmount!==\"auto\" ? px[1] : px[0]>=mCustomScrollBox.width() ? mCustomScrollBox.width()*0.9 : px[0],\n\t\t\t\t\t\tcontentPos=Math.abs($(\"#mCSB_\"+d.idx+\"_container\")[0].offsetLeft),\n\t\t\t\t\t\tdraggerPos=mCSB_dragger[1][0].offsetLeft,\n\t\t\t\t\t\tlimit=mCSB_dragger[1].parent().width()-mCSB_dragger[1].width(),\n\t\t\t\t\t\tdlt=e.deltaX || e.deltaY || delta;\n\t\t\t\t}else{\n\t\t\t\t\tvar dir=\"y\",\n\t\t\t\t\t\tpx=[Math.round(deltaFactor*d.scrollRatio.y),parseInt(o.mouseWheel.scrollAmount)],\n\t\t\t\t\t\tamount=o.mouseWheel.scrollAmount!==\"auto\" ? px[1] : px[0]>=mCustomScrollBox.height() ? mCustomScrollBox.height()*0.9 : px[0],\n\t\t\t\t\t\tcontentPos=Math.abs($(\"#mCSB_\"+d.idx+\"_container\")[0].offsetTop),\n\t\t\t\t\t\tdraggerPos=mCSB_dragger[0][0].offsetTop,\n\t\t\t\t\t\tlimit=mCSB_dragger[0].parent().height()-mCSB_dragger[0].height(),\n\t\t\t\t\t\tdlt=e.deltaY || delta;\n\t\t\t\t}\n\t\t\t\tif((dir===\"y\" && !d.overflowed[0]) || (dir===\"x\" && !d.overflowed[1])){return;}\n\t\t\t\tif(o.mouseWheel.invert || e.webkitDirectionInvertedFromDevice){dlt=-dlt;}\n\t\t\t\tif(o.mouseWheel.normalizeDelta){dlt=dlt<0 ? -1 : 1;}\n\t\t\t\tif((dlt>0 && draggerPos!==0) || (dlt<0 && draggerPos!==limit) || o.mouseWheel.preventDefault){\n\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\te.preventDefault();\n\t\t\t\t}\n\t\t\t\t_scrollTo($this,(contentPos-(dlt*amount)).toString(),{dir:dir});\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* checks if iframe can be accessed */\n\t\t_canAccessIFrame=function(iframe){\n\t\t\tvar html=null;\n\t\t\ttry{\n\t\t\t\tvar doc=iframe.contentDocument || iframe.contentWindow.document;\n\t\t\t\thtml=doc.body.innerHTML;\n\t\t\t}catch(err){/* do nothing */}\n\t\t\treturn(html!==null);\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* disables mouse-wheel when hovering specific elements like select, datalist etc. */\n\t\t_disableMousewheel=function(el,target){\n\t\t\tvar tag=target.nodeName.toLowerCase(),\n\t\t\t\ttags=el.data(pluginPfx).opt.mouseWheel.disableOver,\n\t\t\t\t/* elements that require focus */\n\t\t\t\tfocusTags=[\"select\",\"textarea\"];\n\t\t\treturn $.inArray(tag,tags) > -1 && !($.inArray(tag,focusTags) > -1 && !$(target).is(\":focus\"));\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tDRAGGER RAIL CLICK EVENT\n\t\tscrolls content via dragger rail \n\t\t*/\n\t\t_draggerRail=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\twrapper=mCSB_container.parent(),\n\t\t\t\tmCSB_draggerContainer=$(\".mCSB_\"+d.idx+\"_scrollbar .\"+classes[12]);\n\t\t\tmCSB_draggerContainer.bind(\"touchstart.\"+namespace+\" pointerdown.\"+namespace+\" MSPointerDown.\"+namespace,function(e){\n\t\t\t\ttouchActive=true;\n\t\t\t}).bind(\"touchend.\"+namespace+\" pointerup.\"+namespace+\" MSPointerUp.\"+namespace,function(e){\n\t\t\t\ttouchActive=false;\n\t\t\t}).bind(\"click.\"+namespace,function(e){\n\t\t\t\tif($(e.target).hasClass(classes[12]) || $(e.target).hasClass(\"mCSB_draggerRail\")){\n\t\t\t\t\t_stop($this);\n\t\t\t\t\tvar el=$(this),mCSB_dragger=el.find(\".mCSB_dragger\");\n\t\t\t\t\tif(el.parent(\".mCSB_scrollTools_horizontal\").length>0){\n\t\t\t\t\t\tif(!d.overflowed[1]){return;}\n\t\t\t\t\t\tvar dir=\"x\",\n\t\t\t\t\t\t\tclickDir=e.pageX>mCSB_dragger.offset().left ? -1 : 1,\n\t\t\t\t\t\t\tto=Math.abs(mCSB_container[0].offsetLeft)-(clickDir*(wrapper.width()*0.9));\n\t\t\t\t\t}else{\n\t\t\t\t\t\tif(!d.overflowed[0]){return;}\n\t\t\t\t\t\tvar dir=\"y\",\n\t\t\t\t\t\t\tclickDir=e.pageY>mCSB_dragger.offset().top ? -1 : 1,\n\t\t\t\t\t\t\tto=Math.abs(mCSB_container[0].offsetTop)-(clickDir*(wrapper.height()*0.9));\n\t\t\t\t\t}\n\t\t\t\t\t_scrollTo($this,to.toString(),{dir:dir,scrollEasing:\"mcsEaseInOut\"});\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tFOCUS EVENT\n\t\tscrolls content via element focus (e.g. clicking an input, pressing TAB key etc.)\n\t\t*/\n\t\t_focus=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\twrapper=mCSB_container.parent();\n\t\t\tmCSB_container.bind(\"focusin.\"+namespace,function(e){\n\t\t\t\tvar el=$(document.activeElement),\n\t\t\t\t\tnested=mCSB_container.find(\".mCustomScrollBox\").length,\n\t\t\t\t\tdur=0;\n\t\t\t\tif(!el.is(o.advanced.autoScrollOnFocus)){return;}\n\t\t\t\t_stop($this);\n\t\t\t\tclearTimeout($this[0]._focusTimeout);\n\t\t\t\t$this[0]._focusTimer=nested ? (dur+17)*nested : 0;\n\t\t\t\t$this[0]._focusTimeout=setTimeout(function(){\n\t\t\t\t\tvar\tto=[_childPos(el)[0],_childPos(el)[1]],\n\t\t\t\t\t\tcontentPos=[mCSB_container[0].offsetTop,mCSB_container[0].offsetLeft],\n\t\t\t\t\t\tisVisible=[\n\t\t\t\t\t\t\t(contentPos[0]+to[0]>=0 && contentPos[0]+to[0]<wrapper.height()-el.outerHeight(false)),\n\t\t\t\t\t\t\t(contentPos[1]+to[1]>=0 && contentPos[0]+to[1]<wrapper.width()-el.outerWidth(false))\n\t\t\t\t\t\t],\n\t\t\t\t\t\toverwrite=(o.axis===\"yx\" && !isVisible[0] && !isVisible[1]) ? \"none\" : \"all\";\n\t\t\t\t\tif(o.axis!==\"x\" && !isVisible[0]){\n\t\t\t\t\t\t_scrollTo($this,to[0].toString(),{dir:\"y\",scrollEasing:\"mcsEaseInOut\",overwrite:overwrite,dur:dur});\n\t\t\t\t\t}\n\t\t\t\t\tif(o.axis!==\"y\" && !isVisible[1]){\n\t\t\t\t\t\t_scrollTo($this,to[1].toString(),{dir:\"x\",scrollEasing:\"mcsEaseInOut\",overwrite:overwrite,dur:dur});\n\t\t\t\t\t}\n\t\t\t\t},$this[0]._focusTimer);\n\t\t\t});\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* sets content wrapper scrollTop/scrollLeft always to 0 */\n\t\t_wrapperScroll=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\twrapper=$(\"#mCSB_\"+d.idx+\"_container\").parent();\n\t\t\twrapper.bind(\"scroll.\"+namespace,function(e){\n\t\t\t\tif(wrapper.scrollTop()!==0 || wrapper.scrollLeft()!==0){\n\t\t\t\t\t$(\".mCSB_\"+d.idx+\"_scrollbar\").css(\"visibility\",\"hidden\"); /* hide scrollbar(s) */\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tBUTTONS EVENTS\n\t\tscrolls content via up, down, left and right buttons \n\t\t*/\n\t\t_buttons=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential,\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tsel=\".mCSB_\"+d.idx+\"_scrollbar\",\n\t\t\t\tbtn=$(sel+\">a\");\n\t\t\tbtn.bind(\"mousedown.\"+namespace+\" touchstart.\"+namespace+\" pointerdown.\"+namespace+\" MSPointerDown.\"+namespace+\" mouseup.\"+namespace+\" touchend.\"+namespace+\" pointerup.\"+namespace+\" MSPointerUp.\"+namespace+\" mouseout.\"+namespace+\" pointerout.\"+namespace+\" MSPointerOut.\"+namespace+\" click.\"+namespace,function(e){\n\t\t\t\te.preventDefault();\n\t\t\t\tif(!_mouseBtnLeft(e)){return;} /* left mouse button only */\n\t\t\t\tvar btnClass=$(this).attr(\"class\");\n\t\t\t\tseq.type=o.scrollButtons.scrollType;\n\t\t\t\tswitch(e.type){\n\t\t\t\t\tcase \"mousedown\": case \"touchstart\": case \"pointerdown\": case \"MSPointerDown\":\n\t\t\t\t\t\tif(seq.type===\"stepped\"){return;}\n\t\t\t\t\t\ttouchActive=true;\n\t\t\t\t\t\td.tweenRunning=false;\n\t\t\t\t\t\t_seq(\"on\",btnClass);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"mouseup\": case \"touchend\": case \"pointerup\": case \"MSPointerUp\":\n\t\t\t\t\tcase \"mouseout\": case \"pointerout\": case \"MSPointerOut\":\n\t\t\t\t\t\tif(seq.type===\"stepped\"){return;}\n\t\t\t\t\t\ttouchActive=false;\n\t\t\t\t\t\tif(seq.dir){_seq(\"off\",btnClass);}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"click\":\n\t\t\t\t\t\tif(seq.type!==\"stepped\" || d.tweenRunning){return;}\n\t\t\t\t\t\t_seq(\"on\",btnClass);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfunction _seq(a,c){\n\t\t\t\t\tseq.scrollAmount=o.snapAmount || o.scrollButtons.scrollAmount;\n\t\t\t\t\t_sequentialScroll($this,a,c);\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tKEYBOARD EVENTS\n\t\tscrolls content via keyboard \n\t\tKeys: up arrow, down arrow, left arrow, right arrow, PgUp, PgDn, Home, End\n\t\t*/\n\t\t_keyboard=function(){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential,\n\t\t\t\tnamespace=pluginPfx+\"_\"+d.idx,\n\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\twrapper=mCSB_container.parent(),\n\t\t\t\teditables=\"input,textarea,select,datalist,keygen,[contenteditable='true']\",\n\t\t\t\tiframe=mCSB_container.find(\"iframe\"),\n\t\t\t\tevents=[\"blur.\"+namespace+\" keydown.\"+namespace+\" keyup.\"+namespace];\n\t\t\tif(iframe.length){\n\t\t\t\tiframe.each(function(){\n\t\t\t\t\t$(this).load(function(){\n\t\t\t\t\t\t/* bind events on accessible iframes */\n\t\t\t\t\t\tif(_canAccessIFrame(this)){\n\t\t\t\t\t\t\t$(this.contentDocument || this.contentWindow.document).bind(events[0],function(e){\n\t\t\t\t\t\t\t\t_onKeyboard(e);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t\tmCustomScrollBox.attr(\"tabindex\",\"0\").bind(events[0],function(e){\n\t\t\t\t_onKeyboard(e);\n\t\t\t});\n\t\t\tfunction _onKeyboard(e){\n\t\t\t\tswitch(e.type){\n\t\t\t\t\tcase \"blur\":\n\t\t\t\t\t\tif(d.tweenRunning && seq.dir){_seq(\"off\",null);}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"keydown\": case \"keyup\":\n\t\t\t\t\t\tvar code=e.keyCode ? e.keyCode : e.which,action=\"on\";\n\t\t\t\t\t\tif((o.axis!==\"x\" && (code===38 || code===40)) || (o.axis!==\"y\" && (code===37 || code===39))){\n\t\t\t\t\t\t\t/* up (38), down (40), left (37), right (39) arrows */\n\t\t\t\t\t\t\tif(((code===38 || code===40) && !d.overflowed[0]) || ((code===37 || code===39) && !d.overflowed[1])){return;}\n\t\t\t\t\t\t\tif(e.type===\"keyup\"){action=\"off\";}\n\t\t\t\t\t\t\tif(!$(document.activeElement).is(editables)){\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t\t_seq(action,code);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}else if(code===33 || code===34){\n\t\t\t\t\t\t\t/* PgUp (33), PgDn (34) */\n\t\t\t\t\t\t\tif(d.overflowed[0] || d.overflowed[1]){\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(e.type===\"keyup\"){\n\t\t\t\t\t\t\t\t_stop($this);\n\t\t\t\t\t\t\t\tvar keyboardDir=code===34 ? -1 : 1;\n\t\t\t\t\t\t\t\tif(o.axis===\"x\" || (o.axis===\"yx\" && d.overflowed[1] && !d.overflowed[0])){\n\t\t\t\t\t\t\t\t\tvar dir=\"x\",to=Math.abs(mCSB_container[0].offsetLeft)-(keyboardDir*(wrapper.width()*0.9));\n\t\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\t\tvar dir=\"y\",to=Math.abs(mCSB_container[0].offsetTop)-(keyboardDir*(wrapper.height()*0.9));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t_scrollTo($this,to.toString(),{dir:dir,scrollEasing:\"mcsEaseInOut\"});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}else if(code===35 || code===36){\n\t\t\t\t\t\t\t/* End (35), Home (36) */\n\t\t\t\t\t\t\tif(!$(document.activeElement).is(editables)){\n\t\t\t\t\t\t\t\tif(d.overflowed[0] || d.overflowed[1]){\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(e.type===\"keyup\"){\n\t\t\t\t\t\t\t\t\tif(o.axis===\"x\" || (o.axis===\"yx\" && d.overflowed[1] && !d.overflowed[0])){\n\t\t\t\t\t\t\t\t\t\tvar dir=\"x\",to=code===35 ? Math.abs(wrapper.width()-mCSB_container.outerWidth(false)) : 0;\n\t\t\t\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\t\t\t\tvar dir=\"y\",to=code===35 ? Math.abs(wrapper.height()-mCSB_container.outerHeight(false)) : 0;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t_scrollTo($this,to.toString(),{dir:dir,scrollEasing:\"mcsEaseInOut\"});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfunction _seq(a,c){\n\t\t\t\t\tseq.type=o.keyboard.scrollType;\n\t\t\t\t\tseq.scrollAmount=o.snapAmount || o.keyboard.scrollAmount;\n\t\t\t\t\tif(seq.type===\"stepped\" && d.tweenRunning){return;}\n\t\t\t\t\t_sequentialScroll($this,a,c);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* scrolls content sequentially (used when scrolling via buttons, keyboard arrows etc.) */\n\t\t_sequentialScroll=function(el,action,trigger,e,s){\n\t\t\tvar d=el.data(pluginPfx),o=d.opt,seq=d.sequential,\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\tonce=seq.type===\"stepped\" ? true : false,\n\t\t\t\tsteplessSpeed=o.scrollInertia < 26 ? 26 : o.scrollInertia, /* 26/1.5=17 */\n\t\t\t\tsteppedSpeed=o.scrollInertia < 1 ? 17 : o.scrollInertia;\n\t\t\tswitch(action){\n\t\t\t\tcase \"on\":\n\t\t\t\t\tseq.dir=[\n\t\t\t\t\t\t(trigger===classes[16] || trigger===classes[15] || trigger===39 || trigger===37 ? \"x\" : \"y\"),\n\t\t\t\t\t\t(trigger===classes[13] || trigger===classes[15] || trigger===38 || trigger===37 ? -1 : 1)\n\t\t\t\t\t];\n\t\t\t\t\t_stop(el);\n\t\t\t\t\tif(_isNumeric(trigger) && seq.type===\"stepped\"){return;}\n\t\t\t\t\t_on(once);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"off\":\n\t\t\t\t\t_off();\n\t\t\t\t\tif(once || (d.tweenRunning && seq.dir)){\n\t\t\t\t\t\t_on(true);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* starts sequence */\n\t\t\tfunction _on(once){\n\t\t\t\tvar c=seq.type!==\"stepped\", /* continuous scrolling */\n\t\t\t\t\tt=s ? s : !once ? 1000/60 : c ? steplessSpeed/1.5 : steppedSpeed, /* timer */\n\t\t\t\t\tm=!once ? 2.5 : c ? 7.5 : 40, /* multiplier */\n\t\t\t\t\tcontentPos=[Math.abs(mCSB_container[0].offsetTop),Math.abs(mCSB_container[0].offsetLeft)],\n\t\t\t\t\tratio=[d.scrollRatio.y>10 ? 10 : d.scrollRatio.y,d.scrollRatio.x>10 ? 10 : d.scrollRatio.x],\n\t\t\t\t\tamount=seq.dir[0]===\"x\" ? contentPos[1]+(seq.dir[1]*(ratio[1]*m)) : contentPos[0]+(seq.dir[1]*(ratio[0]*m)),\n\t\t\t\t\tpx=seq.dir[0]===\"x\" ? contentPos[1]+(seq.dir[1]*parseInt(seq.scrollAmount)) : contentPos[0]+(seq.dir[1]*parseInt(seq.scrollAmount)),\n\t\t\t\t\tto=seq.scrollAmount!==\"auto\" ? px : amount,\n\t\t\t\t\teasing=e ? e : !once ? \"mcsLinear\" : c ? \"mcsLinearOut\" : \"mcsEaseInOut\",\n\t\t\t\t\tonComplete=!once ? false : true;\n\t\t\t\tif(once && t<17){\n\t\t\t\t\tto=seq.dir[0]===\"x\" ? contentPos[1] : contentPos[0];\n\t\t\t\t}\n\t\t\t\t_scrollTo(el,to.toString(),{dir:seq.dir[0],scrollEasing:easing,dur:t,onComplete:onComplete});\n\t\t\t\tif(once){\n\t\t\t\t\tseq.dir=false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tclearTimeout(seq.step);\n\t\t\t\tseq.step=setTimeout(function(){\n\t\t\t\t\t_on();\n\t\t\t\t},t);\n\t\t\t}\n\t\t\t/* stops sequence */\n\t\t\tfunction _off(){\n\t\t\t\tclearTimeout(seq.step);\n\t\t\t\t_delete(seq,\"step\");\n\t\t\t\t_stop(el);\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* returns a yx array from value */\n\t\t_arr=function(val){\n\t\t\tvar o=$(this).data(pluginPfx).opt,vals=[];\n\t\t\tif(typeof val===\"function\"){val=val();} /* check if the value is a single anonymous function */\n\t\t\t/* check if value is object or array, its length and create an array with yx values */\n\t\t\tif(!(val instanceof Array)){ /* object value (e.g. {y:\"100\",x:\"100\"}, 100 etc.) */\n\t\t\t\tvals[0]=val.y ? val.y : val.x || o.axis===\"x\" ? null : val;\n\t\t\t\tvals[1]=val.x ? val.x : val.y || o.axis===\"y\" ? null : val;\n\t\t\t}else{ /* array value (e.g. [100,100]) */\n\t\t\t\tvals=val.length>1 ? [val[0],val[1]] : o.axis===\"x\" ? [null,val[0]] : [val[0],null];\n\t\t\t}\n\t\t\t/* check if array values are anonymous functions */\n\t\t\tif(typeof vals[0]===\"function\"){vals[0]=vals[0]();}\n\t\t\tif(typeof vals[1]===\"function\"){vals[1]=vals[1]();}\n\t\t\treturn vals;\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* translates values (e.g. \"top\", 100, \"100px\", \"#id\") to actual scroll-to positions */\n\t\t_to=function(val,dir){\n\t\t\tif(val==null || typeof val==\"undefined\"){return;}\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\twrapper=mCSB_container.parent(),\n\t\t\t\tt=typeof val;\n\t\t\tif(!dir){dir=o.axis===\"x\" ? \"x\" : \"y\";}\n\t\t\tvar contentLength=dir===\"x\" ? mCSB_container.outerWidth(false) : mCSB_container.outerHeight(false),\n\t\t\t\tcontentPos=dir===\"x\" ? mCSB_container[0].offsetLeft : mCSB_container[0].offsetTop,\n\t\t\t\tcssProp=dir===\"x\" ? \"left\" : \"top\";\n\t\t\tswitch(t){\n\t\t\t\tcase \"function\": /* this currently is not used. Consider removing it */\n\t\t\t\t\treturn val();\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"object\": /* js/jquery object */\n\t\t\t\t\tvar obj=val.jquery ? val : $(val);\n\t\t\t\t\tif(!obj.length){return;}\n\t\t\t\t\treturn dir===\"x\" ? _childPos(obj)[1] : _childPos(obj)[0];\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"string\": case \"number\":\n\t\t\t\t\tif(_isNumeric(val)){ /* numeric value */\n\t\t\t\t\t\treturn Math.abs(val);\n\t\t\t\t\t}else if(val.indexOf(\"%\")!==-1){ /* percentage value */\n\t\t\t\t\t\treturn Math.abs(contentLength*parseInt(val)/100);\n\t\t\t\t\t}else if(val.indexOf(\"-=\")!==-1){ /* decrease value */\n\t\t\t\t\t\treturn Math.abs(contentPos-parseInt(val.split(\"-=\")[1]));\n\t\t\t\t\t}else if(val.indexOf(\"+=\")!==-1){ /* inrease value */\n\t\t\t\t\t\tvar p=(contentPos+parseInt(val.split(\"+=\")[1]));\n\t\t\t\t\t\treturn p>=0 ? 0 : Math.abs(p);\n\t\t\t\t\t}else if(val.indexOf(\"px\")!==-1 && _isNumeric(val.split(\"px\")[0])){ /* pixels string value (e.g. \"100px\") */\n\t\t\t\t\t\treturn Math.abs(val.split(\"px\")[0]);\n\t\t\t\t\t}else{\n\t\t\t\t\t\tif(val===\"top\" || val===\"left\"){ /* special strings */\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t}else if(val===\"bottom\"){\n\t\t\t\t\t\t\treturn Math.abs(wrapper.height()-mCSB_container.outerHeight(false));\n\t\t\t\t\t\t}else if(val===\"right\"){\n\t\t\t\t\t\t\treturn Math.abs(wrapper.width()-mCSB_container.outerWidth(false));\n\t\t\t\t\t\t}else if(val===\"first\" || val===\"last\"){\n\t\t\t\t\t\t\tvar obj=mCSB_container.find(\":\"+val);\n\t\t\t\t\t\t\treturn dir===\"x\" ? _childPos(obj)[1] : _childPos(obj)[0];\n\t\t\t\t\t\t}else{\n\t\t\t\t\t\t\tif($(val).length){ /* jquery selector */\n\t\t\t\t\t\t\t\treturn dir===\"x\" ? _childPos($(val))[1] : _childPos($(val))[0];\n\t\t\t\t\t\t\t}else{ /* other values (e.g. \"100em\") */\n\t\t\t\t\t\t\t\tmCSB_container.css(cssProp,val);\n\t\t\t\t\t\t\t\tmethods.update.call(null,$this[0]);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* calls the update method automatically */\n\t\t_autoUpdate=function(rem){\n\t\t\tvar $this=$(this),d=$this.data(pluginPfx),o=d.opt,\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\");\n\t\t\tif(rem){\n\t\t\t\t/* \n\t\t\t\tremoves autoUpdate timer \n\t\t\t\tusage: _autoUpdate.call(this,\"remove\");\n\t\t\t\t*/\n\t\t\t\tclearTimeout(mCSB_container[0].autoUpdate);\n\t\t\t\t_delete(mCSB_container[0],\"autoUpdate\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tupd();\n\t\t\tfunction upd(){\n\t\t\t\tclearTimeout(mCSB_container[0].autoUpdate);\n\t\t\t\tif($this.parents(\"html\").length===0){\n\t\t\t\t\t/* check element in dom tree */\n\t\t\t\t\t$this=null;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tmCSB_container[0].autoUpdate=setTimeout(function(){\n\t\t\t\t\t/* update on specific selector(s) length and size change */\n\t\t\t\t\tif(o.advanced.updateOnSelectorChange){\n\t\t\t\t\t\td.poll.change.n=sizesSum();\n\t\t\t\t\t\tif(d.poll.change.n!==d.poll.change.o){\n\t\t\t\t\t\t\td.poll.change.o=d.poll.change.n;\n\t\t\t\t\t\t\tdoUpd(3);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t/* update on main element and scrollbar size changes */\n\t\t\t\t\tif(o.advanced.updateOnContentResize){\n\t\t\t\t\t\td.poll.size.n=$this[0].scrollHeight+$this[0].scrollWidth+mCSB_container[0].offsetHeight+$this[0].offsetHeight;\n\t\t\t\t\t\tif(d.poll.size.n!==d.poll.size.o){\n\t\t\t\t\t\t\td.poll.size.o=d.poll.size.n;\n\t\t\t\t\t\t\tdoUpd(1);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t/* update on image load */\n\t\t\t\t\tif(o.advanced.updateOnImageLoad){\n\t\t\t\t\t\tif(!(o.advanced.updateOnImageLoad===\"auto\" && o.axis===\"y\")){ //by default, it doesn't run on vertical content\n\t\t\t\t\t\t\td.poll.img.n=mCSB_container.find(\"img\").length;\n\t\t\t\t\t\t\tif(d.poll.img.n!==d.poll.img.o){\n\t\t\t\t\t\t\t\td.poll.img.o=d.poll.img.n;\n\t\t\t\t\t\t\t\tmCSB_container.find(\"img\").each(function(){\n\t\t\t\t\t\t\t\t\timgLoader(this);\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(o.advanced.updateOnSelectorChange || o.advanced.updateOnContentResize || o.advanced.updateOnImageLoad){upd();}\n\t\t\t\t},o.advanced.autoUpdateTimeout);\n\t\t\t}\n\t\t\t/* a tiny image loader */\n\t\t\tfunction imgLoader(el){\n\t\t\t\tif($(el).hasClass(classes[2])){doUpd(); return;}\n\t\t\t\tvar img=new Image();\n\t\t\t\tfunction createDelegate(contextObject,delegateMethod){\n\t\t\t\t\treturn function(){return delegateMethod.apply(contextObject,arguments);}\n\t\t\t\t}\n\t\t\t\tfunction imgOnLoad(){\n\t\t\t\t\tthis.onload=null;\n\t\t\t\t\t$(el).addClass(classes[2]);\n\t\t\t\t\tdoUpd(2);\n\t\t\t\t}\n\t\t\t\timg.onload=createDelegate(img,imgOnLoad);\n\t\t\t\timg.src=el.src;\n\t\t\t}\n\t\t\t/* returns the total height and width sum of all elements matching the selector */\n\t\t\tfunction sizesSum(){\n\t\t\t\tif(o.advanced.updateOnSelectorChange===true){o.advanced.updateOnSelectorChange=\"*\";}\n\t\t\t\tvar total=0,sel=mCSB_container.find(o.advanced.updateOnSelectorChange);\n\t\t\t\tif(o.advanced.updateOnSelectorChange && sel.length>0){sel.each(function(){total+=this.offsetHeight+this.offsetWidth;});}\n\t\t\t\treturn total;\n\t\t\t}\n\t\t\t/* calls the update method */\n\t\t\tfunction doUpd(cb){\n\t\t\t\tclearTimeout(mCSB_container[0].autoUpdate);\n\t\t\t\tmethods.update.call(null,$this[0],cb);\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* snaps scrolling to a multiple of a pixels number */\n\t\t_snapAmount=function(to,amount,offset){\n\t\t\treturn (Math.round(to/amount)*amount-offset); \n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* stops content and scrollbar animations */\n\t\t_stop=function(el){\n\t\t\tvar d=el.data(pluginPfx),\n\t\t\t\tsel=$(\"#mCSB_\"+d.idx+\"_container,#mCSB_\"+d.idx+\"_container_wrapper,#mCSB_\"+d.idx+\"_dragger_vertical,#mCSB_\"+d.idx+\"_dragger_horizontal\");\n\t\t\tsel.each(function(){\n\t\t\t\t_stopTween.call(this);\n\t\t\t});\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tANIMATES CONTENT \n\t\tThis is where the actual scrolling happens\n\t\t*/\n\t\t_scrollTo=function(el,to,options){\n\t\t\tvar d=el.data(pluginPfx),o=d.opt,\n\t\t\t\tdefaults={\n\t\t\t\t\ttrigger:\"internal\",\n\t\t\t\t\tdir:\"y\",\n\t\t\t\t\tscrollEasing:\"mcsEaseOut\",\n\t\t\t\t\tdrag:false,\n\t\t\t\t\tdur:o.scrollInertia,\n\t\t\t\t\toverwrite:\"all\",\n\t\t\t\t\tcallbacks:true,\n\t\t\t\t\tonStart:true,\n\t\t\t\t\tonUpdate:true,\n\t\t\t\t\tonComplete:true\n\t\t\t\t},\n\t\t\t\toptions=$.extend(defaults,options),\n\t\t\t\tdur=[options.dur,(options.drag ? 0 : options.dur)],\n\t\t\t\tmCustomScrollBox=$(\"#mCSB_\"+d.idx),\n\t\t\t\tmCSB_container=$(\"#mCSB_\"+d.idx+\"_container\"),\n\t\t\t\twrapper=mCSB_container.parent(),\n\t\t\t\ttotalScrollOffsets=o.callbacks.onTotalScrollOffset ? _arr.call(el,o.callbacks.onTotalScrollOffset) : [0,0],\n\t\t\t\ttotalScrollBackOffsets=o.callbacks.onTotalScrollBackOffset ? _arr.call(el,o.callbacks.onTotalScrollBackOffset) : [0,0];\n\t\t\td.trigger=options.trigger;\n\t\t\tif(wrapper.scrollTop()!==0 || wrapper.scrollLeft()!==0){ /* always reset scrollTop/Left */\n\t\t\t\t$(\".mCSB_\"+d.idx+\"_scrollbar\").css(\"visibility\",\"visible\");\n\t\t\t\twrapper.scrollTop(0).scrollLeft(0);\n\t\t\t}\n\t\t\tif(to===\"_resetY\" && !d.contentReset.y){\n\t\t\t\t/* callbacks: onOverflowYNone */\n\t\t\t\tif(_cb(\"onOverflowYNone\")){o.callbacks.onOverflowYNone.call(el[0]);}\n\t\t\t\td.contentReset.y=1;\n\t\t\t}\n\t\t\tif(to===\"_resetX\" && !d.contentReset.x){\n\t\t\t\t/* callbacks: onOverflowXNone */\n\t\t\t\tif(_cb(\"onOverflowXNone\")){o.callbacks.onOverflowXNone.call(el[0]);}\n\t\t\t\td.contentReset.x=1;\n\t\t\t}\n\t\t\tif(to===\"_resetY\" || to===\"_resetX\"){return;}\n\t\t\tif((d.contentReset.y || !el[0].mcs) && d.overflowed[0]){\n\t\t\t\t/* callbacks: onOverflowY */\n\t\t\t\tif(_cb(\"onOverflowY\")){o.callbacks.onOverflowY.call(el[0]);}\n\t\t\t\td.contentReset.x=null;\n\t\t\t}\n\t\t\tif((d.contentReset.x || !el[0].mcs) && d.overflowed[1]){\n\t\t\t\t/* callbacks: onOverflowX */\n\t\t\t\tif(_cb(\"onOverflowX\")){o.callbacks.onOverflowX.call(el[0]);}\n\t\t\t\td.contentReset.x=null;\n\t\t\t}\n\t\t\tif(o.snapAmount){to=_snapAmount(to,o.snapAmount,o.snapOffset);} /* scrolling snapping */\n\t\t\tswitch(options.dir){\n\t\t\t\tcase \"x\":\n\t\t\t\t\tvar mCSB_dragger=$(\"#mCSB_\"+d.idx+\"_dragger_horizontal\"),\n\t\t\t\t\t\tproperty=\"left\",\n\t\t\t\t\t\tcontentPos=mCSB_container[0].offsetLeft,\n\t\t\t\t\t\tlimit=[\n\t\t\t\t\t\t\tmCustomScrollBox.width()-mCSB_container.outerWidth(false),\n\t\t\t\t\t\t\tmCSB_dragger.parent().width()-mCSB_dragger.width()\n\t\t\t\t\t\t],\n\t\t\t\t\t\tscrollTo=[to,to===0 ? 0 : (to/d.scrollRatio.x)],\n\t\t\t\t\t\ttso=totalScrollOffsets[1],\n\t\t\t\t\t\ttsbo=totalScrollBackOffsets[1],\n\t\t\t\t\t\ttotalScrollOffset=tso>0 ? tso/d.scrollRatio.x : 0,\n\t\t\t\t\t\ttotalScrollBackOffset=tsbo>0 ? tsbo/d.scrollRatio.x : 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"y\":\n\t\t\t\t\tvar mCSB_dragger=$(\"#mCSB_\"+d.idx+\"_dragger_vertical\"),\n\t\t\t\t\t\tproperty=\"top\",\n\t\t\t\t\t\tcontentPos=mCSB_container[0].offsetTop,\n\t\t\t\t\t\tlimit=[\n\t\t\t\t\t\t\tmCustomScrollBox.height()-mCSB_container.outerHeight(false),\n\t\t\t\t\t\t\tmCSB_dragger.parent().height()-mCSB_dragger.height()\n\t\t\t\t\t\t],\n\t\t\t\t\t\tscrollTo=[to,to===0 ? 0 : (to/d.scrollRatio.y)],\n\t\t\t\t\t\ttso=totalScrollOffsets[0],\n\t\t\t\t\t\ttsbo=totalScrollBackOffsets[0],\n\t\t\t\t\t\ttotalScrollOffset=tso>0 ? tso/d.scrollRatio.y : 0,\n\t\t\t\t\t\ttotalScrollBackOffset=tsbo>0 ? tsbo/d.scrollRatio.y : 0;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(scrollTo[1]<0 || (scrollTo[0]===0 && scrollTo[1]===0)){\n\t\t\t\tscrollTo=[0,0];\n\t\t\t}else if(scrollTo[1]>=limit[1]){\n\t\t\t\tscrollTo=[limit[0],limit[1]];\n\t\t\t}else{\n\t\t\t\tscrollTo[0]=-scrollTo[0];\n\t\t\t}\n\t\t\tif(!el[0].mcs){\n\t\t\t\t_mcs();  /* init mcs object (once) to make it available before callbacks */\n\t\t\t\tif(_cb(\"onInit\")){o.callbacks.onInit.call(el[0]);} /* callbacks: onInit */\n\t\t\t}\n\t\t\tclearTimeout(mCSB_container[0].onCompleteTimeout);\n\t\t\tif(!d.tweenRunning && ((contentPos===0 && scrollTo[0]>=0) || (contentPos===limit[0] && scrollTo[0]<=limit[0]))){return;}\n\t\t\t_tweenTo(mCSB_dragger[0],property,Math.round(scrollTo[1]),dur[1],options.scrollEasing);\n\t\t\t_tweenTo(mCSB_container[0],property,Math.round(scrollTo[0]),dur[0],options.scrollEasing,options.overwrite,{\n\t\t\t\tonStart:function(){\n\t\t\t\t\tif(options.callbacks && options.onStart && !d.tweenRunning){\n\t\t\t\t\t\t/* callbacks: onScrollStart */\n\t\t\t\t\t\tif(_cb(\"onScrollStart\")){_mcs(); o.callbacks.onScrollStart.call(el[0]);}\n\t\t\t\t\t\td.tweenRunning=true;\n\t\t\t\t\t\t_onDragClasses(mCSB_dragger);\n\t\t\t\t\t\td.cbOffsets=_cbOffsets();\n\t\t\t\t\t}\n\t\t\t\t},onUpdate:function(){\n\t\t\t\t\tif(options.callbacks && options.onUpdate){\n\t\t\t\t\t\t/* callbacks: whileScrolling */\n\t\t\t\t\t\tif(_cb(\"whileScrolling\")){_mcs(); o.callbacks.whileScrolling.call(el[0]);}\n\t\t\t\t\t}\n\t\t\t\t},onComplete:function(){\n\t\t\t\t\tif(options.callbacks && options.onComplete){\n\t\t\t\t\t\tif(o.axis===\"yx\"){clearTimeout(mCSB_container[0].onCompleteTimeout);}\n\t\t\t\t\t\tvar t=mCSB_container[0].idleTimer || 0;\n\t\t\t\t\t\tmCSB_container[0].onCompleteTimeout=setTimeout(function(){\n\t\t\t\t\t\t\t/* callbacks: onScroll, onTotalScroll, onTotalScrollBack */\n\t\t\t\t\t\t\tif(_cb(\"onScroll\")){_mcs(); o.callbacks.onScroll.call(el[0]);}\n\t\t\t\t\t\t\tif(_cb(\"onTotalScroll\") && scrollTo[1]>=limit[1]-totalScrollOffset && d.cbOffsets[0]){_mcs(); o.callbacks.onTotalScroll.call(el[0]);}\n\t\t\t\t\t\t\tif(_cb(\"onTotalScrollBack\") && scrollTo[1]<=totalScrollBackOffset && d.cbOffsets[1]){_mcs(); o.callbacks.onTotalScrollBack.call(el[0]);}\n\t\t\t\t\t\t\td.tweenRunning=false;\n\t\t\t\t\t\t\tmCSB_container[0].idleTimer=0;\n\t\t\t\t\t\t\t_onDragClasses(mCSB_dragger,\"hide\");\n\t\t\t\t\t\t},t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\t/* checks if callback function exists */\n\t\t\tfunction _cb(cb){\n\t\t\t\treturn d && o.callbacks[cb] && typeof o.callbacks[cb]===\"function\";\n\t\t\t}\n\t\t\t/* checks whether callback offsets always trigger */\n\t\t\tfunction _cbOffsets(){\n\t\t\t\treturn [o.callbacks.alwaysTriggerOffsets || contentPos>=limit[0]+tso,o.callbacks.alwaysTriggerOffsets || contentPos<=-tsbo];\n\t\t\t}\n\t\t\t/* \n\t\t\tpopulates object with useful values for the user \n\t\t\tvalues: \n\t\t\t\tcontent: this.mcs.content\n\t\t\t\tcontent top position: this.mcs.top \n\t\t\t\tcontent left position: this.mcs.left \n\t\t\t\tdragger top position: this.mcs.draggerTop \n\t\t\t\tdragger left position: this.mcs.draggerLeft \n\t\t\t\tscrolling y percentage: this.mcs.topPct \n\t\t\t\tscrolling x percentage: this.mcs.leftPct \n\t\t\t\tscrolling direction: this.mcs.direction\n\t\t\t*/\n\t\t\tfunction _mcs(){\n\t\t\t\tvar cp=[mCSB_container[0].offsetTop,mCSB_container[0].offsetLeft], /* content position */\n\t\t\t\t\tdp=[mCSB_dragger[0].offsetTop,mCSB_dragger[0].offsetLeft], /* dragger position */\n\t\t\t\t\tcl=[mCSB_container.outerHeight(false),mCSB_container.outerWidth(false)], /* content length */\n\t\t\t\t\tpl=[mCustomScrollBox.height(),mCustomScrollBox.width()]; /* content parent length */\n\t\t\t\tel[0].mcs={\n\t\t\t\t\tcontent:mCSB_container, /* original content wrapper as jquery object */\n\t\t\t\t\ttop:cp[0],left:cp[1],draggerTop:dp[0],draggerLeft:dp[1],\n\t\t\t\t\ttopPct:Math.round((100*Math.abs(cp[0]))/(Math.abs(cl[0])-pl[0])),leftPct:Math.round((100*Math.abs(cp[1]))/(Math.abs(cl[1])-pl[1])),\n\t\t\t\t\tdirection:options.dir\n\t\t\t\t};\n\t\t\t\t/* \n\t\t\t\tthis refers to the original element containing the scrollbar(s)\n\t\t\t\tusage: this.mcs.top, this.mcs.leftPct etc. \n\t\t\t\t*/\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* \n\t\tCUSTOM JAVASCRIPT ANIMATION TWEEN \n\t\tLighter and faster than jquery animate() and css transitions \n\t\tAnimates top/left properties and includes easings \n\t\t*/\n\t\t_tweenTo=function(el,prop,to,duration,easing,overwrite,callbacks){\n\t\t\tif(!el._mTween){el._mTween={top:{},left:{}};}\n\t\t\tvar callbacks=callbacks || {},\n\t\t\t\tonStart=callbacks.onStart || function(){},onUpdate=callbacks.onUpdate || function(){},onComplete=callbacks.onComplete || function(){},\n\t\t\t\tstartTime=_getTime(),_delay,progress=0,from=el.offsetTop,elStyle=el.style,_request,tobj=el._mTween[prop];\n\t\t\tif(prop===\"left\"){from=el.offsetLeft;}\n\t\t\tvar diff=to-from;\n\t\t\ttobj.stop=0;\n\t\t\tif(overwrite!==\"none\"){_cancelTween();}\n\t\t\t_startTween();\n\t\t\tfunction _step(){\n\t\t\t\tif(tobj.stop){return;}\n\t\t\t\tif(!progress){onStart.call();}\n\t\t\t\tprogress=_getTime()-startTime;\n\t\t\t\t_tween();\n\t\t\t\tif(progress>=tobj.time){\n\t\t\t\t\ttobj.time=(progress>tobj.time) ? progress+_delay-(progress-tobj.time) : progress+_delay-1;\n\t\t\t\t\tif(tobj.time<progress+1){tobj.time=progress+1;}\n\t\t\t\t}\n\t\t\t\tif(tobj.time<duration){tobj.id=_request(_step);}else{onComplete.call();}\n\t\t\t}\n\t\t\tfunction _tween(){\n\t\t\t\tif(duration>0){\n\t\t\t\t\ttobj.currVal=_ease(tobj.time,from,diff,duration,easing);\n\t\t\t\t\telStyle[prop]=Math.round(tobj.currVal)+\"px\";\n\t\t\t\t}else{\n\t\t\t\t\telStyle[prop]=to+\"px\";\n\t\t\t\t}\n\t\t\t\tonUpdate.call();\n\t\t\t}\n\t\t\tfunction _startTween(){\n\t\t\t\t_delay=1000/60;\n\t\t\t\ttobj.time=progress+_delay;\n\t\t\t\t_request=(!window.requestAnimationFrame) ? function(f){_tween(); return setTimeout(f,0.01);} : window.requestAnimationFrame;\n\t\t\t\ttobj.id=_request(_step);\n\t\t\t}\n\t\t\tfunction _cancelTween(){\n\t\t\t\tif(tobj.id==null){return;}\n\t\t\t\tif(!window.requestAnimationFrame){clearTimeout(tobj.id);\n\t\t\t\t}else{window.cancelAnimationFrame(tobj.id);}\n\t\t\t\ttobj.id=null;\n\t\t\t}\n\t\t\tfunction _ease(t,b,c,d,type){\n\t\t\t\tswitch(type){\n\t\t\t\t\tcase \"linear\": case \"mcsLinear\":\n\t\t\t\t\t\treturn c*t/d + b;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"mcsLinearOut\":\n\t\t\t\t\t\tt/=d; t--; return c * Math.sqrt(1 - t*t) + b;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"easeInOutSmooth\":\n\t\t\t\t\t\tt/=d/2;\n\t\t\t\t\t\tif(t<1) return c/2*t*t + b;\n\t\t\t\t\t\tt--;\n\t\t\t\t\t\treturn -c/2 * (t*(t-2) - 1) + b;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"easeInOutStrong\":\n\t\t\t\t\t\tt/=d/2;\n\t\t\t\t\t\tif(t<1) return c/2 * Math.pow( 2, 10 * (t - 1) ) + b;\n\t\t\t\t\t\tt--;\n\t\t\t\t\t\treturn c/2 * ( -Math.pow( 2, -10 * t) + 2 ) + b;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"easeInOut\": case \"mcsEaseInOut\":\n\t\t\t\t\t\tt/=d/2;\n\t\t\t\t\t\tif(t<1) return c/2*t*t*t + b;\n\t\t\t\t\t\tt-=2;\n\t\t\t\t\t\treturn c/2*(t*t*t + 2) + b;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"easeOutSmooth\":\n\t\t\t\t\t\tt/=d; t--;\n\t\t\t\t\t\treturn -c * (t*t*t*t - 1) + b;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"easeOutStrong\":\n\t\t\t\t\t\treturn c * ( -Math.pow( 2, -10 * t/d ) + 1 ) + b;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"easeOut\": case \"mcsEaseOut\": default:\n\t\t\t\t\t\tvar ts=(t/=d)*t,tc=ts*t;\n\t\t\t\t\t\treturn b+c*(0.499999999999997*tc*ts + -2.5*ts*ts + 5.5*tc + -6.5*ts + 4*t);\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* returns current time */\n\t\t_getTime=function(){\n\t\t\tif(window.performance && window.performance.now){\n\t\t\t\treturn window.performance.now();\n\t\t\t}else{\n\t\t\t\tif(window.performance && window.performance.webkitNow){\n\t\t\t\t\treturn window.performance.webkitNow();\n\t\t\t\t}else{\n\t\t\t\t\tif(Date.now){return Date.now();}else{return new Date().getTime();}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* stops a tween */\n\t\t_stopTween=function(){\n\t\t\tvar el=this;\n\t\t\tif(!el._mTween){el._mTween={top:{},left:{}};}\n\t\t\tvar props=[\"top\",\"left\"];\n\t\t\tfor(var i=0; i<props.length; i++){\n\t\t\t\tvar prop=props[i];\n\t\t\t\tif(el._mTween[prop].id){\n\t\t\t\t\tif(!window.requestAnimationFrame){clearTimeout(el._mTween[prop].id);\n\t\t\t\t\t}else{window.cancelAnimationFrame(el._mTween[prop].id);}\n\t\t\t\t\tel._mTween[prop].id=null;\n\t\t\t\t\tel._mTween[prop].stop=1;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* deletes a property (avoiding the exception thrown by IE) */\n\t\t_delete=function(c,m){\n\t\t\ttry{delete c[m];}catch(e){c[m]=null;}\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* detects left mouse button */\n\t\t_mouseBtnLeft=function(e){\n\t\t\treturn !(e.which && e.which!==1);\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* detects if pointer type event is touch */\n\t\t_pointerTouch=function(e){\n\t\t\tvar t=e.originalEvent.pointerType;\n\t\t\treturn !(t && t!==\"touch\" && t!==2);\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* checks if value is numeric */\n\t\t_isNumeric=function(val){\n\t\t\treturn !isNaN(parseFloat(val)) && isFinite(val);\n\t\t},\n\t\t/* -------------------- */\n\t\t\n\t\t\n\t\t/* returns element position according to content */\n\t\t_childPos=function(el){\n\t\t\tvar p=el.parents(\".mCSB_container\");\n\t\t\treturn [el.offset().top-p.offset().top,el.offset().left-p.offset().left];\n\t\t};\n\t\t/* -------------------- */\n\t\t\n\t\n\t\n\t\n\t\n\t/* \n\t----------------------------------------\n\tPLUGIN SETUP \n\t----------------------------------------\n\t*/\n\t\n\t/* plugin constructor functions */\n\t$.fn[pluginNS]=function(method){ /* usage: $(selector).mCustomScrollbar(); */\n\t\tif(methods[method]){\n\t\t\treturn methods[method].apply(this,Array.prototype.slice.call(arguments,1));\n\t\t}else if(typeof method===\"object\" || !method){\n\t\t\treturn methods.init.apply(this,arguments);\n\t\t}else{\n\t\t\t$.error(\"Method \"+method+\" does not exist\");\n\t\t}\n\t};\n\t$[pluginNS]=function(method){ /* usage: $.mCustomScrollbar(); */\n\t\tif(methods[method]){\n\t\t\treturn methods[method].apply(this,Array.prototype.slice.call(arguments,1));\n\t\t}else if(typeof method===\"object\" || !method){\n\t\t\treturn methods.init.apply(this,arguments);\n\t\t}else{\n\t\t\t$.error(\"Method \"+method+\" does not exist\");\n\t\t}\n\t};\n\t\n\t/* \n\tallow setting plugin default options. \n\tusage: $.mCustomScrollbar.defaults.scrollInertia=500; \n\tto apply any changed default options on default selectors (below), use inside document ready fn \n\te.g.: $(document).ready(function(){ $.mCustomScrollbar.defaults.scrollInertia=500; });\n\t*/\n\t$[pluginNS].defaults=defaults;\n\t\n\t/* \n\tadd window object (window.mCustomScrollbar) \n\tusage: if(window.mCustomScrollbar){console.log(\"custom scrollbar plugin loaded\");}\n\t*/\n\twindow[pluginNS]=true;\n\t\n\t$(window).load(function(){\n\t\t\n\t\t$(defaultSelector)[pluginNS](); /* add scrollbars automatically on default selector */\n\t\t\n\t\t/* extend jQuery expressions */\n\t\t$.extend($.expr[\":\"],{\n\t\t\t/* checks if element is within scrollable viewport */\n\t\t\tmcsInView:$.expr[\":\"].mcsInView || function(el){\n\t\t\t\tvar $el=$(el),content=$el.parents(\".mCSB_container\"),wrapper,cPos;\n\t\t\t\tif(!content.length){return;}\n\t\t\t\twrapper=content.parent();\n\t\t\t\tcPos=[content[0].offsetTop,content[0].offsetLeft];\n\t\t\t\treturn \tcPos[0]+_childPos($el)[0]>=0 && cPos[0]+_childPos($el)[0]<wrapper.height()-$el.outerHeight(false) && \n\t\t\t\t\t\tcPos[1]+_childPos($el)[1]>=0 && cPos[1]+_childPos($el)[1]<wrapper.width()-$el.outerWidth(false);\n\t\t\t},\n\t\t\t/* checks if element is overflowed having visible scrollbar(s) */\n\t\t\tmcsOverflow:$.expr[\":\"].mcsOverflow || function(el){\n\t\t\t\tvar d=$(el).data(pluginPfx);\n\t\t\t\tif(!d){return;}\n\t\t\t\treturn d.overflowed[0] || d.overflowed[1];\n\t\t\t}\n\t\t});\n\t\n\t});\n\n}))}));"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/material-design-iconic-font/dist/css/material-design-iconic-font.css",
    "content": "/*!\n *  Material Design Iconic Font by Sergey Kupletsky (@zavoloklom) - http://zavoloklom.github.io/material-design-iconic-font/\n *  License - http://zavoloklom.github.io/material-design-iconic-font/license (Font: SIL OFL 1.1, CSS: MIT License)\n */\n@font-face {\n  font-family: 'Material-Design-Iconic-Font';\n  src: url('../fonts/Material-Design-Iconic-Font.woff?v=2.1.0') format('woff'), url('../fonts/Material-Design-Iconic-Font.ttf?v=2.1.0') format('truetype');\n  font-weight: normal;\n  font-style: normal;\n}\n.zmdi {\n  display: inline-block;\n  font: normal normal normal 14px/1 'Material-Design-Iconic-Font';\n  font-size: inherit;\n  text-rendering: auto;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n.zmdi-hc-lg {\n  font-size: 1.33333333em;\n  line-height: 0.75em;\n  vertical-align: -15%;\n}\n.zmdi-hc-2x {\n  font-size: 2em;\n}\n.zmdi-hc-3x {\n  font-size: 3em;\n}\n.zmdi-hc-4x {\n  font-size: 4em;\n}\n.zmdi-hc-5x {\n  font-size: 5em;\n}\n.zmdi-hc-fw {\n  width: 1.28571429em;\n  text-align: center;\n}\n.zmdi-hc-ul {\n  padding-left: 0;\n  margin-left: 2.14285714em;\n  list-style-type: none;\n}\n.zmdi-hc-ul > li {\n  position: relative;\n}\n.zmdi-hc-li {\n  position: absolute;\n  left: -2.14285714em;\n  width: 2.14285714em;\n  top: 0.14285714em;\n  text-align: center;\n}\n.zmdi-hc-li.zmdi-hc-lg {\n  left: -1.85714286em;\n}\n.zmdi-hc-border {\n  padding: .1em .25em;\n  border: solid 0.1em #9e9e9e;\n  border-radius: 2px;\n}\n.zmdi-hc-border-circle {\n  padding: .1em .25em;\n  border: solid 0.1em #9e9e9e;\n  border-radius: 50%;\n}\n.zmdi.pull-left {\n  float: left;\n  margin-right: .15em;\n}\n.zmdi.pull-right {\n  float: right;\n  margin-left: .15em;\n}\n.zmdi-hc-spin {\n  -webkit-animation: zmdi-spin 1.5s infinite linear;\n          animation: zmdi-spin 1.5s infinite linear;\n}\n.zmdi-hc-spin-reverse {\n  -webkit-animation: zmdi-spin-reverse 1.5s infinite linear;\n          animation: zmdi-spin-reverse 1.5s infinite linear;\n}\n@-webkit-keyframes zmdi-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n            transform: rotate(359deg);\n  }\n}\n@keyframes zmdi-spin {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(359deg);\n            transform: rotate(359deg);\n  }\n}\n@-webkit-keyframes zmdi-spin-reverse {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(-359deg);\n            transform: rotate(-359deg);\n  }\n}\n@keyframes zmdi-spin-reverse {\n  0% {\n    -webkit-transform: rotate(0deg);\n            transform: rotate(0deg);\n  }\n  100% {\n    -webkit-transform: rotate(-359deg);\n            transform: rotate(-359deg);\n  }\n}\n.zmdi-hc-rotate-90 {\n  -webkit-transform: rotate(90deg);\n      -ms-transform: rotate(90deg);\n          transform: rotate(90deg);\n}\n.zmdi-hc-rotate-180 {\n  -webkit-transform: rotate(180deg);\n      -ms-transform: rotate(180deg);\n          transform: rotate(180deg);\n}\n.zmdi-hc-rotate-270 {\n  -webkit-transform: rotate(270deg);\n      -ms-transform: rotate(270deg);\n          transform: rotate(270deg);\n}\n.zmdi-hc-flip-horizontal {\n  -webkit-transform: scale(-1, 1);\n      -ms-transform: scale(-1, 1);\n          transform: scale(-1, 1);\n}\n.zmdi-hc-flip-vertical {\n  -webkit-transform: scale(1, -1);\n      -ms-transform: scale(1, -1);\n          transform: scale(1, -1);\n}\n.zmdi-hc-stack {\n  position: relative;\n  display: inline-block;\n  width: 2em;\n  height: 2em;\n  line-height: 2em;\n  vertical-align: middle;\n}\n.zmdi-hc-stack-1x,\n.zmdi-hc-stack-2x {\n  position: absolute;\n  left: 0;\n  width: 100%;\n  text-align: center;\n}\n.zmdi-hc-stack-1x {\n  line-height: inherit;\n}\n.zmdi-hc-stack-2x {\n  font-size: 2em;\n}\n.zmdi-hc-inverse {\n  color: #ffffff;\n}\n/* Material Design Iconic Font uses the Unicode Private Use Area (PUA) to ensure screen\n   readers do not read off random characters that represent icons */\n.zmdi-3d-rotation:before {\n  content: '\\f101';\n}\n.zmdi-airplane-off:before {\n  content: '\\f102';\n}\n.zmdi-airplane:before {\n  content: '\\f103';\n}\n.zmdi-album:before {\n  content: '\\f104';\n}\n.zmdi-archive:before {\n  content: '\\f105';\n}\n.zmdi-assignment-account:before {\n  content: '\\f106';\n}\n.zmdi-assignment-alert:before {\n  content: '\\f107';\n}\n.zmdi-assignment-check:before {\n  content: '\\f108';\n}\n.zmdi-assignment-o:before {\n  content: '\\f109';\n}\n.zmdi-assignment-return:before {\n  content: '\\f10a';\n}\n.zmdi-assignment-returned:before {\n  content: '\\f10b';\n}\n.zmdi-assignment:before {\n  content: '\\f10c';\n}\n.zmdi-attachment-alt:before {\n  content: '\\f10d';\n}\n.zmdi-attachment:before {\n  content: '\\f10e';\n}\n.zmdi-audio:before {\n  content: '\\f10f';\n}\n.zmdi-badge-check:before {\n  content: '\\f110';\n}\n.zmdi-balance-wallet:before {\n  content: '\\f111';\n}\n.zmdi-balance:before {\n  content: '\\f112';\n}\n.zmdi-battery-alert:before {\n  content: '\\f113';\n}\n.zmdi-battery-flash:before {\n  content: '\\f114';\n}\n.zmdi-battery-unknown:before {\n  content: '\\f115';\n}\n.zmdi-battery:before {\n  content: '\\f116';\n}\n.zmdi-bike:before {\n  content: '\\f117';\n}\n.zmdi-block-alt:before {\n  content: '\\f118';\n}\n.zmdi-block:before {\n  content: '\\f119';\n}\n.zmdi-boat:before {\n  content: '\\f11a';\n}\n.zmdi-book-image:before {\n  content: '\\f11b';\n}\n.zmdi-book:before {\n  content: '\\f11c';\n}\n.zmdi-bookmark-outline:before {\n  content: '\\f11d';\n}\n.zmdi-bookmark:before {\n  content: '\\f11e';\n}\n.zmdi-brush:before {\n  content: '\\f11f';\n}\n.zmdi-bug:before {\n  content: '\\f120';\n}\n.zmdi-bus:before {\n  content: '\\f121';\n}\n.zmdi-cake:before {\n  content: '\\f122';\n}\n.zmdi-car-taxi:before {\n  content: '\\f123';\n}\n.zmdi-car-wash:before {\n  content: '\\f124';\n}\n.zmdi-car:before {\n  content: '\\f125';\n}\n.zmdi-card-giftcard:before {\n  content: '\\f126';\n}\n.zmdi-card-membership:before {\n  content: '\\f127';\n}\n.zmdi-card-travel:before {\n  content: '\\f128';\n}\n.zmdi-card:before {\n  content: '\\f129';\n}\n.zmdi-case-check:before {\n  content: '\\f12a';\n}\n.zmdi-case-download:before {\n  content: '\\f12b';\n}\n.zmdi-case-play:before {\n  content: '\\f12c';\n}\n.zmdi-case:before {\n  content: '\\f12d';\n}\n.zmdi-cast-connected:before {\n  content: '\\f12e';\n}\n.zmdi-cast:before {\n  content: '\\f12f';\n}\n.zmdi-chart-donut:before {\n  content: '\\f130';\n}\n.zmdi-chart:before {\n  content: '\\f131';\n}\n.zmdi-city-alt:before {\n  content: '\\f132';\n}\n.zmdi-city:before {\n  content: '\\f133';\n}\n.zmdi-close-circle-o:before {\n  content: '\\f134';\n}\n.zmdi-close-circle:before {\n  content: '\\f135';\n}\n.zmdi-close:before {\n  content: '\\f136';\n}\n.zmdi-cocktail:before {\n  content: '\\f137';\n}\n.zmdi-code-setting:before {\n  content: '\\f138';\n}\n.zmdi-code-smartphone:before {\n  content: '\\f139';\n}\n.zmdi-code:before {\n  content: '\\f13a';\n}\n.zmdi-coffee:before {\n  content: '\\f13b';\n}\n.zmdi-collection-bookmark:before {\n  content: '\\f13c';\n}\n.zmdi-collection-case-play:before {\n  content: '\\f13d';\n}\n.zmdi-collection-folder-image:before {\n  content: '\\f13e';\n}\n.zmdi-collection-image-o:before {\n  content: '\\f13f';\n}\n.zmdi-collection-image:before {\n  content: '\\f140';\n}\n.zmdi-collection-item-1:before {\n  content: '\\f141';\n}\n.zmdi-collection-item-2:before {\n  content: '\\f142';\n}\n.zmdi-collection-item-3:before {\n  content: '\\f143';\n}\n.zmdi-collection-item-4:before {\n  content: '\\f144';\n}\n.zmdi-collection-item-5:before {\n  content: '\\f145';\n}\n.zmdi-collection-item-6:before {\n  content: '\\f146';\n}\n.zmdi-collection-item-7:before {\n  content: '\\f147';\n}\n.zmdi-collection-item-8:before {\n  content: '\\f148';\n}\n.zmdi-collection-item-9-plus:before {\n  content: '\\f149';\n}\n.zmdi-collection-item-9:before {\n  content: '\\f14a';\n}\n.zmdi-collection-item:before {\n  content: '\\f14b';\n}\n.zmdi-collection-music:before {\n  content: '\\f14c';\n}\n.zmdi-collection-pdf:before {\n  content: '\\f14d';\n}\n.zmdi-collection-plus:before {\n  content: '\\f14e';\n}\n.zmdi-collection-speaker:before {\n  content: '\\f14f';\n}\n.zmdi-collection-text:before {\n  content: '\\f150';\n}\n.zmdi-collection-video:before {\n  content: '\\f151';\n}\n.zmdi-compass:before {\n  content: '\\f152';\n}\n.zmdi-cutlery:before {\n  content: '\\f153';\n}\n.zmdi-delete:before {\n  content: '\\f154';\n}\n.zmdi-dialpad:before {\n  content: '\\f155';\n}\n.zmdi-dns:before {\n  content: '\\f156';\n}\n.zmdi-drink:before {\n  content: '\\f157';\n}\n.zmdi-edit:before {\n  content: '\\f158';\n}\n.zmdi-email-open:before {\n  content: '\\f159';\n}\n.zmdi-email:before {\n  content: '\\f15a';\n}\n.zmdi-eye-off:before {\n  content: '\\f15b';\n}\n.zmdi-eye:before {\n  content: '\\f15c';\n}\n.zmdi-eyedropper:before {\n  content: '\\f15d';\n}\n.zmdi-favorite-outline:before {\n  content: '\\f15e';\n}\n.zmdi-favorite:before {\n  content: '\\f15f';\n}\n.zmdi-filter-list:before {\n  content: '\\f160';\n}\n.zmdi-fire:before {\n  content: '\\f161';\n}\n.zmdi-flag:before {\n  content: '\\f162';\n}\n.zmdi-flare:before {\n  content: '\\f163';\n}\n.zmdi-flash-auto:before {\n  content: '\\f164';\n}\n.zmdi-flash-off:before {\n  content: '\\f165';\n}\n.zmdi-flash:before {\n  content: '\\f166';\n}\n.zmdi-flip:before {\n  content: '\\f167';\n}\n.zmdi-flower-alt:before {\n  content: '\\f168';\n}\n.zmdi-flower:before {\n  content: '\\f169';\n}\n.zmdi-font:before {\n  content: '\\f16a';\n}\n.zmdi-fullscreen-alt:before {\n  content: '\\f16b';\n}\n.zmdi-fullscreen-exit:before {\n  content: '\\f16c';\n}\n.zmdi-fullscreen:before {\n  content: '\\f16d';\n}\n.zmdi-functions:before {\n  content: '\\f16e';\n}\n.zmdi-gas-station:before {\n  content: '\\f16f';\n}\n.zmdi-gesture:before {\n  content: '\\f170';\n}\n.zmdi-globe-alt:before {\n  content: '\\f171';\n}\n.zmdi-globe-lock:before {\n  content: '\\f172';\n}\n.zmdi-globe:before {\n  content: '\\f173';\n}\n.zmdi-graduation-cap:before {\n  content: '\\f174';\n}\n.zmdi-home:before {\n  content: '\\f175';\n}\n.zmdi-hospital-alt:before {\n  content: '\\f176';\n}\n.zmdi-hospital:before {\n  content: '\\f177';\n}\n.zmdi-hotel:before {\n  content: '\\f178';\n}\n.zmdi-hourglass-alt:before {\n  content: '\\f179';\n}\n.zmdi-hourglass-outline:before {\n  content: '\\f17a';\n}\n.zmdi-hourglass:before {\n  content: '\\f17b';\n}\n.zmdi-http:before {\n  content: '\\f17c';\n}\n.zmdi-image-alt:before {\n  content: '\\f17d';\n}\n.zmdi-image-o:before {\n  content: '\\f17e';\n}\n.zmdi-image:before {\n  content: '\\f17f';\n}\n.zmdi-inbox:before {\n  content: '\\f180';\n}\n.zmdi-invert-colors-off:before {\n  content: '\\f181';\n}\n.zmdi-invert-colors:before {\n  content: '\\f182';\n}\n.zmdi-key:before {\n  content: '\\f183';\n}\n.zmdi-label-alt-outline:before {\n  content: '\\f184';\n}\n.zmdi-label-alt:before {\n  content: '\\f185';\n}\n.zmdi-label-heart:before {\n  content: '\\f186';\n}\n.zmdi-label:before {\n  content: '\\f187';\n}\n.zmdi-labels:before {\n  content: '\\f188';\n}\n.zmdi-lamp:before {\n  content: '\\f189';\n}\n.zmdi-landscape:before {\n  content: '\\f18a';\n}\n.zmdi-layers-off:before {\n  content: '\\f18b';\n}\n.zmdi-layers:before {\n  content: '\\f18c';\n}\n.zmdi-library:before {\n  content: '\\f18d';\n}\n.zmdi-link:before {\n  content: '\\f18e';\n}\n.zmdi-lock-open:before {\n  content: '\\f18f';\n}\n.zmdi-lock-outline:before {\n  content: '\\f190';\n}\n.zmdi-lock:before {\n  content: '\\f191';\n}\n.zmdi-mail-reply-all:before {\n  content: '\\f192';\n}\n.zmdi-mail-reply:before {\n  content: '\\f193';\n}\n.zmdi-mail-send:before {\n  content: '\\f194';\n}\n.zmdi-mall:before {\n  content: '\\f195';\n}\n.zmdi-map:before {\n  content: '\\f196';\n}\n.zmdi-menu:before {\n  content: '\\f197';\n}\n.zmdi-money-box:before {\n  content: '\\f198';\n}\n.zmdi-money-off:before {\n  content: '\\f199';\n}\n.zmdi-money:before {\n  content: '\\f19a';\n}\n.zmdi-more-vert:before {\n  content: '\\f19b';\n}\n.zmdi-more:before {\n  content: '\\f19c';\n}\n.zmdi-movie-alt:before {\n  content: '\\f19d';\n}\n.zmdi-movie:before {\n  content: '\\f19e';\n}\n.zmdi-nature-people:before {\n  content: '\\f19f';\n}\n.zmdi-nature:before {\n  content: '\\f1a0';\n}\n.zmdi-navigation:before {\n  content: '\\f1a1';\n}\n.zmdi-open-in-browser:before {\n  content: '\\f1a2';\n}\n.zmdi-open-in-new:before {\n  content: '\\f1a3';\n}\n.zmdi-palette:before {\n  content: '\\f1a4';\n}\n.zmdi-parking:before {\n  content: '\\f1a5';\n}\n.zmdi-pin-account:before {\n  content: '\\f1a6';\n}\n.zmdi-pin-assistant:before {\n  content: '\\f1a7';\n}\n.zmdi-pin-drop:before {\n  content: '\\f1a8';\n}\n.zmdi-pin-help:before {\n  content: '\\f1a9';\n}\n.zmdi-pin-off:before {\n  content: '\\f1aa';\n}\n.zmdi-pin:before {\n  content: '\\f1ab';\n}\n.zmdi-pizza:before {\n  content: '\\f1ac';\n}\n.zmdi-plaster:before {\n  content: '\\f1ad';\n}\n.zmdi-power-setting:before {\n  content: '\\f1ae';\n}\n.zmdi-power:before {\n  content: '\\f1af';\n}\n.zmdi-print:before {\n  content: '\\f1b0';\n}\n.zmdi-puzzle-piece:before {\n  content: '\\f1b1';\n}\n.zmdi-quote:before {\n  content: '\\f1b2';\n}\n.zmdi-railway:before {\n  content: '\\f1b3';\n}\n.zmdi-receipt:before {\n  content: '\\f1b4';\n}\n.zmdi-refresh-alt:before {\n  content: '\\f1b5';\n}\n.zmdi-refresh-sync-alert:before {\n  content: '\\f1b6';\n}\n.zmdi-refresh-sync-off:before {\n  content: '\\f1b7';\n}\n.zmdi-refresh-sync:before {\n  content: '\\f1b8';\n}\n.zmdi-refresh:before {\n  content: '\\f1b9';\n}\n.zmdi-roller:before {\n  content: '\\f1ba';\n}\n.zmdi-ruler:before {\n  content: '\\f1bb';\n}\n.zmdi-scissors:before {\n  content: '\\f1bc';\n}\n.zmdi-screen-rotation-lock:before {\n  content: '\\f1bd';\n}\n.zmdi-screen-rotation:before {\n  content: '\\f1be';\n}\n.zmdi-search-for:before {\n  content: '\\f1bf';\n}\n.zmdi-search-in-file:before {\n  content: '\\f1c0';\n}\n.zmdi-search-in-page:before {\n  content: '\\f1c1';\n}\n.zmdi-search-replace:before {\n  content: '\\f1c2';\n}\n.zmdi-search:before {\n  content: '\\f1c3';\n}\n.zmdi-seat:before {\n  content: '\\f1c4';\n}\n.zmdi-settings-square:before {\n  content: '\\f1c5';\n}\n.zmdi-settings:before {\n  content: '\\f1c6';\n}\n.zmdi-shield-check:before {\n  content: '\\f1c7';\n}\n.zmdi-shield-security:before {\n  content: '\\f1c8';\n}\n.zmdi-shopping-basket:before {\n  content: '\\f1c9';\n}\n.zmdi-shopping-cart-plus:before {\n  content: '\\f1ca';\n}\n.zmdi-shopping-cart:before {\n  content: '\\f1cb';\n}\n.zmdi-sign-in:before {\n  content: '\\f1cc';\n}\n.zmdi-sort-amount-asc:before {\n  content: '\\f1cd';\n}\n.zmdi-sort-amount-desc:before {\n  content: '\\f1ce';\n}\n.zmdi-sort-asc:before {\n  content: '\\f1cf';\n}\n.zmdi-sort-desc:before {\n  content: '\\f1d0';\n}\n.zmdi-spellcheck:before {\n  content: '\\f1d1';\n}\n.zmdi-storage:before {\n  content: '\\f1d2';\n}\n.zmdi-store-24:before {\n  content: '\\f1d3';\n}\n.zmdi-store:before {\n  content: '\\f1d4';\n}\n.zmdi-subway:before {\n  content: '\\f1d5';\n}\n.zmdi-sun:before {\n  content: '\\f1d6';\n}\n.zmdi-tab-unselected:before {\n  content: '\\f1d7';\n}\n.zmdi-tab:before {\n  content: '\\f1d8';\n}\n.zmdi-tag-close:before {\n  content: '\\f1d9';\n}\n.zmdi-tag-more:before {\n  content: '\\f1da';\n}\n.zmdi-tag:before {\n  content: '\\f1db';\n}\n.zmdi-thumb-down:before {\n  content: '\\f1dc';\n}\n.zmdi-thumb-up-down:before {\n  content: '\\f1dd';\n}\n.zmdi-thumb-up:before {\n  content: '\\f1de';\n}\n.zmdi-ticket-star:before {\n  content: '\\f1df';\n}\n.zmdi-toll:before {\n  content: '\\f1e0';\n}\n.zmdi-toys:before {\n  content: '\\f1e1';\n}\n.zmdi-traffic:before {\n  content: '\\f1e2';\n}\n.zmdi-translate:before {\n  content: '\\f1e3';\n}\n.zmdi-triangle-down:before {\n  content: '\\f1e4';\n}\n.zmdi-triangle-up:before {\n  content: '\\f1e5';\n}\n.zmdi-truck:before {\n  content: '\\f1e6';\n}\n.zmdi-turning-sign:before {\n  content: '\\f1e7';\n}\n.zmdi-wallpaper:before {\n  content: '\\f1e8';\n}\n.zmdi-washing-machine:before {\n  content: '\\f1e9';\n}\n.zmdi-window-maximize:before {\n  content: '\\f1ea';\n}\n.zmdi-window-minimize:before {\n  content: '\\f1eb';\n}\n.zmdi-window-restore:before {\n  content: '\\f1ec';\n}\n.zmdi-wrench:before {\n  content: '\\f1ed';\n}\n.zmdi-zoom-in:before {\n  content: '\\f1ee';\n}\n.zmdi-zoom-out:before {\n  content: '\\f1ef';\n}\n.zmdi-alert-circle-o:before {\n  content: '\\f1f0';\n}\n.zmdi-alert-circle:before {\n  content: '\\f1f1';\n}\n.zmdi-alert-octagon:before {\n  content: '\\f1f2';\n}\n.zmdi-alert-polygon:before {\n  content: '\\f1f3';\n}\n.zmdi-alert-triangle:before {\n  content: '\\f1f4';\n}\n.zmdi-help-outline:before {\n  content: '\\f1f5';\n}\n.zmdi-help:before {\n  content: '\\f1f6';\n}\n.zmdi-info-outline:before {\n  content: '\\f1f7';\n}\n.zmdi-info:before {\n  content: '\\f1f8';\n}\n.zmdi-notifications-active:before {\n  content: '\\f1f9';\n}\n.zmdi-notifications-add:before {\n  content: '\\f1fa';\n}\n.zmdi-notifications-none:before {\n  content: '\\f1fb';\n}\n.zmdi-notifications-off:before {\n  content: '\\f1fc';\n}\n.zmdi-notifications-paused:before {\n  content: '\\f1fd';\n}\n.zmdi-notifications:before {\n  content: '\\f1fe';\n}\n.zmdi-account-add:before {\n  content: '\\f1ff';\n}\n.zmdi-account-box-mail:before {\n  content: '\\f200';\n}\n.zmdi-account-box-o:before {\n  content: '\\f201';\n}\n.zmdi-account-box-phone:before {\n  content: '\\f202';\n}\n.zmdi-account-box:before {\n  content: '\\f203';\n}\n.zmdi-account-calendar:before {\n  content: '\\f204';\n}\n.zmdi-account-circle:before {\n  content: '\\f205';\n}\n.zmdi-account-o:before {\n  content: '\\f206';\n}\n.zmdi-account:before {\n  content: '\\f207';\n}\n.zmdi-accounts-add:before {\n  content: '\\f208';\n}\n.zmdi-accounts-alt:before {\n  content: '\\f209';\n}\n.zmdi-accounts-list-alt:before {\n  content: '\\f20a';\n}\n.zmdi-accounts-list:before {\n  content: '\\f20b';\n}\n.zmdi-accounts-outline:before {\n  content: '\\f20c';\n}\n.zmdi-accounts:before {\n  content: '\\f20d';\n}\n.zmdi-face:before {\n  content: '\\f20e';\n}\n.zmdi-female:before {\n  content: '\\f20f';\n}\n.zmdi-male-alt:before {\n  content: '\\f210';\n}\n.zmdi-male-female:before {\n  content: '\\f211';\n}\n.zmdi-male:before {\n  content: '\\f212';\n}\n.zmdi-mood-bad:before {\n  content: '\\f213';\n}\n.zmdi-mood:before {\n  content: '\\f214';\n}\n.zmdi-run:before {\n  content: '\\f215';\n}\n.zmdi-walk:before {\n  content: '\\f216';\n}\n.zmdi-cloud-box:before {\n  content: '\\f217';\n}\n.zmdi-cloud-circle:before {\n  content: '\\f218';\n}\n.zmdi-cloud-done:before {\n  content: '\\f219';\n}\n.zmdi-cloud-download:before {\n  content: '\\f21a';\n}\n.zmdi-cloud-off:before {\n  content: '\\f21b';\n}\n.zmdi-cloud-outline-alt:before {\n  content: '\\f21c';\n}\n.zmdi-cloud-outline:before {\n  content: '\\f21d';\n}\n.zmdi-cloud-upload:before {\n  content: '\\f21e';\n}\n.zmdi-cloud:before {\n  content: '\\f21f';\n}\n.zmdi-download:before {\n  content: '\\f220';\n}\n.zmdi-file-plus:before {\n  content: '\\f221';\n}\n.zmdi-file-text:before {\n  content: '\\f222';\n}\n.zmdi-file:before {\n  content: '\\f223';\n}\n.zmdi-folder-outline:before {\n  content: '\\f224';\n}\n.zmdi-folder-person:before {\n  content: '\\f225';\n}\n.zmdi-folder-star-alt:before {\n  content: '\\f226';\n}\n.zmdi-folder-star:before {\n  content: '\\f227';\n}\n.zmdi-folder:before {\n  content: '\\f228';\n}\n.zmdi-gif:before {\n  content: '\\f229';\n}\n.zmdi-upload:before {\n  content: '\\f22a';\n}\n.zmdi-border-all:before {\n  content: '\\f22b';\n}\n.zmdi-border-bottom:before {\n  content: '\\f22c';\n}\n.zmdi-border-clear:before {\n  content: '\\f22d';\n}\n.zmdi-border-color:before {\n  content: '\\f22e';\n}\n.zmdi-border-horizontal:before {\n  content: '\\f22f';\n}\n.zmdi-border-inner:before {\n  content: '\\f230';\n}\n.zmdi-border-left:before {\n  content: '\\f231';\n}\n.zmdi-border-outer:before {\n  content: '\\f232';\n}\n.zmdi-border-right:before {\n  content: '\\f233';\n}\n.zmdi-border-style:before {\n  content: '\\f234';\n}\n.zmdi-border-top:before {\n  content: '\\f235';\n}\n.zmdi-border-vertical:before {\n  content: '\\f236';\n}\n.zmdi-copy:before {\n  content: '\\f237';\n}\n.zmdi-crop:before {\n  content: '\\f238';\n}\n.zmdi-format-align-center:before {\n  content: '\\f239';\n}\n.zmdi-format-align-justify:before {\n  content: '\\f23a';\n}\n.zmdi-format-align-left:before {\n  content: '\\f23b';\n}\n.zmdi-format-align-right:before {\n  content: '\\f23c';\n}\n.zmdi-format-bold:before {\n  content: '\\f23d';\n}\n.zmdi-format-clear-all:before {\n  content: '\\f23e';\n}\n.zmdi-format-clear:before {\n  content: '\\f23f';\n}\n.zmdi-format-color-fill:before {\n  content: '\\f240';\n}\n.zmdi-format-color-reset:before {\n  content: '\\f241';\n}\n.zmdi-format-color-text:before {\n  content: '\\f242';\n}\n.zmdi-format-indent-decrease:before {\n  content: '\\f243';\n}\n.zmdi-format-indent-increase:before {\n  content: '\\f244';\n}\n.zmdi-format-italic:before {\n  content: '\\f245';\n}\n.zmdi-format-line-spacing:before {\n  content: '\\f246';\n}\n.zmdi-format-list-bulleted:before {\n  content: '\\f247';\n}\n.zmdi-format-list-numbered:before {\n  content: '\\f248';\n}\n.zmdi-format-ltr:before {\n  content: '\\f249';\n}\n.zmdi-format-rtl:before {\n  content: '\\f24a';\n}\n.zmdi-format-size:before {\n  content: '\\f24b';\n}\n.zmdi-format-strikethrough-s:before {\n  content: '\\f24c';\n}\n.zmdi-format-strikethrough:before {\n  content: '\\f24d';\n}\n.zmdi-format-subject:before {\n  content: '\\f24e';\n}\n.zmdi-format-underlined:before {\n  content: '\\f24f';\n}\n.zmdi-format-valign-bottom:before {\n  content: '\\f250';\n}\n.zmdi-format-valign-center:before {\n  content: '\\f251';\n}\n.zmdi-format-valign-top:before {\n  content: '\\f252';\n}\n.zmdi-redo:before {\n  content: '\\f253';\n}\n.zmdi-select-all:before {\n  content: '\\f254';\n}\n.zmdi-space-bar:before {\n  content: '\\f255';\n}\n.zmdi-text-format:before {\n  content: '\\f256';\n}\n.zmdi-transform:before {\n  content: '\\f257';\n}\n.zmdi-undo:before {\n  content: '\\f258';\n}\n.zmdi-wrap-text:before {\n  content: '\\f259';\n}\n.zmdi-comment-alert:before {\n  content: '\\f25a';\n}\n.zmdi-comment-alt-text:before {\n  content: '\\f25b';\n}\n.zmdi-comment-alt:before {\n  content: '\\f25c';\n}\n.zmdi-comment-edit:before {\n  content: '\\f25d';\n}\n.zmdi-comment-image:before {\n  content: '\\f25e';\n}\n.zmdi-comment-list:before {\n  content: '\\f25f';\n}\n.zmdi-comment-more:before {\n  content: '\\f260';\n}\n.zmdi-comment-outline:before {\n  content: '\\f261';\n}\n.zmdi-comment-text-alt:before {\n  content: '\\f262';\n}\n.zmdi-comment-text:before {\n  content: '\\f263';\n}\n.zmdi-comment-video:before {\n  content: '\\f264';\n}\n.zmdi-comment:before {\n  content: '\\f265';\n}\n.zmdi-comments:before {\n  content: '\\f266';\n}\n.zmdi-check-all:before {\n  content: '\\f267';\n}\n.zmdi-check-circle-u:before {\n  content: '\\f268';\n}\n.zmdi-check-circle:before {\n  content: '\\f269';\n}\n.zmdi-check-square:before {\n  content: '\\f26a';\n}\n.zmdi-check:before {\n  content: '\\f26b';\n}\n.zmdi-circle-o:before {\n  content: '\\f26c';\n}\n.zmdi-circle:before {\n  content: '\\f26d';\n}\n.zmdi-dot-circle-alt:before {\n  content: '\\f26e';\n}\n.zmdi-dot-circle:before {\n  content: '\\f26f';\n}\n.zmdi-minus-circle-outline:before {\n  content: '\\f270';\n}\n.zmdi-minus-circle:before {\n  content: '\\f271';\n}\n.zmdi-minus-square:before {\n  content: '\\f272';\n}\n.zmdi-minus:before {\n  content: '\\f273';\n}\n.zmdi-plus-circle-o-duplicate:before {\n  content: '\\f274';\n}\n.zmdi-plus-circle-o:before {\n  content: '\\f275';\n}\n.zmdi-plus-circle:before {\n  content: '\\f276';\n}\n.zmdi-plus-square:before {\n  content: '\\f277';\n}\n.zmdi-plus:before {\n  content: '\\f278';\n}\n.zmdi-square-o:before {\n  content: '\\f279';\n}\n.zmdi-star-circle:before {\n  content: '\\f27a';\n}\n.zmdi-star-half:before {\n  content: '\\f27b';\n}\n.zmdi-star-outline:before {\n  content: '\\f27c';\n}\n.zmdi-star:before {\n  content: '\\f27d';\n}\n.zmdi-bluetooth-connected:before {\n  content: '\\f27e';\n}\n.zmdi-bluetooth-off:before {\n  content: '\\f27f';\n}\n.zmdi-bluetooth-search:before {\n  content: '\\f280';\n}\n.zmdi-bluetooth-setting:before {\n  content: '\\f281';\n}\n.zmdi-bluetooth:before {\n  content: '\\f282';\n}\n.zmdi-camera-add:before {\n  content: '\\f283';\n}\n.zmdi-camera-alt:before {\n  content: '\\f284';\n}\n.zmdi-camera-bw:before {\n  content: '\\f285';\n}\n.zmdi-camera-front:before {\n  content: '\\f286';\n}\n.zmdi-camera-mic:before {\n  content: '\\f287';\n}\n.zmdi-camera-party-mode:before {\n  content: '\\f288';\n}\n.zmdi-camera-rear:before {\n  content: '\\f289';\n}\n.zmdi-camera-roll:before {\n  content: '\\f28a';\n}\n.zmdi-camera-switch:before {\n  content: '\\f28b';\n}\n.zmdi-camera:before {\n  content: '\\f28c';\n}\n.zmdi-card-alert:before {\n  content: '\\f28d';\n}\n.zmdi-card-off:before {\n  content: '\\f28e';\n}\n.zmdi-card-sd:before {\n  content: '\\f28f';\n}\n.zmdi-card-sim:before {\n  content: '\\f290';\n}\n.zmdi-desktop-mac:before {\n  content: '\\f291';\n}\n.zmdi-desktop-windows:before {\n  content: '\\f292';\n}\n.zmdi-device-hub:before {\n  content: '\\f293';\n}\n.zmdi-devices-off:before {\n  content: '\\f294';\n}\n.zmdi-devices:before {\n  content: '\\f295';\n}\n.zmdi-dock:before {\n  content: '\\f296';\n}\n.zmdi-floppy:before {\n  content: '\\f297';\n}\n.zmdi-gamepad:before {\n  content: '\\f298';\n}\n.zmdi-gps-dot:before {\n  content: '\\f299';\n}\n.zmdi-gps-off:before {\n  content: '\\f29a';\n}\n.zmdi-gps:before {\n  content: '\\f29b';\n}\n.zmdi-headset-mic:before {\n  content: '\\f29c';\n}\n.zmdi-headset:before {\n  content: '\\f29d';\n}\n.zmdi-input-antenna:before {\n  content: '\\f29e';\n}\n.zmdi-input-composite:before {\n  content: '\\f29f';\n}\n.zmdi-input-hdmi:before {\n  content: '\\f2a0';\n}\n.zmdi-input-power:before {\n  content: '\\f2a1';\n}\n.zmdi-input-svideo:before {\n  content: '\\f2a2';\n}\n.zmdi-keyboard-hide:before {\n  content: '\\f2a3';\n}\n.zmdi-keyboard:before {\n  content: '\\f2a4';\n}\n.zmdi-laptop-chromebook:before {\n  content: '\\f2a5';\n}\n.zmdi-laptop-mac:before {\n  content: '\\f2a6';\n}\n.zmdi-laptop:before {\n  content: '\\f2a7';\n}\n.zmdi-mic-off:before {\n  content: '\\f2a8';\n}\n.zmdi-mic-outline:before {\n  content: '\\f2a9';\n}\n.zmdi-mic-setting:before {\n  content: '\\f2aa';\n}\n.zmdi-mic:before {\n  content: '\\f2ab';\n}\n.zmdi-mouse:before {\n  content: '\\f2ac';\n}\n.zmdi-network-alert:before {\n  content: '\\f2ad';\n}\n.zmdi-network-locked:before {\n  content: '\\f2ae';\n}\n.zmdi-network-off:before {\n  content: '\\f2af';\n}\n.zmdi-network-outline:before {\n  content: '\\f2b0';\n}\n.zmdi-network-setting:before {\n  content: '\\f2b1';\n}\n.zmdi-network:before {\n  content: '\\f2b2';\n}\n.zmdi-phone-bluetooth:before {\n  content: '\\f2b3';\n}\n.zmdi-phone-end:before {\n  content: '\\f2b4';\n}\n.zmdi-phone-forwarded:before {\n  content: '\\f2b5';\n}\n.zmdi-phone-in-talk:before {\n  content: '\\f2b6';\n}\n.zmdi-phone-locked:before {\n  content: '\\f2b7';\n}\n.zmdi-phone-missed:before {\n  content: '\\f2b8';\n}\n.zmdi-phone-msg:before {\n  content: '\\f2b9';\n}\n.zmdi-phone-paused:before {\n  content: '\\f2ba';\n}\n.zmdi-phone-ring:before {\n  content: '\\f2bb';\n}\n.zmdi-phone-setting:before {\n  content: '\\f2bc';\n}\n.zmdi-phone-sip:before {\n  content: '\\f2bd';\n}\n.zmdi-phone:before {\n  content: '\\f2be';\n}\n.zmdi-portable-wifi-changes:before {\n  content: '\\f2bf';\n}\n.zmdi-portable-wifi-off:before {\n  content: '\\f2c0';\n}\n.zmdi-portable-wifi:before {\n  content: '\\f2c1';\n}\n.zmdi-radio:before {\n  content: '\\f2c2';\n}\n.zmdi-reader:before {\n  content: '\\f2c3';\n}\n.zmdi-remote-control-alt:before {\n  content: '\\f2c4';\n}\n.zmdi-remote-control:before {\n  content: '\\f2c5';\n}\n.zmdi-router:before {\n  content: '\\f2c6';\n}\n.zmdi-scanner:before {\n  content: '\\f2c7';\n}\n.zmdi-smartphone-android:before {\n  content: '\\f2c8';\n}\n.zmdi-smartphone-download:before {\n  content: '\\f2c9';\n}\n.zmdi-smartphone-erase:before {\n  content: '\\f2ca';\n}\n.zmdi-smartphone-info:before {\n  content: '\\f2cb';\n}\n.zmdi-smartphone-iphone:before {\n  content: '\\f2cc';\n}\n.zmdi-smartphone-landscape-lock:before {\n  content: '\\f2cd';\n}\n.zmdi-smartphone-landscape:before {\n  content: '\\f2ce';\n}\n.zmdi-smartphone-lock:before {\n  content: '\\f2cf';\n}\n.zmdi-smartphone-portrait-lock:before {\n  content: '\\f2d0';\n}\n.zmdi-smartphone-ring:before {\n  content: '\\f2d1';\n}\n.zmdi-smartphone-setting:before {\n  content: '\\f2d2';\n}\n.zmdi-smartphone-setup:before {\n  content: '\\f2d3';\n}\n.zmdi-smartphone:before {\n  content: '\\f2d4';\n}\n.zmdi-speaker:before {\n  content: '\\f2d5';\n}\n.zmdi-tablet-android:before {\n  content: '\\f2d6';\n}\n.zmdi-tablet-mac:before {\n  content: '\\f2d7';\n}\n.zmdi-tablet:before {\n  content: '\\f2d8';\n}\n.zmdi-tv-alt-play:before {\n  content: '\\f2d9';\n}\n.zmdi-tv-list:before {\n  content: '\\f2da';\n}\n.zmdi-tv-play:before {\n  content: '\\f2db';\n}\n.zmdi-tv:before {\n  content: '\\f2dc';\n}\n.zmdi-usb:before {\n  content: '\\f2dd';\n}\n.zmdi-videocam-off:before {\n  content: '\\f2de';\n}\n.zmdi-videocam-switch:before {\n  content: '\\f2df';\n}\n.zmdi-videocam:before {\n  content: '\\f2e0';\n}\n.zmdi-watch:before {\n  content: '\\f2e1';\n}\n.zmdi-wifi-alt-2:before {\n  content: '\\f2e2';\n}\n.zmdi-wifi-alt:before {\n  content: '\\f2e3';\n}\n.zmdi-wifi-info:before {\n  content: '\\f2e4';\n}\n.zmdi-wifi-lock:before {\n  content: '\\f2e5';\n}\n.zmdi-wifi-off:before {\n  content: '\\f2e6';\n}\n.zmdi-wifi-outline:before {\n  content: '\\f2e7';\n}\n.zmdi-wifi:before {\n  content: '\\f2e8';\n}\n.zmdi-arrow-left-bottom:before {\n  content: '\\f2e9';\n}\n.zmdi-arrow-left:before {\n  content: '\\f2ea';\n}\n.zmdi-arrow-merge:before {\n  content: '\\f2eb';\n}\n.zmdi-arrow-missed:before {\n  content: '\\f2ec';\n}\n.zmdi-arrow-right-top:before {\n  content: '\\f2ed';\n}\n.zmdi-arrow-right:before {\n  content: '\\f2ee';\n}\n.zmdi-arrow-split:before {\n  content: '\\f2ef';\n}\n.zmdi-arrows:before {\n  content: '\\f2f0';\n}\n.zmdi-caret-down-circle:before {\n  content: '\\f2f1';\n}\n.zmdi-caret-down:before {\n  content: '\\f2f2';\n}\n.zmdi-caret-left-circle:before {\n  content: '\\f2f3';\n}\n.zmdi-caret-left:before {\n  content: '\\f2f4';\n}\n.zmdi-caret-right-circle:before {\n  content: '\\f2f5';\n}\n.zmdi-caret-right:before {\n  content: '\\f2f6';\n}\n.zmdi-caret-up-circle:before {\n  content: '\\f2f7';\n}\n.zmdi-caret-up:before {\n  content: '\\f2f8';\n}\n.zmdi-chevron-down:before {\n  content: '\\f2f9';\n}\n.zmdi-chevron-left:before {\n  content: '\\f2fa';\n}\n.zmdi-chevron-right:before {\n  content: '\\f2fb';\n}\n.zmdi-chevron-up:before {\n  content: '\\f2fc';\n}\n.zmdi-forward:before {\n  content: '\\f2fd';\n}\n.zmdi-long-arrow-down:before {\n  content: '\\f2fe';\n}\n.zmdi-long-arrow-left:before {\n  content: '\\f2ff';\n}\n.zmdi-long-arrow-return:before {\n  content: '\\f300';\n}\n.zmdi-long-arrow-right:before {\n  content: '\\f301';\n}\n.zmdi-long-arrow-tab:before {\n  content: '\\f302';\n}\n.zmdi-long-arrow-up:before {\n  content: '\\f303';\n}\n.zmdi-rotate-ccw:before {\n  content: '\\f304';\n}\n.zmdi-rotate-cw:before {\n  content: '\\f305';\n}\n.zmdi-rotate-left:before {\n  content: '\\f306';\n}\n.zmdi-rotate-right:before {\n  content: '\\f307';\n}\n.zmdi-square-down:before {\n  content: '\\f308';\n}\n.zmdi-square-right:before {\n  content: '\\f309';\n}\n.zmdi-swap-alt:before {\n  content: '\\f30a';\n}\n.zmdi-swap-vertical-circle:before {\n  content: '\\f30b';\n}\n.zmdi-swap-vertical:before {\n  content: '\\f30c';\n}\n.zmdi-swap:before {\n  content: '\\f30d';\n}\n.zmdi-trending-down:before {\n  content: '\\f30e';\n}\n.zmdi-trending-flat:before {\n  content: '\\f30f';\n}\n.zmdi-trending-up:before {\n  content: '\\f310';\n}\n.zmdi-unfold-less:before {\n  content: '\\f311';\n}\n.zmdi-unfold-more:before {\n  content: '\\f312';\n}\n.zmdi-apps:before {\n  content: '\\f313';\n}\n.zmdi-grid-off:before {\n  content: '\\f314';\n}\n.zmdi-grid:before {\n  content: '\\f315';\n}\n.zmdi-view-agenda:before {\n  content: '\\f316';\n}\n.zmdi-view-array:before {\n  content: '\\f317';\n}\n.zmdi-view-carousel:before {\n  content: '\\f318';\n}\n.zmdi-view-column:before {\n  content: '\\f319';\n}\n.zmdi-view-comfy:before {\n  content: '\\f31a';\n}\n.zmdi-view-compact:before {\n  content: '\\f31b';\n}\n.zmdi-view-dashboard:before {\n  content: '\\f31c';\n}\n.zmdi-view-day:before {\n  content: '\\f31d';\n}\n.zmdi-view-headline:before {\n  content: '\\f31e';\n}\n.zmdi-view-list-alt:before {\n  content: '\\f31f';\n}\n.zmdi-view-list:before {\n  content: '\\f320';\n}\n.zmdi-view-module:before {\n  content: '\\f321';\n}\n.zmdi-view-quilt:before {\n  content: '\\f322';\n}\n.zmdi-view-stream:before {\n  content: '\\f323';\n}\n.zmdi-view-subtitles:before {\n  content: '\\f324';\n}\n.zmdi-view-toc:before {\n  content: '\\f325';\n}\n.zmdi-view-web:before {\n  content: '\\f326';\n}\n.zmdi-view-week:before {\n  content: '\\f327';\n}\n.zmdi-widgets:before {\n  content: '\\f328';\n}\n.zmdi-alarm-check:before {\n  content: '\\f329';\n}\n.zmdi-alarm-off:before {\n  content: '\\f32a';\n}\n.zmdi-alarm-plus:before {\n  content: '\\f32b';\n}\n.zmdi-alarm-snooze:before {\n  content: '\\f32c';\n}\n.zmdi-alarm:before {\n  content: '\\f32d';\n}\n.zmdi-calendar-alt:before {\n  content: '\\f32e';\n}\n.zmdi-calendar-check:before {\n  content: '\\f32f';\n}\n.zmdi-calendar-close:before {\n  content: '\\f330';\n}\n.zmdi-calendar-note:before {\n  content: '\\f331';\n}\n.zmdi-calendar:before {\n  content: '\\f332';\n}\n.zmdi-time-countdown:before {\n  content: '\\f333';\n}\n.zmdi-time-interval:before {\n  content: '\\f334';\n}\n.zmdi-time-restore-setting:before {\n  content: '\\f335';\n}\n.zmdi-time-restore:before {\n  content: '\\f336';\n}\n.zmdi-time:before {\n  content: '\\f337';\n}\n.zmdi-timer-off:before {\n  content: '\\f338';\n}\n.zmdi-timer:before {\n  content: '\\f339';\n}\n.zmdi-android-alt:before {\n  content: '\\f33a';\n}\n.zmdi-android:before {\n  content: '\\f33b';\n}\n.zmdi-apple:before {\n  content: '\\f33c';\n}\n.zmdi-behance:before {\n  content: '\\f33d';\n}\n.zmdi-codepen:before {\n  content: '\\f33e';\n}\n.zmdi-dribbble:before {\n  content: '\\f33f';\n}\n.zmdi-dropbox:before {\n  content: '\\f340';\n}\n.zmdi-evernote:before {\n  content: '\\f341';\n}\n.zmdi-facebook-box:before {\n  content: '\\f342';\n}\n.zmdi-facebook:before {\n  content: '\\f343';\n}\n.zmdi-github-box:before {\n  content: '\\f344';\n}\n.zmdi-github:before {\n  content: '\\f345';\n}\n.zmdi-google-drive:before {\n  content: '\\f346';\n}\n.zmdi-google-earth:before {\n  content: '\\f347';\n}\n.zmdi-google-glass:before {\n  content: '\\f348';\n}\n.zmdi-google-maps:before {\n  content: '\\f349';\n}\n.zmdi-google-pages:before {\n  content: '\\f34a';\n}\n.zmdi-google-play:before {\n  content: '\\f34b';\n}\n.zmdi-google-plus-box:before {\n  content: '\\f34c';\n}\n.zmdi-google-plus:before {\n  content: '\\f34d';\n}\n.zmdi-google:before {\n  content: '\\f34e';\n}\n.zmdi-instagram:before {\n  content: '\\f34f';\n}\n.zmdi-language-css3:before {\n  content: '\\f350';\n}\n.zmdi-language-html5:before {\n  content: '\\f351';\n}\n.zmdi-language-javascript:before {\n  content: '\\f352';\n}\n.zmdi-language-python-alt:before {\n  content: '\\f353';\n}\n.zmdi-language-python:before {\n  content: '\\f354';\n}\n.zmdi-lastfm:before {\n  content: '\\f355';\n}\n.zmdi-linkedin-box:before {\n  content: '\\f356';\n}\n.zmdi-paypal:before {\n  content: '\\f357';\n}\n.zmdi-pinterest-box:before {\n  content: '\\f358';\n}\n.zmdi-pocket:before {\n  content: '\\f359';\n}\n.zmdi-polymer:before {\n  content: '\\f35a';\n}\n.zmdi-share:before {\n  content: '\\f35b';\n}\n.zmdi-stack-overflow:before {\n  content: '\\f35c';\n}\n.zmdi-steam-square:before {\n  content: '\\f35d';\n}\n.zmdi-steam:before {\n  content: '\\f35e';\n}\n.zmdi-twitter-box:before {\n  content: '\\f35f';\n}\n.zmdi-twitter:before {\n  content: '\\f360';\n}\n.zmdi-vk:before {\n  content: '\\f361';\n}\n.zmdi-wikipedia:before {\n  content: '\\f362';\n}\n.zmdi-windows:before {\n  content: '\\f363';\n}\n.zmdi-aspect-ratio-alt:before {\n  content: '\\f364';\n}\n.zmdi-aspect-ratio:before {\n  content: '\\f365';\n}\n.zmdi-blur-circular:before {\n  content: '\\f366';\n}\n.zmdi-blur-linear:before {\n  content: '\\f367';\n}\n.zmdi-blur-off:before {\n  content: '\\f368';\n}\n.zmdi-blur:before {\n  content: '\\f369';\n}\n.zmdi-brightness-2:before {\n  content: '\\f36a';\n}\n.zmdi-brightness-3:before {\n  content: '\\f36b';\n}\n.zmdi-brightness-4:before {\n  content: '\\f36c';\n}\n.zmdi-brightness-5:before {\n  content: '\\f36d';\n}\n.zmdi-brightness-6:before {\n  content: '\\f36e';\n}\n.zmdi-brightness-7:before {\n  content: '\\f36f';\n}\n.zmdi-brightness-auto:before {\n  content: '\\f370';\n}\n.zmdi-brightness-setting:before {\n  content: '\\f371';\n}\n.zmdi-broken-image:before {\n  content: '\\f372';\n}\n.zmdi-center-focus-strong:before {\n  content: '\\f373';\n}\n.zmdi-center-focus-weak:before {\n  content: '\\f374';\n}\n.zmdi-compare:before {\n  content: '\\f375';\n}\n.zmdi-crop-16-9:before {\n  content: '\\f376';\n}\n.zmdi-crop-3-2:before {\n  content: '\\f377';\n}\n.zmdi-crop-5-4:before {\n  content: '\\f378';\n}\n.zmdi-crop-7-5:before {\n  content: '\\f379';\n}\n.zmdi-crop-din:before {\n  content: '\\f37a';\n}\n.zmdi-crop-free:before {\n  content: '\\f37b';\n}\n.zmdi-crop-landscape:before {\n  content: '\\f37c';\n}\n.zmdi-crop-portrait:before {\n  content: '\\f37d';\n}\n.zmdi-crop-square:before {\n  content: '\\f37e';\n}\n.zmdi-exposure-alt:before {\n  content: '\\f37f';\n}\n.zmdi-exposure:before {\n  content: '\\f380';\n}\n.zmdi-filter-b-and-w:before {\n  content: '\\f381';\n}\n.zmdi-filter-center-focus:before {\n  content: '\\f382';\n}\n.zmdi-filter-frames:before {\n  content: '\\f383';\n}\n.zmdi-filter-tilt-shift:before {\n  content: '\\f384';\n}\n.zmdi-gradient:before {\n  content: '\\f385';\n}\n.zmdi-grain:before {\n  content: '\\f386';\n}\n.zmdi-graphic-eq:before {\n  content: '\\f387';\n}\n.zmdi-hdr-off:before {\n  content: '\\f388';\n}\n.zmdi-hdr-strong:before {\n  content: '\\f389';\n}\n.zmdi-hdr-weak:before {\n  content: '\\f38a';\n}\n.zmdi-hdr:before {\n  content: '\\f38b';\n}\n.zmdi-iridescent:before {\n  content: '\\f38c';\n}\n.zmdi-leak-off:before {\n  content: '\\f38d';\n}\n.zmdi-leak:before {\n  content: '\\f38e';\n}\n.zmdi-looks:before {\n  content: '\\f38f';\n}\n.zmdi-loupe:before {\n  content: '\\f390';\n}\n.zmdi-panorama-horizontal:before {\n  content: '\\f391';\n}\n.zmdi-panorama-vertical:before {\n  content: '\\f392';\n}\n.zmdi-panorama-wide-angle:before {\n  content: '\\f393';\n}\n.zmdi-photo-size-select-large:before {\n  content: '\\f394';\n}\n.zmdi-photo-size-select-small:before {\n  content: '\\f395';\n}\n.zmdi-picture-in-picture:before {\n  content: '\\f396';\n}\n.zmdi-slideshow:before {\n  content: '\\f397';\n}\n.zmdi-texture:before {\n  content: '\\f398';\n}\n.zmdi-tonality:before {\n  content: '\\f399';\n}\n.zmdi-vignette:before {\n  content: '\\f39a';\n}\n.zmdi-wb-auto:before {\n  content: '\\f39b';\n}\n.zmdi-eject-alt:before {\n  content: '\\f39c';\n}\n.zmdi-eject:before {\n  content: '\\f39d';\n}\n.zmdi-equalizer:before {\n  content: '\\f39e';\n}\n.zmdi-fast-forward:before {\n  content: '\\f39f';\n}\n.zmdi-fast-rewind:before {\n  content: '\\f3a0';\n}\n.zmdi-forward-10:before {\n  content: '\\f3a1';\n}\n.zmdi-forward-30:before {\n  content: '\\f3a2';\n}\n.zmdi-forward-5:before {\n  content: '\\f3a3';\n}\n.zmdi-hearing:before {\n  content: '\\f3a4';\n}\n.zmdi-pause-circle-outline:before {\n  content: '\\f3a5';\n}\n.zmdi-pause-circle:before {\n  content: '\\f3a6';\n}\n.zmdi-pause:before {\n  content: '\\f3a7';\n}\n.zmdi-play-circle-outline:before {\n  content: '\\f3a8';\n}\n.zmdi-play-circle:before {\n  content: '\\f3a9';\n}\n.zmdi-play:before {\n  content: '\\f3aa';\n}\n.zmdi-playlist-audio:before {\n  content: '\\f3ab';\n}\n.zmdi-playlist-plus:before {\n  content: '\\f3ac';\n}\n.zmdi-repeat-one:before {\n  content: '\\f3ad';\n}\n.zmdi-repeat:before {\n  content: '\\f3ae';\n}\n.zmdi-replay-10:before {\n  content: '\\f3af';\n}\n.zmdi-replay-30:before {\n  content: '\\f3b0';\n}\n.zmdi-replay-5:before {\n  content: '\\f3b1';\n}\n.zmdi-replay:before {\n  content: '\\f3b2';\n}\n.zmdi-shuffle:before {\n  content: '\\f3b3';\n}\n.zmdi-skip-next:before {\n  content: '\\f3b4';\n}\n.zmdi-skip-previous:before {\n  content: '\\f3b5';\n}\n.zmdi-stop:before {\n  content: '\\f3b6';\n}\n.zmdi-surround-sound:before {\n  content: '\\f3b7';\n}\n.zmdi-tune:before {\n  content: '\\f3b8';\n}\n.zmdi-volume-down:before {\n  content: '\\f3b9';\n}\n.zmdi-volume-mute:before {\n  content: '\\f3ba';\n}\n.zmdi-volume-off:before {\n  content: '\\f3bb';\n}\n.zmdi-volume-up:before {\n  content: '\\f3bc';\n}\n.zmdi-n-1-square:before {\n  content: '\\f3bd';\n}\n.zmdi-n-2-square:before {\n  content: '\\f3be';\n}\n.zmdi-n-3-square:before {\n  content: '\\f3bf';\n}\n.zmdi-n-4-square:before {\n  content: '\\f3c0';\n}\n.zmdi-n-5-square:before {\n  content: '\\f3c1';\n}\n.zmdi-n-6-square:before {\n  content: '\\f3c2';\n}\n.zmdi-neg-1:before {\n  content: '\\f3c3';\n}\n.zmdi-neg-2:before {\n  content: '\\f3c4';\n}\n.zmdi-plus-1:before {\n  content: '\\f3c5';\n}\n.zmdi-plus-2:before {\n  content: '\\f3c6';\n}\n.zmdi-sec-10:before {\n  content: '\\f3c7';\n}\n.zmdi-sec-3:before {\n  content: '\\f3c8';\n}\n.zmdi-zero:before {\n  content: '\\f3c9';\n}\n.zmdi-airline-seat-flat-angled:before {\n  content: '\\f3ca';\n}\n.zmdi-airline-seat-flat:before {\n  content: '\\f3cb';\n}\n.zmdi-airline-seat-individual-suite:before {\n  content: '\\f3cc';\n}\n.zmdi-airline-seat-legroom-extra:before {\n  content: '\\f3cd';\n}\n.zmdi-airline-seat-legroom-normal:before {\n  content: '\\f3ce';\n}\n.zmdi-airline-seat-legroom-reduced:before {\n  content: '\\f3cf';\n}\n.zmdi-airline-seat-recline-extra:before {\n  content: '\\f3d0';\n}\n.zmdi-airline-seat-recline-normal:before {\n  content: '\\f3d1';\n}\n.zmdi-airplay:before {\n  content: '\\f3d2';\n}\n.zmdi-closed-caption:before {\n  content: '\\f3d3';\n}\n.zmdi-confirmation-number:before {\n  content: '\\f3d4';\n}\n.zmdi-developer-board:before {\n  content: '\\f3d5';\n}\n.zmdi-disc-full:before {\n  content: '\\f3d6';\n}\n.zmdi-explicit:before {\n  content: '\\f3d7';\n}\n.zmdi-flight-land:before {\n  content: '\\f3d8';\n}\n.zmdi-flight-takeoff:before {\n  content: '\\f3d9';\n}\n.zmdi-flip-to-back:before {\n  content: '\\f3da';\n}\n.zmdi-flip-to-front:before {\n  content: '\\f3db';\n}\n.zmdi-group-work:before {\n  content: '\\f3dc';\n}\n.zmdi-hd:before {\n  content: '\\f3dd';\n}\n.zmdi-hq:before {\n  content: '\\f3de';\n}\n.zmdi-markunread-mailbox:before {\n  content: '\\f3df';\n}\n.zmdi-memory:before {\n  content: '\\f3e0';\n}\n.zmdi-nfc:before {\n  content: '\\f3e1';\n}\n.zmdi-play-for-work:before {\n  content: '\\f3e2';\n}\n.zmdi-power-input:before {\n  content: '\\f3e3';\n}\n.zmdi-present-to-all:before {\n  content: '\\f3e4';\n}\n.zmdi-satellite:before {\n  content: '\\f3e5';\n}\n.zmdi-tap-and-play:before {\n  content: '\\f3e6';\n}\n.zmdi-vibration:before {\n  content: '\\f3e7';\n}\n.zmdi-voicemail:before {\n  content: '\\f3e8';\n}\n.zmdi-3d-rotation:before {\n  content: '\\f101';\n}\n.zmdi-airplane-off:before {\n  content: '\\f102';\n}\n.zmdi-airplane:before {\n  content: '\\f103';\n}\n.zmdi-album:before {\n  content: '\\f104';\n}\n.zmdi-archive:before {\n  content: '\\f105';\n}\n.zmdi-assignment-account:before {\n  content: '\\f106';\n}\n.zmdi-assignment-alert:before {\n  content: '\\f107';\n}\n.zmdi-assignment-check:before {\n  content: '\\f108';\n}\n.zmdi-assignment-o:before {\n  content: '\\f109';\n}\n.zmdi-assignment-return:before {\n  content: '\\f10a';\n}\n.zmdi-assignment-returned:before {\n  content: '\\f10b';\n}\n.zmdi-assignment:before {\n  content: '\\f10c';\n}\n.zmdi-attachment-alt:before {\n  content: '\\f10d';\n}\n.zmdi-attachment:before {\n  content: '\\f10e';\n}\n.zmdi-audio:before {\n  content: '\\f10f';\n}\n.zmdi-badge-check:before {\n  content: '\\f110';\n}\n.zmdi-balance-wallet:before {\n  content: '\\f111';\n}\n.zmdi-balance:before {\n  content: '\\f112';\n}\n.zmdi-battery-alert:before {\n  content: '\\f113';\n}\n.zmdi-battery-flash:before {\n  content: '\\f114';\n}\n.zmdi-battery-unknown:before {\n  content: '\\f115';\n}\n.zmdi-battery:before {\n  content: '\\f116';\n}\n.zmdi-bike:before {\n  content: '\\f117';\n}\n.zmdi-block-alt:before {\n  content: '\\f118';\n}\n.zmdi-block:before {\n  content: '\\f119';\n}\n.zmdi-boat:before {\n  content: '\\f11a';\n}\n.zmdi-book-image:before {\n  content: '\\f11b';\n}\n.zmdi-book:before {\n  content: '\\f11c';\n}\n.zmdi-bookmark-outline:before {\n  content: '\\f11d';\n}\n.zmdi-bookmark:before {\n  content: '\\f11e';\n}\n.zmdi-brush:before {\n  content: '\\f11f';\n}\n.zmdi-bug:before {\n  content: '\\f120';\n}\n.zmdi-bus:before {\n  content: '\\f121';\n}\n.zmdi-cake:before {\n  content: '\\f122';\n}\n.zmdi-car-taxi:before {\n  content: '\\f123';\n}\n.zmdi-car-wash:before {\n  content: '\\f124';\n}\n.zmdi-car:before {\n  content: '\\f125';\n}\n.zmdi-card-giftcard:before {\n  content: '\\f126';\n}\n.zmdi-card-membership:before {\n  content: '\\f127';\n}\n.zmdi-card-travel:before {\n  content: '\\f128';\n}\n.zmdi-card:before {\n  content: '\\f129';\n}\n.zmdi-case-check:before {\n  content: '\\f12a';\n}\n.zmdi-case-download:before {\n  content: '\\f12b';\n}\n.zmdi-case-play:before {\n  content: '\\f12c';\n}\n.zmdi-case:before {\n  content: '\\f12d';\n}\n.zmdi-cast-connected:before {\n  content: '\\f12e';\n}\n.zmdi-cast:before {\n  content: '\\f12f';\n}\n.zmdi-chart-donut:before {\n  content: '\\f130';\n}\n.zmdi-chart:before {\n  content: '\\f131';\n}\n.zmdi-city-alt:before {\n  content: '\\f132';\n}\n.zmdi-city:before {\n  content: '\\f133';\n}\n.zmdi-close-circle-o:before {\n  content: '\\f134';\n}\n.zmdi-close-circle:before {\n  content: '\\f135';\n}\n.zmdi-close:before {\n  content: '\\f136';\n}\n.zmdi-cocktail:before {\n  content: '\\f137';\n}\n.zmdi-code-setting:before {\n  content: '\\f138';\n}\n.zmdi-code-smartphone:before {\n  content: '\\f139';\n}\n.zmdi-code:before {\n  content: '\\f13a';\n}\n.zmdi-coffee:before {\n  content: '\\f13b';\n}\n.zmdi-collection-bookmark:before {\n  content: '\\f13c';\n}\n.zmdi-collection-case-play:before {\n  content: '\\f13d';\n}\n.zmdi-collection-folder-image:before {\n  content: '\\f13e';\n}\n.zmdi-collection-image-o:before {\n  content: '\\f13f';\n}\n.zmdi-collection-image:before {\n  content: '\\f140';\n}\n.zmdi-collection-item-1:before {\n  content: '\\f141';\n}\n.zmdi-collection-item-2:before {\n  content: '\\f142';\n}\n.zmdi-collection-item-3:before {\n  content: '\\f143';\n}\n.zmdi-collection-item-4:before {\n  content: '\\f144';\n}\n.zmdi-collection-item-5:before {\n  content: '\\f145';\n}\n.zmdi-collection-item-6:before {\n  content: '\\f146';\n}\n.zmdi-collection-item-7:before {\n  content: '\\f147';\n}\n.zmdi-collection-item-8:before {\n  content: '\\f148';\n}\n.zmdi-collection-item-9-plus:before {\n  content: '\\f149';\n}\n.zmdi-collection-item-9:before {\n  content: '\\f14a';\n}\n.zmdi-collection-item:before {\n  content: '\\f14b';\n}\n.zmdi-collection-music:before {\n  content: '\\f14c';\n}\n.zmdi-collection-pdf:before {\n  content: '\\f14d';\n}\n.zmdi-collection-plus:before {\n  content: '\\f14e';\n}\n.zmdi-collection-speaker:before {\n  content: '\\f14f';\n}\n.zmdi-collection-text:before {\n  content: '\\f150';\n}\n.zmdi-collection-video:before {\n  content: '\\f151';\n}\n.zmdi-compass:before {\n  content: '\\f152';\n}\n.zmdi-cutlery:before {\n  content: '\\f153';\n}\n.zmdi-delete:before {\n  content: '\\f154';\n}\n.zmdi-dialpad:before {\n  content: '\\f155';\n}\n.zmdi-dns:before {\n  content: '\\f156';\n}\n.zmdi-drink:before {\n  content: '\\f157';\n}\n.zmdi-edit:before {\n  content: '\\f158';\n}\n.zmdi-email-open:before {\n  content: '\\f159';\n}\n.zmdi-email:before {\n  content: '\\f15a';\n}\n.zmdi-eye-off:before {\n  content: '\\f15b';\n}\n.zmdi-eye:before {\n  content: '\\f15c';\n}\n.zmdi-eyedropper:before {\n  content: '\\f15d';\n}\n.zmdi-favorite-outline:before {\n  content: '\\f15e';\n}\n.zmdi-favorite:before {\n  content: '\\f15f';\n}\n.zmdi-filter-list:before {\n  content: '\\f160';\n}\n.zmdi-fire:before {\n  content: '\\f161';\n}\n.zmdi-flag:before {\n  content: '\\f162';\n}\n.zmdi-flare:before {\n  content: '\\f163';\n}\n.zmdi-flash-auto:before {\n  content: '\\f164';\n}\n.zmdi-flash-off:before {\n  content: '\\f165';\n}\n.zmdi-flash:before {\n  content: '\\f166';\n}\n.zmdi-flip:before {\n  content: '\\f167';\n}\n.zmdi-flower-alt:before {\n  content: '\\f168';\n}\n.zmdi-flower:before {\n  content: '\\f169';\n}\n.zmdi-font:before {\n  content: '\\f16a';\n}\n.zmdi-fullscreen-alt:before {\n  content: '\\f16b';\n}\n.zmdi-fullscreen-exit:before {\n  content: '\\f16c';\n}\n.zmdi-fullscreen:before {\n  content: '\\f16d';\n}\n.zmdi-functions:before {\n  content: '\\f16e';\n}\n.zmdi-gas-station:before {\n  content: '\\f16f';\n}\n.zmdi-gesture:before {\n  content: '\\f170';\n}\n.zmdi-globe-alt:before {\n  content: '\\f171';\n}\n.zmdi-globe-lock:before {\n  content: '\\f172';\n}\n.zmdi-globe:before {\n  content: '\\f173';\n}\n.zmdi-graduation-cap:before {\n  content: '\\f174';\n}\n.zmdi-home:before {\n  content: '\\f175';\n}\n.zmdi-hospital-alt:before {\n  content: '\\f176';\n}\n.zmdi-hospital:before {\n  content: '\\f177';\n}\n.zmdi-hotel:before {\n  content: '\\f178';\n}\n.zmdi-hourglass-alt:before {\n  content: '\\f179';\n}\n.zmdi-hourglass-outline:before {\n  content: '\\f17a';\n}\n.zmdi-hourglass:before {\n  content: '\\f17b';\n}\n.zmdi-http:before {\n  content: '\\f17c';\n}\n.zmdi-image-alt:before {\n  content: '\\f17d';\n}\n.zmdi-image-o:before {\n  content: '\\f17e';\n}\n.zmdi-image:before {\n  content: '\\f17f';\n}\n.zmdi-inbox:before {\n  content: '\\f180';\n}\n.zmdi-invert-colors-off:before {\n  content: '\\f181';\n}\n.zmdi-invert-colors:before {\n  content: '\\f182';\n}\n.zmdi-key:before {\n  content: '\\f183';\n}\n.zmdi-label-alt-outline:before {\n  content: '\\f184';\n}\n.zmdi-label-alt:before {\n  content: '\\f185';\n}\n.zmdi-label-heart:before {\n  content: '\\f186';\n}\n.zmdi-label:before {\n  content: '\\f187';\n}\n.zmdi-labels:before {\n  content: '\\f188';\n}\n.zmdi-lamp:before {\n  content: '\\f189';\n}\n.zmdi-landscape:before {\n  content: '\\f18a';\n}\n.zmdi-layers-off:before {\n  content: '\\f18b';\n}\n.zmdi-layers:before {\n  content: '\\f18c';\n}\n.zmdi-library:before {\n  content: '\\f18d';\n}\n.zmdi-link:before {\n  content: '\\f18e';\n}\n.zmdi-lock-open:before {\n  content: '\\f18f';\n}\n.zmdi-lock-outline:before {\n  content: '\\f190';\n}\n.zmdi-lock:before {\n  content: '\\f191';\n}\n.zmdi-mail-reply-all:before {\n  content: '\\f192';\n}\n.zmdi-mail-reply:before {\n  content: '\\f193';\n}\n.zmdi-mail-send:before {\n  content: '\\f194';\n}\n.zmdi-mall:before {\n  content: '\\f195';\n}\n.zmdi-map:before {\n  content: '\\f196';\n}\n.zmdi-menu:before {\n  content: '\\f197';\n}\n.zmdi-money-box:before {\n  content: '\\f198';\n}\n.zmdi-money-off:before {\n  content: '\\f199';\n}\n.zmdi-money:before {\n  content: '\\f19a';\n}\n.zmdi-more-vert:before {\n  content: '\\f19b';\n}\n.zmdi-more:before {\n  content: '\\f19c';\n}\n.zmdi-movie-alt:before {\n  content: '\\f19d';\n}\n.zmdi-movie:before {\n  content: '\\f19e';\n}\n.zmdi-nature-people:before {\n  content: '\\f19f';\n}\n.zmdi-nature:before {\n  content: '\\f1a0';\n}\n.zmdi-navigation:before {\n  content: '\\f1a1';\n}\n.zmdi-open-in-browser:before {\n  content: '\\f1a2';\n}\n.zmdi-open-in-new:before {\n  content: '\\f1a3';\n}\n.zmdi-palette:before {\n  content: '\\f1a4';\n}\n.zmdi-parking:before {\n  content: '\\f1a5';\n}\n.zmdi-pin-account:before {\n  content: '\\f1a6';\n}\n.zmdi-pin-assistant:before {\n  content: '\\f1a7';\n}\n.zmdi-pin-drop:before {\n  content: '\\f1a8';\n}\n.zmdi-pin-help:before {\n  content: '\\f1a9';\n}\n.zmdi-pin-off:before {\n  content: '\\f1aa';\n}\n.zmdi-pin:before {\n  content: '\\f1ab';\n}\n.zmdi-pizza:before {\n  content: '\\f1ac';\n}\n.zmdi-plaster:before {\n  content: '\\f1ad';\n}\n.zmdi-power-setting:before {\n  content: '\\f1ae';\n}\n.zmdi-power:before {\n  content: '\\f1af';\n}\n.zmdi-print:before {\n  content: '\\f1b0';\n}\n.zmdi-puzzle-piece:before {\n  content: '\\f1b1';\n}\n.zmdi-quote:before {\n  content: '\\f1b2';\n}\n.zmdi-railway:before {\n  content: '\\f1b3';\n}\n.zmdi-receipt:before {\n  content: '\\f1b4';\n}\n.zmdi-refresh-alt:before {\n  content: '\\f1b5';\n}\n.zmdi-refresh-sync-alert:before {\n  content: '\\f1b6';\n}\n.zmdi-refresh-sync-off:before {\n  content: '\\f1b7';\n}\n.zmdi-refresh-sync:before {\n  content: '\\f1b8';\n}\n.zmdi-refresh:before {\n  content: '\\f1b9';\n}\n.zmdi-roller:before {\n  content: '\\f1ba';\n}\n.zmdi-ruler:before {\n  content: '\\f1bb';\n}\n.zmdi-scissors:before {\n  content: '\\f1bc';\n}\n.zmdi-screen-rotation-lock:before {\n  content: '\\f1bd';\n}\n.zmdi-screen-rotation:before {\n  content: '\\f1be';\n}\n.zmdi-search-for:before {\n  content: '\\f1bf';\n}\n.zmdi-search-in-file:before {\n  content: '\\f1c0';\n}\n.zmdi-search-in-page:before {\n  content: '\\f1c1';\n}\n.zmdi-search-replace:before {\n  content: '\\f1c2';\n}\n.zmdi-search:before {\n  content: '\\f1c3';\n}\n.zmdi-seat:before {\n  content: '\\f1c4';\n}\n.zmdi-settings-square:before {\n  content: '\\f1c5';\n}\n.zmdi-settings:before {\n  content: '\\f1c6';\n}\n.zmdi-shield-check:before {\n  content: '\\f1c7';\n}\n.zmdi-shield-security:before {\n  content: '\\f1c8';\n}\n.zmdi-shopping-basket:before {\n  content: '\\f1c9';\n}\n.zmdi-shopping-cart-plus:before {\n  content: '\\f1ca';\n}\n.zmdi-shopping-cart:before {\n  content: '\\f1cb';\n}\n.zmdi-sign-in:before {\n  content: '\\f1cc';\n}\n.zmdi-sort-amount-asc:before {\n  content: '\\f1cd';\n}\n.zmdi-sort-amount-desc:before {\n  content: '\\f1ce';\n}\n.zmdi-sort-asc:before {\n  content: '\\f1cf';\n}\n.zmdi-sort-desc:before {\n  content: '\\f1d0';\n}\n.zmdi-spellcheck:before {\n  content: '\\f1d1';\n}\n.zmdi-storage:before {\n  content: '\\f1d2';\n}\n.zmdi-store-24:before {\n  content: '\\f1d3';\n}\n.zmdi-store:before {\n  content: '\\f1d4';\n}\n.zmdi-subway:before {\n  content: '\\f1d5';\n}\n.zmdi-sun:before {\n  content: '\\f1d6';\n}\n.zmdi-tab-unselected:before {\n  content: '\\f1d7';\n}\n.zmdi-tab:before {\n  content: '\\f1d8';\n}\n.zmdi-tag-close:before {\n  content: '\\f1d9';\n}\n.zmdi-tag-more:before {\n  content: '\\f1da';\n}\n.zmdi-tag:before {\n  content: '\\f1db';\n}\n.zmdi-thumb-down:before {\n  content: '\\f1dc';\n}\n.zmdi-thumb-up-down:before {\n  content: '\\f1dd';\n}\n.zmdi-thumb-up:before {\n  content: '\\f1de';\n}\n.zmdi-ticket-star:before {\n  content: '\\f1df';\n}\n.zmdi-toll:before {\n  content: '\\f1e0';\n}\n.zmdi-toys:before {\n  content: '\\f1e1';\n}\n.zmdi-traffic:before {\n  content: '\\f1e2';\n}\n.zmdi-translate:before {\n  content: '\\f1e3';\n}\n.zmdi-triangle-down:before {\n  content: '\\f1e4';\n}\n.zmdi-triangle-up:before {\n  content: '\\f1e5';\n}\n.zmdi-truck:before {\n  content: '\\f1e6';\n}\n.zmdi-turning-sign:before {\n  content: '\\f1e7';\n}\n.zmdi-wallpaper:before {\n  content: '\\f1e8';\n}\n.zmdi-washing-machine:before {\n  content: '\\f1e9';\n}\n.zmdi-window-maximize:before {\n  content: '\\f1ea';\n}\n.zmdi-window-minimize:before {\n  content: '\\f1eb';\n}\n.zmdi-window-restore:before {\n  content: '\\f1ec';\n}\n.zmdi-wrench:before {\n  content: '\\f1ed';\n}\n.zmdi-zoom-in:before {\n  content: '\\f1ee';\n}\n.zmdi-zoom-out:before {\n  content: '\\f1ef';\n}\n.zmdi-alert-circle-o:before {\n  content: '\\f1f0';\n}\n.zmdi-alert-circle:before {\n  content: '\\f1f1';\n}\n.zmdi-alert-octagon:before {\n  content: '\\f1f2';\n}\n.zmdi-alert-polygon:before {\n  content: '\\f1f3';\n}\n.zmdi-alert-triangle:before {\n  content: '\\f1f4';\n}\n.zmdi-help-outline:before {\n  content: '\\f1f5';\n}\n.zmdi-help:before {\n  content: '\\f1f6';\n}\n.zmdi-info-outline:before {\n  content: '\\f1f7';\n}\n.zmdi-info:before {\n  content: '\\f1f8';\n}\n.zmdi-notifications-active:before {\n  content: '\\f1f9';\n}\n.zmdi-notifications-add:before {\n  content: '\\f1fa';\n}\n.zmdi-notifications-none:before {\n  content: '\\f1fb';\n}\n.zmdi-notifications-off:before {\n  content: '\\f1fc';\n}\n.zmdi-notifications-paused:before {\n  content: '\\f1fd';\n}\n.zmdi-notifications:before {\n  content: '\\f1fe';\n}\n.zmdi-account-add:before {\n  content: '\\f1ff';\n}\n.zmdi-account-box-mail:before {\n  content: '\\f200';\n}\n.zmdi-account-box-o:before {\n  content: '\\f201';\n}\n.zmdi-account-box-phone:before {\n  content: '\\f202';\n}\n.zmdi-account-box:before {\n  content: '\\f203';\n}\n.zmdi-account-calendar:before {\n  content: '\\f204';\n}\n.zmdi-account-circle:before {\n  content: '\\f205';\n}\n.zmdi-account-o:before {\n  content: '\\f206';\n}\n.zmdi-account:before {\n  content: '\\f207';\n}\n.zmdi-accounts-add:before {\n  content: '\\f208';\n}\n.zmdi-accounts-alt:before {\n  content: '\\f209';\n}\n.zmdi-accounts-list-alt:before {\n  content: '\\f20a';\n}\n.zmdi-accounts-list:before {\n  content: '\\f20b';\n}\n.zmdi-accounts-outline:before {\n  content: '\\f20c';\n}\n.zmdi-accounts:before {\n  content: '\\f20d';\n}\n.zmdi-face:before {\n  content: '\\f20e';\n}\n.zmdi-female:before {\n  content: '\\f20f';\n}\n.zmdi-male-alt:before {\n  content: '\\f210';\n}\n.zmdi-male-female:before {\n  content: '\\f211';\n}\n.zmdi-male:before {\n  content: '\\f212';\n}\n.zmdi-mood-bad:before {\n  content: '\\f213';\n}\n.zmdi-mood:before {\n  content: '\\f214';\n}\n.zmdi-run:before {\n  content: '\\f215';\n}\n.zmdi-walk:before {\n  content: '\\f216';\n}\n.zmdi-cloud-box:before {\n  content: '\\f217';\n}\n.zmdi-cloud-circle:before {\n  content: '\\f218';\n}\n.zmdi-cloud-done:before {\n  content: '\\f219';\n}\n.zmdi-cloud-download:before {\n  content: '\\f21a';\n}\n.zmdi-cloud-off:before {\n  content: '\\f21b';\n}\n.zmdi-cloud-outline-alt:before {\n  content: '\\f21c';\n}\n.zmdi-cloud-outline:before {\n  content: '\\f21d';\n}\n.zmdi-cloud-upload:before {\n  content: '\\f21e';\n}\n.zmdi-cloud:before {\n  content: '\\f21f';\n}\n.zmdi-download:before {\n  content: '\\f220';\n}\n.zmdi-file-plus:before {\n  content: '\\f221';\n}\n.zmdi-file-text:before {\n  content: '\\f222';\n}\n.zmdi-file:before {\n  content: '\\f223';\n}\n.zmdi-folder-outline:before {\n  content: '\\f224';\n}\n.zmdi-folder-person:before {\n  content: '\\f225';\n}\n.zmdi-folder-star-alt:before {\n  content: '\\f226';\n}\n.zmdi-folder-star:before {\n  content: '\\f227';\n}\n.zmdi-folder:before {\n  content: '\\f228';\n}\n.zmdi-gif:before {\n  content: '\\f229';\n}\n.zmdi-upload:before {\n  content: '\\f22a';\n}\n.zmdi-border-all:before {\n  content: '\\f22b';\n}\n.zmdi-border-bottom:before {\n  content: '\\f22c';\n}\n.zmdi-border-clear:before {\n  content: '\\f22d';\n}\n.zmdi-border-color:before {\n  content: '\\f22e';\n}\n.zmdi-border-horizontal:before {\n  content: '\\f22f';\n}\n.zmdi-border-inner:before {\n  content: '\\f230';\n}\n.zmdi-border-left:before {\n  content: '\\f231';\n}\n.zmdi-border-outer:before {\n  content: '\\f232';\n}\n.zmdi-border-right:before {\n  content: '\\f233';\n}\n.zmdi-border-style:before {\n  content: '\\f234';\n}\n.zmdi-border-top:before {\n  content: '\\f235';\n}\n.zmdi-border-vertical:before {\n  content: '\\f236';\n}\n.zmdi-copy:before {\n  content: '\\f237';\n}\n.zmdi-crop:before {\n  content: '\\f238';\n}\n.zmdi-format-align-center:before {\n  content: '\\f239';\n}\n.zmdi-format-align-justify:before {\n  content: '\\f23a';\n}\n.zmdi-format-align-left:before {\n  content: '\\f23b';\n}\n.zmdi-format-align-right:before {\n  content: '\\f23c';\n}\n.zmdi-format-bold:before {\n  content: '\\f23d';\n}\n.zmdi-format-clear-all:before {\n  content: '\\f23e';\n}\n.zmdi-format-clear:before {\n  content: '\\f23f';\n}\n.zmdi-format-color-fill:before {\n  content: '\\f240';\n}\n.zmdi-format-color-reset:before {\n  content: '\\f241';\n}\n.zmdi-format-color-text:before {\n  content: '\\f242';\n}\n.zmdi-format-indent-decrease:before {\n  content: '\\f243';\n}\n.zmdi-format-indent-increase:before {\n  content: '\\f244';\n}\n.zmdi-format-italic:before {\n  content: '\\f245';\n}\n.zmdi-format-line-spacing:before {\n  content: '\\f246';\n}\n.zmdi-format-list-bulleted:before {\n  content: '\\f247';\n}\n.zmdi-format-list-numbered:before {\n  content: '\\f248';\n}\n.zmdi-format-ltr:before {\n  content: '\\f249';\n}\n.zmdi-format-rtl:before {\n  content: '\\f24a';\n}\n.zmdi-format-size:before {\n  content: '\\f24b';\n}\n.zmdi-format-strikethrough-s:before {\n  content: '\\f24c';\n}\n.zmdi-format-strikethrough:before {\n  content: '\\f24d';\n}\n.zmdi-format-subject:before {\n  content: '\\f24e';\n}\n.zmdi-format-underlined:before {\n  content: '\\f24f';\n}\n.zmdi-format-valign-bottom:before {\n  content: '\\f250';\n}\n.zmdi-format-valign-center:before {\n  content: '\\f251';\n}\n.zmdi-format-valign-top:before {\n  content: '\\f252';\n}\n.zmdi-redo:before {\n  content: '\\f253';\n}\n.zmdi-select-all:before {\n  content: '\\f254';\n}\n.zmdi-space-bar:before {\n  content: '\\f255';\n}\n.zmdi-text-format:before {\n  content: '\\f256';\n}\n.zmdi-transform:before {\n  content: '\\f257';\n}\n.zmdi-undo:before {\n  content: '\\f258';\n}\n.zmdi-wrap-text:before {\n  content: '\\f259';\n}\n.zmdi-comment-alert:before {\n  content: '\\f25a';\n}\n.zmdi-comment-alt-text:before {\n  content: '\\f25b';\n}\n.zmdi-comment-alt:before {\n  content: '\\f25c';\n}\n.zmdi-comment-edit:before {\n  content: '\\f25d';\n}\n.zmdi-comment-image:before {\n  content: '\\f25e';\n}\n.zmdi-comment-list:before {\n  content: '\\f25f';\n}\n.zmdi-comment-more:before {\n  content: '\\f260';\n}\n.zmdi-comment-outline:before {\n  content: '\\f261';\n}\n.zmdi-comment-text-alt:before {\n  content: '\\f262';\n}\n.zmdi-comment-text:before {\n  content: '\\f263';\n}\n.zmdi-comment-video:before {\n  content: '\\f264';\n}\n.zmdi-comment:before {\n  content: '\\f265';\n}\n.zmdi-comments:before {\n  content: '\\f266';\n}\n.zmdi-check-all:before {\n  content: '\\f267';\n}\n.zmdi-check-circle-u:before {\n  content: '\\f268';\n}\n.zmdi-check-circle:before {\n  content: '\\f269';\n}\n.zmdi-check-square:before {\n  content: '\\f26a';\n}\n.zmdi-check:before {\n  content: '\\f26b';\n}\n.zmdi-circle-o:before {\n  content: '\\f26c';\n}\n.zmdi-circle:before {\n  content: '\\f26d';\n}\n.zmdi-dot-circle-alt:before {\n  content: '\\f26e';\n}\n.zmdi-dot-circle:before {\n  content: '\\f26f';\n}\n.zmdi-minus-circle-outline:before {\n  content: '\\f270';\n}\n.zmdi-minus-circle:before {\n  content: '\\f271';\n}\n.zmdi-minus-square:before {\n  content: '\\f272';\n}\n.zmdi-minus:before {\n  content: '\\f273';\n}\n.zmdi-plus-circle-o-duplicate:before {\n  content: '\\f274';\n}\n.zmdi-plus-circle-o:before {\n  content: '\\f275';\n}\n.zmdi-plus-circle:before {\n  content: '\\f276';\n}\n.zmdi-plus-square:before {\n  content: '\\f277';\n}\n.zmdi-plus:before {\n  content: '\\f278';\n}\n.zmdi-square-o:before {\n  content: '\\f279';\n}\n.zmdi-star-circle:before {\n  content: '\\f27a';\n}\n.zmdi-star-half:before {\n  content: '\\f27b';\n}\n.zmdi-star-outline:before {\n  content: '\\f27c';\n}\n.zmdi-star:before {\n  content: '\\f27d';\n}\n.zmdi-bluetooth-connected:before {\n  content: '\\f27e';\n}\n.zmdi-bluetooth-off:before {\n  content: '\\f27f';\n}\n.zmdi-bluetooth-search:before {\n  content: '\\f280';\n}\n.zmdi-bluetooth-setting:before {\n  content: '\\f281';\n}\n.zmdi-bluetooth:before {\n  content: '\\f282';\n}\n.zmdi-camera-add:before {\n  content: '\\f283';\n}\n.zmdi-camera-alt:before {\n  content: '\\f284';\n}\n.zmdi-camera-bw:before {\n  content: '\\f285';\n}\n.zmdi-camera-front:before {\n  content: '\\f286';\n}\n.zmdi-camera-mic:before {\n  content: '\\f287';\n}\n.zmdi-camera-party-mode:before {\n  content: '\\f288';\n}\n.zmdi-camera-rear:before {\n  content: '\\f289';\n}\n.zmdi-camera-roll:before {\n  content: '\\f28a';\n}\n.zmdi-camera-switch:before {\n  content: '\\f28b';\n}\n.zmdi-camera:before {\n  content: '\\f28c';\n}\n.zmdi-card-alert:before {\n  content: '\\f28d';\n}\n.zmdi-card-off:before {\n  content: '\\f28e';\n}\n.zmdi-card-sd:before {\n  content: '\\f28f';\n}\n.zmdi-card-sim:before {\n  content: '\\f290';\n}\n.zmdi-desktop-mac:before {\n  content: '\\f291';\n}\n.zmdi-desktop-windows:before {\n  content: '\\f292';\n}\n.zmdi-device-hub:before {\n  content: '\\f293';\n}\n.zmdi-devices-off:before {\n  content: '\\f294';\n}\n.zmdi-devices:before {\n  content: '\\f295';\n}\n.zmdi-dock:before {\n  content: '\\f296';\n}\n.zmdi-floppy:before {\n  content: '\\f297';\n}\n.zmdi-gamepad:before {\n  content: '\\f298';\n}\n.zmdi-gps-dot:before {\n  content: '\\f299';\n}\n.zmdi-gps-off:before {\n  content: '\\f29a';\n}\n.zmdi-gps:before {\n  content: '\\f29b';\n}\n.zmdi-headset-mic:before {\n  content: '\\f29c';\n}\n.zmdi-headset:before {\n  content: '\\f29d';\n}\n.zmdi-input-antenna:before {\n  content: '\\f29e';\n}\n.zmdi-input-composite:before {\n  content: '\\f29f';\n}\n.zmdi-input-hdmi:before {\n  content: '\\f2a0';\n}\n.zmdi-input-power:before {\n  content: '\\f2a1';\n}\n.zmdi-input-svideo:before {\n  content: '\\f2a2';\n}\n.zmdi-keyboard-hide:before {\n  content: '\\f2a3';\n}\n.zmdi-keyboard:before {\n  content: '\\f2a4';\n}\n.zmdi-laptop-chromebook:before {\n  content: '\\f2a5';\n}\n.zmdi-laptop-mac:before {\n  content: '\\f2a6';\n}\n.zmdi-laptop:before {\n  content: '\\f2a7';\n}\n.zmdi-mic-off:before {\n  content: '\\f2a8';\n}\n.zmdi-mic-outline:before {\n  content: '\\f2a9';\n}\n.zmdi-mic-setting:before {\n  content: '\\f2aa';\n}\n.zmdi-mic:before {\n  content: '\\f2ab';\n}\n.zmdi-mouse:before {\n  content: '\\f2ac';\n}\n.zmdi-network-alert:before {\n  content: '\\f2ad';\n}\n.zmdi-network-locked:before {\n  content: '\\f2ae';\n}\n.zmdi-network-off:before {\n  content: '\\f2af';\n}\n.zmdi-network-outline:before {\n  content: '\\f2b0';\n}\n.zmdi-network-setting:before {\n  content: '\\f2b1';\n}\n.zmdi-network:before {\n  content: '\\f2b2';\n}\n.zmdi-phone-bluetooth:before {\n  content: '\\f2b3';\n}\n.zmdi-phone-end:before {\n  content: '\\f2b4';\n}\n.zmdi-phone-forwarded:before {\n  content: '\\f2b5';\n}\n.zmdi-phone-in-talk:before {\n  content: '\\f2b6';\n}\n.zmdi-phone-locked:before {\n  content: '\\f2b7';\n}\n.zmdi-phone-missed:before {\n  content: '\\f2b8';\n}\n.zmdi-phone-msg:before {\n  content: '\\f2b9';\n}\n.zmdi-phone-paused:before {\n  content: '\\f2ba';\n}\n.zmdi-phone-ring:before {\n  content: '\\f2bb';\n}\n.zmdi-phone-setting:before {\n  content: '\\f2bc';\n}\n.zmdi-phone-sip:before {\n  content: '\\f2bd';\n}\n.zmdi-phone:before {\n  content: '\\f2be';\n}\n.zmdi-portable-wifi-changes:before {\n  content: '\\f2bf';\n}\n.zmdi-portable-wifi-off:before {\n  content: '\\f2c0';\n}\n.zmdi-portable-wifi:before {\n  content: '\\f2c1';\n}\n.zmdi-radio:before {\n  content: '\\f2c2';\n}\n.zmdi-reader:before {\n  content: '\\f2c3';\n}\n.zmdi-remote-control-alt:before {\n  content: '\\f2c4';\n}\n.zmdi-remote-control:before {\n  content: '\\f2c5';\n}\n.zmdi-router:before {\n  content: '\\f2c6';\n}\n.zmdi-scanner:before {\n  content: '\\f2c7';\n}\n.zmdi-smartphone-android:before {\n  content: '\\f2c8';\n}\n.zmdi-smartphone-download:before {\n  content: '\\f2c9';\n}\n.zmdi-smartphone-erase:before {\n  content: '\\f2ca';\n}\n.zmdi-smartphone-info:before {\n  content: '\\f2cb';\n}\n.zmdi-smartphone-iphone:before {\n  content: '\\f2cc';\n}\n.zmdi-smartphone-landscape-lock:before {\n  content: '\\f2cd';\n}\n.zmdi-smartphone-landscape:before {\n  content: '\\f2ce';\n}\n.zmdi-smartphone-lock:before {\n  content: '\\f2cf';\n}\n.zmdi-smartphone-portrait-lock:before {\n  content: '\\f2d0';\n}\n.zmdi-smartphone-ring:before {\n  content: '\\f2d1';\n}\n.zmdi-smartphone-setting:before {\n  content: '\\f2d2';\n}\n.zmdi-smartphone-setup:before {\n  content: '\\f2d3';\n}\n.zmdi-smartphone:before {\n  content: '\\f2d4';\n}\n.zmdi-speaker:before {\n  content: '\\f2d5';\n}\n.zmdi-tablet-android:before {\n  content: '\\f2d6';\n}\n.zmdi-tablet-mac:before {\n  content: '\\f2d7';\n}\n.zmdi-tablet:before {\n  content: '\\f2d8';\n}\n.zmdi-tv-alt-play:before {\n  content: '\\f2d9';\n}\n.zmdi-tv-list:before {\n  content: '\\f2da';\n}\n.zmdi-tv-play:before {\n  content: '\\f2db';\n}\n.zmdi-tv:before {\n  content: '\\f2dc';\n}\n.zmdi-usb:before {\n  content: '\\f2dd';\n}\n.zmdi-videocam-off:before {\n  content: '\\f2de';\n}\n.zmdi-videocam-switch:before {\n  content: '\\f2df';\n}\n.zmdi-videocam:before {\n  content: '\\f2e0';\n}\n.zmdi-watch:before {\n  content: '\\f2e1';\n}\n.zmdi-wifi-alt-2:before {\n  content: '\\f2e2';\n}\n.zmdi-wifi-alt:before {\n  content: '\\f2e3';\n}\n.zmdi-wifi-info:before {\n  content: '\\f2e4';\n}\n.zmdi-wifi-lock:before {\n  content: '\\f2e5';\n}\n.zmdi-wifi-off:before {\n  content: '\\f2e6';\n}\n.zmdi-wifi-outline:before {\n  content: '\\f2e7';\n}\n.zmdi-wifi:before {\n  content: '\\f2e8';\n}\n.zmdi-arrow-left-bottom:before {\n  content: '\\f2e9';\n}\n.zmdi-arrow-left:before {\n  content: '\\f2ea';\n}\n.zmdi-arrow-merge:before {\n  content: '\\f2eb';\n}\n.zmdi-arrow-missed:before {\n  content: '\\f2ec';\n}\n.zmdi-arrow-right-top:before {\n  content: '\\f2ed';\n}\n.zmdi-arrow-right:before {\n  content: '\\f2ee';\n}\n.zmdi-arrow-split:before {\n  content: '\\f2ef';\n}\n.zmdi-arrows:before {\n  content: '\\f2f0';\n}\n.zmdi-caret-down-circle:before {\n  content: '\\f2f1';\n}\n.zmdi-caret-down:before {\n  content: '\\f2f2';\n}\n.zmdi-caret-left-circle:before {\n  content: '\\f2f3';\n}\n.zmdi-caret-left:before {\n  content: '\\f2f4';\n}\n.zmdi-caret-right-circle:before {\n  content: '\\f2f5';\n}\n.zmdi-caret-right:before {\n  content: '\\f2f6';\n}\n.zmdi-caret-up-circle:before {\n  content: '\\f2f7';\n}\n.zmdi-caret-up:before {\n  content: '\\f2f8';\n}\n.zmdi-chevron-down:before {\n  content: '\\f2f9';\n}\n.zmdi-chevron-left:before {\n  content: '\\f2fa';\n}\n.zmdi-chevron-right:before {\n  content: '\\f2fb';\n}\n.zmdi-chevron-up:before {\n  content: '\\f2fc';\n}\n.zmdi-forward:before {\n  content: '\\f2fd';\n}\n.zmdi-long-arrow-down:before {\n  content: '\\f2fe';\n}\n.zmdi-long-arrow-left:before {\n  content: '\\f2ff';\n}\n.zmdi-long-arrow-return:before {\n  content: '\\f300';\n}\n.zmdi-long-arrow-right:before {\n  content: '\\f301';\n}\n.zmdi-long-arrow-tab:before {\n  content: '\\f302';\n}\n.zmdi-long-arrow-up:before {\n  content: '\\f303';\n}\n.zmdi-rotate-ccw:before {\n  content: '\\f304';\n}\n.zmdi-rotate-cw:before {\n  content: '\\f305';\n}\n.zmdi-rotate-left:before {\n  content: '\\f306';\n}\n.zmdi-rotate-right:before {\n  content: '\\f307';\n}\n.zmdi-square-down:before {\n  content: '\\f308';\n}\n.zmdi-square-right:before {\n  content: '\\f309';\n}\n.zmdi-swap-alt:before {\n  content: '\\f30a';\n}\n.zmdi-swap-vertical-circle:before {\n  content: '\\f30b';\n}\n.zmdi-swap-vertical:before {\n  content: '\\f30c';\n}\n.zmdi-swap:before {\n  content: '\\f30d';\n}\n.zmdi-trending-down:before {\n  content: '\\f30e';\n}\n.zmdi-trending-flat:before {\n  content: '\\f30f';\n}\n.zmdi-trending-up:before {\n  content: '\\f310';\n}\n.zmdi-unfold-less:before {\n  content: '\\f311';\n}\n.zmdi-unfold-more:before {\n  content: '\\f312';\n}\n.zmdi-apps:before {\n  content: '\\f313';\n}\n.zmdi-grid-off:before {\n  content: '\\f314';\n}\n.zmdi-grid:before {\n  content: '\\f315';\n}\n.zmdi-view-agenda:before {\n  content: '\\f316';\n}\n.zmdi-view-array:before {\n  content: '\\f317';\n}\n.zmdi-view-carousel:before {\n  content: '\\f318';\n}\n.zmdi-view-column:before {\n  content: '\\f319';\n}\n.zmdi-view-comfy:before {\n  content: '\\f31a';\n}\n.zmdi-view-compact:before {\n  content: '\\f31b';\n}\n.zmdi-view-dashboard:before {\n  content: '\\f31c';\n}\n.zmdi-view-day:before {\n  content: '\\f31d';\n}\n.zmdi-view-headline:before {\n  content: '\\f31e';\n}\n.zmdi-view-list-alt:before {\n  content: '\\f31f';\n}\n.zmdi-view-list:before {\n  content: '\\f320';\n}\n.zmdi-view-module:before {\n  content: '\\f321';\n}\n.zmdi-view-quilt:before {\n  content: '\\f322';\n}\n.zmdi-view-stream:before {\n  content: '\\f323';\n}\n.zmdi-view-subtitles:before {\n  content: '\\f324';\n}\n.zmdi-view-toc:before {\n  content: '\\f325';\n}\n.zmdi-view-web:before {\n  content: '\\f326';\n}\n.zmdi-view-week:before {\n  content: '\\f327';\n}\n.zmdi-widgets:before {\n  content: '\\f328';\n}\n.zmdi-alarm-check:before {\n  content: '\\f329';\n}\n.zmdi-alarm-off:before {\n  content: '\\f32a';\n}\n.zmdi-alarm-plus:before {\n  content: '\\f32b';\n}\n.zmdi-alarm-snooze:before {\n  content: '\\f32c';\n}\n.zmdi-alarm:before {\n  content: '\\f32d';\n}\n.zmdi-calendar-alt:before {\n  content: '\\f32e';\n}\n.zmdi-calendar-check:before {\n  content: '\\f32f';\n}\n.zmdi-calendar-close:before {\n  content: '\\f330';\n}\n.zmdi-calendar-note:before {\n  content: '\\f331';\n}\n.zmdi-calendar:before {\n  content: '\\f332';\n}\n.zmdi-time-countdown:before {\n  content: '\\f333';\n}\n.zmdi-time-interval:before {\n  content: '\\f334';\n}\n.zmdi-time-restore-setting:before {\n  content: '\\f335';\n}\n.zmdi-time-restore:before {\n  content: '\\f336';\n}\n.zmdi-time:before {\n  content: '\\f337';\n}\n.zmdi-timer-off:before {\n  content: '\\f338';\n}\n.zmdi-timer:before {\n  content: '\\f339';\n}\n.zmdi-android-alt:before {\n  content: '\\f33a';\n}\n.zmdi-android:before {\n  content: '\\f33b';\n}\n.zmdi-apple:before {\n  content: '\\f33c';\n}\n.zmdi-behance:before {\n  content: '\\f33d';\n}\n.zmdi-codepen:before {\n  content: '\\f33e';\n}\n.zmdi-dribbble:before {\n  content: '\\f33f';\n}\n.zmdi-dropbox:before {\n  content: '\\f340';\n}\n.zmdi-evernote:before {\n  content: '\\f341';\n}\n.zmdi-facebook-box:before {\n  content: '\\f342';\n}\n.zmdi-facebook:before {\n  content: '\\f343';\n}\n.zmdi-github-box:before {\n  content: '\\f344';\n}\n.zmdi-github:before {\n  content: '\\f345';\n}\n.zmdi-google-drive:before {\n  content: '\\f346';\n}\n.zmdi-google-earth:before {\n  content: '\\f347';\n}\n.zmdi-google-glass:before {\n  content: '\\f348';\n}\n.zmdi-google-maps:before {\n  content: '\\f349';\n}\n.zmdi-google-pages:before {\n  content: '\\f34a';\n}\n.zmdi-google-play:before {\n  content: '\\f34b';\n}\n.zmdi-google-plus-box:before {\n  content: '\\f34c';\n}\n.zmdi-google-plus:before {\n  content: '\\f34d';\n}\n.zmdi-google:before {\n  content: '\\f34e';\n}\n.zmdi-instagram:before {\n  content: '\\f34f';\n}\n.zmdi-language-css3:before {\n  content: '\\f350';\n}\n.zmdi-language-html5:before {\n  content: '\\f351';\n}\n.zmdi-language-javascript:before {\n  content: '\\f352';\n}\n.zmdi-language-python-alt:before {\n  content: '\\f353';\n}\n.zmdi-language-python:before {\n  content: '\\f354';\n}\n.zmdi-lastfm:before {\n  content: '\\f355';\n}\n.zmdi-linkedin-box:before {\n  content: '\\f356';\n}\n.zmdi-paypal:before {\n  content: '\\f357';\n}\n.zmdi-pinterest-box:before {\n  content: '\\f358';\n}\n.zmdi-pocket:before {\n  content: '\\f359';\n}\n.zmdi-polymer:before {\n  content: '\\f35a';\n}\n.zmdi-share:before {\n  content: '\\f35b';\n}\n.zmdi-stack-overflow:before {\n  content: '\\f35c';\n}\n.zmdi-steam-square:before {\n  content: '\\f35d';\n}\n.zmdi-steam:before {\n  content: '\\f35e';\n}\n.zmdi-twitter-box:before {\n  content: '\\f35f';\n}\n.zmdi-twitter:before {\n  content: '\\f360';\n}\n.zmdi-vk:before {\n  content: '\\f361';\n}\n.zmdi-wikipedia:before {\n  content: '\\f362';\n}\n.zmdi-windows:before {\n  content: '\\f363';\n}\n.zmdi-aspect-ratio-alt:before {\n  content: '\\f364';\n}\n.zmdi-aspect-ratio:before {\n  content: '\\f365';\n}\n.zmdi-blur-circular:before {\n  content: '\\f366';\n}\n.zmdi-blur-linear:before {\n  content: '\\f367';\n}\n.zmdi-blur-off:before {\n  content: '\\f368';\n}\n.zmdi-blur:before {\n  content: '\\f369';\n}\n.zmdi-brightness-2:before {\n  content: '\\f36a';\n}\n.zmdi-brightness-3:before {\n  content: '\\f36b';\n}\n.zmdi-brightness-4:before {\n  content: '\\f36c';\n}\n.zmdi-brightness-5:before {\n  content: '\\f36d';\n}\n.zmdi-brightness-6:before {\n  content: '\\f36e';\n}\n.zmdi-brightness-7:before {\n  content: '\\f36f';\n}\n.zmdi-brightness-auto:before {\n  content: '\\f370';\n}\n.zmdi-brightness-setting:before {\n  content: '\\f371';\n}\n.zmdi-broken-image:before {\n  content: '\\f372';\n}\n.zmdi-center-focus-strong:before {\n  content: '\\f373';\n}\n.zmdi-center-focus-weak:before {\n  content: '\\f374';\n}\n.zmdi-compare:before {\n  content: '\\f375';\n}\n.zmdi-crop-16-9:before {\n  content: '\\f376';\n}\n.zmdi-crop-3-2:before {\n  content: '\\f377';\n}\n.zmdi-crop-5-4:before {\n  content: '\\f378';\n}\n.zmdi-crop-7-5:before {\n  content: '\\f379';\n}\n.zmdi-crop-din:before {\n  content: '\\f37a';\n}\n.zmdi-crop-free:before {\n  content: '\\f37b';\n}\n.zmdi-crop-landscape:before {\n  content: '\\f37c';\n}\n.zmdi-crop-portrait:before {\n  content: '\\f37d';\n}\n.zmdi-crop-square:before {\n  content: '\\f37e';\n}\n.zmdi-exposure-alt:before {\n  content: '\\f37f';\n}\n.zmdi-exposure:before {\n  content: '\\f380';\n}\n.zmdi-filter-b-and-w:before {\n  content: '\\f381';\n}\n.zmdi-filter-center-focus:before {\n  content: '\\f382';\n}\n.zmdi-filter-frames:before {\n  content: '\\f383';\n}\n.zmdi-filter-tilt-shift:before {\n  content: '\\f384';\n}\n.zmdi-gradient:before {\n  content: '\\f385';\n}\n.zmdi-grain:before {\n  content: '\\f386';\n}\n.zmdi-graphic-eq:before {\n  content: '\\f387';\n}\n.zmdi-hdr-off:before {\n  content: '\\f388';\n}\n.zmdi-hdr-strong:before {\n  content: '\\f389';\n}\n.zmdi-hdr-weak:before {\n  content: '\\f38a';\n}\n.zmdi-hdr:before {\n  content: '\\f38b';\n}\n.zmdi-iridescent:before {\n  content: '\\f38c';\n}\n.zmdi-leak-off:before {\n  content: '\\f38d';\n}\n.zmdi-leak:before {\n  content: '\\f38e';\n}\n.zmdi-looks:before {\n  content: '\\f38f';\n}\n.zmdi-loupe:before {\n  content: '\\f390';\n}\n.zmdi-panorama-horizontal:before {\n  content: '\\f391';\n}\n.zmdi-panorama-vertical:before {\n  content: '\\f392';\n}\n.zmdi-panorama-wide-angle:before {\n  content: '\\f393';\n}\n.zmdi-photo-size-select-large:before {\n  content: '\\f394';\n}\n.zmdi-photo-size-select-small:before {\n  content: '\\f395';\n}\n.zmdi-picture-in-picture:before {\n  content: '\\f396';\n}\n.zmdi-slideshow:before {\n  content: '\\f397';\n}\n.zmdi-texture:before {\n  content: '\\f398';\n}\n.zmdi-tonality:before {\n  content: '\\f399';\n}\n.zmdi-vignette:before {\n  content: '\\f39a';\n}\n.zmdi-wb-auto:before {\n  content: '\\f39b';\n}\n.zmdi-eject-alt:before {\n  content: '\\f39c';\n}\n.zmdi-eject:before {\n  content: '\\f39d';\n}\n.zmdi-equalizer:before {\n  content: '\\f39e';\n}\n.zmdi-fast-forward:before {\n  content: '\\f39f';\n}\n.zmdi-fast-rewind:before {\n  content: '\\f3a0';\n}\n.zmdi-forward-10:before {\n  content: '\\f3a1';\n}\n.zmdi-forward-30:before {\n  content: '\\f3a2';\n}\n.zmdi-forward-5:before {\n  content: '\\f3a3';\n}\n.zmdi-hearing:before {\n  content: '\\f3a4';\n}\n.zmdi-pause-circle-outline:before {\n  content: '\\f3a5';\n}\n.zmdi-pause-circle:before {\n  content: '\\f3a6';\n}\n.zmdi-pause:before {\n  content: '\\f3a7';\n}\n.zmdi-play-circle-outline:before {\n  content: '\\f3a8';\n}\n.zmdi-play-circle:before {\n  content: '\\f3a9';\n}\n.zmdi-play:before {\n  content: '\\f3aa';\n}\n.zmdi-playlist-audio:before {\n  content: '\\f3ab';\n}\n.zmdi-playlist-plus:before {\n  content: '\\f3ac';\n}\n.zmdi-repeat-one:before {\n  content: '\\f3ad';\n}\n.zmdi-repeat:before {\n  content: '\\f3ae';\n}\n.zmdi-replay-10:before {\n  content: '\\f3af';\n}\n.zmdi-replay-30:before {\n  content: '\\f3b0';\n}\n.zmdi-replay-5:before {\n  content: '\\f3b1';\n}\n.zmdi-replay:before {\n  content: '\\f3b2';\n}\n.zmdi-shuffle:before {\n  content: '\\f3b3';\n}\n.zmdi-skip-next:before {\n  content: '\\f3b4';\n}\n.zmdi-skip-previous:before {\n  content: '\\f3b5';\n}\n.zmdi-stop:before {\n  content: '\\f3b6';\n}\n.zmdi-surround-sound:before {\n  content: '\\f3b7';\n}\n.zmdi-tune:before {\n  content: '\\f3b8';\n}\n.zmdi-volume-down:before {\n  content: '\\f3b9';\n}\n.zmdi-volume-mute:before {\n  content: '\\f3ba';\n}\n.zmdi-volume-off:before {\n  content: '\\f3bb';\n}\n.zmdi-volume-up:before {\n  content: '\\f3bc';\n}\n.zmdi-n-1-square:before {\n  content: '\\f3bd';\n}\n.zmdi-n-2-square:before {\n  content: '\\f3be';\n}\n.zmdi-n-3-square:before {\n  content: '\\f3bf';\n}\n.zmdi-n-4-square:before {\n  content: '\\f3c0';\n}\n.zmdi-n-5-square:before {\n  content: '\\f3c1';\n}\n.zmdi-n-6-square:before {\n  content: '\\f3c2';\n}\n.zmdi-neg-1:before {\n  content: '\\f3c3';\n}\n.zmdi-neg-2:before {\n  content: '\\f3c4';\n}\n.zmdi-plus-1:before {\n  content: '\\f3c5';\n}\n.zmdi-plus-2:before {\n  content: '\\f3c6';\n}\n.zmdi-sec-10:before {\n  content: '\\f3c7';\n}\n.zmdi-sec-3:before {\n  content: '\\f3c8';\n}\n.zmdi-zero:before {\n  content: '\\f3c9';\n}\n.zmdi-airline-seat-flat-angled:before {\n  content: '\\f3ca';\n}\n.zmdi-airline-seat-flat:before {\n  content: '\\f3cb';\n}\n.zmdi-airline-seat-individual-suite:before {\n  content: '\\f3cc';\n}\n.zmdi-airline-seat-legroom-extra:before {\n  content: '\\f3cd';\n}\n.zmdi-airline-seat-legroom-normal:before {\n  content: '\\f3ce';\n}\n.zmdi-airline-seat-legroom-reduced:before {\n  content: '\\f3cf';\n}\n.zmdi-airline-seat-recline-extra:before {\n  content: '\\f3d0';\n}\n.zmdi-airline-seat-recline-normal:before {\n  content: '\\f3d1';\n}\n.zmdi-airplay:before {\n  content: '\\f3d2';\n}\n.zmdi-closed-caption:before {\n  content: '\\f3d3';\n}\n.zmdi-confirmation-number:before {\n  content: '\\f3d4';\n}\n.zmdi-developer-board:before {\n  content: '\\f3d5';\n}\n.zmdi-disc-full:before {\n  content: '\\f3d6';\n}\n.zmdi-explicit:before {\n  content: '\\f3d7';\n}\n.zmdi-flight-land:before {\n  content: '\\f3d8';\n}\n.zmdi-flight-takeoff:before {\n  content: '\\f3d9';\n}\n.zmdi-flip-to-back:before {\n  content: '\\f3da';\n}\n.zmdi-flip-to-front:before {\n  content: '\\f3db';\n}\n.zmdi-group-work:before {\n  content: '\\f3dc';\n}\n.zmdi-hd:before {\n  content: '\\f3dd';\n}\n.zmdi-hq:before {\n  content: '\\f3de';\n}\n.zmdi-markunread-mailbox:before {\n  content: '\\f3df';\n}\n.zmdi-memory:before {\n  content: '\\f3e0';\n}\n.zmdi-nfc:before {\n  content: '\\f3e1';\n}\n.zmdi-play-for-work:before {\n  content: '\\f3e2';\n}\n.zmdi-power-input:before {\n  content: '\\f3e3';\n}\n.zmdi-present-to-all:before {\n  content: '\\f3e4';\n}\n.zmdi-satellite:before {\n  content: '\\f3e5';\n}\n.zmdi-tap-and-play:before {\n  content: '\\f3e6';\n}\n.zmdi-vibration:before {\n  content: '\\f3e7';\n}\n.zmdi-voicemail:before {\n  content: '\\f3e8';\n}\n.zmdi-import-export:before {\n  content: '\\f30c';\n}\n.zmdi-swap-vertical-:before {\n  content: '\\f30c';\n}\n.zmdi-airplanemode-inactive:before {\n  content: '\\f102';\n}\n.zmdi-airplanemode-active:before {\n  content: '\\f103';\n}\n.zmdi-rate-review:before {\n  content: '\\f103';\n}\n.zmdi-comment-sign:before {\n  content: '\\f25a';\n}\n.zmdi-network-warning:before {\n  content: '\\f2ad';\n}\n.zmdi-shopping-cart-add:before {\n  content: '\\f1ca';\n}\n.zmdi-file-add:before {\n  content: '\\f221';\n}\n.zmdi-network-wifi-scan:before {\n  content: '\\f2e4';\n}\n.zmdi-collection-add:before {\n  content: '\\f14e';\n}\n.zmdi-format-playlist-add:before {\n  content: '\\f3ac';\n}\n.zmdi-format-queue-music:before {\n  content: '\\f3ab';\n}\n.zmdi-plus-box:before {\n  content: '\\f277';\n}\n.zmdi-tag-backspace:before {\n  content: '\\f1d9';\n}\n.zmdi-alarm-add:before {\n  content: '\\f32b';\n}\n.zmdi-battery-charging:before {\n  content: '\\f114';\n}\n.zmdi-daydream-setting:before {\n  content: '\\f217';\n}\n.zmdi-more-horiz:before {\n  content: '\\f19c';\n}\n.zmdi-book-photo:before {\n  content: '\\f11b';\n}\n.zmdi-incandescent:before {\n  content: '\\f189';\n}\n.zmdi-wb-iridescent:before {\n  content: '\\f38c';\n}\n.zmdi-calendar-remove:before {\n  content: '\\f330';\n}\n.zmdi-refresh-sync-disabled:before {\n  content: '\\f1b7';\n}\n.zmdi-refresh-sync-problem:before {\n  content: '\\f1b6';\n}\n.zmdi-crop-original:before {\n  content: '\\f17e';\n}\n.zmdi-power-off:before {\n  content: '\\f1af';\n}\n.zmdi-power-off-setting:before {\n  content: '\\f1ae';\n}\n.zmdi-leak-remove:before {\n  content: '\\f38d';\n}\n.zmdi-star-border:before {\n  content: '\\f27c';\n}\n.zmdi-brightness-low:before {\n  content: '\\f36d';\n}\n.zmdi-brightness-medium:before {\n  content: '\\f36e';\n}\n.zmdi-brightness-high:before {\n  content: '\\f36f';\n}\n.zmdi-smartphone-portrait:before {\n  content: '\\f2d4';\n}\n.zmdi-live-tv:before {\n  content: '\\f2d9';\n}\n.zmdi-format-textdirection-l-to-r:before {\n  content: '\\f249';\n}\n.zmdi-format-textdirection-r-to-l:before {\n  content: '\\f24a';\n}\n.zmdi-arrow-back:before {\n  content: '\\f2ea';\n}\n.zmdi-arrow-forward:before {\n  content: '\\f2ee';\n}\n.zmdi-arrow-in:before {\n  content: '\\f2e9';\n}\n.zmdi-arrow-out:before {\n  content: '\\f2ed';\n}\n.zmdi-rotate-90-degrees-ccw:before {\n  content: '\\f304';\n}\n.zmdi-adb:before {\n  content: '\\f33a';\n}\n.zmdi-network-wifi:before {\n  content: '\\f2e8';\n}\n.zmdi-network-wifi-alt:before {\n  content: '\\f2e3';\n}\n.zmdi-network-wifi-lock:before {\n  content: '\\f2e5';\n}\n.zmdi-network-wifi-off:before {\n  content: '\\f2e6';\n}\n.zmdi-network-wifi-outline:before {\n  content: '\\f2e7';\n}\n.zmdi-network-wifi-info:before {\n  content: '\\f2e4';\n}\n.zmdi-layers-clear:before {\n  content: '\\f18b';\n}\n.zmdi-colorize:before {\n  content: '\\f15d';\n}\n.zmdi-format-paint:before {\n  content: '\\f1ba';\n}\n.zmdi-format-quote:before {\n  content: '\\f1b2';\n}\n.zmdi-camera-monochrome-photos:before {\n  content: '\\f285';\n}\n.zmdi-sort-by-alpha:before {\n  content: '\\f1cf';\n}\n.zmdi-folder-shared:before {\n  content: '\\f225';\n}\n.zmdi-folder-special:before {\n  content: '\\f226';\n}\n.zmdi-comment-dots:before {\n  content: '\\f260';\n}\n.zmdi-reorder:before {\n  content: '\\f31e';\n}\n.zmdi-dehaze:before {\n  content: '\\f197';\n}\n.zmdi-sort:before {\n  content: '\\f1ce';\n}\n.zmdi-pages:before {\n  content: '\\f34a';\n}\n.zmdi-calendar-account:before {\n  content: '\\f204';\n}\n.zmdi-paste:before {\n  content: '\\f109';\n}\n.zmdi-cut:before {\n  content: '\\f1bc';\n}\n.zmdi-save:before {\n  content: '\\f297';\n}\n.zmdi-smartphone-code:before {\n  content: '\\f139';\n}\n.zmdi-directions-bike:before {\n  content: '\\f117';\n}\n.zmdi-directions-boat:before {\n  content: '\\f11a';\n}\n.zmdi-directions-bus:before {\n  content: '\\f121';\n}\n.zmdi-directions-car:before {\n  content: '\\f125';\n}\n.zmdi-directions-railway:before {\n  content: '\\f1b3';\n}\n.zmdi-directions-run:before {\n  content: '\\f215';\n}\n.zmdi-directions-subway:before {\n  content: '\\f1d5';\n}\n.zmdi-directions-walk:before {\n  content: '\\f216';\n}\n.zmdi-local-hotel:before {\n  content: '\\f178';\n}\n.zmdi-local-activity:before {\n  content: '\\f1df';\n}\n.zmdi-local-play:before {\n  content: '\\f1df';\n}\n.zmdi-local-airport:before {\n  content: '\\f103';\n}\n.zmdi-local-atm:before {\n  content: '\\f198';\n}\n.zmdi-local-bar:before {\n  content: '\\f137';\n}\n.zmdi-local-cafe:before {\n  content: '\\f13b';\n}\n.zmdi-local-car-wash:before {\n  content: '\\f124';\n}\n.zmdi-local-convenience-store:before {\n  content: '\\f1d3';\n}\n.zmdi-local-dining:before {\n  content: '\\f153';\n}\n.zmdi-local-drink:before {\n  content: '\\f157';\n}\n.zmdi-local-florist:before {\n  content: '\\f168';\n}\n.zmdi-local-gas-station:before {\n  content: '\\f16f';\n}\n.zmdi-local-grocery-store:before {\n  content: '\\f1cb';\n}\n.zmdi-local-hospital:before {\n  content: '\\f177';\n}\n.zmdi-local-laundry-service:before {\n  content: '\\f1e9';\n}\n.zmdi-local-library:before {\n  content: '\\f18d';\n}\n.zmdi-local-mall:before {\n  content: '\\f195';\n}\n.zmdi-local-movies:before {\n  content: '\\f19d';\n}\n.zmdi-local-offer:before {\n  content: '\\f187';\n}\n.zmdi-local-parking:before {\n  content: '\\f1a5';\n}\n.zmdi-local-parking:before {\n  content: '\\f1a5';\n}\n.zmdi-local-pharmacy:before {\n  content: '\\f176';\n}\n.zmdi-local-phone:before {\n  content: '\\f2be';\n}\n.zmdi-local-pizza:before {\n  content: '\\f1ac';\n}\n.zmdi-local-post-office:before {\n  content: '\\f15a';\n}\n.zmdi-local-printshop:before {\n  content: '\\f1b0';\n}\n.zmdi-local-see:before {\n  content: '\\f28c';\n}\n.zmdi-local-shipping:before {\n  content: '\\f1e6';\n}\n.zmdi-local-store:before {\n  content: '\\f1d4';\n}\n.zmdi-local-taxi:before {\n  content: '\\f123';\n}\n.zmdi-local-wc:before {\n  content: '\\f211';\n}\n.zmdi-my-location:before {\n  content: '\\f299';\n}\n.zmdi-directions:before {\n  content: '\\f1e7';\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/moment/2.10.6/moment-with-locales.js",
    "content": "(function (global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n    typeof define === 'function' && define.amd ? define(factory) :\n    global.moment = factory()\n}(this, function () { 'use strict';\n\n    var hookCallback;\n\n    function utils_hooks__hooks () {\n        return hookCallback.apply(null, arguments);\n    }\n\n    // This is done to register the method called with moment()\n    // without creating circular dependencies.\n    function setHookCallback (callback) {\n        hookCallback = callback;\n    }\n\n    function isArray(input) {\n        return Object.prototype.toString.call(input) === '[object Array]';\n    }\n\n    function isDate(input) {\n        return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n    }\n\n    function map(arr, fn) {\n        var res = [], i;\n        for (i = 0; i < arr.length; ++i) {\n            res.push(fn(arr[i], i));\n        }\n        return res;\n    }\n\n    function hasOwnProp(a, b) {\n        return Object.prototype.hasOwnProperty.call(a, b);\n    }\n\n    function extend(a, b) {\n        for (var i in b) {\n            if (hasOwnProp(b, i)) {\n                a[i] = b[i];\n            }\n        }\n\n        if (hasOwnProp(b, 'toString')) {\n            a.toString = b.toString;\n        }\n\n        if (hasOwnProp(b, 'valueOf')) {\n            a.valueOf = b.valueOf;\n        }\n\n        return a;\n    }\n\n    function create_utc__createUTC (input, format, locale, strict) {\n        return createLocalOrUTC(input, format, locale, strict, true).utc();\n    }\n\n    function defaultParsingFlags() {\n        // We need to deep clone this object.\n        return {\n            empty           : false,\n            unusedTokens    : [],\n            unusedInput     : [],\n            overflow        : -2,\n            charsLeftOver   : 0,\n            nullInput       : false,\n            invalidMonth    : null,\n            invalidFormat   : false,\n            userInvalidated : false,\n            iso             : false\n        };\n    }\n\n    function getParsingFlags(m) {\n        if (m._pf == null) {\n            m._pf = defaultParsingFlags();\n        }\n        return m._pf;\n    }\n\n    function valid__isValid(m) {\n        if (m._isValid == null) {\n            var flags = getParsingFlags(m);\n            m._isValid = !isNaN(m._d.getTime()) &&\n                flags.overflow < 0 &&\n                !flags.empty &&\n                !flags.invalidMonth &&\n                !flags.invalidWeekday &&\n                !flags.nullInput &&\n                !flags.invalidFormat &&\n                !flags.userInvalidated;\n\n            if (m._strict) {\n                m._isValid = m._isValid &&\n                    flags.charsLeftOver === 0 &&\n                    flags.unusedTokens.length === 0 &&\n                    flags.bigHour === undefined;\n            }\n        }\n        return m._isValid;\n    }\n\n    function valid__createInvalid (flags) {\n        var m = create_utc__createUTC(NaN);\n        if (flags != null) {\n            extend(getParsingFlags(m), flags);\n        }\n        else {\n            getParsingFlags(m).userInvalidated = true;\n        }\n\n        return m;\n    }\n\n    var momentProperties = utils_hooks__hooks.momentProperties = [];\n\n    function copyConfig(to, from) {\n        var i, prop, val;\n\n        if (typeof from._isAMomentObject !== 'undefined') {\n            to._isAMomentObject = from._isAMomentObject;\n        }\n        if (typeof from._i !== 'undefined') {\n            to._i = from._i;\n        }\n        if (typeof from._f !== 'undefined') {\n            to._f = from._f;\n        }\n        if (typeof from._l !== 'undefined') {\n            to._l = from._l;\n        }\n        if (typeof from._strict !== 'undefined') {\n            to._strict = from._strict;\n        }\n        if (typeof from._tzm !== 'undefined') {\n            to._tzm = from._tzm;\n        }\n        if (typeof from._isUTC !== 'undefined') {\n            to._isUTC = from._isUTC;\n        }\n        if (typeof from._offset !== 'undefined') {\n            to._offset = from._offset;\n        }\n        if (typeof from._pf !== 'undefined') {\n            to._pf = getParsingFlags(from);\n        }\n        if (typeof from._locale !== 'undefined') {\n            to._locale = from._locale;\n        }\n\n        if (momentProperties.length > 0) {\n            for (i in momentProperties) {\n                prop = momentProperties[i];\n                val = from[prop];\n                if (typeof val !== 'undefined') {\n                    to[prop] = val;\n                }\n            }\n        }\n\n        return to;\n    }\n\n    var updateInProgress = false;\n\n    // Moment prototype object\n    function Moment(config) {\n        copyConfig(this, config);\n        this._d = new Date(config._d != null ? config._d.getTime() : NaN);\n        // Prevent infinite loop in case updateOffset creates new moment\n        // objects.\n        if (updateInProgress === false) {\n            updateInProgress = true;\n            utils_hooks__hooks.updateOffset(this);\n            updateInProgress = false;\n        }\n    }\n\n    function isMoment (obj) {\n        return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);\n    }\n\n    function absFloor (number) {\n        if (number < 0) {\n            return Math.ceil(number);\n        } else {\n            return Math.floor(number);\n        }\n    }\n\n    function toInt(argumentForCoercion) {\n        var coercedNumber = +argumentForCoercion,\n            value = 0;\n\n        if (coercedNumber !== 0 && isFinite(coercedNumber)) {\n            value = absFloor(coercedNumber);\n        }\n\n        return value;\n    }\n\n    function compareArrays(array1, array2, dontConvert) {\n        var len = Math.min(array1.length, array2.length),\n            lengthDiff = Math.abs(array1.length - array2.length),\n            diffs = 0,\n            i;\n        for (i = 0; i < len; i++) {\n            if ((dontConvert && array1[i] !== array2[i]) ||\n                (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {\n                diffs++;\n            }\n        }\n        return diffs + lengthDiff;\n    }\n\n    function Locale() {\n    }\n\n    var locales = {};\n    var globalLocale;\n\n    function normalizeLocale(key) {\n        return key ? key.toLowerCase().replace('_', '-') : key;\n    }\n\n    // pick the locale from the array\n    // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each\n    // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root\n    function chooseLocale(names) {\n        var i = 0, j, next, locale, split;\n\n        while (i < names.length) {\n            split = normalizeLocale(names[i]).split('-');\n            j = split.length;\n            next = normalizeLocale(names[i + 1]);\n            next = next ? next.split('-') : null;\n            while (j > 0) {\n                locale = loadLocale(split.slice(0, j).join('-'));\n                if (locale) {\n                    return locale;\n                }\n                if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {\n                    //the next array item is better than a shallower substring of this one\n                    break;\n                }\n                j--;\n            }\n            i++;\n        }\n        return null;\n    }\n\n    function loadLocale(name) {\n        var oldLocale = null;\n        // TODO: Find a better way to register and load all the locales in Node\n        if (!locales[name] && typeof module !== 'undefined' &&\n                module && module.exports) {\n            try {\n                oldLocale = globalLocale._abbr;\n                require('./locale/' + name);\n                // because defineLocale currently also sets the global locale, we\n                // want to undo that for lazy loaded locales\n                locale_locales__getSetGlobalLocale(oldLocale);\n            } catch (e) { }\n        }\n        return locales[name];\n    }\n\n    // This function will load locale and then set the global locale.  If\n    // no arguments are passed in, it will simply return the current global\n    // locale key.\n    function locale_locales__getSetGlobalLocale (key, values) {\n        var data;\n        if (key) {\n            if (typeof values === 'undefined') {\n                data = locale_locales__getLocale(key);\n            }\n            else {\n                data = defineLocale(key, values);\n            }\n\n            if (data) {\n                // moment.duration._locale = moment._locale = data;\n                globalLocale = data;\n            }\n        }\n\n        return globalLocale._abbr;\n    }\n\n    function defineLocale (name, values) {\n        if (values !== null) {\n            values.abbr = name;\n            locales[name] = locales[name] || new Locale();\n            locales[name].set(values);\n\n            // backwards compat for now: also set the locale\n            locale_locales__getSetGlobalLocale(name);\n\n            return locales[name];\n        } else {\n            // useful for testing\n            delete locales[name];\n            return null;\n        }\n    }\n\n    // returns locale data\n    function locale_locales__getLocale (key) {\n        var locale;\n\n        if (key && key._locale && key._locale._abbr) {\n            key = key._locale._abbr;\n        }\n\n        if (!key) {\n            return globalLocale;\n        }\n\n        if (!isArray(key)) {\n            //short-circuit everything else\n            locale = loadLocale(key);\n            if (locale) {\n                return locale;\n            }\n            key = [key];\n        }\n\n        return chooseLocale(key);\n    }\n\n    var aliases = {};\n\n    function addUnitAlias (unit, shorthand) {\n        var lowerCase = unit.toLowerCase();\n        aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;\n    }\n\n    function normalizeUnits(units) {\n        return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;\n    }\n\n    function normalizeObjectUnits(inputObject) {\n        var normalizedInput = {},\n            normalizedProp,\n            prop;\n\n        for (prop in inputObject) {\n            if (hasOwnProp(inputObject, prop)) {\n                normalizedProp = normalizeUnits(prop);\n                if (normalizedProp) {\n                    normalizedInput[normalizedProp] = inputObject[prop];\n                }\n            }\n        }\n\n        return normalizedInput;\n    }\n\n    function makeGetSet (unit, keepTime) {\n        return function (value) {\n            if (value != null) {\n                get_set__set(this, unit, value);\n                utils_hooks__hooks.updateOffset(this, keepTime);\n                return this;\n            } else {\n                return get_set__get(this, unit);\n            }\n        };\n    }\n\n    function get_set__get (mom, unit) {\n        return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]();\n    }\n\n    function get_set__set (mom, unit, value) {\n        return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);\n    }\n\n    // MOMENTS\n\n    function getSet (units, value) {\n        var unit;\n        if (typeof units === 'object') {\n            for (unit in units) {\n                this.set(unit, units[unit]);\n            }\n        } else {\n            units = normalizeUnits(units);\n            if (typeof this[units] === 'function') {\n                return this[units](value);\n            }\n        }\n        return this;\n    }\n\n    function zeroFill(number, targetLength, forceSign) {\n        var absNumber = '' + Math.abs(number),\n            zerosToFill = targetLength - absNumber.length,\n            sign = number >= 0;\n        return (sign ? (forceSign ? '+' : '') : '-') +\n            Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;\n    }\n\n    var formattingTokens = /(\\[[^\\[]*\\])|(\\\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;\n\n    var localFormattingTokens = /(\\[[^\\[]*\\])|(\\\\)?(LTS|LT|LL?L?L?|l{1,4})/g;\n\n    var formatFunctions = {};\n\n    var formatTokenFunctions = {};\n\n    // token:    'M'\n    // padded:   ['MM', 2]\n    // ordinal:  'Mo'\n    // callback: function () { this.month() + 1 }\n    function addFormatToken (token, padded, ordinal, callback) {\n        var func = callback;\n        if (typeof callback === 'string') {\n            func = function () {\n                return this[callback]();\n            };\n        }\n        if (token) {\n            formatTokenFunctions[token] = func;\n        }\n        if (padded) {\n            formatTokenFunctions[padded[0]] = function () {\n                return zeroFill(func.apply(this, arguments), padded[1], padded[2]);\n            };\n        }\n        if (ordinal) {\n            formatTokenFunctions[ordinal] = function () {\n                return this.localeData().ordinal(func.apply(this, arguments), token);\n            };\n        }\n    }\n\n    function removeFormattingTokens(input) {\n        if (input.match(/\\[[\\s\\S]/)) {\n            return input.replace(/^\\[|\\]$/g, '');\n        }\n        return input.replace(/\\\\/g, '');\n    }\n\n    function makeFormatFunction(format) {\n        var array = format.match(formattingTokens), i, length;\n\n        for (i = 0, length = array.length; i < length; i++) {\n            if (formatTokenFunctions[array[i]]) {\n                array[i] = formatTokenFunctions[array[i]];\n            } else {\n                array[i] = removeFormattingTokens(array[i]);\n            }\n        }\n\n        return function (mom) {\n            var output = '';\n            for (i = 0; i < length; i++) {\n                output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];\n            }\n            return output;\n        };\n    }\n\n    // format date using native date object\n    function formatMoment(m, format) {\n        if (!m.isValid()) {\n            return m.localeData().invalidDate();\n        }\n\n        format = expandFormat(format, m.localeData());\n        formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);\n\n        return formatFunctions[format](m);\n    }\n\n    function expandFormat(format, locale) {\n        var i = 5;\n\n        function replaceLongDateFormatTokens(input) {\n            return locale.longDateFormat(input) || input;\n        }\n\n        localFormattingTokens.lastIndex = 0;\n        while (i >= 0 && localFormattingTokens.test(format)) {\n            format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);\n            localFormattingTokens.lastIndex = 0;\n            i -= 1;\n        }\n\n        return format;\n    }\n\n    var match1         = /\\d/;            //       0 - 9\n    var match2         = /\\d\\d/;          //      00 - 99\n    var match3         = /\\d{3}/;         //     000 - 999\n    var match4         = /\\d{4}/;         //    0000 - 9999\n    var match6         = /[+-]?\\d{6}/;    // -999999 - 999999\n    var match1to2      = /\\d\\d?/;         //       0 - 99\n    var match1to3      = /\\d{1,3}/;       //       0 - 999\n    var match1to4      = /\\d{1,4}/;       //       0 - 9999\n    var match1to6      = /[+-]?\\d{1,6}/;  // -999999 - 999999\n\n    var matchUnsigned  = /\\d+/;           //       0 - inf\n    var matchSigned    = /[+-]?\\d+/;      //    -inf - inf\n\n    var matchOffset    = /Z|[+-]\\d\\d:?\\d\\d/gi; // +00:00 -00:00 +0000 -0000 or Z\n\n    var matchTimestamp = /[+-]?\\d+(\\.\\d{1,3})?/; // 123456789 123456789.123\n\n    // any word (or two) characters or numbers including two/three word month in arabic.\n    var matchWord = /[0-9]*['a-z\\u00A0-\\u05FF\\u0700-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF]+|[\\u0600-\\u06FF\\/]+(\\s*?[\\u0600-\\u06FF]+){1,2}/i;\n\n    var regexes = {};\n\n    function isFunction (sth) {\n        // https://github.com/moment/moment/issues/2325\n        return typeof sth === 'function' &&\n            Object.prototype.toString.call(sth) === '[object Function]';\n    }\n\n\n    function addRegexToken (token, regex, strictRegex) {\n        regexes[token] = isFunction(regex) ? regex : function (isStrict) {\n            return (isStrict && strictRegex) ? strictRegex : regex;\n        };\n    }\n\n    function getParseRegexForToken (token, config) {\n        if (!hasOwnProp(regexes, token)) {\n            return new RegExp(unescapeFormat(token));\n        }\n\n        return regexes[token](config._strict, config._locale);\n    }\n\n    // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript\n    function unescapeFormat(s) {\n        return s.replace('\\\\', '').replace(/\\\\(\\[)|\\\\(\\])|\\[([^\\]\\[]*)\\]|\\\\(.)/g, function (matched, p1, p2, p3, p4) {\n            return p1 || p2 || p3 || p4;\n        }).replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n    }\n\n    var tokens = {};\n\n    function addParseToken (token, callback) {\n        var i, func = callback;\n        if (typeof token === 'string') {\n            token = [token];\n        }\n        if (typeof callback === 'number') {\n            func = function (input, array) {\n                array[callback] = toInt(input);\n            };\n        }\n        for (i = 0; i < token.length; i++) {\n            tokens[token[i]] = func;\n        }\n    }\n\n    function addWeekParseToken (token, callback) {\n        addParseToken(token, function (input, array, config, token) {\n            config._w = config._w || {};\n            callback(input, config._w, config, token);\n        });\n    }\n\n    function addTimeToArrayFromToken(token, input, config) {\n        if (input != null && hasOwnProp(tokens, token)) {\n            tokens[token](input, config._a, config, token);\n        }\n    }\n\n    var YEAR = 0;\n    var MONTH = 1;\n    var DATE = 2;\n    var HOUR = 3;\n    var MINUTE = 4;\n    var SECOND = 5;\n    var MILLISECOND = 6;\n\n    function daysInMonth(year, month) {\n        return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();\n    }\n\n    // FORMATTING\n\n    addFormatToken('M', ['MM', 2], 'Mo', function () {\n        return this.month() + 1;\n    });\n\n    addFormatToken('MMM', 0, 0, function (format) {\n        return this.localeData().monthsShort(this, format);\n    });\n\n    addFormatToken('MMMM', 0, 0, function (format) {\n        return this.localeData().months(this, format);\n    });\n\n    // ALIASES\n\n    addUnitAlias('month', 'M');\n\n    // PARSING\n\n    addRegexToken('M',    match1to2);\n    addRegexToken('MM',   match1to2, match2);\n    addRegexToken('MMM',  matchWord);\n    addRegexToken('MMMM', matchWord);\n\n    addParseToken(['M', 'MM'], function (input, array) {\n        array[MONTH] = toInt(input) - 1;\n    });\n\n    addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {\n        var month = config._locale.monthsParse(input, token, config._strict);\n        // if we didn't find a month name, mark the date as invalid.\n        if (month != null) {\n            array[MONTH] = month;\n        } else {\n            getParsingFlags(config).invalidMonth = input;\n        }\n    });\n\n    // LOCALES\n\n    var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');\n    function localeMonths (m) {\n        return this._months[m.month()];\n    }\n\n    var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');\n    function localeMonthsShort (m) {\n        return this._monthsShort[m.month()];\n    }\n\n    function localeMonthsParse (monthName, format, strict) {\n        var i, mom, regex;\n\n        if (!this._monthsParse) {\n            this._monthsParse = [];\n            this._longMonthsParse = [];\n            this._shortMonthsParse = [];\n        }\n\n        for (i = 0; i < 12; i++) {\n            // make the regex if we don't have it already\n            mom = create_utc__createUTC([2000, i]);\n            if (strict && !this._longMonthsParse[i]) {\n                this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');\n                this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');\n            }\n            if (!strict && !this._monthsParse[i]) {\n                regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');\n                this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');\n            }\n            // test the regex\n            if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {\n                return i;\n            } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {\n                return i;\n            } else if (!strict && this._monthsParse[i].test(monthName)) {\n                return i;\n            }\n        }\n    }\n\n    // MOMENTS\n\n    function setMonth (mom, value) {\n        var dayOfMonth;\n\n        // TODO: Move this out of here!\n        if (typeof value === 'string') {\n            value = mom.localeData().monthsParse(value);\n            // TODO: Another silent failure?\n            if (typeof value !== 'number') {\n                return mom;\n            }\n        }\n\n        dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));\n        mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);\n        return mom;\n    }\n\n    function getSetMonth (value) {\n        if (value != null) {\n            setMonth(this, value);\n            utils_hooks__hooks.updateOffset(this, true);\n            return this;\n        } else {\n            return get_set__get(this, 'Month');\n        }\n    }\n\n    function getDaysInMonth () {\n        return daysInMonth(this.year(), this.month());\n    }\n\n    function checkOverflow (m) {\n        var overflow;\n        var a = m._a;\n\n        if (a && getParsingFlags(m).overflow === -2) {\n            overflow =\n                a[MONTH]       < 0 || a[MONTH]       > 11  ? MONTH :\n                a[DATE]        < 1 || a[DATE]        > daysInMonth(a[YEAR], a[MONTH]) ? DATE :\n                a[HOUR]        < 0 || a[HOUR]        > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :\n                a[MINUTE]      < 0 || a[MINUTE]      > 59  ? MINUTE :\n                a[SECOND]      < 0 || a[SECOND]      > 59  ? SECOND :\n                a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :\n                -1;\n\n            if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {\n                overflow = DATE;\n            }\n\n            getParsingFlags(m).overflow = overflow;\n        }\n\n        return m;\n    }\n\n    function warn(msg) {\n        if (utils_hooks__hooks.suppressDeprecationWarnings === false && typeof console !== 'undefined' && console.warn) {\n            console.warn('Deprecation warning: ' + msg);\n        }\n    }\n\n    function deprecate(msg, fn) {\n        var firstTime = true;\n\n        return extend(function () {\n            if (firstTime) {\n                warn(msg + '\\n' + (new Error()).stack);\n                firstTime = false;\n            }\n            return fn.apply(this, arguments);\n        }, fn);\n    }\n\n    var deprecations = {};\n\n    function deprecateSimple(name, msg) {\n        if (!deprecations[name]) {\n            warn(msg);\n            deprecations[name] = true;\n        }\n    }\n\n    utils_hooks__hooks.suppressDeprecationWarnings = false;\n\n    var from_string__isoRegex = /^\\s*(?:[+-]\\d{6}|\\d{4})-(?:(\\d\\d-\\d\\d)|(W\\d\\d$)|(W\\d\\d-\\d)|(\\d\\d\\d))((T| )(\\d\\d(:\\d\\d(:\\d\\d(\\.\\d+)?)?)?)?([\\+\\-]\\d\\d(?::?\\d\\d)?|\\s*Z)?)?$/;\n\n    var isoDates = [\n        ['YYYYYY-MM-DD', /[+-]\\d{6}-\\d{2}-\\d{2}/],\n        ['YYYY-MM-DD', /\\d{4}-\\d{2}-\\d{2}/],\n        ['GGGG-[W]WW-E', /\\d{4}-W\\d{2}-\\d/],\n        ['GGGG-[W]WW', /\\d{4}-W\\d{2}/],\n        ['YYYY-DDD', /\\d{4}-\\d{3}/]\n    ];\n\n    // iso time formats and regexes\n    var isoTimes = [\n        ['HH:mm:ss.SSSS', /(T| )\\d\\d:\\d\\d:\\d\\d\\.\\d+/],\n        ['HH:mm:ss', /(T| )\\d\\d:\\d\\d:\\d\\d/],\n        ['HH:mm', /(T| )\\d\\d:\\d\\d/],\n        ['HH', /(T| )\\d\\d/]\n    ];\n\n    var aspNetJsonRegex = /^\\/?Date\\((\\-?\\d+)/i;\n\n    // date from iso format\n    function configFromISO(config) {\n        var i, l,\n            string = config._i,\n            match = from_string__isoRegex.exec(string);\n\n        if (match) {\n            getParsingFlags(config).iso = true;\n            for (i = 0, l = isoDates.length; i < l; i++) {\n                if (isoDates[i][1].exec(string)) {\n                    config._f = isoDates[i][0];\n                    break;\n                }\n            }\n            for (i = 0, l = isoTimes.length; i < l; i++) {\n                if (isoTimes[i][1].exec(string)) {\n                    // match[6] should be 'T' or space\n                    config._f += (match[6] || ' ') + isoTimes[i][0];\n                    break;\n                }\n            }\n            if (string.match(matchOffset)) {\n                config._f += 'Z';\n            }\n            configFromStringAndFormat(config);\n        } else {\n            config._isValid = false;\n        }\n    }\n\n    // date from iso format or fallback\n    function configFromString(config) {\n        var matched = aspNetJsonRegex.exec(config._i);\n\n        if (matched !== null) {\n            config._d = new Date(+matched[1]);\n            return;\n        }\n\n        configFromISO(config);\n        if (config._isValid === false) {\n            delete config._isValid;\n            utils_hooks__hooks.createFromInputFallback(config);\n        }\n    }\n\n    utils_hooks__hooks.createFromInputFallback = deprecate(\n        'moment construction falls back to js Date. This is ' +\n        'discouraged and will be removed in upcoming major ' +\n        'release. Please refer to ' +\n        'https://github.com/moment/moment/issues/1407 for more info.',\n        function (config) {\n            config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));\n        }\n    );\n\n    function createDate (y, m, d, h, M, s, ms) {\n        //can't just apply() to create a date:\n        //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply\n        var date = new Date(y, m, d, h, M, s, ms);\n\n        //the date constructor doesn't accept years < 1970\n        if (y < 1970) {\n            date.setFullYear(y);\n        }\n        return date;\n    }\n\n    function createUTCDate (y) {\n        var date = new Date(Date.UTC.apply(null, arguments));\n        if (y < 1970) {\n            date.setUTCFullYear(y);\n        }\n        return date;\n    }\n\n    addFormatToken(0, ['YY', 2], 0, function () {\n        return this.year() % 100;\n    });\n\n    addFormatToken(0, ['YYYY',   4],       0, 'year');\n    addFormatToken(0, ['YYYYY',  5],       0, 'year');\n    addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');\n\n    // ALIASES\n\n    addUnitAlias('year', 'y');\n\n    // PARSING\n\n    addRegexToken('Y',      matchSigned);\n    addRegexToken('YY',     match1to2, match2);\n    addRegexToken('YYYY',   match1to4, match4);\n    addRegexToken('YYYYY',  match1to6, match6);\n    addRegexToken('YYYYYY', match1to6, match6);\n\n    addParseToken(['YYYYY', 'YYYYYY'], YEAR);\n    addParseToken('YYYY', function (input, array) {\n        array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input);\n    });\n    addParseToken('YY', function (input, array) {\n        array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input);\n    });\n\n    // HELPERS\n\n    function daysInYear(year) {\n        return isLeapYear(year) ? 366 : 365;\n    }\n\n    function isLeapYear(year) {\n        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;\n    }\n\n    // HOOKS\n\n    utils_hooks__hooks.parseTwoDigitYear = function (input) {\n        return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);\n    };\n\n    // MOMENTS\n\n    var getSetYear = makeGetSet('FullYear', false);\n\n    function getIsLeapYear () {\n        return isLeapYear(this.year());\n    }\n\n    addFormatToken('w', ['ww', 2], 'wo', 'week');\n    addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');\n\n    // ALIASES\n\n    addUnitAlias('week', 'w');\n    addUnitAlias('isoWeek', 'W');\n\n    // PARSING\n\n    addRegexToken('w',  match1to2);\n    addRegexToken('ww', match1to2, match2);\n    addRegexToken('W',  match1to2);\n    addRegexToken('WW', match1to2, match2);\n\n    addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {\n        week[token.substr(0, 1)] = toInt(input);\n    });\n\n    // HELPERS\n\n    // firstDayOfWeek       0 = sun, 6 = sat\n    //                      the day of the week that starts the week\n    //                      (usually sunday or monday)\n    // firstDayOfWeekOfYear 0 = sun, 6 = sat\n    //                      the first week is the week that contains the first\n    //                      of this day of the week\n    //                      (eg. ISO weeks use thursday (4))\n    function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {\n        var end = firstDayOfWeekOfYear - firstDayOfWeek,\n            daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),\n            adjustedMoment;\n\n\n        if (daysToDayOfWeek > end) {\n            daysToDayOfWeek -= 7;\n        }\n\n        if (daysToDayOfWeek < end - 7) {\n            daysToDayOfWeek += 7;\n        }\n\n        adjustedMoment = local__createLocal(mom).add(daysToDayOfWeek, 'd');\n        return {\n            week: Math.ceil(adjustedMoment.dayOfYear() / 7),\n            year: adjustedMoment.year()\n        };\n    }\n\n    // LOCALES\n\n    function localeWeek (mom) {\n        return weekOfYear(mom, this._week.dow, this._week.doy).week;\n    }\n\n    var defaultLocaleWeek = {\n        dow : 0, // Sunday is the first day of the week.\n        doy : 6  // The week that contains Jan 1st is the first week of the year.\n    };\n\n    function localeFirstDayOfWeek () {\n        return this._week.dow;\n    }\n\n    function localeFirstDayOfYear () {\n        return this._week.doy;\n    }\n\n    // MOMENTS\n\n    function getSetWeek (input) {\n        var week = this.localeData().week(this);\n        return input == null ? week : this.add((input - week) * 7, 'd');\n    }\n\n    function getSetISOWeek (input) {\n        var week = weekOfYear(this, 1, 4).week;\n        return input == null ? week : this.add((input - week) * 7, 'd');\n    }\n\n    addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');\n\n    // ALIASES\n\n    addUnitAlias('dayOfYear', 'DDD');\n\n    // PARSING\n\n    addRegexToken('DDD',  match1to3);\n    addRegexToken('DDDD', match3);\n    addParseToken(['DDD', 'DDDD'], function (input, array, config) {\n        config._dayOfYear = toInt(input);\n    });\n\n    // HELPERS\n\n    //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday\n    function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {\n        var week1Jan = 6 + firstDayOfWeek - firstDayOfWeekOfYear, janX = createUTCDate(year, 0, 1 + week1Jan), d = janX.getUTCDay(), dayOfYear;\n        if (d < firstDayOfWeek) {\n            d += 7;\n        }\n\n        weekday = weekday != null ? 1 * weekday : firstDayOfWeek;\n\n        dayOfYear = 1 + week1Jan + 7 * (week - 1) - d + weekday;\n\n        return {\n            year: dayOfYear > 0 ? year : year - 1,\n            dayOfYear: dayOfYear > 0 ?  dayOfYear : daysInYear(year - 1) + dayOfYear\n        };\n    }\n\n    // MOMENTS\n\n    function getSetDayOfYear (input) {\n        var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;\n        return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');\n    }\n\n    // Pick the first defined of two or three arguments.\n    function defaults(a, b, c) {\n        if (a != null) {\n            return a;\n        }\n        if (b != null) {\n            return b;\n        }\n        return c;\n    }\n\n    function currentDateArray(config) {\n        var now = new Date();\n        if (config._useUTC) {\n            return [now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()];\n        }\n        return [now.getFullYear(), now.getMonth(), now.getDate()];\n    }\n\n    // convert an array to a date.\n    // the array should mirror the parameters below\n    // note: all values past the year are optional and will default to the lowest possible value.\n    // [year, month, day , hour, minute, second, millisecond]\n    function configFromArray (config) {\n        var i, date, input = [], currentDate, yearToUse;\n\n        if (config._d) {\n            return;\n        }\n\n        currentDate = currentDateArray(config);\n\n        //compute day of the year from weeks and weekdays\n        if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {\n            dayOfYearFromWeekInfo(config);\n        }\n\n        //if the day of the year is set, figure out what it is\n        if (config._dayOfYear) {\n            yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);\n\n            if (config._dayOfYear > daysInYear(yearToUse)) {\n                getParsingFlags(config)._overflowDayOfYear = true;\n            }\n\n            date = createUTCDate(yearToUse, 0, config._dayOfYear);\n            config._a[MONTH] = date.getUTCMonth();\n            config._a[DATE] = date.getUTCDate();\n        }\n\n        // Default to current date.\n        // * if no year, month, day of month are given, default to today\n        // * if day of month is given, default month and year\n        // * if month is given, default only year\n        // * if year is given, don't default anything\n        for (i = 0; i < 3 && config._a[i] == null; ++i) {\n            config._a[i] = input[i] = currentDate[i];\n        }\n\n        // Zero out whatever was not defaulted, including time\n        for (; i < 7; i++) {\n            config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];\n        }\n\n        // Check for 24:00:00.000\n        if (config._a[HOUR] === 24 &&\n                config._a[MINUTE] === 0 &&\n                config._a[SECOND] === 0 &&\n                config._a[MILLISECOND] === 0) {\n            config._nextDay = true;\n            config._a[HOUR] = 0;\n        }\n\n        config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);\n        // Apply timezone offset from input. The actual utcOffset can be changed\n        // with parseZone.\n        if (config._tzm != null) {\n            config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);\n        }\n\n        if (config._nextDay) {\n            config._a[HOUR] = 24;\n        }\n    }\n\n    function dayOfYearFromWeekInfo(config) {\n        var w, weekYear, week, weekday, dow, doy, temp;\n\n        w = config._w;\n        if (w.GG != null || w.W != null || w.E != null) {\n            dow = 1;\n            doy = 4;\n\n            // TODO: We need to take the current isoWeekYear, but that depends on\n            // how we interpret now (local, utc, fixed offset). So create\n            // a now version of current config (take local/utc/offset flags, and\n            // create now).\n            weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year);\n            week = defaults(w.W, 1);\n            weekday = defaults(w.E, 1);\n        } else {\n            dow = config._locale._week.dow;\n            doy = config._locale._week.doy;\n\n            weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year);\n            week = defaults(w.w, 1);\n\n            if (w.d != null) {\n                // weekday -- low day numbers are considered next week\n                weekday = w.d;\n                if (weekday < dow) {\n                    ++week;\n                }\n            } else if (w.e != null) {\n                // local weekday -- counting starts from begining of week\n                weekday = w.e + dow;\n            } else {\n                // default to begining of week\n                weekday = dow;\n            }\n        }\n        temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow);\n\n        config._a[YEAR] = temp.year;\n        config._dayOfYear = temp.dayOfYear;\n    }\n\n    utils_hooks__hooks.ISO_8601 = function () {};\n\n    // date from string and format string\n    function configFromStringAndFormat(config) {\n        // TODO: Move this to another part of the creation flow to prevent circular deps\n        if (config._f === utils_hooks__hooks.ISO_8601) {\n            configFromISO(config);\n            return;\n        }\n\n        config._a = [];\n        getParsingFlags(config).empty = true;\n\n        // This array is used to make a Date, either with `new Date` or `Date.UTC`\n        var string = '' + config._i,\n            i, parsedInput, tokens, token, skipped,\n            stringLength = string.length,\n            totalParsedInputLength = 0;\n\n        tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];\n\n        for (i = 0; i < tokens.length; i++) {\n            token = tokens[i];\n            parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];\n            if (parsedInput) {\n                skipped = string.substr(0, string.indexOf(parsedInput));\n                if (skipped.length > 0) {\n                    getParsingFlags(config).unusedInput.push(skipped);\n                }\n                string = string.slice(string.indexOf(parsedInput) + parsedInput.length);\n                totalParsedInputLength += parsedInput.length;\n            }\n            // don't parse if it's not a known token\n            if (formatTokenFunctions[token]) {\n                if (parsedInput) {\n                    getParsingFlags(config).empty = false;\n                }\n                else {\n                    getParsingFlags(config).unusedTokens.push(token);\n                }\n                addTimeToArrayFromToken(token, parsedInput, config);\n            }\n            else if (config._strict && !parsedInput) {\n                getParsingFlags(config).unusedTokens.push(token);\n            }\n        }\n\n        // add remaining unparsed input length to the string\n        getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;\n        if (string.length > 0) {\n            getParsingFlags(config).unusedInput.push(string);\n        }\n\n        // clear _12h flag if hour is <= 12\n        if (getParsingFlags(config).bigHour === true &&\n                config._a[HOUR] <= 12 &&\n                config._a[HOUR] > 0) {\n            getParsingFlags(config).bigHour = undefined;\n        }\n        // handle meridiem\n        config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);\n\n        configFromArray(config);\n        checkOverflow(config);\n    }\n\n\n    function meridiemFixWrap (locale, hour, meridiem) {\n        var isPm;\n\n        if (meridiem == null) {\n            // nothing to do\n            return hour;\n        }\n        if (locale.meridiemHour != null) {\n            return locale.meridiemHour(hour, meridiem);\n        } else if (locale.isPM != null) {\n            // Fallback\n            isPm = locale.isPM(meridiem);\n            if (isPm && hour < 12) {\n                hour += 12;\n            }\n            if (!isPm && hour === 12) {\n                hour = 0;\n            }\n            return hour;\n        } else {\n            // this is not supposed to happen\n            return hour;\n        }\n    }\n\n    function configFromStringAndArray(config) {\n        var tempConfig,\n            bestMoment,\n\n            scoreToBeat,\n            i,\n            currentScore;\n\n        if (config._f.length === 0) {\n            getParsingFlags(config).invalidFormat = true;\n            config._d = new Date(NaN);\n            return;\n        }\n\n        for (i = 0; i < config._f.length; i++) {\n            currentScore = 0;\n            tempConfig = copyConfig({}, config);\n            if (config._useUTC != null) {\n                tempConfig._useUTC = config._useUTC;\n            }\n            tempConfig._f = config._f[i];\n            configFromStringAndFormat(tempConfig);\n\n            if (!valid__isValid(tempConfig)) {\n                continue;\n            }\n\n            // if there is any input that was not parsed add a penalty for that format\n            currentScore += getParsingFlags(tempConfig).charsLeftOver;\n\n            //or tokens\n            currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;\n\n            getParsingFlags(tempConfig).score = currentScore;\n\n            if (scoreToBeat == null || currentScore < scoreToBeat) {\n                scoreToBeat = currentScore;\n                bestMoment = tempConfig;\n            }\n        }\n\n        extend(config, bestMoment || tempConfig);\n    }\n\n    function configFromObject(config) {\n        if (config._d) {\n            return;\n        }\n\n        var i = normalizeObjectUnits(config._i);\n        config._a = [i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond];\n\n        configFromArray(config);\n    }\n\n    function createFromConfig (config) {\n        var res = new Moment(checkOverflow(prepareConfig(config)));\n        if (res._nextDay) {\n            // Adding is smart enough around DST\n            res.add(1, 'd');\n            res._nextDay = undefined;\n        }\n\n        return res;\n    }\n\n    function prepareConfig (config) {\n        var input = config._i,\n            format = config._f;\n\n        config._locale = config._locale || locale_locales__getLocale(config._l);\n\n        if (input === null || (format === undefined && input === '')) {\n            return valid__createInvalid({nullInput: true});\n        }\n\n        if (typeof input === 'string') {\n            config._i = input = config._locale.preparse(input);\n        }\n\n        if (isMoment(input)) {\n            return new Moment(checkOverflow(input));\n        } else if (isArray(format)) {\n            configFromStringAndArray(config);\n        } else if (format) {\n            configFromStringAndFormat(config);\n        } else if (isDate(input)) {\n            config._d = input;\n        } else {\n            configFromInput(config);\n        }\n\n        return config;\n    }\n\n    function configFromInput(config) {\n        var input = config._i;\n        if (input === undefined) {\n            config._d = new Date();\n        } else if (isDate(input)) {\n            config._d = new Date(+input);\n        } else if (typeof input === 'string') {\n            configFromString(config);\n        } else if (isArray(input)) {\n            config._a = map(input.slice(0), function (obj) {\n                return parseInt(obj, 10);\n            });\n            configFromArray(config);\n        } else if (typeof(input) === 'object') {\n            configFromObject(config);\n        } else if (typeof(input) === 'number') {\n            // from milliseconds\n            config._d = new Date(input);\n        } else {\n            utils_hooks__hooks.createFromInputFallback(config);\n        }\n    }\n\n    function createLocalOrUTC (input, format, locale, strict, isUTC) {\n        var c = {};\n\n        if (typeof(locale) === 'boolean') {\n            strict = locale;\n            locale = undefined;\n        }\n        // object construction must be done this way.\n        // https://github.com/moment/moment/issues/1423\n        c._isAMomentObject = true;\n        c._useUTC = c._isUTC = isUTC;\n        c._l = locale;\n        c._i = input;\n        c._f = format;\n        c._strict = strict;\n\n        return createFromConfig(c);\n    }\n\n    function local__createLocal (input, format, locale, strict) {\n        return createLocalOrUTC(input, format, locale, strict, false);\n    }\n\n    var prototypeMin = deprecate(\n         'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548',\n         function () {\n             var other = local__createLocal.apply(null, arguments);\n             return other < this ? this : other;\n         }\n     );\n\n    var prototypeMax = deprecate(\n        'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548',\n        function () {\n            var other = local__createLocal.apply(null, arguments);\n            return other > this ? this : other;\n        }\n    );\n\n    // Pick a moment m from moments so that m[fn](other) is true for all\n    // other. This relies on the function fn to be transitive.\n    //\n    // moments should either be an array of moment objects or an array, whose\n    // first element is an array of moment objects.\n    function pickBy(fn, moments) {\n        var res, i;\n        if (moments.length === 1 && isArray(moments[0])) {\n            moments = moments[0];\n        }\n        if (!moments.length) {\n            return local__createLocal();\n        }\n        res = moments[0];\n        for (i = 1; i < moments.length; ++i) {\n            if (!moments[i].isValid() || moments[i][fn](res)) {\n                res = moments[i];\n            }\n        }\n        return res;\n    }\n\n    // TODO: Use [].sort instead?\n    function min () {\n        var args = [].slice.call(arguments, 0);\n\n        return pickBy('isBefore', args);\n    }\n\n    function max () {\n        var args = [].slice.call(arguments, 0);\n\n        return pickBy('isAfter', args);\n    }\n\n    function Duration (duration) {\n        var normalizedInput = normalizeObjectUnits(duration),\n            years = normalizedInput.year || 0,\n            quarters = normalizedInput.quarter || 0,\n            months = normalizedInput.month || 0,\n            weeks = normalizedInput.week || 0,\n            days = normalizedInput.day || 0,\n            hours = normalizedInput.hour || 0,\n            minutes = normalizedInput.minute || 0,\n            seconds = normalizedInput.second || 0,\n            milliseconds = normalizedInput.millisecond || 0;\n\n        // representation for dateAddRemove\n        this._milliseconds = +milliseconds +\n            seconds * 1e3 + // 1000\n            minutes * 6e4 + // 1000 * 60\n            hours * 36e5; // 1000 * 60 * 60\n        // Because of dateAddRemove treats 24 hours as different from a\n        // day when working around DST, we need to store them separately\n        this._days = +days +\n            weeks * 7;\n        // It is impossible translate months into days without knowing\n        // which months you are are talking about, so we have to store\n        // it separately.\n        this._months = +months +\n            quarters * 3 +\n            years * 12;\n\n        this._data = {};\n\n        this._locale = locale_locales__getLocale();\n\n        this._bubble();\n    }\n\n    function isDuration (obj) {\n        return obj instanceof Duration;\n    }\n\n    function offset (token, separator) {\n        addFormatToken(token, 0, 0, function () {\n            var offset = this.utcOffset();\n            var sign = '+';\n            if (offset < 0) {\n                offset = -offset;\n                sign = '-';\n            }\n            return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);\n        });\n    }\n\n    offset('Z', ':');\n    offset('ZZ', '');\n\n    // PARSING\n\n    addRegexToken('Z',  matchOffset);\n    addRegexToken('ZZ', matchOffset);\n    addParseToken(['Z', 'ZZ'], function (input, array, config) {\n        config._useUTC = true;\n        config._tzm = offsetFromString(input);\n    });\n\n    // HELPERS\n\n    // timezone chunker\n    // '+10:00' > ['10',  '00']\n    // '-1530'  > ['-15', '30']\n    var chunkOffset = /([\\+\\-]|\\d\\d)/gi;\n\n    function offsetFromString(string) {\n        var matches = ((string || '').match(matchOffset) || []);\n        var chunk   = matches[matches.length - 1] || [];\n        var parts   = (chunk + '').match(chunkOffset) || ['-', 0, 0];\n        var minutes = +(parts[1] * 60) + toInt(parts[2]);\n\n        return parts[0] === '+' ? minutes : -minutes;\n    }\n\n    // Return a moment from input, that is local/utc/zone equivalent to model.\n    function cloneWithOffset(input, model) {\n        var res, diff;\n        if (model._isUTC) {\n            res = model.clone();\n            diff = (isMoment(input) || isDate(input) ? +input : +local__createLocal(input)) - (+res);\n            // Use low-level api, because this fn is low-level api.\n            res._d.setTime(+res._d + diff);\n            utils_hooks__hooks.updateOffset(res, false);\n            return res;\n        } else {\n            return local__createLocal(input).local();\n        }\n    }\n\n    function getDateOffset (m) {\n        // On Firefox.24 Date#getTimezoneOffset returns a floating point.\n        // https://github.com/moment/moment/pull/1871\n        return -Math.round(m._d.getTimezoneOffset() / 15) * 15;\n    }\n\n    // HOOKS\n\n    // This function will be called whenever a moment is mutated.\n    // It is intended to keep the offset in sync with the timezone.\n    utils_hooks__hooks.updateOffset = function () {};\n\n    // MOMENTS\n\n    // keepLocalTime = true means only change the timezone, without\n    // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->\n    // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset\n    // +0200, so we adjust the time as needed, to be valid.\n    //\n    // Keeping the time actually adds/subtracts (one hour)\n    // from the actual represented time. That is why we call updateOffset\n    // a second time. In case it wants us to change the offset again\n    // _changeInProgress == true case, then we have to adjust, because\n    // there is no such time in the given timezone.\n    function getSetOffset (input, keepLocalTime) {\n        var offset = this._offset || 0,\n            localAdjust;\n        if (input != null) {\n            if (typeof input === 'string') {\n                input = offsetFromString(input);\n            }\n            if (Math.abs(input) < 16) {\n                input = input * 60;\n            }\n            if (!this._isUTC && keepLocalTime) {\n                localAdjust = getDateOffset(this);\n            }\n            this._offset = input;\n            this._isUTC = true;\n            if (localAdjust != null) {\n                this.add(localAdjust, 'm');\n            }\n            if (offset !== input) {\n                if (!keepLocalTime || this._changeInProgress) {\n                    add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false);\n                } else if (!this._changeInProgress) {\n                    this._changeInProgress = true;\n                    utils_hooks__hooks.updateOffset(this, true);\n                    this._changeInProgress = null;\n                }\n            }\n            return this;\n        } else {\n            return this._isUTC ? offset : getDateOffset(this);\n        }\n    }\n\n    function getSetZone (input, keepLocalTime) {\n        if (input != null) {\n            if (typeof input !== 'string') {\n                input = -input;\n            }\n\n            this.utcOffset(input, keepLocalTime);\n\n            return this;\n        } else {\n            return -this.utcOffset();\n        }\n    }\n\n    function setOffsetToUTC (keepLocalTime) {\n        return this.utcOffset(0, keepLocalTime);\n    }\n\n    function setOffsetToLocal (keepLocalTime) {\n        if (this._isUTC) {\n            this.utcOffset(0, keepLocalTime);\n            this._isUTC = false;\n\n            if (keepLocalTime) {\n                this.subtract(getDateOffset(this), 'm');\n            }\n        }\n        return this;\n    }\n\n    function setOffsetToParsedOffset () {\n        if (this._tzm) {\n            this.utcOffset(this._tzm);\n        } else if (typeof this._i === 'string') {\n            this.utcOffset(offsetFromString(this._i));\n        }\n        return this;\n    }\n\n    function hasAlignedHourOffset (input) {\n        input = input ? local__createLocal(input).utcOffset() : 0;\n\n        return (this.utcOffset() - input) % 60 === 0;\n    }\n\n    function isDaylightSavingTime () {\n        return (\n            this.utcOffset() > this.clone().month(0).utcOffset() ||\n            this.utcOffset() > this.clone().month(5).utcOffset()\n        );\n    }\n\n    function isDaylightSavingTimeShifted () {\n        if (typeof this._isDSTShifted !== 'undefined') {\n            return this._isDSTShifted;\n        }\n\n        var c = {};\n\n        copyConfig(c, this);\n        c = prepareConfig(c);\n\n        if (c._a) {\n            var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a);\n            this._isDSTShifted = this.isValid() &&\n                compareArrays(c._a, other.toArray()) > 0;\n        } else {\n            this._isDSTShifted = false;\n        }\n\n        return this._isDSTShifted;\n    }\n\n    function isLocal () {\n        return !this._isUTC;\n    }\n\n    function isUtcOffset () {\n        return this._isUTC;\n    }\n\n    function isUtc () {\n        return this._isUTC && this._offset === 0;\n    }\n\n    var aspNetRegex = /(\\-)?(?:(\\d*)\\.)?(\\d+)\\:(\\d+)(?:\\:(\\d+)\\.?(\\d{3})?)?/;\n\n    // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html\n    // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere\n    var create__isoRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/;\n\n    function create__createDuration (input, key) {\n        var duration = input,\n            // matching against regexp is expensive, do it on demand\n            match = null,\n            sign,\n            ret,\n            diffRes;\n\n        if (isDuration(input)) {\n            duration = {\n                ms : input._milliseconds,\n                d  : input._days,\n                M  : input._months\n            };\n        } else if (typeof input === 'number') {\n            duration = {};\n            if (key) {\n                duration[key] = input;\n            } else {\n                duration.milliseconds = input;\n            }\n        } else if (!!(match = aspNetRegex.exec(input))) {\n            sign = (match[1] === '-') ? -1 : 1;\n            duration = {\n                y  : 0,\n                d  : toInt(match[DATE])        * sign,\n                h  : toInt(match[HOUR])        * sign,\n                m  : toInt(match[MINUTE])      * sign,\n                s  : toInt(match[SECOND])      * sign,\n                ms : toInt(match[MILLISECOND]) * sign\n            };\n        } else if (!!(match = create__isoRegex.exec(input))) {\n            sign = (match[1] === '-') ? -1 : 1;\n            duration = {\n                y : parseIso(match[2], sign),\n                M : parseIso(match[3], sign),\n                d : parseIso(match[4], sign),\n                h : parseIso(match[5], sign),\n                m : parseIso(match[6], sign),\n                s : parseIso(match[7], sign),\n                w : parseIso(match[8], sign)\n            };\n        } else if (duration == null) {// checks for null or undefined\n            duration = {};\n        } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {\n            diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to));\n\n            duration = {};\n            duration.ms = diffRes.milliseconds;\n            duration.M = diffRes.months;\n        }\n\n        ret = new Duration(duration);\n\n        if (isDuration(input) && hasOwnProp(input, '_locale')) {\n            ret._locale = input._locale;\n        }\n\n        return ret;\n    }\n\n    create__createDuration.fn = Duration.prototype;\n\n    function parseIso (inp, sign) {\n        // We'd normally use ~~inp for this, but unfortunately it also\n        // converts floats to ints.\n        // inp may be undefined, so careful calling replace on it.\n        var res = inp && parseFloat(inp.replace(',', '.'));\n        // apply sign while we're at it\n        return (isNaN(res) ? 0 : res) * sign;\n    }\n\n    function positiveMomentsDifference(base, other) {\n        var res = {milliseconds: 0, months: 0};\n\n        res.months = other.month() - base.month() +\n            (other.year() - base.year()) * 12;\n        if (base.clone().add(res.months, 'M').isAfter(other)) {\n            --res.months;\n        }\n\n        res.milliseconds = +other - +(base.clone().add(res.months, 'M'));\n\n        return res;\n    }\n\n    function momentsDifference(base, other) {\n        var res;\n        other = cloneWithOffset(other, base);\n        if (base.isBefore(other)) {\n            res = positiveMomentsDifference(base, other);\n        } else {\n            res = positiveMomentsDifference(other, base);\n            res.milliseconds = -res.milliseconds;\n            res.months = -res.months;\n        }\n\n        return res;\n    }\n\n    function createAdder(direction, name) {\n        return function (val, period) {\n            var dur, tmp;\n            //invert the arguments, but complain about it\n            if (period !== null && !isNaN(+period)) {\n                deprecateSimple(name, 'moment().' + name  + '(period, number) is deprecated. Please use moment().' + name + '(number, period).');\n                tmp = val; val = period; period = tmp;\n            }\n\n            val = typeof val === 'string' ? +val : val;\n            dur = create__createDuration(val, period);\n            add_subtract__addSubtract(this, dur, direction);\n            return this;\n        };\n    }\n\n    function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) {\n        var milliseconds = duration._milliseconds,\n            days = duration._days,\n            months = duration._months;\n        updateOffset = updateOffset == null ? true : updateOffset;\n\n        if (milliseconds) {\n            mom._d.setTime(+mom._d + milliseconds * isAdding);\n        }\n        if (days) {\n            get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding);\n        }\n        if (months) {\n            setMonth(mom, get_set__get(mom, 'Month') + months * isAdding);\n        }\n        if (updateOffset) {\n            utils_hooks__hooks.updateOffset(mom, days || months);\n        }\n    }\n\n    var add_subtract__add      = createAdder(1, 'add');\n    var add_subtract__subtract = createAdder(-1, 'subtract');\n\n    function moment_calendar__calendar (time, formats) {\n        // We want to compare the start of today, vs this.\n        // Getting start-of-today depends on whether we're local/utc/offset or not.\n        var now = time || local__createLocal(),\n            sod = cloneWithOffset(now, this).startOf('day'),\n            diff = this.diff(sod, 'days', true),\n            format = diff < -6 ? 'sameElse' :\n                diff < -1 ? 'lastWeek' :\n                diff < 0 ? 'lastDay' :\n                diff < 1 ? 'sameDay' :\n                diff < 2 ? 'nextDay' :\n                diff < 7 ? 'nextWeek' : 'sameElse';\n        return this.format(formats && formats[format] || this.localeData().calendar(format, this, local__createLocal(now)));\n    }\n\n    function clone () {\n        return new Moment(this);\n    }\n\n    function isAfter (input, units) {\n        var inputMs;\n        units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');\n        if (units === 'millisecond') {\n            input = isMoment(input) ? input : local__createLocal(input);\n            return +this > +input;\n        } else {\n            inputMs = isMoment(input) ? +input : +local__createLocal(input);\n            return inputMs < +this.clone().startOf(units);\n        }\n    }\n\n    function isBefore (input, units) {\n        var inputMs;\n        units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');\n        if (units === 'millisecond') {\n            input = isMoment(input) ? input : local__createLocal(input);\n            return +this < +input;\n        } else {\n            inputMs = isMoment(input) ? +input : +local__createLocal(input);\n            return +this.clone().endOf(units) < inputMs;\n        }\n    }\n\n    function isBetween (from, to, units) {\n        return this.isAfter(from, units) && this.isBefore(to, units);\n    }\n\n    function isSame (input, units) {\n        var inputMs;\n        units = normalizeUnits(units || 'millisecond');\n        if (units === 'millisecond') {\n            input = isMoment(input) ? input : local__createLocal(input);\n            return +this === +input;\n        } else {\n            inputMs = +local__createLocal(input);\n            return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units));\n        }\n    }\n\n    function diff (input, units, asFloat) {\n        var that = cloneWithOffset(input, this),\n            zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4,\n            delta, output;\n\n        units = normalizeUnits(units);\n\n        if (units === 'year' || units === 'month' || units === 'quarter') {\n            output = monthDiff(this, that);\n            if (units === 'quarter') {\n                output = output / 3;\n            } else if (units === 'year') {\n                output = output / 12;\n            }\n        } else {\n            delta = this - that;\n            output = units === 'second' ? delta / 1e3 : // 1000\n                units === 'minute' ? delta / 6e4 : // 1000 * 60\n                units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60\n                units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst\n                units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst\n                delta;\n        }\n        return asFloat ? output : absFloor(output);\n    }\n\n    function monthDiff (a, b) {\n        // difference in months\n        var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),\n            // b is in (anchor - 1 month, anchor + 1 month)\n            anchor = a.clone().add(wholeMonthDiff, 'months'),\n            anchor2, adjust;\n\n        if (b - anchor < 0) {\n            anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');\n            // linear across the month\n            adjust = (b - anchor) / (anchor - anchor2);\n        } else {\n            anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');\n            // linear across the month\n            adjust = (b - anchor) / (anchor2 - anchor);\n        }\n\n        return -(wholeMonthDiff + adjust);\n    }\n\n    utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';\n\n    function toString () {\n        return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');\n    }\n\n    function moment_format__toISOString () {\n        var m = this.clone().utc();\n        if (0 < m.year() && m.year() <= 9999) {\n            if ('function' === typeof Date.prototype.toISOString) {\n                // native implementation is ~50x faster, use it when we can\n                return this.toDate().toISOString();\n            } else {\n                return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');\n            }\n        } else {\n            return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');\n        }\n    }\n\n    function moment_format__format (inputString) {\n        var output = formatMoment(this, inputString || utils_hooks__hooks.defaultFormat);\n        return this.localeData().postformat(output);\n    }\n\n    function from (time, withoutSuffix) {\n        if (!this.isValid()) {\n            return this.localeData().invalidDate();\n        }\n        return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);\n    }\n\n    function fromNow (withoutSuffix) {\n        return this.from(local__createLocal(), withoutSuffix);\n    }\n\n    function to (time, withoutSuffix) {\n        if (!this.isValid()) {\n            return this.localeData().invalidDate();\n        }\n        return create__createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);\n    }\n\n    function toNow (withoutSuffix) {\n        return this.to(local__createLocal(), withoutSuffix);\n    }\n\n    function locale (key) {\n        var newLocaleData;\n\n        if (key === undefined) {\n            return this._locale._abbr;\n        } else {\n            newLocaleData = locale_locales__getLocale(key);\n            if (newLocaleData != null) {\n                this._locale = newLocaleData;\n            }\n            return this;\n        }\n    }\n\n    var lang = deprecate(\n        'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',\n        function (key) {\n            if (key === undefined) {\n                return this.localeData();\n            } else {\n                return this.locale(key);\n            }\n        }\n    );\n\n    function localeData () {\n        return this._locale;\n    }\n\n    function startOf (units) {\n        units = normalizeUnits(units);\n        // the following switch intentionally omits break keywords\n        // to utilize falling through the cases.\n        switch (units) {\n        case 'year':\n            this.month(0);\n            /* falls through */\n        case 'quarter':\n        case 'month':\n            this.date(1);\n            /* falls through */\n        case 'week':\n        case 'isoWeek':\n        case 'day':\n            this.hours(0);\n            /* falls through */\n        case 'hour':\n            this.minutes(0);\n            /* falls through */\n        case 'minute':\n            this.seconds(0);\n            /* falls through */\n        case 'second':\n            this.milliseconds(0);\n        }\n\n        // weeks are a special case\n        if (units === 'week') {\n            this.weekday(0);\n        }\n        if (units === 'isoWeek') {\n            this.isoWeekday(1);\n        }\n\n        // quarters are also special\n        if (units === 'quarter') {\n            this.month(Math.floor(this.month() / 3) * 3);\n        }\n\n        return this;\n    }\n\n    function endOf (units) {\n        units = normalizeUnits(units);\n        if (units === undefined || units === 'millisecond') {\n            return this;\n        }\n        return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');\n    }\n\n    function to_type__valueOf () {\n        return +this._d - ((this._offset || 0) * 60000);\n    }\n\n    function unix () {\n        return Math.floor(+this / 1000);\n    }\n\n    function toDate () {\n        return this._offset ? new Date(+this) : this._d;\n    }\n\n    function toArray () {\n        var m = this;\n        return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];\n    }\n\n    function toObject () {\n        var m = this;\n        return {\n            years: m.year(),\n            months: m.month(),\n            date: m.date(),\n            hours: m.hours(),\n            minutes: m.minutes(),\n            seconds: m.seconds(),\n            milliseconds: m.milliseconds()\n        };\n    }\n\n    function moment_valid__isValid () {\n        return valid__isValid(this);\n    }\n\n    function parsingFlags () {\n        return extend({}, getParsingFlags(this));\n    }\n\n    function invalidAt () {\n        return getParsingFlags(this).overflow;\n    }\n\n    addFormatToken(0, ['gg', 2], 0, function () {\n        return this.weekYear() % 100;\n    });\n\n    addFormatToken(0, ['GG', 2], 0, function () {\n        return this.isoWeekYear() % 100;\n    });\n\n    function addWeekYearFormatToken (token, getter) {\n        addFormatToken(0, [token, token.length], 0, getter);\n    }\n\n    addWeekYearFormatToken('gggg',     'weekYear');\n    addWeekYearFormatToken('ggggg',    'weekYear');\n    addWeekYearFormatToken('GGGG',  'isoWeekYear');\n    addWeekYearFormatToken('GGGGG', 'isoWeekYear');\n\n    // ALIASES\n\n    addUnitAlias('weekYear', 'gg');\n    addUnitAlias('isoWeekYear', 'GG');\n\n    // PARSING\n\n    addRegexToken('G',      matchSigned);\n    addRegexToken('g',      matchSigned);\n    addRegexToken('GG',     match1to2, match2);\n    addRegexToken('gg',     match1to2, match2);\n    addRegexToken('GGGG',   match1to4, match4);\n    addRegexToken('gggg',   match1to4, match4);\n    addRegexToken('GGGGG',  match1to6, match6);\n    addRegexToken('ggggg',  match1to6, match6);\n\n    addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {\n        week[token.substr(0, 2)] = toInt(input);\n    });\n\n    addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {\n        week[token] = utils_hooks__hooks.parseTwoDigitYear(input);\n    });\n\n    // HELPERS\n\n    function weeksInYear(year, dow, doy) {\n        return weekOfYear(local__createLocal([year, 11, 31 + dow - doy]), dow, doy).week;\n    }\n\n    // MOMENTS\n\n    function getSetWeekYear (input) {\n        var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year;\n        return input == null ? year : this.add((input - year), 'y');\n    }\n\n    function getSetISOWeekYear (input) {\n        var year = weekOfYear(this, 1, 4).year;\n        return input == null ? year : this.add((input - year), 'y');\n    }\n\n    function getISOWeeksInYear () {\n        return weeksInYear(this.year(), 1, 4);\n    }\n\n    function getWeeksInYear () {\n        var weekInfo = this.localeData()._week;\n        return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);\n    }\n\n    addFormatToken('Q', 0, 0, 'quarter');\n\n    // ALIASES\n\n    addUnitAlias('quarter', 'Q');\n\n    // PARSING\n\n    addRegexToken('Q', match1);\n    addParseToken('Q', function (input, array) {\n        array[MONTH] = (toInt(input) - 1) * 3;\n    });\n\n    // MOMENTS\n\n    function getSetQuarter (input) {\n        return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);\n    }\n\n    addFormatToken('D', ['DD', 2], 'Do', 'date');\n\n    // ALIASES\n\n    addUnitAlias('date', 'D');\n\n    // PARSING\n\n    addRegexToken('D',  match1to2);\n    addRegexToken('DD', match1to2, match2);\n    addRegexToken('Do', function (isStrict, locale) {\n        return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;\n    });\n\n    addParseToken(['D', 'DD'], DATE);\n    addParseToken('Do', function (input, array) {\n        array[DATE] = toInt(input.match(match1to2)[0], 10);\n    });\n\n    // MOMENTS\n\n    var getSetDayOfMonth = makeGetSet('Date', true);\n\n    addFormatToken('d', 0, 'do', 'day');\n\n    addFormatToken('dd', 0, 0, function (format) {\n        return this.localeData().weekdaysMin(this, format);\n    });\n\n    addFormatToken('ddd', 0, 0, function (format) {\n        return this.localeData().weekdaysShort(this, format);\n    });\n\n    addFormatToken('dddd', 0, 0, function (format) {\n        return this.localeData().weekdays(this, format);\n    });\n\n    addFormatToken('e', 0, 0, 'weekday');\n    addFormatToken('E', 0, 0, 'isoWeekday');\n\n    // ALIASES\n\n    addUnitAlias('day', 'd');\n    addUnitAlias('weekday', 'e');\n    addUnitAlias('isoWeekday', 'E');\n\n    // PARSING\n\n    addRegexToken('d',    match1to2);\n    addRegexToken('e',    match1to2);\n    addRegexToken('E',    match1to2);\n    addRegexToken('dd',   matchWord);\n    addRegexToken('ddd',  matchWord);\n    addRegexToken('dddd', matchWord);\n\n    addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config) {\n        var weekday = config._locale.weekdaysParse(input);\n        // if we didn't get a weekday name, mark the date as invalid\n        if (weekday != null) {\n            week.d = weekday;\n        } else {\n            getParsingFlags(config).invalidWeekday = input;\n        }\n    });\n\n    addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {\n        week[token] = toInt(input);\n    });\n\n    // HELPERS\n\n    function parseWeekday(input, locale) {\n        if (typeof input !== 'string') {\n            return input;\n        }\n\n        if (!isNaN(input)) {\n            return parseInt(input, 10);\n        }\n\n        input = locale.weekdaysParse(input);\n        if (typeof input === 'number') {\n            return input;\n        }\n\n        return null;\n    }\n\n    // LOCALES\n\n    var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');\n    function localeWeekdays (m) {\n        return this._weekdays[m.day()];\n    }\n\n    var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');\n    function localeWeekdaysShort (m) {\n        return this._weekdaysShort[m.day()];\n    }\n\n    var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');\n    function localeWeekdaysMin (m) {\n        return this._weekdaysMin[m.day()];\n    }\n\n    function localeWeekdaysParse (weekdayName) {\n        var i, mom, regex;\n\n        this._weekdaysParse = this._weekdaysParse || [];\n\n        for (i = 0; i < 7; i++) {\n            // make the regex if we don't have it already\n            if (!this._weekdaysParse[i]) {\n                mom = local__createLocal([2000, 1]).day(i);\n                regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');\n                this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');\n            }\n            // test the regex\n            if (this._weekdaysParse[i].test(weekdayName)) {\n                return i;\n            }\n        }\n    }\n\n    // MOMENTS\n\n    function getSetDayOfWeek (input) {\n        var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();\n        if (input != null) {\n            input = parseWeekday(input, this.localeData());\n            return this.add(input - day, 'd');\n        } else {\n            return day;\n        }\n    }\n\n    function getSetLocaleDayOfWeek (input) {\n        var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;\n        return input == null ? weekday : this.add(input - weekday, 'd');\n    }\n\n    function getSetISODayOfWeek (input) {\n        // behaves the same as moment#day except\n        // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)\n        // as a setter, sunday should belong to the previous week.\n        return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);\n    }\n\n    addFormatToken('H', ['HH', 2], 0, 'hour');\n    addFormatToken('h', ['hh', 2], 0, function () {\n        return this.hours() % 12 || 12;\n    });\n\n    function meridiem (token, lowercase) {\n        addFormatToken(token, 0, 0, function () {\n            return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);\n        });\n    }\n\n    meridiem('a', true);\n    meridiem('A', false);\n\n    // ALIASES\n\n    addUnitAlias('hour', 'h');\n\n    // PARSING\n\n    function matchMeridiem (isStrict, locale) {\n        return locale._meridiemParse;\n    }\n\n    addRegexToken('a',  matchMeridiem);\n    addRegexToken('A',  matchMeridiem);\n    addRegexToken('H',  match1to2);\n    addRegexToken('h',  match1to2);\n    addRegexToken('HH', match1to2, match2);\n    addRegexToken('hh', match1to2, match2);\n\n    addParseToken(['H', 'HH'], HOUR);\n    addParseToken(['a', 'A'], function (input, array, config) {\n        config._isPm = config._locale.isPM(input);\n        config._meridiem = input;\n    });\n    addParseToken(['h', 'hh'], function (input, array, config) {\n        array[HOUR] = toInt(input);\n        getParsingFlags(config).bigHour = true;\n    });\n\n    // LOCALES\n\n    function localeIsPM (input) {\n        // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays\n        // Using charAt should be more compatible.\n        return ((input + '').toLowerCase().charAt(0) === 'p');\n    }\n\n    var defaultLocaleMeridiemParse = /[ap]\\.?m?\\.?/i;\n    function localeMeridiem (hours, minutes, isLower) {\n        if (hours > 11) {\n            return isLower ? 'pm' : 'PM';\n        } else {\n            return isLower ? 'am' : 'AM';\n        }\n    }\n\n\n    // MOMENTS\n\n    // Setting the hour should keep the time, because the user explicitly\n    // specified which hour he wants. So trying to maintain the same hour (in\n    // a new timezone) makes sense. Adding/subtracting hours does not follow\n    // this rule.\n    var getSetHour = makeGetSet('Hours', true);\n\n    addFormatToken('m', ['mm', 2], 0, 'minute');\n\n    // ALIASES\n\n    addUnitAlias('minute', 'm');\n\n    // PARSING\n\n    addRegexToken('m',  match1to2);\n    addRegexToken('mm', match1to2, match2);\n    addParseToken(['m', 'mm'], MINUTE);\n\n    // MOMENTS\n\n    var getSetMinute = makeGetSet('Minutes', false);\n\n    addFormatToken('s', ['ss', 2], 0, 'second');\n\n    // ALIASES\n\n    addUnitAlias('second', 's');\n\n    // PARSING\n\n    addRegexToken('s',  match1to2);\n    addRegexToken('ss', match1to2, match2);\n    addParseToken(['s', 'ss'], SECOND);\n\n    // MOMENTS\n\n    var getSetSecond = makeGetSet('Seconds', false);\n\n    addFormatToken('S', 0, 0, function () {\n        return ~~(this.millisecond() / 100);\n    });\n\n    addFormatToken(0, ['SS', 2], 0, function () {\n        return ~~(this.millisecond() / 10);\n    });\n\n    addFormatToken(0, ['SSS', 3], 0, 'millisecond');\n    addFormatToken(0, ['SSSS', 4], 0, function () {\n        return this.millisecond() * 10;\n    });\n    addFormatToken(0, ['SSSSS', 5], 0, function () {\n        return this.millisecond() * 100;\n    });\n    addFormatToken(0, ['SSSSSS', 6], 0, function () {\n        return this.millisecond() * 1000;\n    });\n    addFormatToken(0, ['SSSSSSS', 7], 0, function () {\n        return this.millisecond() * 10000;\n    });\n    addFormatToken(0, ['SSSSSSSS', 8], 0, function () {\n        return this.millisecond() * 100000;\n    });\n    addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {\n        return this.millisecond() * 1000000;\n    });\n\n\n    // ALIASES\n\n    addUnitAlias('millisecond', 'ms');\n\n    // PARSING\n\n    addRegexToken('S',    match1to3, match1);\n    addRegexToken('SS',   match1to3, match2);\n    addRegexToken('SSS',  match1to3, match3);\n\n    var token;\n    for (token = 'SSSS'; token.length <= 9; token += 'S') {\n        addRegexToken(token, matchUnsigned);\n    }\n\n    function parseMs(input, array) {\n        array[MILLISECOND] = toInt(('0.' + input) * 1000);\n    }\n\n    for (token = 'S'; token.length <= 9; token += 'S') {\n        addParseToken(token, parseMs);\n    }\n    // MOMENTS\n\n    var getSetMillisecond = makeGetSet('Milliseconds', false);\n\n    addFormatToken('z',  0, 0, 'zoneAbbr');\n    addFormatToken('zz', 0, 0, 'zoneName');\n\n    // MOMENTS\n\n    function getZoneAbbr () {\n        return this._isUTC ? 'UTC' : '';\n    }\n\n    function getZoneName () {\n        return this._isUTC ? 'Coordinated Universal Time' : '';\n    }\n\n    var momentPrototype__proto = Moment.prototype;\n\n    momentPrototype__proto.add          = add_subtract__add;\n    momentPrototype__proto.calendar     = moment_calendar__calendar;\n    momentPrototype__proto.clone        = clone;\n    momentPrototype__proto.diff         = diff;\n    momentPrototype__proto.endOf        = endOf;\n    momentPrototype__proto.format       = moment_format__format;\n    momentPrototype__proto.from         = from;\n    momentPrototype__proto.fromNow      = fromNow;\n    momentPrototype__proto.to           = to;\n    momentPrototype__proto.toNow        = toNow;\n    momentPrototype__proto.get          = getSet;\n    momentPrototype__proto.invalidAt    = invalidAt;\n    momentPrototype__proto.isAfter      = isAfter;\n    momentPrototype__proto.isBefore     = isBefore;\n    momentPrototype__proto.isBetween    = isBetween;\n    momentPrototype__proto.isSame       = isSame;\n    momentPrototype__proto.isValid      = moment_valid__isValid;\n    momentPrototype__proto.lang         = lang;\n    momentPrototype__proto.locale       = locale;\n    momentPrototype__proto.localeData   = localeData;\n    momentPrototype__proto.max          = prototypeMax;\n    momentPrototype__proto.min          = prototypeMin;\n    momentPrototype__proto.parsingFlags = parsingFlags;\n    momentPrototype__proto.set          = getSet;\n    momentPrototype__proto.startOf      = startOf;\n    momentPrototype__proto.subtract     = add_subtract__subtract;\n    momentPrototype__proto.toArray      = toArray;\n    momentPrototype__proto.toObject     = toObject;\n    momentPrototype__proto.toDate       = toDate;\n    momentPrototype__proto.toISOString  = moment_format__toISOString;\n    momentPrototype__proto.toJSON       = moment_format__toISOString;\n    momentPrototype__proto.toString     = toString;\n    momentPrototype__proto.unix         = unix;\n    momentPrototype__proto.valueOf      = to_type__valueOf;\n\n    // Year\n    momentPrototype__proto.year       = getSetYear;\n    momentPrototype__proto.isLeapYear = getIsLeapYear;\n\n    // Week Year\n    momentPrototype__proto.weekYear    = getSetWeekYear;\n    momentPrototype__proto.isoWeekYear = getSetISOWeekYear;\n\n    // Quarter\n    momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter;\n\n    // Month\n    momentPrototype__proto.month       = getSetMonth;\n    momentPrototype__proto.daysInMonth = getDaysInMonth;\n\n    // Week\n    momentPrototype__proto.week           = momentPrototype__proto.weeks        = getSetWeek;\n    momentPrototype__proto.isoWeek        = momentPrototype__proto.isoWeeks     = getSetISOWeek;\n    momentPrototype__proto.weeksInYear    = getWeeksInYear;\n    momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear;\n\n    // Day\n    momentPrototype__proto.date       = getSetDayOfMonth;\n    momentPrototype__proto.day        = momentPrototype__proto.days             = getSetDayOfWeek;\n    momentPrototype__proto.weekday    = getSetLocaleDayOfWeek;\n    momentPrototype__proto.isoWeekday = getSetISODayOfWeek;\n    momentPrototype__proto.dayOfYear  = getSetDayOfYear;\n\n    // Hour\n    momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour;\n\n    // Minute\n    momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute;\n\n    // Second\n    momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond;\n\n    // Millisecond\n    momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond;\n\n    // Offset\n    momentPrototype__proto.utcOffset            = getSetOffset;\n    momentPrototype__proto.utc                  = setOffsetToUTC;\n    momentPrototype__proto.local                = setOffsetToLocal;\n    momentPrototype__proto.parseZone            = setOffsetToParsedOffset;\n    momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset;\n    momentPrototype__proto.isDST                = isDaylightSavingTime;\n    momentPrototype__proto.isDSTShifted         = isDaylightSavingTimeShifted;\n    momentPrototype__proto.isLocal              = isLocal;\n    momentPrototype__proto.isUtcOffset          = isUtcOffset;\n    momentPrototype__proto.isUtc                = isUtc;\n    momentPrototype__proto.isUTC                = isUtc;\n\n    // Timezone\n    momentPrototype__proto.zoneAbbr = getZoneAbbr;\n    momentPrototype__proto.zoneName = getZoneName;\n\n    // Deprecations\n    momentPrototype__proto.dates  = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);\n    momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);\n    momentPrototype__proto.years  = deprecate('years accessor is deprecated. Use year instead', getSetYear);\n    momentPrototype__proto.zone   = deprecate('moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779', getSetZone);\n\n    var momentPrototype = momentPrototype__proto;\n\n    function moment_moment__createUnix (input) {\n        return local__createLocal(input * 1000);\n    }\n\n    function moment_moment__createInZone () {\n        return local__createLocal.apply(null, arguments).parseZone();\n    }\n\n    var defaultCalendar = {\n        sameDay : '[Today at] LT',\n        nextDay : '[Tomorrow at] LT',\n        nextWeek : 'dddd [at] LT',\n        lastDay : '[Yesterday at] LT',\n        lastWeek : '[Last] dddd [at] LT',\n        sameElse : 'L'\n    };\n\n    function locale_calendar__calendar (key, mom, now) {\n        var output = this._calendar[key];\n        return typeof output === 'function' ? output.call(mom, now) : output;\n    }\n\n    var defaultLongDateFormat = {\n        LTS  : 'h:mm:ss A',\n        LT   : 'h:mm A',\n        L    : 'MM/DD/YYYY',\n        LL   : 'MMMM D, YYYY',\n        LLL  : 'MMMM D, YYYY h:mm A',\n        LLLL : 'dddd, MMMM D, YYYY h:mm A'\n    };\n\n    function longDateFormat (key) {\n        var format = this._longDateFormat[key],\n            formatUpper = this._longDateFormat[key.toUpperCase()];\n\n        if (format || !formatUpper) {\n            return format;\n        }\n\n        this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {\n            return val.slice(1);\n        });\n\n        return this._longDateFormat[key];\n    }\n\n    var defaultInvalidDate = 'Invalid date';\n\n    function invalidDate () {\n        return this._invalidDate;\n    }\n\n    var defaultOrdinal = '%d';\n    var defaultOrdinalParse = /\\d{1,2}/;\n\n    function ordinal (number) {\n        return this._ordinal.replace('%d', number);\n    }\n\n    function preParsePostFormat (string) {\n        return string;\n    }\n\n    var defaultRelativeTime = {\n        future : 'in %s',\n        past   : '%s ago',\n        s  : 'a few seconds',\n        m  : 'a minute',\n        mm : '%d minutes',\n        h  : 'an hour',\n        hh : '%d hours',\n        d  : 'a day',\n        dd : '%d days',\n        M  : 'a month',\n        MM : '%d months',\n        y  : 'a year',\n        yy : '%d years'\n    };\n\n    function relative__relativeTime (number, withoutSuffix, string, isFuture) {\n        var output = this._relativeTime[string];\n        return (typeof output === 'function') ?\n            output(number, withoutSuffix, string, isFuture) :\n            output.replace(/%d/i, number);\n    }\n\n    function pastFuture (diff, output) {\n        var format = this._relativeTime[diff > 0 ? 'future' : 'past'];\n        return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);\n    }\n\n    function locale_set__set (config) {\n        var prop, i;\n        for (i in config) {\n            prop = config[i];\n            if (typeof prop === 'function') {\n                this[i] = prop;\n            } else {\n                this['_' + i] = prop;\n            }\n        }\n        // Lenient ordinal parsing accepts just a number in addition to\n        // number + (possibly) stuff coming from _ordinalParseLenient.\n        this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\\d{1,2}/).source);\n    }\n\n    var prototype__proto = Locale.prototype;\n\n    prototype__proto._calendar       = defaultCalendar;\n    prototype__proto.calendar        = locale_calendar__calendar;\n    prototype__proto._longDateFormat = defaultLongDateFormat;\n    prototype__proto.longDateFormat  = longDateFormat;\n    prototype__proto._invalidDate    = defaultInvalidDate;\n    prototype__proto.invalidDate     = invalidDate;\n    prototype__proto._ordinal        = defaultOrdinal;\n    prototype__proto.ordinal         = ordinal;\n    prototype__proto._ordinalParse   = defaultOrdinalParse;\n    prototype__proto.preparse        = preParsePostFormat;\n    prototype__proto.postformat      = preParsePostFormat;\n    prototype__proto._relativeTime   = defaultRelativeTime;\n    prototype__proto.relativeTime    = relative__relativeTime;\n    prototype__proto.pastFuture      = pastFuture;\n    prototype__proto.set             = locale_set__set;\n\n    // Month\n    prototype__proto.months       =        localeMonths;\n    prototype__proto._months      = defaultLocaleMonths;\n    prototype__proto.monthsShort  =        localeMonthsShort;\n    prototype__proto._monthsShort = defaultLocaleMonthsShort;\n    prototype__proto.monthsParse  =        localeMonthsParse;\n\n    // Week\n    prototype__proto.week = localeWeek;\n    prototype__proto._week = defaultLocaleWeek;\n    prototype__proto.firstDayOfYear = localeFirstDayOfYear;\n    prototype__proto.firstDayOfWeek = localeFirstDayOfWeek;\n\n    // Day of Week\n    prototype__proto.weekdays       =        localeWeekdays;\n    prototype__proto._weekdays      = defaultLocaleWeekdays;\n    prototype__proto.weekdaysMin    =        localeWeekdaysMin;\n    prototype__proto._weekdaysMin   = defaultLocaleWeekdaysMin;\n    prototype__proto.weekdaysShort  =        localeWeekdaysShort;\n    prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort;\n    prototype__proto.weekdaysParse  =        localeWeekdaysParse;\n\n    // Hours\n    prototype__proto.isPM = localeIsPM;\n    prototype__proto._meridiemParse = defaultLocaleMeridiemParse;\n    prototype__proto.meridiem = localeMeridiem;\n\n    function lists__get (format, index, field, setter) {\n        var locale = locale_locales__getLocale();\n        var utc = create_utc__createUTC().set(setter, index);\n        return locale[field](utc, format);\n    }\n\n    function list (format, index, field, count, setter) {\n        if (typeof format === 'number') {\n            index = format;\n            format = undefined;\n        }\n\n        format = format || '';\n\n        if (index != null) {\n            return lists__get(format, index, field, setter);\n        }\n\n        var i;\n        var out = [];\n        for (i = 0; i < count; i++) {\n            out[i] = lists__get(format, i, field, setter);\n        }\n        return out;\n    }\n\n    function lists__listMonths (format, index) {\n        return list(format, index, 'months', 12, 'month');\n    }\n\n    function lists__listMonthsShort (format, index) {\n        return list(format, index, 'monthsShort', 12, 'month');\n    }\n\n    function lists__listWeekdays (format, index) {\n        return list(format, index, 'weekdays', 7, 'day');\n    }\n\n    function lists__listWeekdaysShort (format, index) {\n        return list(format, index, 'weekdaysShort', 7, 'day');\n    }\n\n    function lists__listWeekdaysMin (format, index) {\n        return list(format, index, 'weekdaysMin', 7, 'day');\n    }\n\n    locale_locales__getSetGlobalLocale('en', {\n        ordinalParse: /\\d{1,2}(th|st|nd|rd)/,\n        ordinal : function (number) {\n            var b = number % 10,\n                output = (toInt(number % 100 / 10) === 1) ? 'th' :\n                (b === 1) ? 'st' :\n                (b === 2) ? 'nd' :\n                (b === 3) ? 'rd' : 'th';\n            return number + output;\n        }\n    });\n\n    // Side effect imports\n    utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale);\n    utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale);\n\n    var mathAbs = Math.abs;\n\n    function duration_abs__abs () {\n        var data           = this._data;\n\n        this._milliseconds = mathAbs(this._milliseconds);\n        this._days         = mathAbs(this._days);\n        this._months       = mathAbs(this._months);\n\n        data.milliseconds  = mathAbs(data.milliseconds);\n        data.seconds       = mathAbs(data.seconds);\n        data.minutes       = mathAbs(data.minutes);\n        data.hours         = mathAbs(data.hours);\n        data.months        = mathAbs(data.months);\n        data.years         = mathAbs(data.years);\n\n        return this;\n    }\n\n    function duration_add_subtract__addSubtract (duration, input, value, direction) {\n        var other = create__createDuration(input, value);\n\n        duration._milliseconds += direction * other._milliseconds;\n        duration._days         += direction * other._days;\n        duration._months       += direction * other._months;\n\n        return duration._bubble();\n    }\n\n    // supports only 2.0-style add(1, 's') or add(duration)\n    function duration_add_subtract__add (input, value) {\n        return duration_add_subtract__addSubtract(this, input, value, 1);\n    }\n\n    // supports only 2.0-style subtract(1, 's') or subtract(duration)\n    function duration_add_subtract__subtract (input, value) {\n        return duration_add_subtract__addSubtract(this, input, value, -1);\n    }\n\n    function absCeil (number) {\n        if (number < 0) {\n            return Math.floor(number);\n        } else {\n            return Math.ceil(number);\n        }\n    }\n\n    function bubble () {\n        var milliseconds = this._milliseconds;\n        var days         = this._days;\n        var months       = this._months;\n        var data         = this._data;\n        var seconds, minutes, hours, years, monthsFromDays;\n\n        // if we have a mix of positive and negative values, bubble down first\n        // check: https://github.com/moment/moment/issues/2166\n        if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||\n                (milliseconds <= 0 && days <= 0 && months <= 0))) {\n            milliseconds += absCeil(monthsToDays(months) + days) * 864e5;\n            days = 0;\n            months = 0;\n        }\n\n        // The following code bubbles up values, see the tests for\n        // examples of what that means.\n        data.milliseconds = milliseconds % 1000;\n\n        seconds           = absFloor(milliseconds / 1000);\n        data.seconds      = seconds % 60;\n\n        minutes           = absFloor(seconds / 60);\n        data.minutes      = minutes % 60;\n\n        hours             = absFloor(minutes / 60);\n        data.hours        = hours % 24;\n\n        days += absFloor(hours / 24);\n\n        // convert days to months\n        monthsFromDays = absFloor(daysToMonths(days));\n        months += monthsFromDays;\n        days -= absCeil(monthsToDays(monthsFromDays));\n\n        // 12 months -> 1 year\n        years = absFloor(months / 12);\n        months %= 12;\n\n        data.days   = days;\n        data.months = months;\n        data.years  = years;\n\n        return this;\n    }\n\n    function daysToMonths (days) {\n        // 400 years have 146097 days (taking into account leap year rules)\n        // 400 years have 12 months === 4800\n        return days * 4800 / 146097;\n    }\n\n    function monthsToDays (months) {\n        // the reverse of daysToMonths\n        return months * 146097 / 4800;\n    }\n\n    function as (units) {\n        var days;\n        var months;\n        var milliseconds = this._milliseconds;\n\n        units = normalizeUnits(units);\n\n        if (units === 'month' || units === 'year') {\n            days   = this._days   + milliseconds / 864e5;\n            months = this._months + daysToMonths(days);\n            return units === 'month' ? months : months / 12;\n        } else {\n            // handle milliseconds separately because of floating point math errors (issue #1867)\n            days = this._days + Math.round(monthsToDays(this._months));\n            switch (units) {\n                case 'week'   : return days / 7     + milliseconds / 6048e5;\n                case 'day'    : return days         + milliseconds / 864e5;\n                case 'hour'   : return days * 24    + milliseconds / 36e5;\n                case 'minute' : return days * 1440  + milliseconds / 6e4;\n                case 'second' : return days * 86400 + milliseconds / 1000;\n                // Math.floor prevents floating point math errors here\n                case 'millisecond': return Math.floor(days * 864e5) + milliseconds;\n                default: throw new Error('Unknown unit ' + units);\n            }\n        }\n    }\n\n    // TODO: Use this.as('ms')?\n    function duration_as__valueOf () {\n        return (\n            this._milliseconds +\n            this._days * 864e5 +\n            (this._months % 12) * 2592e6 +\n            toInt(this._months / 12) * 31536e6\n        );\n    }\n\n    function makeAs (alias) {\n        return function () {\n            return this.as(alias);\n        };\n    }\n\n    var asMilliseconds = makeAs('ms');\n    var asSeconds      = makeAs('s');\n    var asMinutes      = makeAs('m');\n    var asHours        = makeAs('h');\n    var asDays         = makeAs('d');\n    var asWeeks        = makeAs('w');\n    var asMonths       = makeAs('M');\n    var asYears        = makeAs('y');\n\n    function duration_get__get (units) {\n        units = normalizeUnits(units);\n        return this[units + 's']();\n    }\n\n    function makeGetter(name) {\n        return function () {\n            return this._data[name];\n        };\n    }\n\n    var milliseconds = makeGetter('milliseconds');\n    var seconds      = makeGetter('seconds');\n    var minutes      = makeGetter('minutes');\n    var hours        = makeGetter('hours');\n    var days         = makeGetter('days');\n    var duration_get__months       = makeGetter('months');\n    var years        = makeGetter('years');\n\n    function weeks () {\n        return absFloor(this.days() / 7);\n    }\n\n    var round = Math.round;\n    var thresholds = {\n        s: 45,  // seconds to minute\n        m: 45,  // minutes to hour\n        h: 22,  // hours to day\n        d: 26,  // days to month\n        M: 11   // months to year\n    };\n\n    // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize\n    function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {\n        return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);\n    }\n\n    function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) {\n        var duration = create__createDuration(posNegDuration).abs();\n        var seconds  = round(duration.as('s'));\n        var minutes  = round(duration.as('m'));\n        var hours    = round(duration.as('h'));\n        var days     = round(duration.as('d'));\n        var months   = round(duration.as('M'));\n        var years    = round(duration.as('y'));\n\n        var a = seconds < thresholds.s && ['s', seconds]  ||\n                minutes === 1          && ['m']           ||\n                minutes < thresholds.m && ['mm', minutes] ||\n                hours   === 1          && ['h']           ||\n                hours   < thresholds.h && ['hh', hours]   ||\n                days    === 1          && ['d']           ||\n                days    < thresholds.d && ['dd', days]    ||\n                months  === 1          && ['M']           ||\n                months  < thresholds.M && ['MM', months]  ||\n                years   === 1          && ['y']           || ['yy', years];\n\n        a[2] = withoutSuffix;\n        a[3] = +posNegDuration > 0;\n        a[4] = locale;\n        return substituteTimeAgo.apply(null, a);\n    }\n\n    // This function allows you to set a threshold for relative time strings\n    function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) {\n        if (thresholds[threshold] === undefined) {\n            return false;\n        }\n        if (limit === undefined) {\n            return thresholds[threshold];\n        }\n        thresholds[threshold] = limit;\n        return true;\n    }\n\n    function humanize (withSuffix) {\n        var locale = this.localeData();\n        var output = duration_humanize__relativeTime(this, !withSuffix, locale);\n\n        if (withSuffix) {\n            output = locale.pastFuture(+this, output);\n        }\n\n        return locale.postformat(output);\n    }\n\n    var iso_string__abs = Math.abs;\n\n    function iso_string__toISOString() {\n        // for ISO strings we do not use the normal bubbling rules:\n        //  * milliseconds bubble up until they become hours\n        //  * days do not bubble at all\n        //  * months bubble up until they become years\n        // This is because there is no context-free conversion between hours and days\n        // (think of clock changes)\n        // and also not between days and months (28-31 days per month)\n        var seconds = iso_string__abs(this._milliseconds) / 1000;\n        var days         = iso_string__abs(this._days);\n        var months       = iso_string__abs(this._months);\n        var minutes, hours, years;\n\n        // 3600 seconds -> 60 minutes -> 1 hour\n        minutes           = absFloor(seconds / 60);\n        hours             = absFloor(minutes / 60);\n        seconds %= 60;\n        minutes %= 60;\n\n        // 12 months -> 1 year\n        years  = absFloor(months / 12);\n        months %= 12;\n\n\n        // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js\n        var Y = years;\n        var M = months;\n        var D = days;\n        var h = hours;\n        var m = minutes;\n        var s = seconds;\n        var total = this.asSeconds();\n\n        if (!total) {\n            // this is the same as C#'s (Noda) and python (isodate)...\n            // but not other JS (goog.date)\n            return 'P0D';\n        }\n\n        return (total < 0 ? '-' : '') +\n            'P' +\n            (Y ? Y + 'Y' : '') +\n            (M ? M + 'M' : '') +\n            (D ? D + 'D' : '') +\n            ((h || m || s) ? 'T' : '') +\n            (h ? h + 'H' : '') +\n            (m ? m + 'M' : '') +\n            (s ? s + 'S' : '');\n    }\n\n    var duration_prototype__proto = Duration.prototype;\n\n    duration_prototype__proto.abs            = duration_abs__abs;\n    duration_prototype__proto.add            = duration_add_subtract__add;\n    duration_prototype__proto.subtract       = duration_add_subtract__subtract;\n    duration_prototype__proto.as             = as;\n    duration_prototype__proto.asMilliseconds = asMilliseconds;\n    duration_prototype__proto.asSeconds      = asSeconds;\n    duration_prototype__proto.asMinutes      = asMinutes;\n    duration_prototype__proto.asHours        = asHours;\n    duration_prototype__proto.asDays         = asDays;\n    duration_prototype__proto.asWeeks        = asWeeks;\n    duration_prototype__proto.asMonths       = asMonths;\n    duration_prototype__proto.asYears        = asYears;\n    duration_prototype__proto.valueOf        = duration_as__valueOf;\n    duration_prototype__proto._bubble        = bubble;\n    duration_prototype__proto.get            = duration_get__get;\n    duration_prototype__proto.milliseconds   = milliseconds;\n    duration_prototype__proto.seconds        = seconds;\n    duration_prototype__proto.minutes        = minutes;\n    duration_prototype__proto.hours          = hours;\n    duration_prototype__proto.days           = days;\n    duration_prototype__proto.weeks          = weeks;\n    duration_prototype__proto.months         = duration_get__months;\n    duration_prototype__proto.years          = years;\n    duration_prototype__proto.humanize       = humanize;\n    duration_prototype__proto.toISOString    = iso_string__toISOString;\n    duration_prototype__proto.toString       = iso_string__toISOString;\n    duration_prototype__proto.toJSON         = iso_string__toISOString;\n    duration_prototype__proto.locale         = locale;\n    duration_prototype__proto.localeData     = localeData;\n\n    // Deprecations\n    duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString);\n    duration_prototype__proto.lang = lang;\n\n    // Side effect imports\n\n    addFormatToken('X', 0, 0, 'unix');\n    addFormatToken('x', 0, 0, 'valueOf');\n\n    // PARSING\n\n    addRegexToken('x', matchSigned);\n    addRegexToken('X', matchTimestamp);\n    addParseToken('X', function (input, array, config) {\n        config._d = new Date(parseFloat(input, 10) * 1000);\n    });\n    addParseToken('x', function (input, array, config) {\n        config._d = new Date(toInt(input));\n    });\n\n    // Side effect imports\n\n    ;\n\n    //! moment.js\n    //! version : 2.10.6\n    //! authors : Tim Wood, Iskren Chernev, Moment.js contributors\n    //! license : MIT\n    //! momentjs.com\n\n    utils_hooks__hooks.version = '2.10.6';\n\n    setHookCallback(local__createLocal);\n\n    utils_hooks__hooks.fn                    = momentPrototype;\n    utils_hooks__hooks.min                   = min;\n    utils_hooks__hooks.max                   = max;\n    utils_hooks__hooks.utc                   = create_utc__createUTC;\n    utils_hooks__hooks.unix                  = moment_moment__createUnix;\n    utils_hooks__hooks.months                = lists__listMonths;\n    utils_hooks__hooks.isDate                = isDate;\n    utils_hooks__hooks.locale                = locale_locales__getSetGlobalLocale;\n    utils_hooks__hooks.invalid               = valid__createInvalid;\n    utils_hooks__hooks.duration              = create__createDuration;\n    utils_hooks__hooks.isMoment              = isMoment;\n    utils_hooks__hooks.weekdays              = lists__listWeekdays;\n    utils_hooks__hooks.parseZone             = moment_moment__createInZone;\n    utils_hooks__hooks.localeData            = locale_locales__getLocale;\n    utils_hooks__hooks.isDuration            = isDuration;\n    utils_hooks__hooks.monthsShort           = lists__listMonthsShort;\n    utils_hooks__hooks.weekdaysMin           = lists__listWeekdaysMin;\n    utils_hooks__hooks.defineLocale          = defineLocale;\n    utils_hooks__hooks.weekdaysShort         = lists__listWeekdaysShort;\n    utils_hooks__hooks.normalizeUnits        = normalizeUnits;\n    utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold;\n\n    var _moment__default = utils_hooks__hooks;\n\n    //! moment.js locale configuration\n    //! locale : afrikaans (af)\n    //! author : Werner Mollentze : https://github.com/wernerm\n\n    var af = _moment__default.defineLocale('af', {\n        months : 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split('_'),\n        monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'),\n        weekdays : 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split('_'),\n        weekdaysShort : 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'),\n        weekdaysMin : 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'),\n        meridiemParse: /vm|nm/i,\n        isPM : function (input) {\n            return /^nm$/i.test(input);\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours < 12) {\n                return isLower ? 'vm' : 'VM';\n            } else {\n                return isLower ? 'nm' : 'NM';\n            }\n        },\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay : '[Vandag om] LT',\n            nextDay : '[Môre om] LT',\n            nextWeek : 'dddd [om] LT',\n            lastDay : '[Gister om] LT',\n            lastWeek : '[Laas] dddd [om] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'oor %s',\n            past : '%s gelede',\n            s : '\\'n paar sekondes',\n            m : '\\'n minuut',\n            mm : '%d minute',\n            h : '\\'n uur',\n            hh : '%d ure',\n            d : '\\'n dag',\n            dd : '%d dae',\n            M : '\\'n maand',\n            MM : '%d maande',\n            y : '\\'n jaar',\n            yy : '%d jaar'\n        },\n        ordinalParse: /\\d{1,2}(ste|de)/,\n        ordinal : function (number) {\n            return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter\n        },\n        week : {\n            dow : 1, // Maandag is die eerste dag van die week.\n            doy : 4  // Die week wat die 4de Januarie bevat is die eerste week van die jaar.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Moroccan Arabic (ar-ma)\n    //! author : ElFadili Yassine : https://github.com/ElFadiliY\n    //! author : Abdel Said : https://github.com/abdelsaid\n\n    var ar_ma = _moment__default.defineLocale('ar-ma', {\n        months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),\n        monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'),\n        weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),\n        weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'),\n        weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[اليوم على الساعة] LT',\n            nextDay: '[غدا على الساعة] LT',\n            nextWeek: 'dddd [على الساعة] LT',\n            lastDay: '[أمس على الساعة] LT',\n            lastWeek: 'dddd [على الساعة] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'في %s',\n            past : 'منذ %s',\n            s : 'ثوان',\n            m : 'دقيقة',\n            mm : '%d دقائق',\n            h : 'ساعة',\n            hh : '%d ساعات',\n            d : 'يوم',\n            dd : '%d أيام',\n            M : 'شهر',\n            MM : '%d أشهر',\n            y : 'سنة',\n            yy : '%d سنوات'\n        },\n        week : {\n            dow : 6, // Saturday is the first day of the week.\n            doy : 12  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Arabic Saudi Arabia (ar-sa)\n    //! author : Suhail Alkowaileet : https://github.com/xsoh\n\n    var ar_sa__symbolMap = {\n        '1': '١',\n        '2': '٢',\n        '3': '٣',\n        '4': '٤',\n        '5': '٥',\n        '6': '٦',\n        '7': '٧',\n        '8': '٨',\n        '9': '٩',\n        '0': '٠'\n    }, ar_sa__numberMap = {\n        '١': '1',\n        '٢': '2',\n        '٣': '3',\n        '٤': '4',\n        '٥': '5',\n        '٦': '6',\n        '٧': '7',\n        '٨': '8',\n        '٩': '9',\n        '٠': '0'\n    };\n\n    var ar_sa = _moment__default.defineLocale('ar-sa', {\n        months : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),\n        monthsShort : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),\n        weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),\n        weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),\n        weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        meridiemParse: /ص|م/,\n        isPM : function (input) {\n            return 'م' === input;\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 12) {\n                return 'ص';\n            } else {\n                return 'م';\n            }\n        },\n        calendar : {\n            sameDay: '[اليوم على الساعة] LT',\n            nextDay: '[غدا على الساعة] LT',\n            nextWeek: 'dddd [على الساعة] LT',\n            lastDay: '[أمس على الساعة] LT',\n            lastWeek: 'dddd [على الساعة] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'في %s',\n            past : 'منذ %s',\n            s : 'ثوان',\n            m : 'دقيقة',\n            mm : '%d دقائق',\n            h : 'ساعة',\n            hh : '%d ساعات',\n            d : 'يوم',\n            dd : '%d أيام',\n            M : 'شهر',\n            MM : '%d أشهر',\n            y : 'سنة',\n            yy : '%d سنوات'\n        },\n        preparse: function (string) {\n            return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {\n                return ar_sa__numberMap[match];\n            }).replace(/،/g, ',');\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return ar_sa__symbolMap[match];\n            }).replace(/,/g, '،');\n        },\n        week : {\n            dow : 6, // Saturday is the first day of the week.\n            doy : 12  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale  : Tunisian Arabic (ar-tn)\n\n    var ar_tn = _moment__default.defineLocale('ar-tn', {\n        months: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),\n        monthsShort: 'جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'),\n        weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),\n        weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),\n        weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'),\n        longDateFormat: {\n            LT: 'HH:mm',\n            LTS: 'HH:mm:ss',\n            L: 'DD/MM/YYYY',\n            LL: 'D MMMM YYYY',\n            LLL: 'D MMMM YYYY HH:mm',\n            LLLL: 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar: {\n            sameDay: '[اليوم على الساعة] LT',\n            nextDay: '[غدا على الساعة] LT',\n            nextWeek: 'dddd [على الساعة] LT',\n            lastDay: '[أمس على الساعة] LT',\n            lastWeek: 'dddd [على الساعة] LT',\n            sameElse: 'L'\n        },\n        relativeTime: {\n            future: 'في %s',\n            past: 'منذ %s',\n            s: 'ثوان',\n            m: 'دقيقة',\n            mm: '%d دقائق',\n            h: 'ساعة',\n            hh: '%d ساعات',\n            d: 'يوم',\n            dd: '%d أيام',\n            M: 'شهر',\n            MM: '%d أشهر',\n            y: 'سنة',\n            yy: '%d سنوات'\n        },\n        week: {\n            dow: 1, // Monday is the first day of the week.\n            doy: 4 // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! Locale: Arabic (ar)\n    //! Author: Abdel Said: https://github.com/abdelsaid\n    //! Changes in months, weekdays: Ahmed Elkhatib\n    //! Native plural forms: forabi https://github.com/forabi\n\n    var ar__symbolMap = {\n        '1': '١',\n        '2': '٢',\n        '3': '٣',\n        '4': '٤',\n        '5': '٥',\n        '6': '٦',\n        '7': '٧',\n        '8': '٨',\n        '9': '٩',\n        '0': '٠'\n    }, ar__numberMap = {\n        '١': '1',\n        '٢': '2',\n        '٣': '3',\n        '٤': '4',\n        '٥': '5',\n        '٦': '6',\n        '٧': '7',\n        '٨': '8',\n        '٩': '9',\n        '٠': '0'\n    }, pluralForm = function (n) {\n        return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5;\n    }, plurals = {\n        s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'],\n        m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'],\n        h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'],\n        d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'],\n        M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'],\n        y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام']\n    }, pluralize = function (u) {\n        return function (number, withoutSuffix, string, isFuture) {\n            var f = pluralForm(number),\n                str = plurals[u][pluralForm(number)];\n            if (f === 2) {\n                str = str[withoutSuffix ? 0 : 1];\n            }\n            return str.replace(/%d/i, number);\n        };\n    }, ar__months = [\n        'كانون الثاني يناير',\n        'شباط فبراير',\n        'آذار مارس',\n        'نيسان أبريل',\n        'أيار مايو',\n        'حزيران يونيو',\n        'تموز يوليو',\n        'آب أغسطس',\n        'أيلول سبتمبر',\n        'تشرين الأول أكتوبر',\n        'تشرين الثاني نوفمبر',\n        'كانون الأول ديسمبر'\n    ];\n\n    var ar = _moment__default.defineLocale('ar', {\n        months : ar__months,\n        monthsShort : ar__months,\n        weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),\n        weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),\n        weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'D/\\u200FM/\\u200FYYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        meridiemParse: /ص|م/,\n        isPM : function (input) {\n            return 'م' === input;\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 12) {\n                return 'ص';\n            } else {\n                return 'م';\n            }\n        },\n        calendar : {\n            sameDay: '[اليوم عند الساعة] LT',\n            nextDay: '[غدًا عند الساعة] LT',\n            nextWeek: 'dddd [عند الساعة] LT',\n            lastDay: '[أمس عند الساعة] LT',\n            lastWeek: 'dddd [عند الساعة] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'بعد %s',\n            past : 'منذ %s',\n            s : pluralize('s'),\n            m : pluralize('m'),\n            mm : pluralize('m'),\n            h : pluralize('h'),\n            hh : pluralize('h'),\n            d : pluralize('d'),\n            dd : pluralize('d'),\n            M : pluralize('M'),\n            MM : pluralize('M'),\n            y : pluralize('y'),\n            yy : pluralize('y')\n        },\n        preparse: function (string) {\n            return string.replace(/\\u200f/g, '').replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {\n                return ar__numberMap[match];\n            }).replace(/،/g, ',');\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return ar__symbolMap[match];\n            }).replace(/,/g, '،');\n        },\n        week : {\n            dow : 6, // Saturday is the first day of the week.\n            doy : 12  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : azerbaijani (az)\n    //! author : topchiyev : https://github.com/topchiyev\n\n    var az__suffixes = {\n        1: '-inci',\n        5: '-inci',\n        8: '-inci',\n        70: '-inci',\n        80: '-inci',\n        2: '-nci',\n        7: '-nci',\n        20: '-nci',\n        50: '-nci',\n        3: '-üncü',\n        4: '-üncü',\n        100: '-üncü',\n        6: '-ncı',\n        9: '-uncu',\n        10: '-uncu',\n        30: '-uncu',\n        60: '-ıncı',\n        90: '-ıncı'\n    };\n\n    var az = _moment__default.defineLocale('az', {\n        months : 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split('_'),\n        monthsShort : 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'),\n        weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'),\n        weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'),\n        weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay : '[bugün saat] LT',\n            nextDay : '[sabah saat] LT',\n            nextWeek : '[gələn həftə] dddd [saat] LT',\n            lastDay : '[dünən] LT',\n            lastWeek : '[keçən həftə] dddd [saat] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s sonra',\n            past : '%s əvvəl',\n            s : 'birneçə saniyyə',\n            m : 'bir dəqiqə',\n            mm : '%d dəqiqə',\n            h : 'bir saat',\n            hh : '%d saat',\n            d : 'bir gün',\n            dd : '%d gün',\n            M : 'bir ay',\n            MM : '%d ay',\n            y : 'bir il',\n            yy : '%d il'\n        },\n        meridiemParse: /gecə|səhər|gündüz|axşam/,\n        isPM : function (input) {\n            return /^(gündüz|axşam)$/.test(input);\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'gecə';\n            } else if (hour < 12) {\n                return 'səhər';\n            } else if (hour < 17) {\n                return 'gündüz';\n            } else {\n                return 'axşam';\n            }\n        },\n        ordinalParse: /\\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,\n        ordinal : function (number) {\n            if (number === 0) {  // special case for zero\n                return number + '-ıncı';\n            }\n            var a = number % 10,\n                b = number % 100 - a,\n                c = number >= 100 ? 100 : null;\n            return number + (az__suffixes[a] || az__suffixes[b] || az__suffixes[c]);\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : belarusian (be)\n    //! author : Dmitry Demidov : https://github.com/demidov91\n    //! author: Praleska: http://praleska.pro/\n    //! Author : Menelion Elensúle : https://github.com/Oire\n\n    function be__plural(word, num) {\n        var forms = word.split('_');\n        return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);\n    }\n    function be__relativeTimeWithPlural(number, withoutSuffix, key) {\n        var format = {\n            'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін',\n            'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін',\n            'dd': 'дзень_дні_дзён',\n            'MM': 'месяц_месяцы_месяцаў',\n            'yy': 'год_гады_гадоў'\n        };\n        if (key === 'm') {\n            return withoutSuffix ? 'хвіліна' : 'хвіліну';\n        }\n        else if (key === 'h') {\n            return withoutSuffix ? 'гадзіна' : 'гадзіну';\n        }\n        else {\n            return number + ' ' + be__plural(format[key], +number);\n        }\n    }\n    function be__monthsCaseReplace(m, format) {\n        var months = {\n            'nominative': 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_'),\n            'accusative': 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_')\n        },\n        nounCase = (/D[oD]?(\\[[^\\[\\]]*\\]|\\s+)+MMMM?/).test(format) ?\n            'accusative' :\n            'nominative';\n        return months[nounCase][m.month()];\n    }\n    function be__weekdaysCaseReplace(m, format) {\n        var weekdays = {\n            'nominative': 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'),\n            'accusative': 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_')\n        },\n        nounCase = (/\\[ ?[Вв] ?(?:мінулую|наступную)? ?\\] ?dddd/).test(format) ?\n            'accusative' :\n            'nominative';\n        return weekdays[nounCase][m.day()];\n    }\n\n    var be = _moment__default.defineLocale('be', {\n        months : be__monthsCaseReplace,\n        monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'),\n        weekdays : be__weekdaysCaseReplace,\n        weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),\n        weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY г.',\n            LLL : 'D MMMM YYYY г., HH:mm',\n            LLLL : 'dddd, D MMMM YYYY г., HH:mm'\n        },\n        calendar : {\n            sameDay: '[Сёння ў] LT',\n            nextDay: '[Заўтра ў] LT',\n            lastDay: '[Учора ў] LT',\n            nextWeek: function () {\n                return '[У] dddd [ў] LT';\n            },\n            lastWeek: function () {\n                switch (this.day()) {\n                case 0:\n                case 3:\n                case 5:\n                case 6:\n                    return '[У мінулую] dddd [ў] LT';\n                case 1:\n                case 2:\n                case 4:\n                    return '[У мінулы] dddd [ў] LT';\n                }\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'праз %s',\n            past : '%s таму',\n            s : 'некалькі секунд',\n            m : be__relativeTimeWithPlural,\n            mm : be__relativeTimeWithPlural,\n            h : be__relativeTimeWithPlural,\n            hh : be__relativeTimeWithPlural,\n            d : 'дзень',\n            dd : be__relativeTimeWithPlural,\n            M : 'месяц',\n            MM : be__relativeTimeWithPlural,\n            y : 'год',\n            yy : be__relativeTimeWithPlural\n        },\n        meridiemParse: /ночы|раніцы|дня|вечара/,\n        isPM : function (input) {\n            return /^(дня|вечара)$/.test(input);\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'ночы';\n            } else if (hour < 12) {\n                return 'раніцы';\n            } else if (hour < 17) {\n                return 'дня';\n            } else {\n                return 'вечара';\n            }\n        },\n        ordinalParse: /\\d{1,2}-(і|ы|га)/,\n        ordinal: function (number, period) {\n            switch (period) {\n            case 'M':\n            case 'd':\n            case 'DDD':\n            case 'w':\n            case 'W':\n                return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-і' : number + '-ы';\n            case 'D':\n                return number + '-га';\n            default:\n                return number;\n            }\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : bulgarian (bg)\n    //! author : Krasen Borisov : https://github.com/kraz\n\n    var bg = _moment__default.defineLocale('bg', {\n        months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'),\n        monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'),\n        weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'),\n        weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'),\n        weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'D.MM.YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY H:mm',\n            LLLL : 'dddd, D MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay : '[Днес в] LT',\n            nextDay : '[Утре в] LT',\n            nextWeek : 'dddd [в] LT',\n            lastDay : '[Вчера в] LT',\n            lastWeek : function () {\n                switch (this.day()) {\n                case 0:\n                case 3:\n                case 6:\n                    return '[В изминалата] dddd [в] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[В изминалия] dddd [в] LT';\n                }\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'след %s',\n            past : 'преди %s',\n            s : 'няколко секунди',\n            m : 'минута',\n            mm : '%d минути',\n            h : 'час',\n            hh : '%d часа',\n            d : 'ден',\n            dd : '%d дни',\n            M : 'месец',\n            MM : '%d месеца',\n            y : 'година',\n            yy : '%d години'\n        },\n        ordinalParse: /\\d{1,2}-(ев|ен|ти|ви|ри|ми)/,\n        ordinal : function (number) {\n            var lastDigit = number % 10,\n                last2Digits = number % 100;\n            if (number === 0) {\n                return number + '-ев';\n            } else if (last2Digits === 0) {\n                return number + '-ен';\n            } else if (last2Digits > 10 && last2Digits < 20) {\n                return number + '-ти';\n            } else if (lastDigit === 1) {\n                return number + '-ви';\n            } else if (lastDigit === 2) {\n                return number + '-ри';\n            } else if (lastDigit === 7 || lastDigit === 8) {\n                return number + '-ми';\n            } else {\n                return number + '-ти';\n            }\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Bengali (bn)\n    //! author : Kaushik Gandhi : https://github.com/kaushikgandhi\n\n    var bn__symbolMap = {\n        '1': '১',\n        '2': '২',\n        '3': '৩',\n        '4': '৪',\n        '5': '৫',\n        '6': '৬',\n        '7': '৭',\n        '8': '৮',\n        '9': '৯',\n        '0': '০'\n    },\n    bn__numberMap = {\n        '১': '1',\n        '২': '2',\n        '৩': '3',\n        '৪': '4',\n        '৫': '5',\n        '৬': '6',\n        '৭': '7',\n        '৮': '8',\n        '৯': '9',\n        '০': '0'\n    };\n\n    var bn = _moment__default.defineLocale('bn', {\n        months : 'জানুয়ারী_ফেবুয়ারী_মার্চ_এপ্রিল_মে_জুন_জুলাই_অগাস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split('_'),\n        monthsShort : 'জানু_ফেব_মার্চ_এপর_মে_জুন_জুল_অগ_সেপ্ট_অক্টো_নভ_ডিসেম্'.split('_'),\n        weekdays : 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পত্তিবার_শুক্রুবার_শনিবার'.split('_'),\n        weekdaysShort : 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পত্তি_শুক্রু_শনি'.split('_'),\n        weekdaysMin : 'রব_সম_মঙ্গ_বু_ব্রিহ_শু_শনি'.split('_'),\n        longDateFormat : {\n            LT : 'A h:mm সময়',\n            LTS : 'A h:mm:ss সময়',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY, A h:mm সময়',\n            LLLL : 'dddd, D MMMM YYYY, A h:mm সময়'\n        },\n        calendar : {\n            sameDay : '[আজ] LT',\n            nextDay : '[আগামীকাল] LT',\n            nextWeek : 'dddd, LT',\n            lastDay : '[গতকাল] LT',\n            lastWeek : '[গত] dddd, LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s পরে',\n            past : '%s আগে',\n            s : 'কএক সেকেন্ড',\n            m : 'এক মিনিট',\n            mm : '%d মিনিট',\n            h : 'এক ঘন্টা',\n            hh : '%d ঘন্টা',\n            d : 'এক দিন',\n            dd : '%d দিন',\n            M : 'এক মাস',\n            MM : '%d মাস',\n            y : 'এক বছর',\n            yy : '%d বছর'\n        },\n        preparse: function (string) {\n            return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) {\n                return bn__numberMap[match];\n            });\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return bn__symbolMap[match];\n            });\n        },\n        meridiemParse: /রাত|সকাল|দুপুর|বিকেল|রাত/,\n        isPM: function (input) {\n            return /^(দুপুর|বিকেল|রাত)$/.test(input);\n        },\n        //Bengali is a vast language its spoken\n        //in different forms in various parts of the world.\n        //I have just generalized with most common one used\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'রাত';\n            } else if (hour < 10) {\n                return 'সকাল';\n            } else if (hour < 17) {\n                return 'দুপুর';\n            } else if (hour < 20) {\n                return 'বিকেল';\n            } else {\n                return 'রাত';\n            }\n        },\n        week : {\n            dow : 0, // Sunday is the first day of the week.\n            doy : 6  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : tibetan (bo)\n    //! author : Thupten N. Chakrishar : https://github.com/vajradog\n\n    var bo__symbolMap = {\n        '1': '༡',\n        '2': '༢',\n        '3': '༣',\n        '4': '༤',\n        '5': '༥',\n        '6': '༦',\n        '7': '༧',\n        '8': '༨',\n        '9': '༩',\n        '0': '༠'\n    },\n    bo__numberMap = {\n        '༡': '1',\n        '༢': '2',\n        '༣': '3',\n        '༤': '4',\n        '༥': '5',\n        '༦': '6',\n        '༧': '7',\n        '༨': '8',\n        '༩': '9',\n        '༠': '0'\n    };\n\n    var bo = _moment__default.defineLocale('bo', {\n        months : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),\n        monthsShort : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'),\n        weekdays : 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split('_'),\n        weekdaysShort : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),\n        weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),\n        longDateFormat : {\n            LT : 'A h:mm',\n            LTS : 'A h:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY, A h:mm',\n            LLLL : 'dddd, D MMMM YYYY, A h:mm'\n        },\n        calendar : {\n            sameDay : '[དི་རིང] LT',\n            nextDay : '[སང་ཉིན] LT',\n            nextWeek : '[བདུན་ཕྲག་རྗེས་མ], LT',\n            lastDay : '[ཁ་སང] LT',\n            lastWeek : '[བདུན་ཕྲག་མཐའ་མ] dddd, LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s ལ་',\n            past : '%s སྔན་ལ',\n            s : 'ལམ་སང',\n            m : 'སྐར་མ་གཅིག',\n            mm : '%d སྐར་མ',\n            h : 'ཆུ་ཚོད་གཅིག',\n            hh : '%d ཆུ་ཚོད',\n            d : 'ཉིན་གཅིག',\n            dd : '%d ཉིན་',\n            M : 'ཟླ་བ་གཅིག',\n            MM : '%d ཟླ་བ',\n            y : 'ལོ་གཅིག',\n            yy : '%d ལོ'\n        },\n        preparse: function (string) {\n            return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) {\n                return bo__numberMap[match];\n            });\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return bo__symbolMap[match];\n            });\n        },\n        meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,\n        isPM: function (input) {\n            return /^(ཉིན་གུང|དགོང་དག|མཚན་མོ)$/.test(input);\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'མཚན་མོ';\n            } else if (hour < 10) {\n                return 'ཞོགས་ཀས';\n            } else if (hour < 17) {\n                return 'ཉིན་གུང';\n            } else if (hour < 20) {\n                return 'དགོང་དག';\n            } else {\n                return 'མཚན་མོ';\n            }\n        },\n        week : {\n            dow : 0, // Sunday is the first day of the week.\n            doy : 6  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : breton (br)\n    //! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou\n\n    function relativeTimeWithMutation(number, withoutSuffix, key) {\n        var format = {\n            'mm': 'munutenn',\n            'MM': 'miz',\n            'dd': 'devezh'\n        };\n        return number + ' ' + mutation(format[key], number);\n    }\n    function specialMutationForYears(number) {\n        switch (lastNumber(number)) {\n        case 1:\n        case 3:\n        case 4:\n        case 5:\n        case 9:\n            return number + ' bloaz';\n        default:\n            return number + ' vloaz';\n        }\n    }\n    function lastNumber(number) {\n        if (number > 9) {\n            return lastNumber(number % 10);\n        }\n        return number;\n    }\n    function mutation(text, number) {\n        if (number === 2) {\n            return softMutation(text);\n        }\n        return text;\n    }\n    function softMutation(text) {\n        var mutationTable = {\n            'm': 'v',\n            'b': 'v',\n            'd': 'z'\n        };\n        if (mutationTable[text.charAt(0)] === undefined) {\n            return text;\n        }\n        return mutationTable[text.charAt(0)] + text.substring(1);\n    }\n\n    var br = _moment__default.defineLocale('br', {\n        months : 'Genver_C\\'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split('_'),\n        monthsShort : 'Gen_C\\'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'),\n        weekdays : 'Sul_Lun_Meurzh_Merc\\'her_Yaou_Gwener_Sadorn'.split('_'),\n        weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'),\n        weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'),\n        longDateFormat : {\n            LT : 'h[e]mm A',\n            LTS : 'h[e]mm:ss A',\n            L : 'DD/MM/YYYY',\n            LL : 'D [a viz] MMMM YYYY',\n            LLL : 'D [a viz] MMMM YYYY h[e]mm A',\n            LLLL : 'dddd, D [a viz] MMMM YYYY h[e]mm A'\n        },\n        calendar : {\n            sameDay : '[Hiziv da] LT',\n            nextDay : '[Warc\\'hoazh da] LT',\n            nextWeek : 'dddd [da] LT',\n            lastDay : '[Dec\\'h da] LT',\n            lastWeek : 'dddd [paset da] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'a-benn %s',\n            past : '%s \\'zo',\n            s : 'un nebeud segondennoù',\n            m : 'ur vunutenn',\n            mm : relativeTimeWithMutation,\n            h : 'un eur',\n            hh : '%d eur',\n            d : 'un devezh',\n            dd : relativeTimeWithMutation,\n            M : 'ur miz',\n            MM : relativeTimeWithMutation,\n            y : 'ur bloaz',\n            yy : specialMutationForYears\n        },\n        ordinalParse: /\\d{1,2}(añ|vet)/,\n        ordinal : function (number) {\n            var output = (number === 1) ? 'añ' : 'vet';\n            return number + output;\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : bosnian (bs)\n    //! author : Nedim Cholich : https://github.com/frontyard\n    //! based on (hr) translation by Bojan Marković\n\n    function bs__translate(number, withoutSuffix, key) {\n        var result = number + ' ';\n        switch (key) {\n        case 'm':\n            return withoutSuffix ? 'jedna minuta' : 'jedne minute';\n        case 'mm':\n            if (number === 1) {\n                result += 'minuta';\n            } else if (number === 2 || number === 3 || number === 4) {\n                result += 'minute';\n            } else {\n                result += 'minuta';\n            }\n            return result;\n        case 'h':\n            return withoutSuffix ? 'jedan sat' : 'jednog sata';\n        case 'hh':\n            if (number === 1) {\n                result += 'sat';\n            } else if (number === 2 || number === 3 || number === 4) {\n                result += 'sata';\n            } else {\n                result += 'sati';\n            }\n            return result;\n        case 'dd':\n            if (number === 1) {\n                result += 'dan';\n            } else {\n                result += 'dana';\n            }\n            return result;\n        case 'MM':\n            if (number === 1) {\n                result += 'mjesec';\n            } else if (number === 2 || number === 3 || number === 4) {\n                result += 'mjeseca';\n            } else {\n                result += 'mjeseci';\n            }\n            return result;\n        case 'yy':\n            if (number === 1) {\n                result += 'godina';\n            } else if (number === 2 || number === 3 || number === 4) {\n                result += 'godine';\n            } else {\n                result += 'godina';\n            }\n            return result;\n        }\n    }\n\n    var bs = _moment__default.defineLocale('bs', {\n        months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'),\n        monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'),\n        weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),\n        weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),\n        weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD. MM. YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY H:mm',\n            LLLL : 'dddd, D. MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay  : '[danas u] LT',\n            nextDay  : '[sutra u] LT',\n            nextWeek : function () {\n                switch (this.day()) {\n                case 0:\n                    return '[u] [nedjelju] [u] LT';\n                case 3:\n                    return '[u] [srijedu] [u] LT';\n                case 6:\n                    return '[u] [subotu] [u] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[u] dddd [u] LT';\n                }\n            },\n            lastDay  : '[jučer u] LT',\n            lastWeek : function () {\n                switch (this.day()) {\n                case 0:\n                case 3:\n                    return '[prošlu] dddd [u] LT';\n                case 6:\n                    return '[prošle] [subote] [u] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[prošli] dddd [u] LT';\n                }\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'za %s',\n            past   : 'prije %s',\n            s      : 'par sekundi',\n            m      : bs__translate,\n            mm     : bs__translate,\n            h      : bs__translate,\n            hh     : bs__translate,\n            d      : 'dan',\n            dd     : bs__translate,\n            M      : 'mjesec',\n            MM     : bs__translate,\n            y      : 'godinu',\n            yy     : bs__translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : catalan (ca)\n    //! author : Juan G. Hurtado : https://github.com/juanghurtado\n\n    var ca = _moment__default.defineLocale('ca', {\n        months : 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split('_'),\n        monthsShort : 'gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.'.split('_'),\n        weekdays : 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split('_'),\n        weekdaysShort : 'dg._dl._dt._dc._dj._dv._ds.'.split('_'),\n        weekdaysMin : 'Dg_Dl_Dt_Dc_Dj_Dv_Ds'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'LT:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY H:mm',\n            LLLL : 'dddd D MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay : function () {\n                return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';\n            },\n            nextDay : function () {\n                return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';\n            },\n            nextWeek : function () {\n                return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';\n            },\n            lastDay : function () {\n                return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';\n            },\n            lastWeek : function () {\n                return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT';\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'en %s',\n            past : 'fa %s',\n            s : 'uns segons',\n            m : 'un minut',\n            mm : '%d minuts',\n            h : 'una hora',\n            hh : '%d hores',\n            d : 'un dia',\n            dd : '%d dies',\n            M : 'un mes',\n            MM : '%d mesos',\n            y : 'un any',\n            yy : '%d anys'\n        },\n        ordinalParse: /\\d{1,2}(r|n|t|è|a)/,\n        ordinal : function (number, period) {\n            var output = (number === 1) ? 'r' :\n                (number === 2) ? 'n' :\n                (number === 3) ? 'r' :\n                (number === 4) ? 't' : 'è';\n            if (period === 'w' || period === 'W') {\n                output = 'a';\n            }\n            return number + output;\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : czech (cs)\n    //! author : petrbela : https://github.com/petrbela\n\n    var cs__months = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_'),\n        cs__monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_');\n    function cs__plural(n) {\n        return (n > 1) && (n < 5) && (~~(n / 10) !== 1);\n    }\n    function cs__translate(number, withoutSuffix, key, isFuture) {\n        var result = number + ' ';\n        switch (key) {\n        case 's':  // a few seconds / in a few seconds / a few seconds ago\n            return (withoutSuffix || isFuture) ? 'pár sekund' : 'pár sekundami';\n        case 'm':  // a minute / in a minute / a minute ago\n            return withoutSuffix ? 'minuta' : (isFuture ? 'minutu' : 'minutou');\n        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago\n            if (withoutSuffix || isFuture) {\n                return result + (cs__plural(number) ? 'minuty' : 'minut');\n            } else {\n                return result + 'minutami';\n            }\n            break;\n        case 'h':  // an hour / in an hour / an hour ago\n            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');\n        case 'hh': // 9 hours / in 9 hours / 9 hours ago\n            if (withoutSuffix || isFuture) {\n                return result + (cs__plural(number) ? 'hodiny' : 'hodin');\n            } else {\n                return result + 'hodinami';\n            }\n            break;\n        case 'd':  // a day / in a day / a day ago\n            return (withoutSuffix || isFuture) ? 'den' : 'dnem';\n        case 'dd': // 9 days / in 9 days / 9 days ago\n            if (withoutSuffix || isFuture) {\n                return result + (cs__plural(number) ? 'dny' : 'dní');\n            } else {\n                return result + 'dny';\n            }\n            break;\n        case 'M':  // a month / in a month / a month ago\n            return (withoutSuffix || isFuture) ? 'měsíc' : 'měsícem';\n        case 'MM': // 9 months / in 9 months / 9 months ago\n            if (withoutSuffix || isFuture) {\n                return result + (cs__plural(number) ? 'měsíce' : 'měsíců');\n            } else {\n                return result + 'měsíci';\n            }\n            break;\n        case 'y':  // a year / in a year / a year ago\n            return (withoutSuffix || isFuture) ? 'rok' : 'rokem';\n        case 'yy': // 9 years / in 9 years / 9 years ago\n            if (withoutSuffix || isFuture) {\n                return result + (cs__plural(number) ? 'roky' : 'let');\n            } else {\n                return result + 'lety';\n            }\n            break;\n        }\n    }\n\n    var cs = _moment__default.defineLocale('cs', {\n        months : cs__months,\n        monthsShort : cs__monthsShort,\n        monthsParse : (function (months, monthsShort) {\n            var i, _monthsParse = [];\n            for (i = 0; i < 12; i++) {\n                // use custom parser to solve problem with July (červenec)\n                _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i');\n            }\n            return _monthsParse;\n        }(cs__months, cs__monthsShort)),\n        weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'),\n        weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'),\n        weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'),\n        longDateFormat : {\n            LT: 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY H:mm',\n            LLLL : 'dddd D. MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay: '[dnes v] LT',\n            nextDay: '[zítra v] LT',\n            nextWeek: function () {\n                switch (this.day()) {\n                case 0:\n                    return '[v neděli v] LT';\n                case 1:\n                case 2:\n                    return '[v] dddd [v] LT';\n                case 3:\n                    return '[ve středu v] LT';\n                case 4:\n                    return '[ve čtvrtek v] LT';\n                case 5:\n                    return '[v pátek v] LT';\n                case 6:\n                    return '[v sobotu v] LT';\n                }\n            },\n            lastDay: '[včera v] LT',\n            lastWeek: function () {\n                switch (this.day()) {\n                case 0:\n                    return '[minulou neděli v] LT';\n                case 1:\n                case 2:\n                    return '[minulé] dddd [v] LT';\n                case 3:\n                    return '[minulou středu v] LT';\n                case 4:\n                case 5:\n                    return '[minulý] dddd [v] LT';\n                case 6:\n                    return '[minulou sobotu v] LT';\n                }\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'za %s',\n            past : 'před %s',\n            s : cs__translate,\n            m : cs__translate,\n            mm : cs__translate,\n            h : cs__translate,\n            hh : cs__translate,\n            d : cs__translate,\n            dd : cs__translate,\n            M : cs__translate,\n            MM : cs__translate,\n            y : cs__translate,\n            yy : cs__translate\n        },\n        ordinalParse : /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : chuvash (cv)\n    //! author : Anatoly Mironov : https://github.com/mirontoli\n\n    var cv = _moment__default.defineLocale('cv', {\n        months : 'кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав'.split('_'),\n        monthsShort : 'кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш'.split('_'),\n        weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун'.split('_'),\n        weekdaysShort : 'выр_тун_ытл_юн_кӗҫ_эрн_шӑм'.split('_'),\n        weekdaysMin : 'вр_тн_ыт_юн_кҫ_эр_шм'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD-MM-YYYY',\n            LL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]',\n            LLL : 'YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm',\n            LLLL : 'dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm'\n        },\n        calendar : {\n            sameDay: '[Паян] LT [сехетре]',\n            nextDay: '[Ыран] LT [сехетре]',\n            lastDay: '[Ӗнер] LT [сехетре]',\n            nextWeek: '[Ҫитес] dddd LT [сехетре]',\n            lastWeek: '[Иртнӗ] dddd LT [сехетре]',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : function (output) {\n                var affix = /сехет$/i.exec(output) ? 'рен' : /ҫул$/i.exec(output) ? 'тан' : 'ран';\n                return output + affix;\n            },\n            past : '%s каялла',\n            s : 'пӗр-ик ҫеккунт',\n            m : 'пӗр минут',\n            mm : '%d минут',\n            h : 'пӗр сехет',\n            hh : '%d сехет',\n            d : 'пӗр кун',\n            dd : '%d кун',\n            M : 'пӗр уйӑх',\n            MM : '%d уйӑх',\n            y : 'пӗр ҫул',\n            yy : '%d ҫул'\n        },\n        ordinalParse: /\\d{1,2}-мӗш/,\n        ordinal : '%d-мӗш',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Welsh (cy)\n    //! author : Robert Allen\n\n    var cy = _moment__default.defineLocale('cy', {\n        months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split('_'),\n        monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split('_'),\n        weekdays: 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split('_'),\n        weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'),\n        weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'),\n        // time formats are the same as en-gb\n        longDateFormat: {\n            LT: 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L: 'DD/MM/YYYY',\n            LL: 'D MMMM YYYY',\n            LLL: 'D MMMM YYYY HH:mm',\n            LLLL: 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar: {\n            sameDay: '[Heddiw am] LT',\n            nextDay: '[Yfory am] LT',\n            nextWeek: 'dddd [am] LT',\n            lastDay: '[Ddoe am] LT',\n            lastWeek: 'dddd [diwethaf am] LT',\n            sameElse: 'L'\n        },\n        relativeTime: {\n            future: 'mewn %s',\n            past: '%s yn ôl',\n            s: 'ychydig eiliadau',\n            m: 'munud',\n            mm: '%d munud',\n            h: 'awr',\n            hh: '%d awr',\n            d: 'diwrnod',\n            dd: '%d diwrnod',\n            M: 'mis',\n            MM: '%d mis',\n            y: 'blwyddyn',\n            yy: '%d flynedd'\n        },\n        ordinalParse: /\\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,\n        // traditional ordinal numbers above 31 are not commonly used in colloquial Welsh\n        ordinal: function (number) {\n            var b = number,\n                output = '',\n                lookup = [\n                    '', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed\n                    'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed' // 11eg to 20fed\n                ];\n            if (b > 20) {\n                if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) {\n                    output = 'fed'; // not 30ain, 70ain or 90ain\n                } else {\n                    output = 'ain';\n                }\n            } else if (b > 0) {\n                output = lookup[b];\n            }\n            return number + output;\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : danish (da)\n    //! author : Ulrik Nielsen : https://github.com/mrbase\n\n    var da = _moment__default.defineLocale('da', {\n        months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'),\n        monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),\n        weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),\n        weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'),\n        weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY HH:mm',\n            LLLL : 'dddd [d.] D. MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay : '[I dag kl.] LT',\n            nextDay : '[I morgen kl.] LT',\n            nextWeek : 'dddd [kl.] LT',\n            lastDay : '[I går kl.] LT',\n            lastWeek : '[sidste] dddd [kl] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'om %s',\n            past : '%s siden',\n            s : 'få sekunder',\n            m : 'et minut',\n            mm : '%d minutter',\n            h : 'en time',\n            hh : '%d timer',\n            d : 'en dag',\n            dd : '%d dage',\n            M : 'en måned',\n            MM : '%d måneder',\n            y : 'et år',\n            yy : '%d år'\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : austrian german (de-at)\n    //! author : lluchs : https://github.com/lluchs\n    //! author: Menelion Elensúle: https://github.com/Oire\n    //! author : Martin Groller : https://github.com/MadMG\n\n    function de_at__processRelativeTime(number, withoutSuffix, key, isFuture) {\n        var format = {\n            'm': ['eine Minute', 'einer Minute'],\n            'h': ['eine Stunde', 'einer Stunde'],\n            'd': ['ein Tag', 'einem Tag'],\n            'dd': [number + ' Tage', number + ' Tagen'],\n            'M': ['ein Monat', 'einem Monat'],\n            'MM': [number + ' Monate', number + ' Monaten'],\n            'y': ['ein Jahr', 'einem Jahr'],\n            'yy': [number + ' Jahre', number + ' Jahren']\n        };\n        return withoutSuffix ? format[key][0] : format[key][1];\n    }\n\n    var de_at = _moment__default.defineLocale('de-at', {\n        months : 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),\n        monthsShort : 'Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),\n        weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),\n        weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),\n        weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),\n        longDateFormat : {\n            LT: 'HH:mm',\n            LTS: 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY HH:mm',\n            LLLL : 'dddd, D. MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Heute um] LT [Uhr]',\n            sameElse: 'L',\n            nextDay: '[Morgen um] LT [Uhr]',\n            nextWeek: 'dddd [um] LT [Uhr]',\n            lastDay: '[Gestern um] LT [Uhr]',\n            lastWeek: '[letzten] dddd [um] LT [Uhr]'\n        },\n        relativeTime : {\n            future : 'in %s',\n            past : 'vor %s',\n            s : 'ein paar Sekunden',\n            m : de_at__processRelativeTime,\n            mm : '%d Minuten',\n            h : de_at__processRelativeTime,\n            hh : '%d Stunden',\n            d : de_at__processRelativeTime,\n            dd : de_at__processRelativeTime,\n            M : de_at__processRelativeTime,\n            MM : de_at__processRelativeTime,\n            y : de_at__processRelativeTime,\n            yy : de_at__processRelativeTime\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : german (de)\n    //! author : lluchs : https://github.com/lluchs\n    //! author: Menelion Elensúle: https://github.com/Oire\n\n    function de__processRelativeTime(number, withoutSuffix, key, isFuture) {\n        var format = {\n            'm': ['eine Minute', 'einer Minute'],\n            'h': ['eine Stunde', 'einer Stunde'],\n            'd': ['ein Tag', 'einem Tag'],\n            'dd': [number + ' Tage', number + ' Tagen'],\n            'M': ['ein Monat', 'einem Monat'],\n            'MM': [number + ' Monate', number + ' Monaten'],\n            'y': ['ein Jahr', 'einem Jahr'],\n            'yy': [number + ' Jahre', number + ' Jahren']\n        };\n        return withoutSuffix ? format[key][0] : format[key][1];\n    }\n\n    var de = _moment__default.defineLocale('de', {\n        months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),\n        monthsShort : 'Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),\n        weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'),\n        weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),\n        weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),\n        longDateFormat : {\n            LT: 'HH:mm',\n            LTS: 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY HH:mm',\n            LLLL : 'dddd, D. MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Heute um] LT [Uhr]',\n            sameElse: 'L',\n            nextDay: '[Morgen um] LT [Uhr]',\n            nextWeek: 'dddd [um] LT [Uhr]',\n            lastDay: '[Gestern um] LT [Uhr]',\n            lastWeek: '[letzten] dddd [um] LT [Uhr]'\n        },\n        relativeTime : {\n            future : 'in %s',\n            past : 'vor %s',\n            s : 'ein paar Sekunden',\n            m : de__processRelativeTime,\n            mm : '%d Minuten',\n            h : de__processRelativeTime,\n            hh : '%d Stunden',\n            d : de__processRelativeTime,\n            dd : de__processRelativeTime,\n            M : de__processRelativeTime,\n            MM : de__processRelativeTime,\n            y : de__processRelativeTime,\n            yy : de__processRelativeTime\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : modern greek (el)\n    //! author : Aggelos Karalias : https://github.com/mehiel\n\n    var el = _moment__default.defineLocale('el', {\n        monthsNominativeEl : 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'),\n        monthsGenitiveEl : 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split('_'),\n        months : function (momentToFormat, format) {\n            if (/D/.test(format.substring(0, format.indexOf('MMMM')))) { // if there is a day number before 'MMMM'\n                return this._monthsGenitiveEl[momentToFormat.month()];\n            } else {\n                return this._monthsNominativeEl[momentToFormat.month()];\n            }\n        },\n        monthsShort : 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'),\n        weekdays : 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'),\n        weekdaysShort : 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'),\n        weekdaysMin : 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'),\n        meridiem : function (hours, minutes, isLower) {\n            if (hours > 11) {\n                return isLower ? 'μμ' : 'ΜΜ';\n            } else {\n                return isLower ? 'πμ' : 'ΠΜ';\n            }\n        },\n        isPM : function (input) {\n            return ((input + '').toLowerCase()[0] === 'μ');\n        },\n        meridiemParse : /[ΠΜ]\\.?Μ?\\.?/i,\n        longDateFormat : {\n            LT : 'h:mm A',\n            LTS : 'h:mm:ss A',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY h:mm A',\n            LLLL : 'dddd, D MMMM YYYY h:mm A'\n        },\n        calendarEl : {\n            sameDay : '[Σήμερα {}] LT',\n            nextDay : '[Αύριο {}] LT',\n            nextWeek : 'dddd [{}] LT',\n            lastDay : '[Χθες {}] LT',\n            lastWeek : function () {\n                switch (this.day()) {\n                    case 6:\n                        return '[το προηγούμενο] dddd [{}] LT';\n                    default:\n                        return '[την προηγούμενη] dddd [{}] LT';\n                }\n            },\n            sameElse : 'L'\n        },\n        calendar : function (key, mom) {\n            var output = this._calendarEl[key],\n                hours = mom && mom.hours();\n            if (typeof output === 'function') {\n                output = output.apply(mom);\n            }\n            return output.replace('{}', (hours % 12 === 1 ? 'στη' : 'στις'));\n        },\n        relativeTime : {\n            future : 'σε %s',\n            past : '%s πριν',\n            s : 'λίγα δευτερόλεπτα',\n            m : 'ένα λεπτό',\n            mm : '%d λεπτά',\n            h : 'μία ώρα',\n            hh : '%d ώρες',\n            d : 'μία μέρα',\n            dd : '%d μέρες',\n            M : 'ένας μήνας',\n            MM : '%d μήνες',\n            y : 'ένας χρόνος',\n            yy : '%d χρόνια'\n        },\n        ordinalParse: /\\d{1,2}η/,\n        ordinal: '%dη',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : australian english (en-au)\n\n    var en_au = _moment__default.defineLocale('en-au', {\n        months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),\n        monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),\n        weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),\n        weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),\n        weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),\n        longDateFormat : {\n            LT : 'h:mm A',\n            LTS : 'h:mm:ss A',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY h:mm A',\n            LLLL : 'dddd, D MMMM YYYY h:mm A'\n        },\n        calendar : {\n            sameDay : '[Today at] LT',\n            nextDay : '[Tomorrow at] LT',\n            nextWeek : 'dddd [at] LT',\n            lastDay : '[Yesterday at] LT',\n            lastWeek : '[Last] dddd [at] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'in %s',\n            past : '%s ago',\n            s : 'a few seconds',\n            m : 'a minute',\n            mm : '%d minutes',\n            h : 'an hour',\n            hh : '%d hours',\n            d : 'a day',\n            dd : '%d days',\n            M : 'a month',\n            MM : '%d months',\n            y : 'a year',\n            yy : '%d years'\n        },\n        ordinalParse: /\\d{1,2}(st|nd|rd|th)/,\n        ordinal : function (number) {\n            var b = number % 10,\n                output = (~~(number % 100 / 10) === 1) ? 'th' :\n                (b === 1) ? 'st' :\n                (b === 2) ? 'nd' :\n                (b === 3) ? 'rd' : 'th';\n            return number + output;\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : canadian english (en-ca)\n    //! author : Jonathan Abourbih : https://github.com/jonbca\n\n    var en_ca = _moment__default.defineLocale('en-ca', {\n        months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),\n        monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),\n        weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),\n        weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),\n        weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),\n        longDateFormat : {\n            LT : 'h:mm A',\n            LTS : 'h:mm:ss A',\n            L : 'YYYY-MM-DD',\n            LL : 'D MMMM, YYYY',\n            LLL : 'D MMMM, YYYY h:mm A',\n            LLLL : 'dddd, D MMMM, YYYY h:mm A'\n        },\n        calendar : {\n            sameDay : '[Today at] LT',\n            nextDay : '[Tomorrow at] LT',\n            nextWeek : 'dddd [at] LT',\n            lastDay : '[Yesterday at] LT',\n            lastWeek : '[Last] dddd [at] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'in %s',\n            past : '%s ago',\n            s : 'a few seconds',\n            m : 'a minute',\n            mm : '%d minutes',\n            h : 'an hour',\n            hh : '%d hours',\n            d : 'a day',\n            dd : '%d days',\n            M : 'a month',\n            MM : '%d months',\n            y : 'a year',\n            yy : '%d years'\n        },\n        ordinalParse: /\\d{1,2}(st|nd|rd|th)/,\n        ordinal : function (number) {\n            var b = number % 10,\n                output = (~~(number % 100 / 10) === 1) ? 'th' :\n                (b === 1) ? 'st' :\n                (b === 2) ? 'nd' :\n                (b === 3) ? 'rd' : 'th';\n            return number + output;\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : great britain english (en-gb)\n    //! author : Chris Gedrim : https://github.com/chrisgedrim\n\n    var en_gb = _moment__default.defineLocale('en-gb', {\n        months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),\n        monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'),\n        weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'),\n        weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'),\n        weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay : '[Today at] LT',\n            nextDay : '[Tomorrow at] LT',\n            nextWeek : 'dddd [at] LT',\n            lastDay : '[Yesterday at] LT',\n            lastWeek : '[Last] dddd [at] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'in %s',\n            past : '%s ago',\n            s : 'a few seconds',\n            m : 'a minute',\n            mm : '%d minutes',\n            h : 'an hour',\n            hh : '%d hours',\n            d : 'a day',\n            dd : '%d days',\n            M : 'a month',\n            MM : '%d months',\n            y : 'a year',\n            yy : '%d years'\n        },\n        ordinalParse: /\\d{1,2}(st|nd|rd|th)/,\n        ordinal : function (number) {\n            var b = number % 10,\n                output = (~~(number % 100 / 10) === 1) ? 'th' :\n                (b === 1) ? 'st' :\n                (b === 2) ? 'nd' :\n                (b === 3) ? 'rd' : 'th';\n            return number + output;\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : esperanto (eo)\n    //! author : Colin Dean : https://github.com/colindean\n    //! komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko.\n    //!          Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni!\n\n    var eo = _moment__default.defineLocale('eo', {\n        months : 'januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro'.split('_'),\n        monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aŭg_sep_okt_nov_dec'.split('_'),\n        weekdays : 'Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato'.split('_'),\n        weekdaysShort : 'Dim_Lun_Mard_Merk_Ĵaŭ_Ven_Sab'.split('_'),\n        weekdaysMin : 'Di_Lu_Ma_Me_Ĵa_Ve_Sa'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'YYYY-MM-DD',\n            LL : 'D[-an de] MMMM, YYYY',\n            LLL : 'D[-an de] MMMM, YYYY HH:mm',\n            LLLL : 'dddd, [la] D[-an de] MMMM, YYYY HH:mm'\n        },\n        meridiemParse: /[ap]\\.t\\.m/i,\n        isPM: function (input) {\n            return input.charAt(0).toLowerCase() === 'p';\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours > 11) {\n                return isLower ? 'p.t.m.' : 'P.T.M.';\n            } else {\n                return isLower ? 'a.t.m.' : 'A.T.M.';\n            }\n        },\n        calendar : {\n            sameDay : '[Hodiaŭ je] LT',\n            nextDay : '[Morgaŭ je] LT',\n            nextWeek : 'dddd [je] LT',\n            lastDay : '[Hieraŭ je] LT',\n            lastWeek : '[pasinta] dddd [je] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'je %s',\n            past : 'antaŭ %s',\n            s : 'sekundoj',\n            m : 'minuto',\n            mm : '%d minutoj',\n            h : 'horo',\n            hh : '%d horoj',\n            d : 'tago',//ne 'diurno', ĉar estas uzita por proksimumo\n            dd : '%d tagoj',\n            M : 'monato',\n            MM : '%d monatoj',\n            y : 'jaro',\n            yy : '%d jaroj'\n        },\n        ordinalParse: /\\d{1,2}a/,\n        ordinal : '%da',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : spanish (es)\n    //! author : Julio Napurí : https://github.com/julionc\n\n    var monthsShortDot = 'Ene._Feb._Mar._Abr._May._Jun._Jul._Ago._Sep._Oct._Nov._Dic.'.split('_'),\n        es__monthsShort = 'Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Sep_Oct_Nov_Dic'.split('_');\n\n    var es = _moment__default.defineLocale('es', {\n        months : 'Enero_Febrero_Marzo_Abril_Mayo_Junio_Julio_Agosto_Septiembre_Octubre_Noviembre_Diciembre'.split('_'),\n        monthsShort : function (m, format) {\n            if (/-MMM-/.test(format)) {\n                return es__monthsShort[m.month()];\n            } else {\n                return monthsShortDot[m.month()];\n            }\n        },\n        weekdays : 'Domingo_Lunes_Martes_Miércoles_Jueves_Viernes_Sábado'.split('_'),\n        weekdaysShort : 'Dom._Lun._Mar._Mié._Jue._Vie._Sáb.'.split('_'),\n        weekdaysMin : 'Do_Lu_Ma_Mi_Ju_Vi_Sá'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D [de] MMMM [de] YYYY',\n            LLL : 'D [de] MMMM [de] YYYY H:mm',\n            LLLL : 'dddd, D [de] MMMM [de] YYYY H:mm'\n        },\n        calendar : {\n            sameDay : function () {\n                return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';\n            },\n            nextDay : function () {\n                return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';\n            },\n            nextWeek : function () {\n                return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';\n            },\n            lastDay : function () {\n                return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';\n            },\n            lastWeek : function () {\n                return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT';\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'en %s',\n            past : 'hace %s',\n            s : 'unos segundos',\n            m : 'un minuto',\n            mm : '%d minutos',\n            h : 'una hora',\n            hh : '%d horas',\n            d : 'un día',\n            dd : '%d días',\n            M : 'un mes',\n            MM : '%d meses',\n            y : 'un año',\n            yy : '%d años'\n        },\n        ordinalParse : /\\d{1,2}º/,\n        ordinal : '%dº',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : estonian (et)\n    //! author : Henry Kehlmann : https://github.com/madhenry\n    //! improvements : Illimar Tambek : https://github.com/ragulka\n\n    function et__processRelativeTime(number, withoutSuffix, key, isFuture) {\n        var format = {\n            's' : ['mõne sekundi', 'mõni sekund', 'paar sekundit'],\n            'm' : ['ühe minuti', 'üks minut'],\n            'mm': [number + ' minuti', number + ' minutit'],\n            'h' : ['ühe tunni', 'tund aega', 'üks tund'],\n            'hh': [number + ' tunni', number + ' tundi'],\n            'd' : ['ühe päeva', 'üks päev'],\n            'M' : ['kuu aja', 'kuu aega', 'üks kuu'],\n            'MM': [number + ' kuu', number + ' kuud'],\n            'y' : ['ühe aasta', 'aasta', 'üks aasta'],\n            'yy': [number + ' aasta', number + ' aastat']\n        };\n        if (withoutSuffix) {\n            return format[key][2] ? format[key][2] : format[key][1];\n        }\n        return isFuture ? format[key][0] : format[key][1];\n    }\n\n    var et = _moment__default.defineLocale('et', {\n        months        : 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split('_'),\n        monthsShort   : 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'),\n        weekdays      : 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split('_'),\n        weekdaysShort : 'P_E_T_K_N_R_L'.split('_'),\n        weekdaysMin   : 'P_E_T_K_N_R_L'.split('_'),\n        longDateFormat : {\n            LT   : 'H:mm',\n            LTS : 'H:mm:ss',\n            L    : 'DD.MM.YYYY',\n            LL   : 'D. MMMM YYYY',\n            LLL  : 'D. MMMM YYYY H:mm',\n            LLLL : 'dddd, D. MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay  : '[Täna,] LT',\n            nextDay  : '[Homme,] LT',\n            nextWeek : '[Järgmine] dddd LT',\n            lastDay  : '[Eile,] LT',\n            lastWeek : '[Eelmine] dddd LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s pärast',\n            past   : '%s tagasi',\n            s      : et__processRelativeTime,\n            m      : et__processRelativeTime,\n            mm     : et__processRelativeTime,\n            h      : et__processRelativeTime,\n            hh     : et__processRelativeTime,\n            d      : et__processRelativeTime,\n            dd     : '%d päeva',\n            M      : et__processRelativeTime,\n            MM     : et__processRelativeTime,\n            y      : et__processRelativeTime,\n            yy     : et__processRelativeTime\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : euskara (eu)\n    //! author : Eneko Illarramendi : https://github.com/eillarra\n\n    var eu = _moment__default.defineLocale('eu', {\n        months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'),\n        monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'),\n        weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'),\n        weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'),\n        weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'YYYY-MM-DD',\n            LL : 'YYYY[ko] MMMM[ren] D[a]',\n            LLL : 'YYYY[ko] MMMM[ren] D[a] HH:mm',\n            LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] HH:mm',\n            l : 'YYYY-M-D',\n            ll : 'YYYY[ko] MMM D[a]',\n            lll : 'YYYY[ko] MMM D[a] HH:mm',\n            llll : 'ddd, YYYY[ko] MMM D[a] HH:mm'\n        },\n        calendar : {\n            sameDay : '[gaur] LT[etan]',\n            nextDay : '[bihar] LT[etan]',\n            nextWeek : 'dddd LT[etan]',\n            lastDay : '[atzo] LT[etan]',\n            lastWeek : '[aurreko] dddd LT[etan]',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s barru',\n            past : 'duela %s',\n            s : 'segundo batzuk',\n            m : 'minutu bat',\n            mm : '%d minutu',\n            h : 'ordu bat',\n            hh : '%d ordu',\n            d : 'egun bat',\n            dd : '%d egun',\n            M : 'hilabete bat',\n            MM : '%d hilabete',\n            y : 'urte bat',\n            yy : '%d urte'\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Persian (fa)\n    //! author : Ebrahim Byagowi : https://github.com/ebraminio\n\n    var fa__symbolMap = {\n        '1': '۱',\n        '2': '۲',\n        '3': '۳',\n        '4': '۴',\n        '5': '۵',\n        '6': '۶',\n        '7': '۷',\n        '8': '۸',\n        '9': '۹',\n        '0': '۰'\n    }, fa__numberMap = {\n        '۱': '1',\n        '۲': '2',\n        '۳': '3',\n        '۴': '4',\n        '۵': '5',\n        '۶': '6',\n        '۷': '7',\n        '۸': '8',\n        '۹': '9',\n        '۰': '0'\n    };\n\n    var fa = _moment__default.defineLocale('fa', {\n        months : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),\n        monthsShort : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'),\n        weekdays : 'یک\\u200cشنبه_دوشنبه_سه\\u200cشنبه_چهارشنبه_پنج\\u200cشنبه_جمعه_شنبه'.split('_'),\n        weekdaysShort : 'یک\\u200cشنبه_دوشنبه_سه\\u200cشنبه_چهارشنبه_پنج\\u200cشنبه_جمعه_شنبه'.split('_'),\n        weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd, D MMMM YYYY HH:mm'\n        },\n        meridiemParse: /قبل از ظهر|بعد از ظهر/,\n        isPM: function (input) {\n            return /بعد از ظهر/.test(input);\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 12) {\n                return 'قبل از ظهر';\n            } else {\n                return 'بعد از ظهر';\n            }\n        },\n        calendar : {\n            sameDay : '[امروز ساعت] LT',\n            nextDay : '[فردا ساعت] LT',\n            nextWeek : 'dddd [ساعت] LT',\n            lastDay : '[دیروز ساعت] LT',\n            lastWeek : 'dddd [پیش] [ساعت] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'در %s',\n            past : '%s پیش',\n            s : 'چندین ثانیه',\n            m : 'یک دقیقه',\n            mm : '%d دقیقه',\n            h : 'یک ساعت',\n            hh : '%d ساعت',\n            d : 'یک روز',\n            dd : '%d روز',\n            M : 'یک ماه',\n            MM : '%d ماه',\n            y : 'یک سال',\n            yy : '%d سال'\n        },\n        preparse: function (string) {\n            return string.replace(/[۰-۹]/g, function (match) {\n                return fa__numberMap[match];\n            }).replace(/،/g, ',');\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return fa__symbolMap[match];\n            }).replace(/,/g, '،');\n        },\n        ordinalParse: /\\d{1,2}م/,\n        ordinal : '%dم',\n        week : {\n            dow : 6, // Saturday is the first day of the week.\n            doy : 12 // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : finnish (fi)\n    //! author : Tarmo Aidantausta : https://github.com/bleadof\n\n    var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' '),\n        numbersFuture = [\n            'nolla', 'yhden', 'kahden', 'kolmen', 'neljän', 'viiden', 'kuuden',\n            numbersPast[7], numbersPast[8], numbersPast[9]\n        ];\n    function fi__translate(number, withoutSuffix, key, isFuture) {\n        var result = '';\n        switch (key) {\n        case 's':\n            return isFuture ? 'muutaman sekunnin' : 'muutama sekunti';\n        case 'm':\n            return isFuture ? 'minuutin' : 'minuutti';\n        case 'mm':\n            result = isFuture ? 'minuutin' : 'minuuttia';\n            break;\n        case 'h':\n            return isFuture ? 'tunnin' : 'tunti';\n        case 'hh':\n            result = isFuture ? 'tunnin' : 'tuntia';\n            break;\n        case 'd':\n            return isFuture ? 'päivän' : 'päivä';\n        case 'dd':\n            result = isFuture ? 'päivän' : 'päivää';\n            break;\n        case 'M':\n            return isFuture ? 'kuukauden' : 'kuukausi';\n        case 'MM':\n            result = isFuture ? 'kuukauden' : 'kuukautta';\n            break;\n        case 'y':\n            return isFuture ? 'vuoden' : 'vuosi';\n        case 'yy':\n            result = isFuture ? 'vuoden' : 'vuotta';\n            break;\n        }\n        result = verbalNumber(number, isFuture) + ' ' + result;\n        return result;\n    }\n    function verbalNumber(number, isFuture) {\n        return number < 10 ? (isFuture ? numbersFuture[number] : numbersPast[number]) : number;\n    }\n\n    var fi = _moment__default.defineLocale('fi', {\n        months : 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split('_'),\n        monthsShort : 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split('_'),\n        weekdays : 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split('_'),\n        weekdaysShort : 'su_ma_ti_ke_to_pe_la'.split('_'),\n        weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'),\n        longDateFormat : {\n            LT : 'HH.mm',\n            LTS : 'HH.mm.ss',\n            L : 'DD.MM.YYYY',\n            LL : 'Do MMMM[ta] YYYY',\n            LLL : 'Do MMMM[ta] YYYY, [klo] HH.mm',\n            LLLL : 'dddd, Do MMMM[ta] YYYY, [klo] HH.mm',\n            l : 'D.M.YYYY',\n            ll : 'Do MMM YYYY',\n            lll : 'Do MMM YYYY, [klo] HH.mm',\n            llll : 'ddd, Do MMM YYYY, [klo] HH.mm'\n        },\n        calendar : {\n            sameDay : '[tänään] [klo] LT',\n            nextDay : '[huomenna] [klo] LT',\n            nextWeek : 'dddd [klo] LT',\n            lastDay : '[eilen] [klo] LT',\n            lastWeek : '[viime] dddd[na] [klo] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s päästä',\n            past : '%s sitten',\n            s : fi__translate,\n            m : fi__translate,\n            mm : fi__translate,\n            h : fi__translate,\n            hh : fi__translate,\n            d : fi__translate,\n            dd : fi__translate,\n            M : fi__translate,\n            MM : fi__translate,\n            y : fi__translate,\n            yy : fi__translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : faroese (fo)\n    //! author : Ragnar Johannesen : https://github.com/ragnar123\n\n    var fo = _moment__default.defineLocale('fo', {\n        months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'),\n        monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),\n        weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'),\n        weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'),\n        weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D. MMMM, YYYY HH:mm'\n        },\n        calendar : {\n            sameDay : '[Í dag kl.] LT',\n            nextDay : '[Í morgin kl.] LT',\n            nextWeek : 'dddd [kl.] LT',\n            lastDay : '[Í gjár kl.] LT',\n            lastWeek : '[síðstu] dddd [kl] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'um %s',\n            past : '%s síðani',\n            s : 'fá sekund',\n            m : 'ein minutt',\n            mm : '%d minuttir',\n            h : 'ein tími',\n            hh : '%d tímar',\n            d : 'ein dagur',\n            dd : '%d dagar',\n            M : 'ein mánaði',\n            MM : '%d mánaðir',\n            y : 'eitt ár',\n            yy : '%d ár'\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : canadian french (fr-ca)\n    //! author : Jonathan Abourbih : https://github.com/jonbca\n\n    var fr_ca = _moment__default.defineLocale('fr-ca', {\n        months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),\n        monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),\n        weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),\n        weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),\n        weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'YYYY-MM-DD',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Aujourd\\'hui à] LT',\n            nextDay: '[Demain à] LT',\n            nextWeek: 'dddd [à] LT',\n            lastDay: '[Hier à] LT',\n            lastWeek: 'dddd [dernier à] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'dans %s',\n            past : 'il y a %s',\n            s : 'quelques secondes',\n            m : 'une minute',\n            mm : '%d minutes',\n            h : 'une heure',\n            hh : '%d heures',\n            d : 'un jour',\n            dd : '%d jours',\n            M : 'un mois',\n            MM : '%d mois',\n            y : 'un an',\n            yy : '%d ans'\n        },\n        ordinalParse: /\\d{1,2}(er|e)/,\n        ordinal : function (number) {\n            return number + (number === 1 ? 'er' : 'e');\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : french (fr)\n    //! author : John Fischer : https://github.com/jfroffice\n\n    var fr = _moment__default.defineLocale('fr', {\n        months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'),\n        monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'),\n        weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'),\n        weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'),\n        weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Aujourd\\'hui à] LT',\n            nextDay: '[Demain à] LT',\n            nextWeek: 'dddd [à] LT',\n            lastDay: '[Hier à] LT',\n            lastWeek: 'dddd [dernier à] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'dans %s',\n            past : 'il y a %s',\n            s : 'quelques secondes',\n            m : 'une minute',\n            mm : '%d minutes',\n            h : 'une heure',\n            hh : '%d heures',\n            d : 'un jour',\n            dd : '%d jours',\n            M : 'un mois',\n            MM : '%d mois',\n            y : 'un an',\n            yy : '%d ans'\n        },\n        ordinalParse: /\\d{1,2}(er|)/,\n        ordinal : function (number) {\n            return number + (number === 1 ? 'er' : '');\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : frisian (fy)\n    //! author : Robin van der Vliet : https://github.com/robin0van0der0v\n\n    var fy__monthsShortWithDots = 'jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.'.split('_'),\n        fy__monthsShortWithoutDots = 'jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_');\n\n    var fy = _moment__default.defineLocale('fy', {\n        months : 'jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber'.split('_'),\n        monthsShort : function (m, format) {\n            if (/-MMM-/.test(format)) {\n                return fy__monthsShortWithoutDots[m.month()];\n            } else {\n                return fy__monthsShortWithDots[m.month()];\n            }\n        },\n        weekdays : 'snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon'.split('_'),\n        weekdaysShort : 'si._mo._ti._wo._to._fr._so.'.split('_'),\n        weekdaysMin : 'Si_Mo_Ti_Wo_To_Fr_So'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD-MM-YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[hjoed om] LT',\n            nextDay: '[moarn om] LT',\n            nextWeek: 'dddd [om] LT',\n            lastDay: '[juster om] LT',\n            lastWeek: '[ôfrûne] dddd [om] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'oer %s',\n            past : '%s lyn',\n            s : 'in pear sekonden',\n            m : 'ien minút',\n            mm : '%d minuten',\n            h : 'ien oere',\n            hh : '%d oeren',\n            d : 'ien dei',\n            dd : '%d dagen',\n            M : 'ien moanne',\n            MM : '%d moannen',\n            y : 'ien jier',\n            yy : '%d jierren'\n        },\n        ordinalParse: /\\d{1,2}(ste|de)/,\n        ordinal : function (number) {\n            return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : galician (gl)\n    //! author : Juan G. Hurtado : https://github.com/juanghurtado\n\n    var gl = _moment__default.defineLocale('gl', {\n        months : 'Xaneiro_Febreiro_Marzo_Abril_Maio_Xuño_Xullo_Agosto_Setembro_Outubro_Novembro_Decembro'.split('_'),\n        monthsShort : 'Xan._Feb._Mar._Abr._Mai._Xuñ._Xul._Ago._Set._Out._Nov._Dec.'.split('_'),\n        weekdays : 'Domingo_Luns_Martes_Mércores_Xoves_Venres_Sábado'.split('_'),\n        weekdaysShort : 'Dom._Lun._Mar._Mér._Xov._Ven._Sáb.'.split('_'),\n        weekdaysMin : 'Do_Lu_Ma_Mé_Xo_Ve_Sá'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY H:mm',\n            LLLL : 'dddd D MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay : function () {\n                return '[hoxe ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';\n            },\n            nextDay : function () {\n                return '[mañá ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT';\n            },\n            nextWeek : function () {\n                return 'dddd [' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';\n            },\n            lastDay : function () {\n                return '[onte ' + ((this.hours() !== 1) ? 'á' : 'a') + '] LT';\n            },\n            lastWeek : function () {\n                return '[o] dddd [pasado ' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT';\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : function (str) {\n                if (str === 'uns segundos') {\n                    return 'nuns segundos';\n                }\n                return 'en ' + str;\n            },\n            past : 'hai %s',\n            s : 'uns segundos',\n            m : 'un minuto',\n            mm : '%d minutos',\n            h : 'unha hora',\n            hh : '%d horas',\n            d : 'un día',\n            dd : '%d días',\n            M : 'un mes',\n            MM : '%d meses',\n            y : 'un ano',\n            yy : '%d anos'\n        },\n        ordinalParse : /\\d{1,2}º/,\n        ordinal : '%dº',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Hebrew (he)\n    //! author : Tomer Cohen : https://github.com/tomer\n    //! author : Moshe Simantov : https://github.com/DevelopmentIL\n    //! author : Tal Ater : https://github.com/TalAter\n\n    var he = _moment__default.defineLocale('he', {\n        months : 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split('_'),\n        monthsShort : 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'),\n        weekdays : 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'),\n        weekdaysShort : 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'),\n        weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D [ב]MMMM YYYY',\n            LLL : 'D [ב]MMMM YYYY HH:mm',\n            LLLL : 'dddd, D [ב]MMMM YYYY HH:mm',\n            l : 'D/M/YYYY',\n            ll : 'D MMM YYYY',\n            lll : 'D MMM YYYY HH:mm',\n            llll : 'ddd, D MMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay : '[היום ב־]LT',\n            nextDay : '[מחר ב־]LT',\n            nextWeek : 'dddd [בשעה] LT',\n            lastDay : '[אתמול ב־]LT',\n            lastWeek : '[ביום] dddd [האחרון בשעה] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'בעוד %s',\n            past : 'לפני %s',\n            s : 'מספר שניות',\n            m : 'דקה',\n            mm : '%d דקות',\n            h : 'שעה',\n            hh : function (number) {\n                if (number === 2) {\n                    return 'שעתיים';\n                }\n                return number + ' שעות';\n            },\n            d : 'יום',\n            dd : function (number) {\n                if (number === 2) {\n                    return 'יומיים';\n                }\n                return number + ' ימים';\n            },\n            M : 'חודש',\n            MM : function (number) {\n                if (number === 2) {\n                    return 'חודשיים';\n                }\n                return number + ' חודשים';\n            },\n            y : 'שנה',\n            yy : function (number) {\n                if (number === 2) {\n                    return 'שנתיים';\n                } else if (number % 10 === 0 && number !== 10) {\n                    return number + ' שנה';\n                }\n                return number + ' שנים';\n            }\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : hindi (hi)\n    //! author : Mayank Singhal : https://github.com/mayanksinghal\n\n    var hi__symbolMap = {\n        '1': '१',\n        '2': '२',\n        '3': '३',\n        '4': '४',\n        '5': '५',\n        '6': '६',\n        '7': '७',\n        '8': '८',\n        '9': '९',\n        '0': '०'\n    },\n    hi__numberMap = {\n        '१': '1',\n        '२': '2',\n        '३': '3',\n        '४': '4',\n        '५': '5',\n        '६': '6',\n        '७': '7',\n        '८': '8',\n        '९': '9',\n        '०': '0'\n    };\n\n    var hi = _moment__default.defineLocale('hi', {\n        months : 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split('_'),\n        monthsShort : 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'),\n        weekdays : 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),\n        weekdaysShort : 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'),\n        weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),\n        longDateFormat : {\n            LT : 'A h:mm बजे',\n            LTS : 'A h:mm:ss बजे',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY, A h:mm बजे',\n            LLLL : 'dddd, D MMMM YYYY, A h:mm बजे'\n        },\n        calendar : {\n            sameDay : '[आज] LT',\n            nextDay : '[कल] LT',\n            nextWeek : 'dddd, LT',\n            lastDay : '[कल] LT',\n            lastWeek : '[पिछले] dddd, LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s में',\n            past : '%s पहले',\n            s : 'कुछ ही क्षण',\n            m : 'एक मिनट',\n            mm : '%d मिनट',\n            h : 'एक घंटा',\n            hh : '%d घंटे',\n            d : 'एक दिन',\n            dd : '%d दिन',\n            M : 'एक महीने',\n            MM : '%d महीने',\n            y : 'एक वर्ष',\n            yy : '%d वर्ष'\n        },\n        preparse: function (string) {\n            return string.replace(/[१२३४५६७८९०]/g, function (match) {\n                return hi__numberMap[match];\n            });\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return hi__symbolMap[match];\n            });\n        },\n        // Hindi notation for meridiems are quite fuzzy in practice. While there exists\n        // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi.\n        meridiemParse: /रात|सुबह|दोपहर|शाम/,\n        meridiemHour : function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === 'रात') {\n                return hour < 4 ? hour : hour + 12;\n            } else if (meridiem === 'सुबह') {\n                return hour;\n            } else if (meridiem === 'दोपहर') {\n                return hour >= 10 ? hour : hour + 12;\n            } else if (meridiem === 'शाम') {\n                return hour + 12;\n            }\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'रात';\n            } else if (hour < 10) {\n                return 'सुबह';\n            } else if (hour < 17) {\n                return 'दोपहर';\n            } else if (hour < 20) {\n                return 'शाम';\n            } else {\n                return 'रात';\n            }\n        },\n        week : {\n            dow : 0, // Sunday is the first day of the week.\n            doy : 6  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : hrvatski (hr)\n    //! author : Bojan Marković : https://github.com/bmarkovic\n\n    function hr__translate(number, withoutSuffix, key) {\n        var result = number + ' ';\n        switch (key) {\n        case 'm':\n            return withoutSuffix ? 'jedna minuta' : 'jedne minute';\n        case 'mm':\n            if (number === 1) {\n                result += 'minuta';\n            } else if (number === 2 || number === 3 || number === 4) {\n                result += 'minute';\n            } else {\n                result += 'minuta';\n            }\n            return result;\n        case 'h':\n            return withoutSuffix ? 'jedan sat' : 'jednog sata';\n        case 'hh':\n            if (number === 1) {\n                result += 'sat';\n            } else if (number === 2 || number === 3 || number === 4) {\n                result += 'sata';\n            } else {\n                result += 'sati';\n            }\n            return result;\n        case 'dd':\n            if (number === 1) {\n                result += 'dan';\n            } else {\n                result += 'dana';\n            }\n            return result;\n        case 'MM':\n            if (number === 1) {\n                result += 'mjesec';\n            } else if (number === 2 || number === 3 || number === 4) {\n                result += 'mjeseca';\n            } else {\n                result += 'mjeseci';\n            }\n            return result;\n        case 'yy':\n            if (number === 1) {\n                result += 'godina';\n            } else if (number === 2 || number === 3 || number === 4) {\n                result += 'godine';\n            } else {\n                result += 'godina';\n            }\n            return result;\n        }\n    }\n\n    var hr = _moment__default.defineLocale('hr', {\n        months : 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_'),\n        monthsShort : 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'),\n        weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),\n        weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),\n        weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD. MM. YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY H:mm',\n            LLLL : 'dddd, D. MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay  : '[danas u] LT',\n            nextDay  : '[sutra u] LT',\n            nextWeek : function () {\n                switch (this.day()) {\n                case 0:\n                    return '[u] [nedjelju] [u] LT';\n                case 3:\n                    return '[u] [srijedu] [u] LT';\n                case 6:\n                    return '[u] [subotu] [u] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[u] dddd [u] LT';\n                }\n            },\n            lastDay  : '[jučer u] LT',\n            lastWeek : function () {\n                switch (this.day()) {\n                case 0:\n                case 3:\n                    return '[prošlu] dddd [u] LT';\n                case 6:\n                    return '[prošle] [subote] [u] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[prošli] dddd [u] LT';\n                }\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'za %s',\n            past   : 'prije %s',\n            s      : 'par sekundi',\n            m      : hr__translate,\n            mm     : hr__translate,\n            h      : hr__translate,\n            hh     : hr__translate,\n            d      : 'dan',\n            dd     : hr__translate,\n            M      : 'mjesec',\n            MM     : hr__translate,\n            y      : 'godinu',\n            yy     : hr__translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : hungarian (hu)\n    //! author : Adam Brunner : https://github.com/adambrunner\n\n    var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' ');\n    function hu__translate(number, withoutSuffix, key, isFuture) {\n        var num = number,\n            suffix;\n        switch (key) {\n        case 's':\n            return (isFuture || withoutSuffix) ? 'néhány másodperc' : 'néhány másodperce';\n        case 'm':\n            return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce');\n        case 'mm':\n            return num + (isFuture || withoutSuffix ? ' perc' : ' perce');\n        case 'h':\n            return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája');\n        case 'hh':\n            return num + (isFuture || withoutSuffix ? ' óra' : ' órája');\n        case 'd':\n            return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja');\n        case 'dd':\n            return num + (isFuture || withoutSuffix ? ' nap' : ' napja');\n        case 'M':\n            return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');\n        case 'MM':\n            return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja');\n        case 'y':\n            return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve');\n        case 'yy':\n            return num + (isFuture || withoutSuffix ? ' év' : ' éve');\n        }\n        return '';\n    }\n    function week(isFuture) {\n        return (isFuture ? '' : '[múlt] ') + '[' + weekEndings[this.day()] + '] LT[-kor]';\n    }\n\n    var hu = _moment__default.defineLocale('hu', {\n        months : 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split('_'),\n        monthsShort : 'jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec'.split('_'),\n        weekdays : 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'),\n        weekdaysShort : 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'),\n        weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'YYYY.MM.DD.',\n            LL : 'YYYY. MMMM D.',\n            LLL : 'YYYY. MMMM D. H:mm',\n            LLLL : 'YYYY. MMMM D., dddd H:mm'\n        },\n        meridiemParse: /de|du/i,\n        isPM: function (input) {\n            return input.charAt(1).toLowerCase() === 'u';\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours < 12) {\n                return isLower === true ? 'de' : 'DE';\n            } else {\n                return isLower === true ? 'du' : 'DU';\n            }\n        },\n        calendar : {\n            sameDay : '[ma] LT[-kor]',\n            nextDay : '[holnap] LT[-kor]',\n            nextWeek : function () {\n                return week.call(this, true);\n            },\n            lastDay : '[tegnap] LT[-kor]',\n            lastWeek : function () {\n                return week.call(this, false);\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s múlva',\n            past : '%s',\n            s : hu__translate,\n            m : hu__translate,\n            mm : hu__translate,\n            h : hu__translate,\n            hh : hu__translate,\n            d : hu__translate,\n            dd : hu__translate,\n            M : hu__translate,\n            MM : hu__translate,\n            y : hu__translate,\n            yy : hu__translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Armenian (hy-am)\n    //! author : Armendarabyan : https://github.com/armendarabyan\n\n    function hy_am__monthsCaseReplace(m, format) {\n        var months = {\n            'nominative': 'հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր'.split('_'),\n            'accusative': 'հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի'.split('_')\n        },\n        nounCase = (/D[oD]?(\\[[^\\[\\]]*\\]|\\s+)+MMMM?/).test(format) ?\n            'accusative' :\n            'nominative';\n        return months[nounCase][m.month()];\n    }\n    function hy_am__monthsShortCaseReplace(m, format) {\n        var monthsShort = 'հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ'.split('_');\n        return monthsShort[m.month()];\n    }\n    function hy_am__weekdaysCaseReplace(m, format) {\n        var weekdays = 'կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ'.split('_');\n        return weekdays[m.day()];\n    }\n\n    var hy_am = _moment__default.defineLocale('hy-am', {\n        months : hy_am__monthsCaseReplace,\n        monthsShort : hy_am__monthsShortCaseReplace,\n        weekdays : hy_am__weekdaysCaseReplace,\n        weekdaysShort : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'),\n        weekdaysMin : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY թ.',\n            LLL : 'D MMMM YYYY թ., HH:mm',\n            LLLL : 'dddd, D MMMM YYYY թ., HH:mm'\n        },\n        calendar : {\n            sameDay: '[այսօր] LT',\n            nextDay: '[վաղը] LT',\n            lastDay: '[երեկ] LT',\n            nextWeek: function () {\n                return 'dddd [օրը ժամը] LT';\n            },\n            lastWeek: function () {\n                return '[անցած] dddd [օրը ժամը] LT';\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : '%s հետո',\n            past : '%s առաջ',\n            s : 'մի քանի վայրկյան',\n            m : 'րոպե',\n            mm : '%d րոպե',\n            h : 'ժամ',\n            hh : '%d ժամ',\n            d : 'օր',\n            dd : '%d օր',\n            M : 'ամիս',\n            MM : '%d ամիս',\n            y : 'տարի',\n            yy : '%d տարի'\n        },\n        meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,\n        isPM: function (input) {\n            return /^(ցերեկվա|երեկոյան)$/.test(input);\n        },\n        meridiem : function (hour) {\n            if (hour < 4) {\n                return 'գիշերվա';\n            } else if (hour < 12) {\n                return 'առավոտվա';\n            } else if (hour < 17) {\n                return 'ցերեկվա';\n            } else {\n                return 'երեկոյան';\n            }\n        },\n        ordinalParse: /\\d{1,2}|\\d{1,2}-(ին|րդ)/,\n        ordinal: function (number, period) {\n            switch (period) {\n            case 'DDD':\n            case 'w':\n            case 'W':\n            case 'DDDo':\n                if (number === 1) {\n                    return number + '-ին';\n                }\n                return number + '-րդ';\n            default:\n                return number;\n            }\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Bahasa Indonesia (id)\n    //! author : Mohammad Satrio Utomo : https://github.com/tyok\n    //! reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan\n\n    var id = _moment__default.defineLocale('id', {\n        months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'),\n        monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des'.split('_'),\n        weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'),\n        weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'),\n        weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'),\n        longDateFormat : {\n            LT : 'HH.mm',\n            LTS : 'HH.mm.ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY [pukul] HH.mm',\n            LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'\n        },\n        meridiemParse: /pagi|siang|sore|malam/,\n        meridiemHour : function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === 'pagi') {\n                return hour;\n            } else if (meridiem === 'siang') {\n                return hour >= 11 ? hour : hour + 12;\n            } else if (meridiem === 'sore' || meridiem === 'malam') {\n                return hour + 12;\n            }\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours < 11) {\n                return 'pagi';\n            } else if (hours < 15) {\n                return 'siang';\n            } else if (hours < 19) {\n                return 'sore';\n            } else {\n                return 'malam';\n            }\n        },\n        calendar : {\n            sameDay : '[Hari ini pukul] LT',\n            nextDay : '[Besok pukul] LT',\n            nextWeek : 'dddd [pukul] LT',\n            lastDay : '[Kemarin pukul] LT',\n            lastWeek : 'dddd [lalu pukul] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'dalam %s',\n            past : '%s yang lalu',\n            s : 'beberapa detik',\n            m : 'semenit',\n            mm : '%d menit',\n            h : 'sejam',\n            hh : '%d jam',\n            d : 'sehari',\n            dd : '%d hari',\n            M : 'sebulan',\n            MM : '%d bulan',\n            y : 'setahun',\n            yy : '%d tahun'\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : icelandic (is)\n    //! author : Hinrik Örn Sigurðsson : https://github.com/hinrik\n\n    function is__plural(n) {\n        if (n % 100 === 11) {\n            return true;\n        } else if (n % 10 === 1) {\n            return false;\n        }\n        return true;\n    }\n    function is__translate(number, withoutSuffix, key, isFuture) {\n        var result = number + ' ';\n        switch (key) {\n        case 's':\n            return withoutSuffix || isFuture ? 'nokkrar sekúndur' : 'nokkrum sekúndum';\n        case 'm':\n            return withoutSuffix ? 'mínúta' : 'mínútu';\n        case 'mm':\n            if (is__plural(number)) {\n                return result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum');\n            } else if (withoutSuffix) {\n                return result + 'mínúta';\n            }\n            return result + 'mínútu';\n        case 'hh':\n            if (is__plural(number)) {\n                return result + (withoutSuffix || isFuture ? 'klukkustundir' : 'klukkustundum');\n            }\n            return result + 'klukkustund';\n        case 'd':\n            if (withoutSuffix) {\n                return 'dagur';\n            }\n            return isFuture ? 'dag' : 'degi';\n        case 'dd':\n            if (is__plural(number)) {\n                if (withoutSuffix) {\n                    return result + 'dagar';\n                }\n                return result + (isFuture ? 'daga' : 'dögum');\n            } else if (withoutSuffix) {\n                return result + 'dagur';\n            }\n            return result + (isFuture ? 'dag' : 'degi');\n        case 'M':\n            if (withoutSuffix) {\n                return 'mánuður';\n            }\n            return isFuture ? 'mánuð' : 'mánuði';\n        case 'MM':\n            if (is__plural(number)) {\n                if (withoutSuffix) {\n                    return result + 'mánuðir';\n                }\n                return result + (isFuture ? 'mánuði' : 'mánuðum');\n            } else if (withoutSuffix) {\n                return result + 'mánuður';\n            }\n            return result + (isFuture ? 'mánuð' : 'mánuði');\n        case 'y':\n            return withoutSuffix || isFuture ? 'ár' : 'ári';\n        case 'yy':\n            if (is__plural(number)) {\n                return result + (withoutSuffix || isFuture ? 'ár' : 'árum');\n            }\n            return result + (withoutSuffix || isFuture ? 'ár' : 'ári');\n        }\n    }\n\n    var is = _moment__default.defineLocale('is', {\n        months : 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split('_'),\n        monthsShort : 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'),\n        weekdays : 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split('_'),\n        weekdaysShort : 'sun_mán_þri_mið_fim_fös_lau'.split('_'),\n        weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY [kl.] H:mm',\n            LLLL : 'dddd, D. MMMM YYYY [kl.] H:mm'\n        },\n        calendar : {\n            sameDay : '[í dag kl.] LT',\n            nextDay : '[á morgun kl.] LT',\n            nextWeek : 'dddd [kl.] LT',\n            lastDay : '[í gær kl.] LT',\n            lastWeek : '[síðasta] dddd [kl.] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'eftir %s',\n            past : 'fyrir %s síðan',\n            s : is__translate,\n            m : is__translate,\n            mm : is__translate,\n            h : 'klukkustund',\n            hh : is__translate,\n            d : is__translate,\n            dd : is__translate,\n            M : is__translate,\n            MM : is__translate,\n            y : is__translate,\n            yy : is__translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : italian (it)\n    //! author : Lorenzo : https://github.com/aliem\n    //! author: Mattia Larentis: https://github.com/nostalgiaz\n\n    var it = _moment__default.defineLocale('it', {\n        months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'),\n        monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'),\n        weekdays : 'Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato'.split('_'),\n        weekdaysShort : 'Dom_Lun_Mar_Mer_Gio_Ven_Sab'.split('_'),\n        weekdaysMin : 'D_L_Ma_Me_G_V_S'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Oggi alle] LT',\n            nextDay: '[Domani alle] LT',\n            nextWeek: 'dddd [alle] LT',\n            lastDay: '[Ieri alle] LT',\n            lastWeek: function () {\n                switch (this.day()) {\n                    case 0:\n                        return '[la scorsa] dddd [alle] LT';\n                    default:\n                        return '[lo scorso] dddd [alle] LT';\n                }\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : function (s) {\n                return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s;\n            },\n            past : '%s fa',\n            s : 'alcuni secondi',\n            m : 'un minuto',\n            mm : '%d minuti',\n            h : 'un\\'ora',\n            hh : '%d ore',\n            d : 'un giorno',\n            dd : '%d giorni',\n            M : 'un mese',\n            MM : '%d mesi',\n            y : 'un anno',\n            yy : '%d anni'\n        },\n        ordinalParse : /\\d{1,2}º/,\n        ordinal: '%dº',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : japanese (ja)\n    //! author : LI Long : https://github.com/baryon\n\n    var ja = _moment__default.defineLocale('ja', {\n        months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),\n        monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),\n        weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'),\n        weekdaysShort : '日_月_火_水_木_金_土'.split('_'),\n        weekdaysMin : '日_月_火_水_木_金_土'.split('_'),\n        longDateFormat : {\n            LT : 'Ah時m分',\n            LTS : 'Ah時m分s秒',\n            L : 'YYYY/MM/DD',\n            LL : 'YYYY年M月D日',\n            LLL : 'YYYY年M月D日Ah時m分',\n            LLLL : 'YYYY年M月D日Ah時m分 dddd'\n        },\n        meridiemParse: /午前|午後/i,\n        isPM : function (input) {\n            return input === '午後';\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 12) {\n                return '午前';\n            } else {\n                return '午後';\n            }\n        },\n        calendar : {\n            sameDay : '[今日] LT',\n            nextDay : '[明日] LT',\n            nextWeek : '[来週]dddd LT',\n            lastDay : '[昨日] LT',\n            lastWeek : '[前週]dddd LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s後',\n            past : '%s前',\n            s : '数秒',\n            m : '1分',\n            mm : '%d分',\n            h : '1時間',\n            hh : '%d時間',\n            d : '1日',\n            dd : '%d日',\n            M : '1ヶ月',\n            MM : '%dヶ月',\n            y : '1年',\n            yy : '%d年'\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Boso Jowo (jv)\n    //! author : Rony Lantip : https://github.com/lantip\n    //! reference: http://jv.wikipedia.org/wiki/Basa_Jawa\n\n    var jv = _moment__default.defineLocale('jv', {\n        months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember'.split('_'),\n        monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des'.split('_'),\n        weekdays : 'Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu'.split('_'),\n        weekdaysShort : 'Min_Sen_Sel_Reb_Kem_Jem_Sep'.split('_'),\n        weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sp'.split('_'),\n        longDateFormat : {\n            LT : 'HH.mm',\n            LTS : 'HH.mm.ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY [pukul] HH.mm',\n            LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'\n        },\n        meridiemParse: /enjing|siyang|sonten|ndalu/,\n        meridiemHour : function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === 'enjing') {\n                return hour;\n            } else if (meridiem === 'siyang') {\n                return hour >= 11 ? hour : hour + 12;\n            } else if (meridiem === 'sonten' || meridiem === 'ndalu') {\n                return hour + 12;\n            }\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours < 11) {\n                return 'enjing';\n            } else if (hours < 15) {\n                return 'siyang';\n            } else if (hours < 19) {\n                return 'sonten';\n            } else {\n                return 'ndalu';\n            }\n        },\n        calendar : {\n            sameDay : '[Dinten puniko pukul] LT',\n            nextDay : '[Mbenjang pukul] LT',\n            nextWeek : 'dddd [pukul] LT',\n            lastDay : '[Kala wingi pukul] LT',\n            lastWeek : 'dddd [kepengker pukul] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'wonten ing %s',\n            past : '%s ingkang kepengker',\n            s : 'sawetawis detik',\n            m : 'setunggal menit',\n            mm : '%d menit',\n            h : 'setunggal jam',\n            hh : '%d jam',\n            d : 'sedinten',\n            dd : '%d dinten',\n            M : 'sewulan',\n            MM : '%d wulan',\n            y : 'setaun',\n            yy : '%d taun'\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Georgian (ka)\n    //! author : Irakli Janiashvili : https://github.com/irakli-janiashvili\n\n    function ka__monthsCaseReplace(m, format) {\n        var months = {\n            'nominative': 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split('_'),\n            'accusative': 'იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს'.split('_')\n        },\n        nounCase = (/D[oD] *MMMM?/).test(format) ?\n            'accusative' :\n            'nominative';\n        return months[nounCase][m.month()];\n    }\n    function ka__weekdaysCaseReplace(m, format) {\n        var weekdays = {\n            'nominative': 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split('_'),\n            'accusative': 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split('_')\n        },\n        nounCase = (/(წინა|შემდეგ)/).test(format) ?\n            'accusative' :\n            'nominative';\n        return weekdays[nounCase][m.day()];\n    }\n\n    var ka = _moment__default.defineLocale('ka', {\n        months : ka__monthsCaseReplace,\n        monthsShort : 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'),\n        weekdays : ka__weekdaysCaseReplace,\n        weekdaysShort : 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'),\n        weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'),\n        longDateFormat : {\n            LT : 'h:mm A',\n            LTS : 'h:mm:ss A',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY h:mm A',\n            LLLL : 'dddd, D MMMM YYYY h:mm A'\n        },\n        calendar : {\n            sameDay : '[დღეს] LT[-ზე]',\n            nextDay : '[ხვალ] LT[-ზე]',\n            lastDay : '[გუშინ] LT[-ზე]',\n            nextWeek : '[შემდეგ] dddd LT[-ზე]',\n            lastWeek : '[წინა] dddd LT-ზე',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : function (s) {\n                return (/(წამი|წუთი|საათი|წელი)/).test(s) ?\n                    s.replace(/ი$/, 'ში') :\n                    s + 'ში';\n            },\n            past : function (s) {\n                if ((/(წამი|წუთი|საათი|დღე|თვე)/).test(s)) {\n                    return s.replace(/(ი|ე)$/, 'ის წინ');\n                }\n                if ((/წელი/).test(s)) {\n                    return s.replace(/წელი$/, 'წლის წინ');\n                }\n            },\n            s : 'რამდენიმე წამი',\n            m : 'წუთი',\n            mm : '%d წუთი',\n            h : 'საათი',\n            hh : '%d საათი',\n            d : 'დღე',\n            dd : '%d დღე',\n            M : 'თვე',\n            MM : '%d თვე',\n            y : 'წელი',\n            yy : '%d წელი'\n        },\n        ordinalParse: /0|1-ლი|მე-\\d{1,2}|\\d{1,2}-ე/,\n        ordinal : function (number) {\n            if (number === 0) {\n                return number;\n            }\n            if (number === 1) {\n                return number + '-ლი';\n            }\n            if ((number < 20) || (number <= 100 && (number % 20 === 0)) || (number % 100 === 0)) {\n                return 'მე-' + number;\n            }\n            return number + '-ე';\n        },\n        week : {\n            dow : 1,\n            doy : 7\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : khmer (km)\n    //! author : Kruy Vanna : https://github.com/kruyvanna\n\n    var km = _moment__default.defineLocale('km', {\n        months: 'មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),\n        monthsShort: 'មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'),\n        weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),\n        weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),\n        weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),\n        longDateFormat: {\n            LT: 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L: 'DD/MM/YYYY',\n            LL: 'D MMMM YYYY',\n            LLL: 'D MMMM YYYY HH:mm',\n            LLLL: 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar: {\n            sameDay: '[ថ្ងៃនៈ ម៉ោង] LT',\n            nextDay: '[ស្អែក ម៉ោង] LT',\n            nextWeek: 'dddd [ម៉ោង] LT',\n            lastDay: '[ម្សិលមិញ ម៉ោង] LT',\n            lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT',\n            sameElse: 'L'\n        },\n        relativeTime: {\n            future: '%sទៀត',\n            past: '%sមុន',\n            s: 'ប៉ុន្មានវិនាទី',\n            m: 'មួយនាទី',\n            mm: '%d នាទី',\n            h: 'មួយម៉ោង',\n            hh: '%d ម៉ោង',\n            d: 'មួយថ្ងៃ',\n            dd: '%d ថ្ងៃ',\n            M: 'មួយខែ',\n            MM: '%d ខែ',\n            y: 'មួយឆ្នាំ',\n            yy: '%d ឆ្នាំ'\n        },\n        week: {\n            dow: 1, // Monday is the first day of the week.\n            doy: 4 // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : korean (ko)\n    //!\n    //! authors\n    //!\n    //! - Kyungwook, Park : https://github.com/kyungw00k\n    //! - Jeeeyul Lee <jeeeyul@gmail.com>\n\n    var ko = _moment__default.defineLocale('ko', {\n        months : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'),\n        monthsShort : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'),\n        weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'),\n        weekdaysShort : '일_월_화_수_목_금_토'.split('_'),\n        weekdaysMin : '일_월_화_수_목_금_토'.split('_'),\n        longDateFormat : {\n            LT : 'A h시 m분',\n            LTS : 'A h시 m분 s초',\n            L : 'YYYY.MM.DD',\n            LL : 'YYYY년 MMMM D일',\n            LLL : 'YYYY년 MMMM D일 A h시 m분',\n            LLLL : 'YYYY년 MMMM D일 dddd A h시 m분'\n        },\n        calendar : {\n            sameDay : '오늘 LT',\n            nextDay : '내일 LT',\n            nextWeek : 'dddd LT',\n            lastDay : '어제 LT',\n            lastWeek : '지난주 dddd LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s 후',\n            past : '%s 전',\n            s : '몇초',\n            ss : '%d초',\n            m : '일분',\n            mm : '%d분',\n            h : '한시간',\n            hh : '%d시간',\n            d : '하루',\n            dd : '%d일',\n            M : '한달',\n            MM : '%d달',\n            y : '일년',\n            yy : '%d년'\n        },\n        ordinalParse : /\\d{1,2}일/,\n        ordinal : '%d일',\n        meridiemParse : /오전|오후/,\n        isPM : function (token) {\n            return token === '오후';\n        },\n        meridiem : function (hour, minute, isUpper) {\n            return hour < 12 ? '오전' : '오후';\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Luxembourgish (lb)\n    //! author : mweimerskirch : https://github.com/mweimerskirch, David Raison : https://github.com/kwisatz\n\n    function lb__processRelativeTime(number, withoutSuffix, key, isFuture) {\n        var format = {\n            'm': ['eng Minutt', 'enger Minutt'],\n            'h': ['eng Stonn', 'enger Stonn'],\n            'd': ['een Dag', 'engem Dag'],\n            'M': ['ee Mount', 'engem Mount'],\n            'y': ['ee Joer', 'engem Joer']\n        };\n        return withoutSuffix ? format[key][0] : format[key][1];\n    }\n    function processFutureTime(string) {\n        var number = string.substr(0, string.indexOf(' '));\n        if (eifelerRegelAppliesToNumber(number)) {\n            return 'a ' + string;\n        }\n        return 'an ' + string;\n    }\n    function processPastTime(string) {\n        var number = string.substr(0, string.indexOf(' '));\n        if (eifelerRegelAppliesToNumber(number)) {\n            return 'viru ' + string;\n        }\n        return 'virun ' + string;\n    }\n    /**\n     * Returns true if the word before the given number loses the '-n' ending.\n     * e.g. 'an 10 Deeg' but 'a 5 Deeg'\n     *\n     * @param number {integer}\n     * @returns {boolean}\n     */\n    function eifelerRegelAppliesToNumber(number) {\n        number = parseInt(number, 10);\n        if (isNaN(number)) {\n            return false;\n        }\n        if (number < 0) {\n            // Negative Number --> always true\n            return true;\n        } else if (number < 10) {\n            // Only 1 digit\n            if (4 <= number && number <= 7) {\n                return true;\n            }\n            return false;\n        } else if (number < 100) {\n            // 2 digits\n            var lastDigit = number % 10, firstDigit = number / 10;\n            if (lastDigit === 0) {\n                return eifelerRegelAppliesToNumber(firstDigit);\n            }\n            return eifelerRegelAppliesToNumber(lastDigit);\n        } else if (number < 10000) {\n            // 3 or 4 digits --> recursively check first digit\n            while (number >= 10) {\n                number = number / 10;\n            }\n            return eifelerRegelAppliesToNumber(number);\n        } else {\n            // Anything larger than 4 digits: recursively check first n-3 digits\n            number = number / 1000;\n            return eifelerRegelAppliesToNumber(number);\n        }\n    }\n\n    var lb = _moment__default.defineLocale('lb', {\n        months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'),\n        monthsShort: 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'),\n        weekdays: 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split('_'),\n        weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'),\n        weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'),\n        longDateFormat: {\n            LT: 'H:mm [Auer]',\n            LTS: 'H:mm:ss [Auer]',\n            L: 'DD.MM.YYYY',\n            LL: 'D. MMMM YYYY',\n            LLL: 'D. MMMM YYYY H:mm [Auer]',\n            LLLL: 'dddd, D. MMMM YYYY H:mm [Auer]'\n        },\n        calendar: {\n            sameDay: '[Haut um] LT',\n            sameElse: 'L',\n            nextDay: '[Muer um] LT',\n            nextWeek: 'dddd [um] LT',\n            lastDay: '[Gëschter um] LT',\n            lastWeek: function () {\n                // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule\n                switch (this.day()) {\n                    case 2:\n                    case 4:\n                        return '[Leschten] dddd [um] LT';\n                    default:\n                        return '[Leschte] dddd [um] LT';\n                }\n            }\n        },\n        relativeTime : {\n            future : processFutureTime,\n            past : processPastTime,\n            s : 'e puer Sekonnen',\n            m : lb__processRelativeTime,\n            mm : '%d Minutten',\n            h : lb__processRelativeTime,\n            hh : '%d Stonnen',\n            d : lb__processRelativeTime,\n            dd : '%d Deeg',\n            M : lb__processRelativeTime,\n            MM : '%d Méint',\n            y : lb__processRelativeTime,\n            yy : '%d Joer'\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal: '%d.',\n        week: {\n            dow: 1, // Monday is the first day of the week.\n            doy: 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Lithuanian (lt)\n    //! author : Mindaugas Mozūras : https://github.com/mmozuras\n\n    var lt__units = {\n        'm' : 'minutė_minutės_minutę',\n        'mm': 'minutės_minučių_minutes',\n        'h' : 'valanda_valandos_valandą',\n        'hh': 'valandos_valandų_valandas',\n        'd' : 'diena_dienos_dieną',\n        'dd': 'dienos_dienų_dienas',\n        'M' : 'mėnuo_mėnesio_mėnesį',\n        'MM': 'mėnesiai_mėnesių_mėnesius',\n        'y' : 'metai_metų_metus',\n        'yy': 'metai_metų_metus'\n    },\n    weekDays = 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_');\n    function translateSeconds(number, withoutSuffix, key, isFuture) {\n        if (withoutSuffix) {\n            return 'kelios sekundės';\n        } else {\n            return isFuture ? 'kelių sekundžių' : 'kelias sekundes';\n        }\n    }\n    function lt__monthsCaseReplace(m, format) {\n        var months = {\n                'nominative': 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split('_'),\n                'accusative': 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_')\n            },\n            nounCase = (/D[oD]?(\\[[^\\[\\]]*\\]|\\s+)+MMMM?/).test(format) ?\n                'accusative' :\n                'nominative';\n        return months[nounCase][m.month()];\n    }\n    function translateSingular(number, withoutSuffix, key, isFuture) {\n        return withoutSuffix ? forms(key)[0] : (isFuture ? forms(key)[1] : forms(key)[2]);\n    }\n    function special(number) {\n        return number % 10 === 0 || (number > 10 && number < 20);\n    }\n    function forms(key) {\n        return lt__units[key].split('_');\n    }\n    function lt__translate(number, withoutSuffix, key, isFuture) {\n        var result = number + ' ';\n        if (number === 1) {\n            return result + translateSingular(number, withoutSuffix, key[0], isFuture);\n        } else if (withoutSuffix) {\n            return result + (special(number) ? forms(key)[1] : forms(key)[0]);\n        } else {\n            if (isFuture) {\n                return result + forms(key)[1];\n            } else {\n                return result + (special(number) ? forms(key)[1] : forms(key)[2]);\n            }\n        }\n    }\n    function relativeWeekDay(moment, format) {\n        var nominative = format.indexOf('dddd HH:mm') === -1,\n            weekDay = weekDays[moment.day()];\n        return nominative ? weekDay : weekDay.substring(0, weekDay.length - 2) + 'į';\n    }\n\n    var lt = _moment__default.defineLocale('lt', {\n        months : lt__monthsCaseReplace,\n        monthsShort : 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'),\n        weekdays : relativeWeekDay,\n        weekdaysShort : 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'),\n        weekdaysMin : 'S_P_A_T_K_Pn_Š'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'YYYY-MM-DD',\n            LL : 'YYYY [m.] MMMM D [d.]',\n            LLL : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',\n            LLLL : 'YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]',\n            l : 'YYYY-MM-DD',\n            ll : 'YYYY [m.] MMMM D [d.]',\n            lll : 'YYYY [m.] MMMM D [d.], HH:mm [val.]',\n            llll : 'YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]'\n        },\n        calendar : {\n            sameDay : '[Šiandien] LT',\n            nextDay : '[Rytoj] LT',\n            nextWeek : 'dddd LT',\n            lastDay : '[Vakar] LT',\n            lastWeek : '[Praėjusį] dddd LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'po %s',\n            past : 'prieš %s',\n            s : translateSeconds,\n            m : translateSingular,\n            mm : lt__translate,\n            h : translateSingular,\n            hh : lt__translate,\n            d : translateSingular,\n            dd : lt__translate,\n            M : translateSingular,\n            MM : lt__translate,\n            y : translateSingular,\n            yy : lt__translate\n        },\n        ordinalParse: /\\d{1,2}-oji/,\n        ordinal : function (number) {\n            return number + '-oji';\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : latvian (lv)\n    //! author : Kristaps Karlsons : https://github.com/skakri\n    //! author : Jānis Elmeris : https://github.com/JanisE\n\n    var lv__units = {\n        'm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),\n        'mm': 'minūtes_minūtēm_minūte_minūtes'.split('_'),\n        'h': 'stundas_stundām_stunda_stundas'.split('_'),\n        'hh': 'stundas_stundām_stunda_stundas'.split('_'),\n        'd': 'dienas_dienām_diena_dienas'.split('_'),\n        'dd': 'dienas_dienām_diena_dienas'.split('_'),\n        'M': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),\n        'MM': 'mēneša_mēnešiem_mēnesis_mēneši'.split('_'),\n        'y': 'gada_gadiem_gads_gadi'.split('_'),\n        'yy': 'gada_gadiem_gads_gadi'.split('_')\n    };\n    /**\n     * @param withoutSuffix boolean true = a length of time; false = before/after a period of time.\n     */\n    function lv__format(forms, number, withoutSuffix) {\n        if (withoutSuffix) {\n            // E.g. \"21 minūte\", \"3 minūtes\".\n            return number % 10 === 1 && number !== 11 ? forms[2] : forms[3];\n        } else {\n            // E.g. \"21 minūtes\" as in \"pēc 21 minūtes\".\n            // E.g. \"3 minūtēm\" as in \"pēc 3 minūtēm\".\n            return number % 10 === 1 && number !== 11 ? forms[0] : forms[1];\n        }\n    }\n    function lv__relativeTimeWithPlural(number, withoutSuffix, key) {\n        return number + ' ' + lv__format(lv__units[key], number, withoutSuffix);\n    }\n    function relativeTimeWithSingular(number, withoutSuffix, key) {\n        return lv__format(lv__units[key], number, withoutSuffix);\n    }\n    function relativeSeconds(number, withoutSuffix) {\n        return withoutSuffix ? 'dažas sekundes' : 'dažām sekundēm';\n    }\n\n    var lv = _moment__default.defineLocale('lv', {\n        months : 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split('_'),\n        monthsShort : 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'),\n        weekdays : 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split('_'),\n        weekdaysShort : 'Sv_P_O_T_C_Pk_S'.split('_'),\n        weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY.',\n            LL : 'YYYY. [gada] D. MMMM',\n            LLL : 'YYYY. [gada] D. MMMM, HH:mm',\n            LLLL : 'YYYY. [gada] D. MMMM, dddd, HH:mm'\n        },\n        calendar : {\n            sameDay : '[Šodien pulksten] LT',\n            nextDay : '[Rīt pulksten] LT',\n            nextWeek : 'dddd [pulksten] LT',\n            lastDay : '[Vakar pulksten] LT',\n            lastWeek : '[Pagājušā] dddd [pulksten] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'pēc %s',\n            past : 'pirms %s',\n            s : relativeSeconds,\n            m : relativeTimeWithSingular,\n            mm : lv__relativeTimeWithPlural,\n            h : relativeTimeWithSingular,\n            hh : lv__relativeTimeWithPlural,\n            d : relativeTimeWithSingular,\n            dd : lv__relativeTimeWithPlural,\n            M : relativeTimeWithSingular,\n            MM : lv__relativeTimeWithPlural,\n            y : relativeTimeWithSingular,\n            yy : lv__relativeTimeWithPlural\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Montenegrin (me)\n    //! author : Miodrag Nikač <miodrag@restartit.me> : https://github.com/miodragnikac\n\n    var me__translator = {\n        words: { //Different grammatical cases\n            m: ['jedan minut', 'jednog minuta'],\n            mm: ['minut', 'minuta', 'minuta'],\n            h: ['jedan sat', 'jednog sata'],\n            hh: ['sat', 'sata', 'sati'],\n            dd: ['dan', 'dana', 'dana'],\n            MM: ['mjesec', 'mjeseca', 'mjeseci'],\n            yy: ['godina', 'godine', 'godina']\n        },\n        correctGrammaticalCase: function (number, wordKey) {\n            return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);\n        },\n        translate: function (number, withoutSuffix, key) {\n            var wordKey = me__translator.words[key];\n            if (key.length === 1) {\n                return withoutSuffix ? wordKey[0] : wordKey[1];\n            } else {\n                return number + ' ' + me__translator.correctGrammaticalCase(number, wordKey);\n            }\n        }\n    };\n\n    var me = _moment__default.defineLocale('me', {\n        months: ['januar', 'februar', 'mart', 'april', 'maj', 'jun', 'jul', 'avgust', 'septembar', 'oktobar', 'novembar', 'decembar'],\n        monthsShort: ['jan.', 'feb.', 'mar.', 'apr.', 'maj', 'jun', 'jul', 'avg.', 'sep.', 'okt.', 'nov.', 'dec.'],\n        weekdays: ['nedjelja', 'ponedjeljak', 'utorak', 'srijeda', 'četvrtak', 'petak', 'subota'],\n        weekdaysShort: ['ned.', 'pon.', 'uto.', 'sri.', 'čet.', 'pet.', 'sub.'],\n        weekdaysMin: ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'],\n        longDateFormat: {\n            LT: 'H:mm',\n            LTS : 'H:mm:ss',\n            L: 'DD. MM. YYYY',\n            LL: 'D. MMMM YYYY',\n            LLL: 'D. MMMM YYYY H:mm',\n            LLLL: 'dddd, D. MMMM YYYY H:mm'\n        },\n        calendar: {\n            sameDay: '[danas u] LT',\n            nextDay: '[sjutra u] LT',\n\n            nextWeek: function () {\n                switch (this.day()) {\n                case 0:\n                    return '[u] [nedjelju] [u] LT';\n                case 3:\n                    return '[u] [srijedu] [u] LT';\n                case 6:\n                    return '[u] [subotu] [u] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[u] dddd [u] LT';\n                }\n            },\n            lastDay  : '[juče u] LT',\n            lastWeek : function () {\n                var lastWeekDays = [\n                    '[prošle] [nedjelje] [u] LT',\n                    '[prošlog] [ponedjeljka] [u] LT',\n                    '[prošlog] [utorka] [u] LT',\n                    '[prošle] [srijede] [u] LT',\n                    '[prošlog] [četvrtka] [u] LT',\n                    '[prošlog] [petka] [u] LT',\n                    '[prošle] [subote] [u] LT'\n                ];\n                return lastWeekDays[this.day()];\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'za %s',\n            past   : 'prije %s',\n            s      : 'nekoliko sekundi',\n            m      : me__translator.translate,\n            mm     : me__translator.translate,\n            h      : me__translator.translate,\n            hh     : me__translator.translate,\n            d      : 'dan',\n            dd     : me__translator.translate,\n            M      : 'mjesec',\n            MM     : me__translator.translate,\n            y      : 'godinu',\n            yy     : me__translator.translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : macedonian (mk)\n    //! author : Borislav Mickov : https://github.com/B0k0\n\n    var mk = _moment__default.defineLocale('mk', {\n        months : 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split('_'),\n        monthsShort : 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'),\n        weekdays : 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split('_'),\n        weekdaysShort : 'нед_пон_вто_сре_чет_пет_саб'.split('_'),\n        weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'D.MM.YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY H:mm',\n            LLLL : 'dddd, D MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay : '[Денес во] LT',\n            nextDay : '[Утре во] LT',\n            nextWeek : 'dddd [во] LT',\n            lastDay : '[Вчера во] LT',\n            lastWeek : function () {\n                switch (this.day()) {\n                case 0:\n                case 3:\n                case 6:\n                    return '[Во изминатата] dddd [во] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[Во изминатиот] dddd [во] LT';\n                }\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'после %s',\n            past : 'пред %s',\n            s : 'неколку секунди',\n            m : 'минута',\n            mm : '%d минути',\n            h : 'час',\n            hh : '%d часа',\n            d : 'ден',\n            dd : '%d дена',\n            M : 'месец',\n            MM : '%d месеци',\n            y : 'година',\n            yy : '%d години'\n        },\n        ordinalParse: /\\d{1,2}-(ев|ен|ти|ви|ри|ми)/,\n        ordinal : function (number) {\n            var lastDigit = number % 10,\n                last2Digits = number % 100;\n            if (number === 0) {\n                return number + '-ев';\n            } else if (last2Digits === 0) {\n                return number + '-ен';\n            } else if (last2Digits > 10 && last2Digits < 20) {\n                return number + '-ти';\n            } else if (lastDigit === 1) {\n                return number + '-ви';\n            } else if (lastDigit === 2) {\n                return number + '-ри';\n            } else if (lastDigit === 7 || lastDigit === 8) {\n                return number + '-ми';\n            } else {\n                return number + '-ти';\n            }\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : malayalam (ml)\n    //! author : Floyd Pink : https://github.com/floydpink\n\n    var ml = _moment__default.defineLocale('ml', {\n        months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'),\n        monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'),\n        weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'),\n        weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'),\n        weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'),\n        longDateFormat : {\n            LT : 'A h:mm -നു',\n            LTS : 'A h:mm:ss -നു',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY, A h:mm -നു',\n            LLLL : 'dddd, D MMMM YYYY, A h:mm -നു'\n        },\n        calendar : {\n            sameDay : '[ഇന്ന്] LT',\n            nextDay : '[നാളെ] LT',\n            nextWeek : 'dddd, LT',\n            lastDay : '[ഇന്നലെ] LT',\n            lastWeek : '[കഴിഞ്ഞ] dddd, LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s കഴിഞ്ഞ്',\n            past : '%s മുൻപ്',\n            s : 'അൽപ നിമിഷങ്ങൾ',\n            m : 'ഒരു മിനിറ്റ്',\n            mm : '%d മിനിറ്റ്',\n            h : 'ഒരു മണിക്കൂർ',\n            hh : '%d മണിക്കൂർ',\n            d : 'ഒരു ദിവസം',\n            dd : '%d ദിവസം',\n            M : 'ഒരു മാസം',\n            MM : '%d മാസം',\n            y : 'ഒരു വർഷം',\n            yy : '%d വർഷം'\n        },\n        meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,\n        isPM : function (input) {\n            return /^(ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി)$/.test(input);\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'രാത്രി';\n            } else if (hour < 12) {\n                return 'രാവിലെ';\n            } else if (hour < 17) {\n                return 'ഉച്ച കഴിഞ്ഞ്';\n            } else if (hour < 20) {\n                return 'വൈകുന്നേരം';\n            } else {\n                return 'രാത്രി';\n            }\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Marathi (mr)\n    //! author : Harshad Kale : https://github.com/kalehv\n\n    var mr__symbolMap = {\n        '1': '१',\n        '2': '२',\n        '3': '३',\n        '4': '४',\n        '5': '५',\n        '6': '६',\n        '7': '७',\n        '8': '८',\n        '9': '९',\n        '0': '०'\n    },\n    mr__numberMap = {\n        '१': '1',\n        '२': '2',\n        '३': '3',\n        '४': '4',\n        '५': '5',\n        '६': '6',\n        '७': '7',\n        '८': '8',\n        '९': '9',\n        '०': '0'\n    };\n\n    var mr = _moment__default.defineLocale('mr', {\n        months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'),\n        monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'),\n        weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),\n        weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'),\n        weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),\n        longDateFormat : {\n            LT : 'A h:mm वाजता',\n            LTS : 'A h:mm:ss वाजता',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY, A h:mm वाजता',\n            LLLL : 'dddd, D MMMM YYYY, A h:mm वाजता'\n        },\n        calendar : {\n            sameDay : '[आज] LT',\n            nextDay : '[उद्या] LT',\n            nextWeek : 'dddd, LT',\n            lastDay : '[काल] LT',\n            lastWeek: '[मागील] dddd, LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s नंतर',\n            past : '%s पूर्वी',\n            s : 'सेकंद',\n            m: 'एक मिनिट',\n            mm: '%d मिनिटे',\n            h : 'एक तास',\n            hh : '%d तास',\n            d : 'एक दिवस',\n            dd : '%d दिवस',\n            M : 'एक महिना',\n            MM : '%d महिने',\n            y : 'एक वर्ष',\n            yy : '%d वर्षे'\n        },\n        preparse: function (string) {\n            return string.replace(/[१२३४५६७८९०]/g, function (match) {\n                return mr__numberMap[match];\n            });\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return mr__symbolMap[match];\n            });\n        },\n        meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/,\n        meridiemHour : function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === 'रात्री') {\n                return hour < 4 ? hour : hour + 12;\n            } else if (meridiem === 'सकाळी') {\n                return hour;\n            } else if (meridiem === 'दुपारी') {\n                return hour >= 10 ? hour : hour + 12;\n            } else if (meridiem === 'सायंकाळी') {\n                return hour + 12;\n            }\n        },\n        meridiem: function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'रात्री';\n            } else if (hour < 10) {\n                return 'सकाळी';\n            } else if (hour < 17) {\n                return 'दुपारी';\n            } else if (hour < 20) {\n                return 'सायंकाळी';\n            } else {\n                return 'रात्री';\n            }\n        },\n        week : {\n            dow : 0, // Sunday is the first day of the week.\n            doy : 6  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Bahasa Malaysia (ms-MY)\n    //! author : Weldan Jamili : https://github.com/weldan\n\n    var ms_my = _moment__default.defineLocale('ms-my', {\n        months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),\n        monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),\n        weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),\n        weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),\n        weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),\n        longDateFormat : {\n            LT : 'HH.mm',\n            LTS : 'HH.mm.ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY [pukul] HH.mm',\n            LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'\n        },\n        meridiemParse: /pagi|tengahari|petang|malam/,\n        meridiemHour: function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === 'pagi') {\n                return hour;\n            } else if (meridiem === 'tengahari') {\n                return hour >= 11 ? hour : hour + 12;\n            } else if (meridiem === 'petang' || meridiem === 'malam') {\n                return hour + 12;\n            }\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours < 11) {\n                return 'pagi';\n            } else if (hours < 15) {\n                return 'tengahari';\n            } else if (hours < 19) {\n                return 'petang';\n            } else {\n                return 'malam';\n            }\n        },\n        calendar : {\n            sameDay : '[Hari ini pukul] LT',\n            nextDay : '[Esok pukul] LT',\n            nextWeek : 'dddd [pukul] LT',\n            lastDay : '[Kelmarin pukul] LT',\n            lastWeek : 'dddd [lepas pukul] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'dalam %s',\n            past : '%s yang lepas',\n            s : 'beberapa saat',\n            m : 'seminit',\n            mm : '%d minit',\n            h : 'sejam',\n            hh : '%d jam',\n            d : 'sehari',\n            dd : '%d hari',\n            M : 'sebulan',\n            MM : '%d bulan',\n            y : 'setahun',\n            yy : '%d tahun'\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Bahasa Malaysia (ms-MY)\n    //! author : Weldan Jamili : https://github.com/weldan\n\n    var locale_ms = _moment__default.defineLocale('ms', {\n        months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'),\n        monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'),\n        weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'),\n        weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'),\n        weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),\n        longDateFormat : {\n            LT : 'HH.mm',\n            LTS : 'HH.mm.ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY [pukul] HH.mm',\n            LLLL : 'dddd, D MMMM YYYY [pukul] HH.mm'\n        },\n        meridiemParse: /pagi|tengahari|petang|malam/,\n        meridiemHour: function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === 'pagi') {\n                return hour;\n            } else if (meridiem === 'tengahari') {\n                return hour >= 11 ? hour : hour + 12;\n            } else if (meridiem === 'petang' || meridiem === 'malam') {\n                return hour + 12;\n            }\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours < 11) {\n                return 'pagi';\n            } else if (hours < 15) {\n                return 'tengahari';\n            } else if (hours < 19) {\n                return 'petang';\n            } else {\n                return 'malam';\n            }\n        },\n        calendar : {\n            sameDay : '[Hari ini pukul] LT',\n            nextDay : '[Esok pukul] LT',\n            nextWeek : 'dddd [pukul] LT',\n            lastDay : '[Kelmarin pukul] LT',\n            lastWeek : 'dddd [lepas pukul] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'dalam %s',\n            past : '%s yang lepas',\n            s : 'beberapa saat',\n            m : 'seminit',\n            mm : '%d minit',\n            h : 'sejam',\n            hh : '%d jam',\n            d : 'sehari',\n            dd : '%d hari',\n            M : 'sebulan',\n            MM : '%d bulan',\n            y : 'setahun',\n            yy : '%d tahun'\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Burmese (my)\n    //! author : Squar team, mysquar.com\n\n    var my__symbolMap = {\n        '1': '၁',\n        '2': '၂',\n        '3': '၃',\n        '4': '၄',\n        '5': '၅',\n        '6': '၆',\n        '7': '၇',\n        '8': '၈',\n        '9': '၉',\n        '0': '၀'\n    }, my__numberMap = {\n        '၁': '1',\n        '၂': '2',\n        '၃': '3',\n        '၄': '4',\n        '၅': '5',\n        '၆': '6',\n        '၇': '7',\n        '၈': '8',\n        '၉': '9',\n        '၀': '0'\n    };\n\n    var my = _moment__default.defineLocale('my', {\n        months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split('_'),\n        monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'),\n        weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split('_'),\n        weekdaysShort: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),\n        weekdaysMin: 'နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),\n\n        longDateFormat: {\n            LT: 'HH:mm',\n            LTS: 'HH:mm:ss',\n            L: 'DD/MM/YYYY',\n            LL: 'D MMMM YYYY',\n            LLL: 'D MMMM YYYY HH:mm',\n            LLLL: 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar: {\n            sameDay: '[ယနေ.] LT [မှာ]',\n            nextDay: '[မနက်ဖြန်] LT [မှာ]',\n            nextWeek: 'dddd LT [မှာ]',\n            lastDay: '[မနေ.က] LT [မှာ]',\n            lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]',\n            sameElse: 'L'\n        },\n        relativeTime: {\n            future: 'လာမည့် %s မှာ',\n            past: 'လွန်ခဲ့သော %s က',\n            s: 'စက္ကန်.အနည်းငယ်',\n            m: 'တစ်မိနစ်',\n            mm: '%d မိနစ်',\n            h: 'တစ်နာရီ',\n            hh: '%d နာရီ',\n            d: 'တစ်ရက်',\n            dd: '%d ရက်',\n            M: 'တစ်လ',\n            MM: '%d လ',\n            y: 'တစ်နှစ်',\n            yy: '%d နှစ်'\n        },\n        preparse: function (string) {\n            return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) {\n                return my__numberMap[match];\n            });\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return my__symbolMap[match];\n            });\n        },\n        week: {\n            dow: 1, // Monday is the first day of the week.\n            doy: 4 // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : norwegian bokmål (nb)\n    //! authors : Espen Hovlandsdal : https://github.com/rexxars\n    //!           Sigurd Gartmann : https://github.com/sigurdga\n\n    var nb = _moment__default.defineLocale('nb', {\n        months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),\n        monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),\n        weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'),\n        weekdaysShort : 'søn_man_tirs_ons_tors_fre_lør'.split('_'),\n        weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),\n        longDateFormat : {\n            LT : 'H.mm',\n            LTS : 'H.mm.ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY [kl.] H.mm',\n            LLLL : 'dddd D. MMMM YYYY [kl.] H.mm'\n        },\n        calendar : {\n            sameDay: '[i dag kl.] LT',\n            nextDay: '[i morgen kl.] LT',\n            nextWeek: 'dddd [kl.] LT',\n            lastDay: '[i går kl.] LT',\n            lastWeek: '[forrige] dddd [kl.] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'om %s',\n            past : 'for %s siden',\n            s : 'noen sekunder',\n            m : 'ett minutt',\n            mm : '%d minutter',\n            h : 'en time',\n            hh : '%d timer',\n            d : 'en dag',\n            dd : '%d dager',\n            M : 'en måned',\n            MM : '%d måneder',\n            y : 'ett år',\n            yy : '%d år'\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : nepali/nepalese\n    //! author : suvash : https://github.com/suvash\n\n    var ne__symbolMap = {\n        '1': '१',\n        '2': '२',\n        '3': '३',\n        '4': '४',\n        '5': '५',\n        '6': '६',\n        '7': '७',\n        '8': '८',\n        '9': '९',\n        '0': '०'\n    },\n    ne__numberMap = {\n        '१': '1',\n        '२': '2',\n        '३': '3',\n        '४': '4',\n        '५': '5',\n        '६': '6',\n        '७': '7',\n        '८': '8',\n        '९': '9',\n        '०': '0'\n    };\n\n    var ne = _moment__default.defineLocale('ne', {\n        months : 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split('_'),\n        monthsShort : 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split('_'),\n        weekdays : 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split('_'),\n        weekdaysShort : 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'),\n        weekdaysMin : 'आइ._सो._मङ्_बु._बि._शु._श.'.split('_'),\n        longDateFormat : {\n            LT : 'Aको h:mm बजे',\n            LTS : 'Aको h:mm:ss बजे',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY, Aको h:mm बजे',\n            LLLL : 'dddd, D MMMM YYYY, Aको h:mm बजे'\n        },\n        preparse: function (string) {\n            return string.replace(/[१२३४५६७८९०]/g, function (match) {\n                return ne__numberMap[match];\n            });\n        },\n        postformat: function (string) {\n            return string.replace(/\\d/g, function (match) {\n                return ne__symbolMap[match];\n            });\n        },\n        meridiemParse: /राती|बिहान|दिउँसो|बेलुका|साँझ|राती/,\n        meridiemHour : function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === 'राती') {\n                return hour < 3 ? hour : hour + 12;\n            } else if (meridiem === 'बिहान') {\n                return hour;\n            } else if (meridiem === 'दिउँसो') {\n                return hour >= 10 ? hour : hour + 12;\n            } else if (meridiem === 'बेलुका' || meridiem === 'साँझ') {\n                return hour + 12;\n            }\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 3) {\n                return 'राती';\n            } else if (hour < 10) {\n                return 'बिहान';\n            } else if (hour < 15) {\n                return 'दिउँसो';\n            } else if (hour < 18) {\n                return 'बेलुका';\n            } else if (hour < 20) {\n                return 'साँझ';\n            } else {\n                return 'राती';\n            }\n        },\n        calendar : {\n            sameDay : '[आज] LT',\n            nextDay : '[भोली] LT',\n            nextWeek : '[आउँदो] dddd[,] LT',\n            lastDay : '[हिजो] LT',\n            lastWeek : '[गएको] dddd[,] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%sमा',\n            past : '%s अगाडी',\n            s : 'केही समय',\n            m : 'एक मिनेट',\n            mm : '%d मिनेट',\n            h : 'एक घण्टा',\n            hh : '%d घण्टा',\n            d : 'एक दिन',\n            dd : '%d दिन',\n            M : 'एक महिना',\n            MM : '%d महिना',\n            y : 'एक बर्ष',\n            yy : '%d बर्ष'\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : dutch (nl)\n    //! author : Joris Röling : https://github.com/jjupiter\n\n    var nl__monthsShortWithDots = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'),\n        nl__monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_');\n\n    var nl = _moment__default.defineLocale('nl', {\n        months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'),\n        monthsShort : function (m, format) {\n            if (/-MMM-/.test(format)) {\n                return nl__monthsShortWithoutDots[m.month()];\n            } else {\n                return nl__monthsShortWithDots[m.month()];\n            }\n        },\n        weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'),\n        weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'),\n        weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD-MM-YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[vandaag om] LT',\n            nextDay: '[morgen om] LT',\n            nextWeek: 'dddd [om] LT',\n            lastDay: '[gisteren om] LT',\n            lastWeek: '[afgelopen] dddd [om] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'over %s',\n            past : '%s geleden',\n            s : 'een paar seconden',\n            m : 'één minuut',\n            mm : '%d minuten',\n            h : 'één uur',\n            hh : '%d uur',\n            d : 'één dag',\n            dd : '%d dagen',\n            M : 'één maand',\n            MM : '%d maanden',\n            y : 'één jaar',\n            yy : '%d jaar'\n        },\n        ordinalParse: /\\d{1,2}(ste|de)/,\n        ordinal : function (number) {\n            return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : norwegian nynorsk (nn)\n    //! author : https://github.com/mechuwind\n\n    var nn = _moment__default.defineLocale('nn', {\n        months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'),\n        monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'),\n        weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'),\n        weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'),\n        weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[I dag klokka] LT',\n            nextDay: '[I morgon klokka] LT',\n            nextWeek: 'dddd [klokka] LT',\n            lastDay: '[I går klokka] LT',\n            lastWeek: '[Føregåande] dddd [klokka] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'om %s',\n            past : 'for %s sidan',\n            s : 'nokre sekund',\n            m : 'eit minutt',\n            mm : '%d minutt',\n            h : 'ein time',\n            hh : '%d timar',\n            d : 'ein dag',\n            dd : '%d dagar',\n            M : 'ein månad',\n            MM : '%d månader',\n            y : 'eit år',\n            yy : '%d år'\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : polish (pl)\n    //! author : Rafal Hirsz : https://github.com/evoL\n\n    var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_'),\n        monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_');\n    function pl__plural(n) {\n        return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1);\n    }\n    function pl__translate(number, withoutSuffix, key) {\n        var result = number + ' ';\n        switch (key) {\n        case 'm':\n            return withoutSuffix ? 'minuta' : 'minutę';\n        case 'mm':\n            return result + (pl__plural(number) ? 'minuty' : 'minut');\n        case 'h':\n            return withoutSuffix  ? 'godzina'  : 'godzinę';\n        case 'hh':\n            return result + (pl__plural(number) ? 'godziny' : 'godzin');\n        case 'MM':\n            return result + (pl__plural(number) ? 'miesiące' : 'miesięcy');\n        case 'yy':\n            return result + (pl__plural(number) ? 'lata' : 'lat');\n        }\n    }\n\n    var pl = _moment__default.defineLocale('pl', {\n        months : function (momentToFormat, format) {\n            if (format === '') {\n                // Hack: if format empty we know this is used to generate\n                // RegExp by moment. Give then back both valid forms of months\n                // in RegExp ready format.\n                return '(' + monthsSubjective[momentToFormat.month()] + '|' + monthsNominative[momentToFormat.month()] + ')';\n            } else if (/D MMMM/.test(format)) {\n                return monthsSubjective[momentToFormat.month()];\n            } else {\n                return monthsNominative[momentToFormat.month()];\n            }\n        },\n        monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'),\n        weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'),\n        weekdaysShort : 'nie_pon_wt_śr_czw_pt_sb'.split('_'),\n        weekdaysMin : 'N_Pn_Wt_Śr_Cz_Pt_So'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Dziś o] LT',\n            nextDay: '[Jutro o] LT',\n            nextWeek: '[W] dddd [o] LT',\n            lastDay: '[Wczoraj o] LT',\n            lastWeek: function () {\n                switch (this.day()) {\n                case 0:\n                    return '[W zeszłą niedzielę o] LT';\n                case 3:\n                    return '[W zeszłą środę o] LT';\n                case 6:\n                    return '[W zeszłą sobotę o] LT';\n                default:\n                    return '[W zeszły] dddd [o] LT';\n                }\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'za %s',\n            past : '%s temu',\n            s : 'kilka sekund',\n            m : pl__translate,\n            mm : pl__translate,\n            h : pl__translate,\n            hh : pl__translate,\n            d : '1 dzień',\n            dd : '%d dni',\n            M : 'miesiąc',\n            MM : pl__translate,\n            y : 'rok',\n            yy : pl__translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : brazilian portuguese (pt-br)\n    //! author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira\n\n    var pt_br = _moment__default.defineLocale('pt-br', {\n        months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),\n        monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),\n        weekdays : 'Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado'.split('_'),\n        weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),\n        weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D [de] MMMM [de] YYYY',\n            LLL : 'D [de] MMMM [de] YYYY [às] HH:mm',\n            LLLL : 'dddd, D [de] MMMM [de] YYYY [às] HH:mm'\n        },\n        calendar : {\n            sameDay: '[Hoje às] LT',\n            nextDay: '[Amanhã às] LT',\n            nextWeek: 'dddd [às] LT',\n            lastDay: '[Ontem às] LT',\n            lastWeek: function () {\n                return (this.day() === 0 || this.day() === 6) ?\n                    '[Último] dddd [às] LT' : // Saturday + Sunday\n                    '[Última] dddd [às] LT'; // Monday - Friday\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'em %s',\n            past : '%s atrás',\n            s : 'poucos segundos',\n            m : 'um minuto',\n            mm : '%d minutos',\n            h : 'uma hora',\n            hh : '%d horas',\n            d : 'um dia',\n            dd : '%d dias',\n            M : 'um mês',\n            MM : '%d meses',\n            y : 'um ano',\n            yy : '%d anos'\n        },\n        ordinalParse: /\\d{1,2}º/,\n        ordinal : '%dº'\n    });\n\n    //! moment.js locale configuration\n    //! locale : portuguese (pt)\n    //! author : Jefferson : https://github.com/jalex79\n\n    var pt = _moment__default.defineLocale('pt', {\n        months : 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),\n        monthsShort : 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),\n        weekdays : 'Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado'.split('_'),\n        weekdaysShort : 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),\n        weekdaysMin : 'Dom_2ª_3ª_4ª_5ª_6ª_Sáb'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D [de] MMMM [de] YYYY',\n            LLL : 'D [de] MMMM [de] YYYY HH:mm',\n            LLLL : 'dddd, D [de] MMMM [de] YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Hoje às] LT',\n            nextDay: '[Amanhã às] LT',\n            nextWeek: 'dddd [às] LT',\n            lastDay: '[Ontem às] LT',\n            lastWeek: function () {\n                return (this.day() === 0 || this.day() === 6) ?\n                    '[Último] dddd [às] LT' : // Saturday + Sunday\n                    '[Última] dddd [às] LT'; // Monday - Friday\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'em %s',\n            past : 'há %s',\n            s : 'segundos',\n            m : 'um minuto',\n            mm : '%d minutos',\n            h : 'uma hora',\n            hh : '%d horas',\n            d : 'um dia',\n            dd : '%d dias',\n            M : 'um mês',\n            MM : '%d meses',\n            y : 'um ano',\n            yy : '%d anos'\n        },\n        ordinalParse: /\\d{1,2}º/,\n        ordinal : '%dº',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : romanian (ro)\n    //! author : Vlad Gurdiga : https://github.com/gurdiga\n    //! author : Valentin Agachi : https://github.com/avaly\n\n    function ro__relativeTimeWithPlural(number, withoutSuffix, key) {\n        var format = {\n                'mm': 'minute',\n                'hh': 'ore',\n                'dd': 'zile',\n                'MM': 'luni',\n                'yy': 'ani'\n            },\n            separator = ' ';\n        if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) {\n            separator = ' de ';\n        }\n        return number + separator + format[key];\n    }\n\n    var ro = _moment__default.defineLocale('ro', {\n        months : 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split('_'),\n        monthsShort : 'ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split('_'),\n        weekdays : 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'),\n        weekdaysShort : 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'),\n        weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY H:mm',\n            LLLL : 'dddd, D MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay: '[azi la] LT',\n            nextDay: '[mâine la] LT',\n            nextWeek: 'dddd [la] LT',\n            lastDay: '[ieri la] LT',\n            lastWeek: '[fosta] dddd [la] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'peste %s',\n            past : '%s în urmă',\n            s : 'câteva secunde',\n            m : 'un minut',\n            mm : ro__relativeTimeWithPlural,\n            h : 'o oră',\n            hh : ro__relativeTimeWithPlural,\n            d : 'o zi',\n            dd : ro__relativeTimeWithPlural,\n            M : 'o lună',\n            MM : ro__relativeTimeWithPlural,\n            y : 'un an',\n            yy : ro__relativeTimeWithPlural\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : russian (ru)\n    //! author : Viktorminator : https://github.com/Viktorminator\n    //! Author : Menelion Elensúle : https://github.com/Oire\n\n    function ru__plural(word, num) {\n        var forms = word.split('_');\n        return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);\n    }\n    function ru__relativeTimeWithPlural(number, withoutSuffix, key) {\n        var format = {\n            'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут',\n            'hh': 'час_часа_часов',\n            'dd': 'день_дня_дней',\n            'MM': 'месяц_месяца_месяцев',\n            'yy': 'год_года_лет'\n        };\n        if (key === 'm') {\n            return withoutSuffix ? 'минута' : 'минуту';\n        }\n        else {\n            return number + ' ' + ru__plural(format[key], +number);\n        }\n    }\n    function ru__monthsCaseReplace(m, format) {\n        var months = {\n            'nominative': 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),\n            'accusative': 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_')\n        },\n        nounCase = (/D[oD]?(\\[[^\\[\\]]*\\]|\\s+)+MMMM?/).test(format) ?\n            'accusative' :\n            'nominative';\n        return months[nounCase][m.month()];\n    }\n    function ru__monthsShortCaseReplace(m, format) {\n        var monthsShort = {\n            'nominative': 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),\n            'accusative': 'янв_фев_мар_апр_мая_июня_июля_авг_сен_окт_ноя_дек'.split('_')\n        },\n        nounCase = (/D[oD]?(\\[[^\\[\\]]*\\]|\\s+)+MMMM?/).test(format) ?\n            'accusative' :\n            'nominative';\n        return monthsShort[nounCase][m.month()];\n    }\n    function ru__weekdaysCaseReplace(m, format) {\n        var weekdays = {\n            'nominative': 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'),\n            'accusative': 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_')\n        },\n        nounCase = (/\\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\\] ?dddd/).test(format) ?\n            'accusative' :\n            'nominative';\n        return weekdays[nounCase][m.day()];\n    }\n\n    var ru = _moment__default.defineLocale('ru', {\n        months : ru__monthsCaseReplace,\n        monthsShort : ru__monthsShortCaseReplace,\n        weekdays : ru__weekdaysCaseReplace,\n        weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),\n        weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'),\n        monthsParse : [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[й|я]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i],\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY г.',\n            LLL : 'D MMMM YYYY г., HH:mm',\n            LLLL : 'dddd, D MMMM YYYY г., HH:mm'\n        },\n        calendar : {\n            sameDay: '[Сегодня в] LT',\n            nextDay: '[Завтра в] LT',\n            lastDay: '[Вчера в] LT',\n            nextWeek: function () {\n                return this.day() === 2 ? '[Во] dddd [в] LT' : '[В] dddd [в] LT';\n            },\n            lastWeek: function (now) {\n                if (now.week() !== this.week()) {\n                    switch (this.day()) {\n                    case 0:\n                        return '[В прошлое] dddd [в] LT';\n                    case 1:\n                    case 2:\n                    case 4:\n                        return '[В прошлый] dddd [в] LT';\n                    case 3:\n                    case 5:\n                    case 6:\n                        return '[В прошлую] dddd [в] LT';\n                    }\n                } else {\n                    if (this.day() === 2) {\n                        return '[Во] dddd [в] LT';\n                    } else {\n                        return '[В] dddd [в] LT';\n                    }\n                }\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'через %s',\n            past : '%s назад',\n            s : 'несколько секунд',\n            m : ru__relativeTimeWithPlural,\n            mm : ru__relativeTimeWithPlural,\n            h : 'час',\n            hh : ru__relativeTimeWithPlural,\n            d : 'день',\n            dd : ru__relativeTimeWithPlural,\n            M : 'месяц',\n            MM : ru__relativeTimeWithPlural,\n            y : 'год',\n            yy : ru__relativeTimeWithPlural\n        },\n        meridiemParse: /ночи|утра|дня|вечера/i,\n        isPM : function (input) {\n            return /^(дня|вечера)$/.test(input);\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'ночи';\n            } else if (hour < 12) {\n                return 'утра';\n            } else if (hour < 17) {\n                return 'дня';\n            } else {\n                return 'вечера';\n            }\n        },\n        ordinalParse: /\\d{1,2}-(й|го|я)/,\n        ordinal: function (number, period) {\n            switch (period) {\n            case 'M':\n            case 'd':\n            case 'DDD':\n                return number + '-й';\n            case 'D':\n                return number + '-го';\n            case 'w':\n            case 'W':\n                return number + '-я';\n            default:\n                return number;\n            }\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Sinhalese (si)\n    //! author : Sampath Sitinamaluwa : https://github.com/sampathsris\n\n    var si = _moment__default.defineLocale('si', {\n        months : 'ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්'.split('_'),\n        monthsShort : 'ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ'.split('_'),\n        weekdays : 'ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා'.split('_'),\n        weekdaysShort : 'ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන'.split('_'),\n        weekdaysMin : 'ඉ_ස_අ_බ_බ්‍ර_සි_සෙ'.split('_'),\n        longDateFormat : {\n            LT : 'a h:mm',\n            LTS : 'a h:mm:ss',\n            L : 'YYYY/MM/DD',\n            LL : 'YYYY MMMM D',\n            LLL : 'YYYY MMMM D, a h:mm',\n            LLLL : 'YYYY MMMM D [වැනි] dddd, a h:mm:ss'\n        },\n        calendar : {\n            sameDay : '[අද] LT[ට]',\n            nextDay : '[හෙට] LT[ට]',\n            nextWeek : 'dddd LT[ට]',\n            lastDay : '[ඊයේ] LT[ට]',\n            lastWeek : '[පසුගිය] dddd LT[ට]',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%sකින්',\n            past : '%sකට පෙර',\n            s : 'තත්පර කිහිපය',\n            m : 'මිනිත්තුව',\n            mm : 'මිනිත්තු %d',\n            h : 'පැය',\n            hh : 'පැය %d',\n            d : 'දිනය',\n            dd : 'දින %d',\n            M : 'මාසය',\n            MM : 'මාස %d',\n            y : 'වසර',\n            yy : 'වසර %d'\n        },\n        ordinalParse: /\\d{1,2} වැනි/,\n        ordinal : function (number) {\n            return number + ' වැනි';\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours > 11) {\n                return isLower ? 'ප.ව.' : 'පස් වරු';\n            } else {\n                return isLower ? 'පෙ.ව.' : 'පෙර වරු';\n            }\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : slovak (sk)\n    //! author : Martin Minka : https://github.com/k2s\n    //! based on work of petrbela : https://github.com/petrbela\n\n    var sk__months = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_'),\n        sk__monthsShort = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_');\n    function sk__plural(n) {\n        return (n > 1) && (n < 5);\n    }\n    function sk__translate(number, withoutSuffix, key, isFuture) {\n        var result = number + ' ';\n        switch (key) {\n        case 's':  // a few seconds / in a few seconds / a few seconds ago\n            return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami';\n        case 'm':  // a minute / in a minute / a minute ago\n            return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou');\n        case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago\n            if (withoutSuffix || isFuture) {\n                return result + (sk__plural(number) ? 'minúty' : 'minút');\n            } else {\n                return result + 'minútami';\n            }\n            break;\n        case 'h':  // an hour / in an hour / an hour ago\n            return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou');\n        case 'hh': // 9 hours / in 9 hours / 9 hours ago\n            if (withoutSuffix || isFuture) {\n                return result + (sk__plural(number) ? 'hodiny' : 'hodín');\n            } else {\n                return result + 'hodinami';\n            }\n            break;\n        case 'd':  // a day / in a day / a day ago\n            return (withoutSuffix || isFuture) ? 'deň' : 'dňom';\n        case 'dd': // 9 days / in 9 days / 9 days ago\n            if (withoutSuffix || isFuture) {\n                return result + (sk__plural(number) ? 'dni' : 'dní');\n            } else {\n                return result + 'dňami';\n            }\n            break;\n        case 'M':  // a month / in a month / a month ago\n            return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom';\n        case 'MM': // 9 months / in 9 months / 9 months ago\n            if (withoutSuffix || isFuture) {\n                return result + (sk__plural(number) ? 'mesiace' : 'mesiacov');\n            } else {\n                return result + 'mesiacmi';\n            }\n            break;\n        case 'y':  // a year / in a year / a year ago\n            return (withoutSuffix || isFuture) ? 'rok' : 'rokom';\n        case 'yy': // 9 years / in 9 years / 9 years ago\n            if (withoutSuffix || isFuture) {\n                return result + (sk__plural(number) ? 'roky' : 'rokov');\n            } else {\n                return result + 'rokmi';\n            }\n            break;\n        }\n    }\n\n    var sk = _moment__default.defineLocale('sk', {\n        months : sk__months,\n        monthsShort : sk__monthsShort,\n        monthsParse : (function (months, monthsShort) {\n            var i, _monthsParse = [];\n            for (i = 0; i < 12; i++) {\n                // use custom parser to solve problem with July (červenec)\n                _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i');\n            }\n            return _monthsParse;\n        }(sk__months, sk__monthsShort)),\n        weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'),\n        weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'),\n        weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'),\n        longDateFormat : {\n            LT: 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY H:mm',\n            LLLL : 'dddd D. MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay: '[dnes o] LT',\n            nextDay: '[zajtra o] LT',\n            nextWeek: function () {\n                switch (this.day()) {\n                case 0:\n                    return '[v nedeľu o] LT';\n                case 1:\n                case 2:\n                    return '[v] dddd [o] LT';\n                case 3:\n                    return '[v stredu o] LT';\n                case 4:\n                    return '[vo štvrtok o] LT';\n                case 5:\n                    return '[v piatok o] LT';\n                case 6:\n                    return '[v sobotu o] LT';\n                }\n            },\n            lastDay: '[včera o] LT',\n            lastWeek: function () {\n                switch (this.day()) {\n                case 0:\n                    return '[minulú nedeľu o] LT';\n                case 1:\n                case 2:\n                    return '[minulý] dddd [o] LT';\n                case 3:\n                    return '[minulú stredu o] LT';\n                case 4:\n                case 5:\n                    return '[minulý] dddd [o] LT';\n                case 6:\n                    return '[minulú sobotu o] LT';\n                }\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'za %s',\n            past : 'pred %s',\n            s : sk__translate,\n            m : sk__translate,\n            mm : sk__translate,\n            h : sk__translate,\n            hh : sk__translate,\n            d : sk__translate,\n            dd : sk__translate,\n            M : sk__translate,\n            MM : sk__translate,\n            y : sk__translate,\n            yy : sk__translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : slovenian (sl)\n    //! author : Robert Sedovšek : https://github.com/sedovsek\n\n    function sl__processRelativeTime(number, withoutSuffix, key, isFuture) {\n        var result = number + ' ';\n        switch (key) {\n        case 's':\n            return withoutSuffix || isFuture ? 'nekaj sekund' : 'nekaj sekundami';\n        case 'm':\n            return withoutSuffix ? 'ena minuta' : 'eno minuto';\n        case 'mm':\n            if (number === 1) {\n                result += withoutSuffix ? 'minuta' : 'minuto';\n            } else if (number === 2) {\n                result += withoutSuffix || isFuture ? 'minuti' : 'minutama';\n            } else if (number < 5) {\n                result += withoutSuffix || isFuture ? 'minute' : 'minutami';\n            } else {\n                result += withoutSuffix || isFuture ? 'minut' : 'minutami';\n            }\n            return result;\n        case 'h':\n            return withoutSuffix ? 'ena ura' : 'eno uro';\n        case 'hh':\n            if (number === 1) {\n                result += withoutSuffix ? 'ura' : 'uro';\n            } else if (number === 2) {\n                result += withoutSuffix || isFuture ? 'uri' : 'urama';\n            } else if (number < 5) {\n                result += withoutSuffix || isFuture ? 'ure' : 'urami';\n            } else {\n                result += withoutSuffix || isFuture ? 'ur' : 'urami';\n            }\n            return result;\n        case 'd':\n            return withoutSuffix || isFuture ? 'en dan' : 'enim dnem';\n        case 'dd':\n            if (number === 1) {\n                result += withoutSuffix || isFuture ? 'dan' : 'dnem';\n            } else if (number === 2) {\n                result += withoutSuffix || isFuture ? 'dni' : 'dnevoma';\n            } else {\n                result += withoutSuffix || isFuture ? 'dni' : 'dnevi';\n            }\n            return result;\n        case 'M':\n            return withoutSuffix || isFuture ? 'en mesec' : 'enim mesecem';\n        case 'MM':\n            if (number === 1) {\n                result += withoutSuffix || isFuture ? 'mesec' : 'mesecem';\n            } else if (number === 2) {\n                result += withoutSuffix || isFuture ? 'meseca' : 'mesecema';\n            } else if (number < 5) {\n                result += withoutSuffix || isFuture ? 'mesece' : 'meseci';\n            } else {\n                result += withoutSuffix || isFuture ? 'mesecev' : 'meseci';\n            }\n            return result;\n        case 'y':\n            return withoutSuffix || isFuture ? 'eno leto' : 'enim letom';\n        case 'yy':\n            if (number === 1) {\n                result += withoutSuffix || isFuture ? 'leto' : 'letom';\n            } else if (number === 2) {\n                result += withoutSuffix || isFuture ? 'leti' : 'letoma';\n            } else if (number < 5) {\n                result += withoutSuffix || isFuture ? 'leta' : 'leti';\n            } else {\n                result += withoutSuffix || isFuture ? 'let' : 'leti';\n            }\n            return result;\n        }\n    }\n\n    var sl = _moment__default.defineLocale('sl', {\n        months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'),\n        monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'),\n        weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'),\n        weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'),\n        weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'),\n        longDateFormat : {\n            LT : 'H:mm',\n            LTS : 'H:mm:ss',\n            L : 'DD. MM. YYYY',\n            LL : 'D. MMMM YYYY',\n            LLL : 'D. MMMM YYYY H:mm',\n            LLLL : 'dddd, D. MMMM YYYY H:mm'\n        },\n        calendar : {\n            sameDay  : '[danes ob] LT',\n            nextDay  : '[jutri ob] LT',\n\n            nextWeek : function () {\n                switch (this.day()) {\n                case 0:\n                    return '[v] [nedeljo] [ob] LT';\n                case 3:\n                    return '[v] [sredo] [ob] LT';\n                case 6:\n                    return '[v] [soboto] [ob] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[v] dddd [ob] LT';\n                }\n            },\n            lastDay  : '[včeraj ob] LT',\n            lastWeek : function () {\n                switch (this.day()) {\n                case 0:\n                    return '[prejšnjo] [nedeljo] [ob] LT';\n                case 3:\n                    return '[prejšnjo] [sredo] [ob] LT';\n                case 6:\n                    return '[prejšnjo] [soboto] [ob] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[prejšnji] dddd [ob] LT';\n                }\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'čez %s',\n            past   : 'pred %s',\n            s      : sl__processRelativeTime,\n            m      : sl__processRelativeTime,\n            mm     : sl__processRelativeTime,\n            h      : sl__processRelativeTime,\n            hh     : sl__processRelativeTime,\n            d      : sl__processRelativeTime,\n            dd     : sl__processRelativeTime,\n            M      : sl__processRelativeTime,\n            MM     : sl__processRelativeTime,\n            y      : sl__processRelativeTime,\n            yy     : sl__processRelativeTime\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Albanian (sq)\n    //! author : Flakërim Ismani : https://github.com/flakerimi\n    //! author: Menelion Elensúle: https://github.com/Oire (tests)\n    //! author : Oerd Cukalla : https://github.com/oerd (fixes)\n\n    var sq = _moment__default.defineLocale('sq', {\n        months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'),\n        monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'),\n        weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'),\n        weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'),\n        weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'),\n        meridiemParse: /PD|MD/,\n        isPM: function (input) {\n            return input.charAt(0) === 'M';\n        },\n        meridiem : function (hours, minutes, isLower) {\n            return hours < 12 ? 'PD' : 'MD';\n        },\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay : '[Sot në] LT',\n            nextDay : '[Nesër në] LT',\n            nextWeek : 'dddd [në] LT',\n            lastDay : '[Dje në] LT',\n            lastWeek : 'dddd [e kaluar në] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'në %s',\n            past : '%s më parë',\n            s : 'disa sekonda',\n            m : 'një minutë',\n            mm : '%d minuta',\n            h : 'një orë',\n            hh : '%d orë',\n            d : 'një ditë',\n            dd : '%d ditë',\n            M : 'një muaj',\n            MM : '%d muaj',\n            y : 'një vit',\n            yy : '%d vite'\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Serbian-cyrillic (sr-cyrl)\n    //! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j\n\n    var sr_cyrl__translator = {\n        words: { //Different grammatical cases\n            m: ['један минут', 'једне минуте'],\n            mm: ['минут', 'минуте', 'минута'],\n            h: ['један сат', 'једног сата'],\n            hh: ['сат', 'сата', 'сати'],\n            dd: ['дан', 'дана', 'дана'],\n            MM: ['месец', 'месеца', 'месеци'],\n            yy: ['година', 'године', 'година']\n        },\n        correctGrammaticalCase: function (number, wordKey) {\n            return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);\n        },\n        translate: function (number, withoutSuffix, key) {\n            var wordKey = sr_cyrl__translator.words[key];\n            if (key.length === 1) {\n                return withoutSuffix ? wordKey[0] : wordKey[1];\n            } else {\n                return number + ' ' + sr_cyrl__translator.correctGrammaticalCase(number, wordKey);\n            }\n        }\n    };\n\n    var sr_cyrl = _moment__default.defineLocale('sr-cyrl', {\n        months: ['јануар', 'фебруар', 'март', 'април', 'мај', 'јун', 'јул', 'август', 'септембар', 'октобар', 'новембар', 'децембар'],\n        monthsShort: ['јан.', 'феб.', 'мар.', 'апр.', 'мај', 'јун', 'јул', 'авг.', 'сеп.', 'окт.', 'нов.', 'дец.'],\n        weekdays: ['недеља', 'понедељак', 'уторак', 'среда', 'четвртак', 'петак', 'субота'],\n        weekdaysShort: ['нед.', 'пон.', 'уто.', 'сре.', 'чет.', 'пет.', 'суб.'],\n        weekdaysMin: ['не', 'по', 'ут', 'ср', 'че', 'пе', 'су'],\n        longDateFormat: {\n            LT: 'H:mm',\n            LTS : 'H:mm:ss',\n            L: 'DD. MM. YYYY',\n            LL: 'D. MMMM YYYY',\n            LLL: 'D. MMMM YYYY H:mm',\n            LLLL: 'dddd, D. MMMM YYYY H:mm'\n        },\n        calendar: {\n            sameDay: '[данас у] LT',\n            nextDay: '[сутра у] LT',\n            nextWeek: function () {\n                switch (this.day()) {\n                case 0:\n                    return '[у] [недељу] [у] LT';\n                case 3:\n                    return '[у] [среду] [у] LT';\n                case 6:\n                    return '[у] [суботу] [у] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[у] dddd [у] LT';\n                }\n            },\n            lastDay  : '[јуче у] LT',\n            lastWeek : function () {\n                var lastWeekDays = [\n                    '[прошле] [недеље] [у] LT',\n                    '[прошлог] [понедељка] [у] LT',\n                    '[прошлог] [уторка] [у] LT',\n                    '[прошле] [среде] [у] LT',\n                    '[прошлог] [четвртка] [у] LT',\n                    '[прошлог] [петка] [у] LT',\n                    '[прошле] [суботе] [у] LT'\n                ];\n                return lastWeekDays[this.day()];\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'за %s',\n            past   : 'пре %s',\n            s      : 'неколико секунди',\n            m      : sr_cyrl__translator.translate,\n            mm     : sr_cyrl__translator.translate,\n            h      : sr_cyrl__translator.translate,\n            hh     : sr_cyrl__translator.translate,\n            d      : 'дан',\n            dd     : sr_cyrl__translator.translate,\n            M      : 'месец',\n            MM     : sr_cyrl__translator.translate,\n            y      : 'годину',\n            yy     : sr_cyrl__translator.translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Serbian-latin (sr)\n    //! author : Milan Janačković<milanjanackovic@gmail.com> : https://github.com/milan-j\n\n    var sr__translator = {\n        words: { //Different grammatical cases\n            m: ['jedan minut', 'jedne minute'],\n            mm: ['minut', 'minute', 'minuta'],\n            h: ['jedan sat', 'jednog sata'],\n            hh: ['sat', 'sata', 'sati'],\n            dd: ['dan', 'dana', 'dana'],\n            MM: ['mesec', 'meseca', 'meseci'],\n            yy: ['godina', 'godine', 'godina']\n        },\n        correctGrammaticalCase: function (number, wordKey) {\n            return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]);\n        },\n        translate: function (number, withoutSuffix, key) {\n            var wordKey = sr__translator.words[key];\n            if (key.length === 1) {\n                return withoutSuffix ? wordKey[0] : wordKey[1];\n            } else {\n                return number + ' ' + sr__translator.correctGrammaticalCase(number, wordKey);\n            }\n        }\n    };\n\n    var sr = _moment__default.defineLocale('sr', {\n        months: ['januar', 'februar', 'mart', 'april', 'maj', 'jun', 'jul', 'avgust', 'septembar', 'oktobar', 'novembar', 'decembar'],\n        monthsShort: ['jan.', 'feb.', 'mar.', 'apr.', 'maj', 'jun', 'jul', 'avg.', 'sep.', 'okt.', 'nov.', 'dec.'],\n        weekdays: ['nedelja', 'ponedeljak', 'utorak', 'sreda', 'četvrtak', 'petak', 'subota'],\n        weekdaysShort: ['ned.', 'pon.', 'uto.', 'sre.', 'čet.', 'pet.', 'sub.'],\n        weekdaysMin: ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'],\n        longDateFormat: {\n            LT: 'H:mm',\n            LTS : 'H:mm:ss',\n            L: 'DD. MM. YYYY',\n            LL: 'D. MMMM YYYY',\n            LLL: 'D. MMMM YYYY H:mm',\n            LLLL: 'dddd, D. MMMM YYYY H:mm'\n        },\n        calendar: {\n            sameDay: '[danas u] LT',\n            nextDay: '[sutra u] LT',\n            nextWeek: function () {\n                switch (this.day()) {\n                case 0:\n                    return '[u] [nedelju] [u] LT';\n                case 3:\n                    return '[u] [sredu] [u] LT';\n                case 6:\n                    return '[u] [subotu] [u] LT';\n                case 1:\n                case 2:\n                case 4:\n                case 5:\n                    return '[u] dddd [u] LT';\n                }\n            },\n            lastDay  : '[juče u] LT',\n            lastWeek : function () {\n                var lastWeekDays = [\n                    '[prošle] [nedelje] [u] LT',\n                    '[prošlog] [ponedeljka] [u] LT',\n                    '[prošlog] [utorka] [u] LT',\n                    '[prošle] [srede] [u] LT',\n                    '[prošlog] [četvrtka] [u] LT',\n                    '[prošlog] [petka] [u] LT',\n                    '[prošle] [subote] [u] LT'\n                ];\n                return lastWeekDays[this.day()];\n            },\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'za %s',\n            past   : 'pre %s',\n            s      : 'nekoliko sekundi',\n            m      : sr__translator.translate,\n            mm     : sr__translator.translate,\n            h      : sr__translator.translate,\n            hh     : sr__translator.translate,\n            d      : 'dan',\n            dd     : sr__translator.translate,\n            M      : 'mesec',\n            MM     : sr__translator.translate,\n            y      : 'godinu',\n            yy     : sr__translator.translate\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : swedish (sv)\n    //! author : Jens Alm : https://github.com/ulmus\n\n    var sv = _moment__default.defineLocale('sv', {\n        months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'),\n        monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'),\n        weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'),\n        weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'),\n        weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'YYYY-MM-DD',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Idag] LT',\n            nextDay: '[Imorgon] LT',\n            lastDay: '[Igår] LT',\n            nextWeek: '[På] dddd LT',\n            lastWeek: '[I] dddd[s] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'om %s',\n            past : 'för %s sedan',\n            s : 'några sekunder',\n            m : 'en minut',\n            mm : '%d minuter',\n            h : 'en timme',\n            hh : '%d timmar',\n            d : 'en dag',\n            dd : '%d dagar',\n            M : 'en månad',\n            MM : '%d månader',\n            y : 'ett år',\n            yy : '%d år'\n        },\n        ordinalParse: /\\d{1,2}(e|a)/,\n        ordinal : function (number) {\n            var b = number % 10,\n                output = (~~(number % 100 / 10) === 1) ? 'e' :\n                (b === 1) ? 'a' :\n                (b === 2) ? 'a' :\n                (b === 3) ? 'e' : 'e';\n            return number + output;\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : tamil (ta)\n    //! author : Arjunkumar Krishnamoorthy : https://github.com/tk120404\n\n    var ta = _moment__default.defineLocale('ta', {\n        months : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),\n        monthsShort : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'),\n        weekdays : 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split('_'),\n        weekdaysShort : 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split('_'),\n        weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY, HH:mm',\n            LLLL : 'dddd, D MMMM YYYY, HH:mm'\n        },\n        calendar : {\n            sameDay : '[இன்று] LT',\n            nextDay : '[நாளை] LT',\n            nextWeek : 'dddd, LT',\n            lastDay : '[நேற்று] LT',\n            lastWeek : '[கடந்த வாரம்] dddd, LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s இல்',\n            past : '%s முன்',\n            s : 'ஒரு சில விநாடிகள்',\n            m : 'ஒரு நிமிடம்',\n            mm : '%d நிமிடங்கள்',\n            h : 'ஒரு மணி நேரம்',\n            hh : '%d மணி நேரம்',\n            d : 'ஒரு நாள்',\n            dd : '%d நாட்கள்',\n            M : 'ஒரு மாதம்',\n            MM : '%d மாதங்கள்',\n            y : 'ஒரு வருடம்',\n            yy : '%d ஆண்டுகள்'\n        },\n        ordinalParse: /\\d{1,2}வது/,\n        ordinal : function (number) {\n            return number + 'வது';\n        },\n        // refer http://ta.wikipedia.org/s/1er1\n        meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 2) {\n                return ' யாமம்';\n            } else if (hour < 6) {\n                return ' வைகறை';  // வைகறை\n            } else if (hour < 10) {\n                return ' காலை'; // காலை\n            } else if (hour < 14) {\n                return ' நண்பகல்'; // நண்பகல்\n            } else if (hour < 18) {\n                return ' எற்பாடு'; // எற்பாடு\n            } else if (hour < 22) {\n                return ' மாலை'; // மாலை\n            } else {\n                return ' யாமம்';\n            }\n        },\n        meridiemHour : function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === 'யாமம்') {\n                return hour < 2 ? hour : hour + 12;\n            } else if (meridiem === 'வைகறை' || meridiem === 'காலை') {\n                return hour;\n            } else if (meridiem === 'நண்பகல்') {\n                return hour >= 10 ? hour : hour + 12;\n            } else {\n                return hour + 12;\n            }\n        },\n        week : {\n            dow : 0, // Sunday is the first day of the week.\n            doy : 6  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : thai (th)\n    //! author : Kridsada Thanabulpong : https://github.com/sirn\n\n    var th = _moment__default.defineLocale('th', {\n        months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'),\n        monthsShort : 'มกรา_กุมภา_มีนา_เมษา_พฤษภา_มิถุนา_กรกฎา_สิงหา_กันยา_ตุลา_พฤศจิกา_ธันวา'.split('_'),\n        weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'),\n        weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference\n        weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'),\n        longDateFormat : {\n            LT : 'H นาฬิกา m นาที',\n            LTS : 'H นาฬิกา m นาที s วินาที',\n            L : 'YYYY/MM/DD',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY เวลา H นาฬิกา m นาที',\n            LLLL : 'วันddddที่ D MMMM YYYY เวลา H นาฬิกา m นาที'\n        },\n        meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/,\n        isPM: function (input) {\n            return input === 'หลังเที่ยง';\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 12) {\n                return 'ก่อนเที่ยง';\n            } else {\n                return 'หลังเที่ยง';\n            }\n        },\n        calendar : {\n            sameDay : '[วันนี้ เวลา] LT',\n            nextDay : '[พรุ่งนี้ เวลา] LT',\n            nextWeek : 'dddd[หน้า เวลา] LT',\n            lastDay : '[เมื่อวานนี้ เวลา] LT',\n            lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'อีก %s',\n            past : '%sที่แล้ว',\n            s : 'ไม่กี่วินาที',\n            m : '1 นาที',\n            mm : '%d นาที',\n            h : '1 ชั่วโมง',\n            hh : '%d ชั่วโมง',\n            d : '1 วัน',\n            dd : '%d วัน',\n            M : '1 เดือน',\n            MM : '%d เดือน',\n            y : '1 ปี',\n            yy : '%d ปี'\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Tagalog/Filipino (tl-ph)\n    //! author : Dan Hagman\n\n    var tl_ph = _moment__default.defineLocale('tl-ph', {\n        months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'),\n        monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'),\n        weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'),\n        weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'),\n        weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'MM/D/YYYY',\n            LL : 'MMMM D, YYYY',\n            LLL : 'MMMM D, YYYY HH:mm',\n            LLLL : 'dddd, MMMM DD, YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Ngayon sa] LT',\n            nextDay: '[Bukas sa] LT',\n            nextWeek: 'dddd [sa] LT',\n            lastDay: '[Kahapon sa] LT',\n            lastWeek: 'dddd [huling linggo] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'sa loob ng %s',\n            past : '%s ang nakalipas',\n            s : 'ilang segundo',\n            m : 'isang minuto',\n            mm : '%d minuto',\n            h : 'isang oras',\n            hh : '%d oras',\n            d : 'isang araw',\n            dd : '%d araw',\n            M : 'isang buwan',\n            MM : '%d buwan',\n            y : 'isang taon',\n            yy : '%d taon'\n        },\n        ordinalParse: /\\d{1,2}/,\n        ordinal : function (number) {\n            return number;\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : turkish (tr)\n    //! authors : Erhan Gundogan : https://github.com/erhangundogan,\n    //!           Burak Yiğit Kaya: https://github.com/BYK\n\n    var tr__suffixes = {\n        1: '\\'inci',\n        5: '\\'inci',\n        8: '\\'inci',\n        70: '\\'inci',\n        80: '\\'inci',\n        2: '\\'nci',\n        7: '\\'nci',\n        20: '\\'nci',\n        50: '\\'nci',\n        3: '\\'üncü',\n        4: '\\'üncü',\n        100: '\\'üncü',\n        6: '\\'ncı',\n        9: '\\'uncu',\n        10: '\\'uncu',\n        30: '\\'uncu',\n        60: '\\'ıncı',\n        90: '\\'ıncı'\n    };\n\n    var tr = _moment__default.defineLocale('tr', {\n        months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'),\n        monthsShort : 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'),\n        weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'),\n        weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'),\n        weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd, D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay : '[bugün saat] LT',\n            nextDay : '[yarın saat] LT',\n            nextWeek : '[haftaya] dddd [saat] LT',\n            lastDay : '[dün] LT',\n            lastWeek : '[geçen hafta] dddd [saat] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : '%s sonra',\n            past : '%s önce',\n            s : 'birkaç saniye',\n            m : 'bir dakika',\n            mm : '%d dakika',\n            h : 'bir saat',\n            hh : '%d saat',\n            d : 'bir gün',\n            dd : '%d gün',\n            M : 'bir ay',\n            MM : '%d ay',\n            y : 'bir yıl',\n            yy : '%d yıl'\n        },\n        ordinalParse: /\\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,\n        ordinal : function (number) {\n            if (number === 0) {  // special case for zero\n                return number + '\\'ıncı';\n            }\n            var a = number % 10,\n                b = number % 100 - a,\n                c = number >= 100 ? 100 : null;\n            return number + (tr__suffixes[a] || tr__suffixes[b] || tr__suffixes[c]);\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : talossan (tzl)\n    //! author : Robin van der Vliet : https://github.com/robin0van0der0v with the help of Iustì Canun\n\n\n    var tzl = _moment__default.defineLocale('tzl', {\n        months : 'Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar'.split('_'),\n        monthsShort : 'Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec'.split('_'),\n        weekdays : 'Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi'.split('_'),\n        weekdaysShort : 'Súl_Lún_Mai_Már_Xhú_Vié_Sát'.split('_'),\n        weekdaysMin : 'Sú_Lú_Ma_Má_Xh_Vi_Sá'.split('_'),\n        longDateFormat : {\n            LT : 'HH.mm',\n            LTS : 'LT.ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D. MMMM [dallas] YYYY',\n            LLL : 'D. MMMM [dallas] YYYY LT',\n            LLLL : 'dddd, [li] D. MMMM [dallas] YYYY LT'\n        },\n        meridiem : function (hours, minutes, isLower) {\n            if (hours > 11) {\n                return isLower ? 'd\\'o' : 'D\\'O';\n            } else {\n                return isLower ? 'd\\'a' : 'D\\'A';\n            }\n        },\n        calendar : {\n            sameDay : '[oxhi à] LT',\n            nextDay : '[demà à] LT',\n            nextWeek : 'dddd [à] LT',\n            lastDay : '[ieiri à] LT',\n            lastWeek : '[sür el] dddd [lasteu à] LT',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'osprei %s',\n            past : 'ja%s',\n            s : tzl__processRelativeTime,\n            m : tzl__processRelativeTime,\n            mm : tzl__processRelativeTime,\n            h : tzl__processRelativeTime,\n            hh : tzl__processRelativeTime,\n            d : tzl__processRelativeTime,\n            dd : tzl__processRelativeTime,\n            M : tzl__processRelativeTime,\n            MM : tzl__processRelativeTime,\n            y : tzl__processRelativeTime,\n            yy : tzl__processRelativeTime\n        },\n        ordinalParse: /\\d{1,2}\\./,\n        ordinal : '%d.',\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    function tzl__processRelativeTime(number, withoutSuffix, key, isFuture) {\n        var format = {\n            's': ['viensas secunds', '\\'iensas secunds'],\n            'm': ['\\'n míut', '\\'iens míut'],\n            'mm': [number + ' míuts', ' ' + number + ' míuts'],\n            'h': ['\\'n þora', '\\'iensa þora'],\n            'hh': [number + ' þoras', ' ' + number + ' þoras'],\n            'd': ['\\'n ziua', '\\'iensa ziua'],\n            'dd': [number + ' ziuas', ' ' + number + ' ziuas'],\n            'M': ['\\'n mes', '\\'iens mes'],\n            'MM': [number + ' mesen', ' ' + number + ' mesen'],\n            'y': ['\\'n ar', '\\'iens ar'],\n            'yy': [number + ' ars', ' ' + number + ' ars']\n        };\n        return isFuture ? format[key][0] : (withoutSuffix ? format[key][0] : format[key][1].trim());\n    }\n\n    //! moment.js locale configuration\n    //! locale : Morocco Central Atlas Tamaziɣt in Latin (tzm-latn)\n    //! author : Abdel Said : https://github.com/abdelsaid\n\n    var tzm_latn = _moment__default.defineLocale('tzm-latn', {\n        months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),\n        monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'),\n        weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),\n        weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),\n        weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[asdkh g] LT',\n            nextDay: '[aska g] LT',\n            nextWeek: 'dddd [g] LT',\n            lastDay: '[assant g] LT',\n            lastWeek: 'dddd [g] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'dadkh s yan %s',\n            past : 'yan %s',\n            s : 'imik',\n            m : 'minuḍ',\n            mm : '%d minuḍ',\n            h : 'saɛa',\n            hh : '%d tassaɛin',\n            d : 'ass',\n            dd : '%d ossan',\n            M : 'ayowr',\n            MM : '%d iyyirn',\n            y : 'asgas',\n            yy : '%d isgasn'\n        },\n        week : {\n            dow : 6, // Saturday is the first day of the week.\n            doy : 12  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : Morocco Central Atlas Tamaziɣt (tzm)\n    //! author : Abdel Said : https://github.com/abdelsaid\n\n    var tzm = _moment__default.defineLocale('tzm', {\n        months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),\n        monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'),\n        weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),\n        weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),\n        weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS: 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'dddd D MMMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[ⴰⵙⴷⵅ ⴴ] LT',\n            nextDay: '[ⴰⵙⴽⴰ ⴴ] LT',\n            nextWeek: 'dddd [ⴴ] LT',\n            lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT',\n            lastWeek: 'dddd [ⴴ] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s',\n            past : 'ⵢⴰⵏ %s',\n            s : 'ⵉⵎⵉⴽ',\n            m : 'ⵎⵉⵏⵓⴺ',\n            mm : '%d ⵎⵉⵏⵓⴺ',\n            h : 'ⵙⴰⵄⴰ',\n            hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ',\n            d : 'ⴰⵙⵙ',\n            dd : '%d oⵙⵙⴰⵏ',\n            M : 'ⴰⵢoⵓⵔ',\n            MM : '%d ⵉⵢⵢⵉⵔⵏ',\n            y : 'ⴰⵙⴳⴰⵙ',\n            yy : '%d ⵉⵙⴳⴰⵙⵏ'\n        },\n        week : {\n            dow : 6, // Saturday is the first day of the week.\n            doy : 12  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : ukrainian (uk)\n    //! author : zemlanin : https://github.com/zemlanin\n    //! Author : Menelion Elensúle : https://github.com/Oire\n\n    function uk__plural(word, num) {\n        var forms = word.split('_');\n        return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]);\n    }\n    function uk__relativeTimeWithPlural(number, withoutSuffix, key) {\n        var format = {\n            'mm': 'хвилина_хвилини_хвилин',\n            'hh': 'година_години_годин',\n            'dd': 'день_дні_днів',\n            'MM': 'місяць_місяці_місяців',\n            'yy': 'рік_роки_років'\n        };\n        if (key === 'm') {\n            return withoutSuffix ? 'хвилина' : 'хвилину';\n        }\n        else if (key === 'h') {\n            return withoutSuffix ? 'година' : 'годину';\n        }\n        else {\n            return number + ' ' + uk__plural(format[key], +number);\n        }\n    }\n    function uk__monthsCaseReplace(m, format) {\n        var months = {\n            'nominative': 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split('_'),\n            'accusative': 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split('_')\n        },\n        nounCase = (/D[oD]? *MMMM?/).test(format) ?\n            'accusative' :\n            'nominative';\n        return months[nounCase][m.month()];\n    }\n    function uk__weekdaysCaseReplace(m, format) {\n        var weekdays = {\n            'nominative': 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'),\n            'accusative': 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split('_'),\n            'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_')\n        },\n        nounCase = (/(\\[[ВвУу]\\]) ?dddd/).test(format) ?\n            'accusative' :\n            ((/\\[?(?:минулої|наступної)? ?\\] ?dddd/).test(format) ?\n                'genitive' :\n                'nominative');\n        return weekdays[nounCase][m.day()];\n    }\n    function processHoursFunction(str) {\n        return function () {\n            return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT';\n        };\n    }\n\n    var uk = _moment__default.defineLocale('uk', {\n        months : uk__monthsCaseReplace,\n        monthsShort : 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'),\n        weekdays : uk__weekdaysCaseReplace,\n        weekdaysShort : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),\n        weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD.MM.YYYY',\n            LL : 'D MMMM YYYY р.',\n            LLL : 'D MMMM YYYY р., HH:mm',\n            LLLL : 'dddd, D MMMM YYYY р., HH:mm'\n        },\n        calendar : {\n            sameDay: processHoursFunction('[Сьогодні '),\n            nextDay: processHoursFunction('[Завтра '),\n            lastDay: processHoursFunction('[Вчора '),\n            nextWeek: processHoursFunction('[У] dddd ['),\n            lastWeek: function () {\n                switch (this.day()) {\n                case 0:\n                case 3:\n                case 5:\n                case 6:\n                    return processHoursFunction('[Минулої] dddd [').call(this);\n                case 1:\n                case 2:\n                case 4:\n                    return processHoursFunction('[Минулого] dddd [').call(this);\n                }\n            },\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : 'за %s',\n            past : '%s тому',\n            s : 'декілька секунд',\n            m : uk__relativeTimeWithPlural,\n            mm : uk__relativeTimeWithPlural,\n            h : 'годину',\n            hh : uk__relativeTimeWithPlural,\n            d : 'день',\n            dd : uk__relativeTimeWithPlural,\n            M : 'місяць',\n            MM : uk__relativeTimeWithPlural,\n            y : 'рік',\n            yy : uk__relativeTimeWithPlural\n        },\n        // M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason\n        meridiemParse: /ночі|ранку|дня|вечора/,\n        isPM: function (input) {\n            return /^(дня|вечора)$/.test(input);\n        },\n        meridiem : function (hour, minute, isLower) {\n            if (hour < 4) {\n                return 'ночі';\n            } else if (hour < 12) {\n                return 'ранку';\n            } else if (hour < 17) {\n                return 'дня';\n            } else {\n                return 'вечора';\n            }\n        },\n        ordinalParse: /\\d{1,2}-(й|го)/,\n        ordinal: function (number, period) {\n            switch (period) {\n            case 'M':\n            case 'd':\n            case 'DDD':\n            case 'w':\n            case 'W':\n                return number + '-й';\n            case 'D':\n                return number + '-го';\n            default:\n                return number;\n            }\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 1st is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : uzbek (uz)\n    //! author : Sardor Muminov : https://github.com/muminoff\n\n    var uz = _moment__default.defineLocale('uz', {\n        months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'),\n        monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'),\n        weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'),\n        weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'),\n        weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM YYYY',\n            LLL : 'D MMMM YYYY HH:mm',\n            LLLL : 'D MMMM YYYY, dddd HH:mm'\n        },\n        calendar : {\n            sameDay : '[Бугун соат] LT [да]',\n            nextDay : '[Эртага] LT [да]',\n            nextWeek : 'dddd [куни соат] LT [да]',\n            lastDay : '[Кеча соат] LT [да]',\n            lastWeek : '[Утган] dddd [куни соат] LT [да]',\n            sameElse : 'L'\n        },\n        relativeTime : {\n            future : 'Якин %s ичида',\n            past : 'Бир неча %s олдин',\n            s : 'фурсат',\n            m : 'бир дакика',\n            mm : '%d дакика',\n            h : 'бир соат',\n            hh : '%d соат',\n            d : 'бир кун',\n            dd : '%d кун',\n            M : 'бир ой',\n            MM : '%d ой',\n            y : 'бир йил',\n            yy : '%d йил'\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 7  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : vietnamese (vi)\n    //! author : Bang Nguyen : https://github.com/bangnk\n\n    var vi = _moment__default.defineLocale('vi', {\n        months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'),\n        monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'),\n        weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'),\n        weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),\n        weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),\n        longDateFormat : {\n            LT : 'HH:mm',\n            LTS : 'HH:mm:ss',\n            L : 'DD/MM/YYYY',\n            LL : 'D MMMM [năm] YYYY',\n            LLL : 'D MMMM [năm] YYYY HH:mm',\n            LLLL : 'dddd, D MMMM [năm] YYYY HH:mm',\n            l : 'DD/M/YYYY',\n            ll : 'D MMM YYYY',\n            lll : 'D MMM YYYY HH:mm',\n            llll : 'ddd, D MMM YYYY HH:mm'\n        },\n        calendar : {\n            sameDay: '[Hôm nay lúc] LT',\n            nextDay: '[Ngày mai lúc] LT',\n            nextWeek: 'dddd [tuần tới lúc] LT',\n            lastDay: '[Hôm qua lúc] LT',\n            lastWeek: 'dddd [tuần rồi lúc] LT',\n            sameElse: 'L'\n        },\n        relativeTime : {\n            future : '%s tới',\n            past : '%s trước',\n            s : 'vài giây',\n            m : 'một phút',\n            mm : '%d phút',\n            h : 'một giờ',\n            hh : '%d giờ',\n            d : 'một ngày',\n            dd : '%d ngày',\n            M : 'một tháng',\n            MM : '%d tháng',\n            y : 'một năm',\n            yy : '%d năm'\n        },\n        ordinalParse: /\\d{1,2}/,\n        ordinal : function (number) {\n            return number;\n        },\n        week : {\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : chinese (zh-cn)\n    //! author : suupic : https://github.com/suupic\n    //! author : Zeno Zeng : https://github.com/zenozeng\n\n    var zh_cn = _moment__default.defineLocale('zh-cn', {\n        months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),\n        monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),\n        weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),\n        weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'),\n        weekdaysMin : '日_一_二_三_四_五_六'.split('_'),\n        longDateFormat : {\n            LT : 'Ah点mm分',\n            LTS : 'Ah点m分s秒',\n            L : 'YYYY-MM-DD',\n            LL : 'YYYY年MMMD日',\n            LLL : 'YYYY年MMMD日Ah点mm分',\n            LLLL : 'YYYY年MMMD日ddddAh点mm分',\n            l : 'YYYY-MM-DD',\n            ll : 'YYYY年MMMD日',\n            lll : 'YYYY年MMMD日Ah点mm分',\n            llll : 'YYYY年MMMD日ddddAh点mm分'\n        },\n        meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,\n        meridiemHour: function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === '凌晨' || meridiem === '早上' ||\n                    meridiem === '上午') {\n                return hour;\n            } else if (meridiem === '下午' || meridiem === '晚上') {\n                return hour + 12;\n            } else {\n                // '中午'\n                return hour >= 11 ? hour : hour + 12;\n            }\n        },\n        meridiem : function (hour, minute, isLower) {\n            var hm = hour * 100 + minute;\n            if (hm < 600) {\n                return '凌晨';\n            } else if (hm < 900) {\n                return '早上';\n            } else if (hm < 1130) {\n                return '上午';\n            } else if (hm < 1230) {\n                return '中午';\n            } else if (hm < 1800) {\n                return '下午';\n            } else {\n                return '晚上';\n            }\n        },\n        calendar : {\n            sameDay : function () {\n                return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT';\n            },\n            nextDay : function () {\n                return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT';\n            },\n            lastDay : function () {\n                return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT';\n            },\n            nextWeek : function () {\n                var startOfWeek, prefix;\n                startOfWeek = _moment__default().startOf('week');\n                prefix = this.unix() - startOfWeek.unix() >= 7 * 24 * 3600 ? '[下]' : '[本]';\n                return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';\n            },\n            lastWeek : function () {\n                var startOfWeek, prefix;\n                startOfWeek = _moment__default().startOf('week');\n                prefix = this.unix() < startOfWeek.unix()  ? '[上]' : '[本]';\n                return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm';\n            },\n            sameElse : 'LL'\n        },\n        ordinalParse: /\\d{1,2}(日|月|周)/,\n        ordinal : function (number, period) {\n            switch (period) {\n            case 'd':\n            case 'D':\n            case 'DDD':\n                return number + '日';\n            case 'M':\n                return number + '月';\n            case 'w':\n            case 'W':\n                return number + '周';\n            default:\n                return number;\n            }\n        },\n        relativeTime : {\n            future : '%s内',\n            past : '%s前',\n            s : '几秒',\n            m : '1 分钟',\n            mm : '%d 分钟',\n            h : '1 小时',\n            hh : '%d 小时',\n            d : '1 天',\n            dd : '%d 天',\n            M : '1 个月',\n            MM : '%d 个月',\n            y : '1 年',\n            yy : '%d 年'\n        },\n        week : {\n            // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效\n            dow : 1, // Monday is the first day of the week.\n            doy : 4  // The week that contains Jan 4th is the first week of the year.\n        }\n    });\n\n    //! moment.js locale configuration\n    //! locale : traditional chinese (zh-tw)\n    //! author : Ben : https://github.com/ben-lin\n\n    var zh_tw = _moment__default.defineLocale('zh-tw', {\n        months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),\n        monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),\n        weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),\n        weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'),\n        weekdaysMin : '日_一_二_三_四_五_六'.split('_'),\n        longDateFormat : {\n            LT : 'Ah點mm分',\n            LTS : 'Ah點m分s秒',\n            L : 'YYYY年MMMD日',\n            LL : 'YYYY年MMMD日',\n            LLL : 'YYYY年MMMD日Ah點mm分',\n            LLLL : 'YYYY年MMMD日ddddAh點mm分',\n            l : 'YYYY年MMMD日',\n            ll : 'YYYY年MMMD日',\n            lll : 'YYYY年MMMD日Ah點mm分',\n            llll : 'YYYY年MMMD日ddddAh點mm分'\n        },\n        meridiemParse: /早上|上午|中午|下午|晚上/,\n        meridiemHour : function (hour, meridiem) {\n            if (hour === 12) {\n                hour = 0;\n            }\n            if (meridiem === '早上' || meridiem === '上午') {\n                return hour;\n            } else if (meridiem === '中午') {\n                return hour >= 11 ? hour : hour + 12;\n            } else if (meridiem === '下午' || meridiem === '晚上') {\n                return hour + 12;\n            }\n        },\n        meridiem : function (hour, minute, isLower) {\n            var hm = hour * 100 + minute;\n            if (hm < 900) {\n                return '早上';\n            } else if (hm < 1130) {\n                return '上午';\n            } else if (hm < 1230) {\n                return '中午';\n            } else if (hm < 1800) {\n                return '下午';\n            } else {\n                return '晚上';\n            }\n        },\n        calendar : {\n            sameDay : '[今天]LT',\n            nextDay : '[明天]LT',\n            nextWeek : '[下]ddddLT',\n            lastDay : '[昨天]LT',\n            lastWeek : '[上]ddddLT',\n            sameElse : 'L'\n        },\n        ordinalParse: /\\d{1,2}(日|月|週)/,\n        ordinal : function (number, period) {\n            switch (period) {\n            case 'd' :\n            case 'D' :\n            case 'DDD' :\n                return number + '日';\n            case 'M' :\n                return number + '月';\n            case 'w' :\n            case 'W' :\n                return number + '週';\n            default :\n                return number;\n            }\n        },\n        relativeTime : {\n            future : '%s內',\n            past : '%s前',\n            s : '幾秒',\n            m : '一分鐘',\n            mm : '%d分鐘',\n            h : '一小時',\n            hh : '%d小時',\n            d : '一天',\n            dd : '%d天',\n            M : '一個月',\n            MM : '%d個月',\n            y : '一年',\n            yy : '%d年'\n        }\n    });\n\n    var moment_with_locales = _moment__default;\n    moment_with_locales.locale('en');\n\n    return moment_with_locales;\n\n}));"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/nouislider/distribute/jquery.nouislider.all.js",
    "content": "/*! noUiSlider - 7.0.10 - 2014-12-27 14:50:46 */\n\n(function(){\n\n\t'use strict';\n\nvar\n/** @const */ FormatOptions = [\n\t'decimals',\n\t'thousand',\n\t'mark',\n\t'prefix',\n\t'postfix',\n\t'encoder',\n\t'decoder',\n\t'negativeBefore',\n\t'negative',\n\t'edit',\n\t'undo'\n];\n\n// General\n\n\t// Reverse a string\n\tfunction strReverse ( a ) {\n\t\treturn a.split('').reverse().join('');\n\t}\n\n\t// Check if a string starts with a specified prefix.\n\tfunction strStartsWith ( input, match ) {\n\t\treturn input.substring(0, match.length) === match;\n\t}\n\n\t// Check is a string ends in a specified postfix.\n\tfunction strEndsWith ( input, match ) {\n\t\treturn input.slice(-1 * match.length) === match;\n\t}\n\n\t// Throw an error if formatting options are incompatible.\n\tfunction throwEqualError( F, a, b ) {\n\t\tif ( (F[a] || F[b]) && (F[a] === F[b]) ) {\n\t\t\tthrow new Error(a);\n\t\t}\n\t}\n\n\t// Check if a number is finite and not NaN\n\tfunction isValidNumber ( input ) {\n\t\treturn typeof input === 'number' && isFinite( input );\n\t}\n\n\t// Provide rounding-accurate toFixed method.\n\tfunction toFixed ( value, decimals ) {\n\t\tvar scale = Math.pow(10, decimals);\n\t\treturn ( Math.round(value * scale) / scale).toFixed( decimals );\n\t}\n\n\n// Formatting\n\n\t// Accept a number as input, output formatted string.\n\tfunction formatTo ( decimals, thousand, mark, prefix, postfix, encoder, decoder, negativeBefore, negative, edit, undo, input ) {\n\n\t\tvar originalInput = input, inputIsNegative, inputPieces, inputBase, inputDecimals = '', output = '';\n\n\t\t// Apply user encoder to the input.\n\t\t// Expected outcome: number.\n\t\tif ( encoder ) {\n\t\t\tinput = encoder(input);\n\t\t}\n\n\t\t// Stop if no valid number was provided, the number is infinite or NaN.\n\t\tif ( !isValidNumber(input) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Rounding away decimals might cause a value of -0\n\t\t// when using very small ranges. Remove those cases.\n\t\tif ( decimals !== false && parseFloat(input.toFixed(decimals)) === 0 ) {\n\t\t\tinput = 0;\n\t\t}\n\n\t\t// Formatting is done on absolute numbers,\n\t\t// decorated by an optional negative symbol.\n\t\tif ( input < 0 ) {\n\t\t\tinputIsNegative = true;\n\t\t\tinput = Math.abs(input);\n\t\t}\n\n\t\t// Reduce the number of decimals to the specified option.\n\t\tif ( decimals !== false ) {\n\t\t\tinput = toFixed( input, decimals );\n\t\t}\n\n\t\t// Transform the number into a string, so it can be split.\n\t\tinput = input.toString();\n\n\t\t// Break the number on the decimal separator.\n\t\tif ( input.indexOf('.') !== -1 ) {\n\t\t\tinputPieces = input.split('.');\n\n\t\t\tinputBase = inputPieces[0];\n\n\t\t\tif ( mark ) {\n\t\t\t\tinputDecimals = mark + inputPieces[1];\n\t\t\t}\n\n\t\t} else {\n\n\t\t// If it isn't split, the entire number will do.\n\t\t\tinputBase = input;\n\t\t}\n\n\t\t// Group numbers in sets of three.\n\t\tif ( thousand ) {\n\t\t\tinputBase = strReverse(inputBase).match(/.{1,3}/g);\n\t\t\tinputBase = strReverse(inputBase.join( strReverse( thousand ) ));\n\t\t}\n\n\t\t// If the number is negative, prefix with negation symbol.\n\t\tif ( inputIsNegative && negativeBefore ) {\n\t\t\toutput += negativeBefore;\n\t\t}\n\n\t\t// Prefix the number\n\t\tif ( prefix ) {\n\t\t\toutput += prefix;\n\t\t}\n\n\t\t// Normal negative option comes after the prefix. Defaults to '-'.\n\t\tif ( inputIsNegative && negative ) {\n\t\t\toutput += negative;\n\t\t}\n\n\t\t// Append the actual number.\n\t\toutput += inputBase;\n\t\toutput += inputDecimals;\n\n\t\t// Apply the postfix.\n\t\tif ( postfix ) {\n\t\t\toutput += postfix;\n\t\t}\n\n\t\t// Run the output through a user-specified post-formatter.\n\t\tif ( edit ) {\n\t\t\toutput = edit ( output, originalInput );\n\t\t}\n\n\t\t// All done.\n\t\treturn output;\n\t}\n\n\t// Accept a sting as input, output decoded number.\n\tfunction formatFrom ( decimals, thousand, mark, prefix, postfix, encoder, decoder, negativeBefore, negative, edit, undo, input ) {\n\n\t\tvar originalInput = input, inputIsNegative, output = '';\n\n\t\t// User defined pre-decoder. Result must be a non empty string.\n\t\tif ( undo ) {\n\t\t\tinput = undo(input);\n\t\t}\n\n\t\t// Test the input. Can't be empty.\n\t\tif ( !input || typeof input !== 'string' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// If the string starts with the negativeBefore value: remove it.\n\t\t// Remember is was there, the number is negative.\n\t\tif ( negativeBefore && strStartsWith(input, negativeBefore) ) {\n\t\t\tinput = input.replace(negativeBefore, '');\n\t\t\tinputIsNegative = true;\n\t\t}\n\n\t\t// Repeat the same procedure for the prefix.\n\t\tif ( prefix && strStartsWith(input, prefix) ) {\n\t\t\tinput = input.replace(prefix, '');\n\t\t}\n\n\t\t// And again for negative.\n\t\tif ( negative && strStartsWith(input, negative) ) {\n\t\t\tinput = input.replace(negative, '');\n\t\t\tinputIsNegative = true;\n\t\t}\n\n\t\t// Remove the postfix.\n\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice\n\t\tif ( postfix && strEndsWith(input, postfix) ) {\n\t\t\tinput = input.slice(0, -1 * postfix.length);\n\t\t}\n\n\t\t// Remove the thousand grouping.\n\t\tif ( thousand ) {\n\t\t\tinput = input.split(thousand).join('');\n\t\t}\n\n\t\t// Set the decimal separator back to period.\n\t\tif ( mark ) {\n\t\t\tinput = input.replace(mark, '.');\n\t\t}\n\n\t\t// Prepend the negative symbol.\n\t\tif ( inputIsNegative ) {\n\t\t\toutput += '-';\n\t\t}\n\n\t\t// Add the number\n\t\toutput += input;\n\n\t\t// Trim all non-numeric characters (allow '.' and '-');\n\t\toutput = output.replace(/[^0-9\\.\\-.]/g, '');\n\n\t\t// The value contains no parse-able number.\n\t\tif ( output === '' ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Covert to number.\n\t\toutput = Number(output);\n\n\t\t// Run the user-specified post-decoder.\n\t\tif ( decoder ) {\n\t\t\toutput = decoder(output);\n\t\t}\n\n\t\t// Check is the output is valid, otherwise: return false.\n\t\tif ( !isValidNumber(output) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn output;\n\t}\n\n\n// Framework\n\n\t// Validate formatting options\n\tfunction validate ( inputOptions ) {\n\n\t\tvar i, optionName, optionValue,\n\t\t\tfilteredOptions = {};\n\n\t\tfor ( i = 0; i < FormatOptions.length; i+=1 ) {\n\n\t\t\toptionName = FormatOptions[i];\n\t\t\toptionValue = inputOptions[optionName];\n\n\t\t\tif ( optionValue === undefined ) {\n\n\t\t\t\t// Only default if negativeBefore isn't set.\n\t\t\t\tif ( optionName === 'negative' && !filteredOptions.negativeBefore ) {\n\t\t\t\t\tfilteredOptions[optionName] = '-';\n\t\t\t\t// Don't set a default for mark when 'thousand' is set.\n\t\t\t\t} else if ( optionName === 'mark' && filteredOptions.thousand !== '.' ) {\n\t\t\t\t\tfilteredOptions[optionName] = '.';\n\t\t\t\t} else {\n\t\t\t\t\tfilteredOptions[optionName] = false;\n\t\t\t\t}\n\n\t\t\t// Floating points in JS are stable up to 7 decimals.\n\t\t\t} else if ( optionName === 'decimals' ) {\n\t\t\t\tif ( optionValue >= 0 && optionValue < 8 ) {\n\t\t\t\t\tfilteredOptions[optionName] = optionValue;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(optionName);\n\t\t\t\t}\n\n\t\t\t// These options, when provided, must be functions.\n\t\t\t} else if ( optionName === 'encoder' || optionName === 'decoder' || optionName === 'edit' || optionName === 'undo' ) {\n\t\t\t\tif ( typeof optionValue === 'function' ) {\n\t\t\t\t\tfilteredOptions[optionName] = optionValue;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(optionName);\n\t\t\t\t}\n\n\t\t\t// Other options are strings.\n\t\t\t} else {\n\n\t\t\t\tif ( typeof optionValue === 'string' ) {\n\t\t\t\t\tfilteredOptions[optionName] = optionValue;\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(optionName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Some values can't be extracted from a\n\t\t// string if certain combinations are present.\n\t\tthrowEqualError(filteredOptions, 'mark', 'thousand');\n\t\tthrowEqualError(filteredOptions, 'prefix', 'negative');\n\t\tthrowEqualError(filteredOptions, 'prefix', 'negativeBefore');\n\n\t\treturn filteredOptions;\n\t}\n\n\t// Pass all options as function arguments\n\tfunction passAll ( options, method, input ) {\n\t\tvar i, args = [];\n\n\t\t// Add all options in order of FormatOptions\n\t\tfor ( i = 0; i < FormatOptions.length; i+=1 ) {\n\t\t\targs.push(options[FormatOptions[i]]);\n\t\t}\n\n\t\t// Append the input, then call the method, presenting all\n\t\t// options as arguments.\n\t\targs.push(input);\n\t\treturn method.apply('', args);\n\t}\n\n\t/** @constructor */\n\tfunction wNumb ( options ) {\n\n\t\tif ( !(this instanceof wNumb) ) {\n\t\t\treturn new wNumb ( options );\n\t\t}\n\n\t\tif ( typeof options !== \"object\" ) {\n\t\t\treturn;\n\t\t}\n\n\t\toptions = validate(options);\n\n\t\t// Call 'formatTo' with proper arguments.\n\t\tthis.to = function ( input ) {\n\t\t\treturn passAll(options, formatTo, input);\n\t\t};\n\n\t\t// Call 'formatFrom' with proper arguments.\n\t\tthis.from = function ( input ) {\n\t\t\treturn passAll(options, formatFrom, input);\n\t\t};\n\t}\n\n\t/** @export */\n\twindow.wNumb = wNumb;\n\n}());\n\n/*jslint browser: true */\n/*jslint white: true */\n\n(function( $ ){\n\n\t'use strict';\n\n// Helpers\n\n\t// Test in an object is an instance of jQuery or Zepto.\n\tfunction isInstance ( a ) {\n\t\treturn a instanceof $ || ( $.zepto && $.zepto.isZ(a) );\n\t}\n\n\n// Link types\n\n\tfunction fromPrefix ( target, method ) {\n\n\t\t// If target is a string, a new hidden input will be created.\n\t\tif ( typeof target === 'string' && target.indexOf('-inline-') === 0 ) {\n\n\t\t\t// By default, use the 'html' method.\n\t\t\tthis.method = method || 'html';\n\n\t\t\t// Use jQuery to create the element\n\t\t\tthis.target = this.el = $( target.replace('-inline-', '') || '<div/>' );\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tfunction fromString ( target ) {\n\n\t\t// If the string doesn't begin with '-', which is reserved, add a new hidden input.\n\t\tif ( typeof target === 'string' && target.indexOf('-') !== 0 ) {\n\n\t\t\tthis.method = 'val';\n\n\t\t\tvar element = document.createElement('input');\n\t\t\t\telement.name = target;\n\t\t\t\telement.type = 'hidden';\n\t\t\tthis.target = this.el = $(element);\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tfunction fromFunction ( target ) {\n\n\t\t// The target can also be a function, which will be called.\n\t\tif ( typeof target === 'function' ) {\n\t\t\tthis.target = false;\n\t\t\tthis.method = target;\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tfunction fromInstance ( target, method ) {\n\n\t\tif ( isInstance( target ) && !method ) {\n\n\t\t// If a jQuery/Zepto input element is provided, but no method is set,\n\t\t// the element can assume it needs to respond to 'change'...\n\t\t\tif ( target.is('input, select, textarea') ) {\n\n\t\t\t\t// Default to .val if this is an input element.\n\t\t\t\tthis.method = 'val';\n\n\t\t\t\t// Fire the API changehandler when the target changes.\n\t\t\t\tthis.target = target.on('change.liblink', this.changeHandler);\n\n\t\t\t} else {\n\n\t\t\t\tthis.target = target;\n\n\t\t\t\t// If no method is set, and we are not auto-binding an input, default to 'html'.\n\t\t\t\tthis.method = 'html';\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\t}\n\n\tfunction fromInstanceMethod ( target, method ) {\n\n\t\t// The method must exist on the element.\n\t\tif ( isInstance( target ) &&\n\t\t\t(typeof method === 'function' ||\n\t\t\t\t(typeof method === 'string' && target[method]))\n\t\t) {\n\t\t\tthis.method = method;\n\t\t\tthis.target = target;\n\n\t\t\treturn true;\n\t\t}\n\t}\n\nvar\n/** @const */\n\tcreationFunctions = [fromPrefix, fromString, fromFunction, fromInstance, fromInstanceMethod];\n\n\n// Link Instance\n\n/** @constructor */\n\tfunction Link ( target, method, format ) {\n\n\t\tvar that = this, valid = false;\n\n\t\t// Forward calls within scope.\n\t\tthis.changeHandler = function ( changeEvent ) {\n\t\t\tvar decodedValue = that.formatInstance.from( $(this).val() );\n\n\t\t\t// If the value is invalid, stop this event, as well as it's propagation.\n\t\t\tif ( decodedValue === false || isNaN(decodedValue) ) {\n\n\t\t\t\t// Reset the value.\n\t\t\t\t$(this).val(that.lastSetValue);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthat.changeHandlerMethod.call( '', changeEvent, decodedValue );\n\t\t};\n\n\t\t// See if this Link needs individual targets based on its usage.\n\t\t// If so, return the element that needs to be copied by the\n\t\t// implementing interface.\n\t\t// Default the element to false.\n\t\tthis.el = false;\n\n\t\t// Store the formatter, or use the default.\n\t\tthis.formatInstance = format;\n\n\t\t// Try all Link types.\n\t\t/*jslint unparam: true*/\n\t\t$.each(creationFunctions, function(i, fn){\n\t\t\tvalid = fn.call(that, target, method);\n\t\t\treturn !valid;\n\t\t});\n\t\t/*jslint unparam: false*/\n\n\t\t// Nothing matched, throw error.\n\t\tif ( !valid ) {\n\t\t\tthrow new RangeError(\"(Link) Invalid Link.\");\n\t\t}\n\t}\n\n\t// Provides external items with the object value.\n\tLink.prototype.set = function ( value ) {\n\n\t\t// Ignore the value, so only the passed-on arguments remain.\n\t\tvar args = Array.prototype.slice.call( arguments ),\n\t\t\tadditionalArgs = args.slice(1);\n\n\t\t// Store some values. The actual, numerical value,\n\t\t// the formatted value and the parameters for use in 'resetValue'.\n\t\t// Slice additionalArgs to break the relation.\n\t\tthis.lastSetValue = this.formatInstance.to( value );\n\n\t\t// Prepend the value to the function arguments.\n\t\tadditionalArgs.unshift(\n\t\t\tthis.lastSetValue\n\t\t);\n\n\t\t// When target is undefined, the target was a function.\n\t\t// In that case, provided the object as the calling scope.\n\t\t// Branch between writing to a function or an object.\n\t\t( typeof this.method === 'function' ?\n\t\t\tthis.method :\n\t\t\tthis.target[ this.method ] ).apply( this.target, additionalArgs );\n\t};\n\n\n// Developer API\n\n/** @constructor */\n\tfunction LinkAPI ( origin ) {\n\t\tthis.items = [];\n\t\tthis.elements = [];\n\t\tthis.origin = origin;\n\t}\n\n\tLinkAPI.prototype.push = function( item, element ) {\n\t\tthis.items.push(item);\n\n\t\t// Prevent 'false' elements\n\t\tif ( element ) {\n\t\t\tthis.elements.push(element);\n\t\t}\n\t};\n\n\tLinkAPI.prototype.reconfirm = function ( flag ) {\n\t\tvar i;\n\t\tfor ( i = 0; i < this.elements.length; i += 1 ) {\n\t\t\tthis.origin.LinkConfirm(flag, this.elements[i]);\n\t\t}\n\t};\n\n\tLinkAPI.prototype.remove = function ( flag ) {\n\t\tvar i;\n\t\tfor ( i = 0; i < this.items.length; i += 1 ) {\n\t\t\tthis.items[i].target.off('.liblink');\n\t\t}\n\t\tfor ( i = 0; i < this.elements.length; i += 1 ) {\n\t\t\tthis.elements[i].remove();\n\t\t}\n\t};\n\n\tLinkAPI.prototype.change = function ( value ) {\n\n\t\tif ( this.origin.LinkIsEmitting ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.origin.LinkIsEmitting = true;\n\n\t\tvar args = Array.prototype.slice.call( arguments, 1 ), i;\n\t\targs.unshift( value );\n\n\t\t// Write values to serialization Links.\n\t\t// Convert the value to the correct relative representation.\n\t\tfor ( i = 0; i < this.items.length; i += 1 ) {\n\t\t\tthis.items[i].set.apply(this.items[i], args);\n\t\t}\n\n\t\tthis.origin.LinkIsEmitting = false;\n\t};\n\n\n// jQuery plugin\n\n\tfunction binder ( flag, target, method, format ){\n\n\t\tif ( flag === 0 ) {\n\t\t\tflag = this.LinkDefaultFlag;\n\t\t}\n\n\t\t// Create a list of API's (if it didn't exist yet);\n\t\tif ( !this.linkAPI ) {\n\t\t\tthis.linkAPI = {};\n\t\t}\n\n\t\t// Add an API point.\n\t\tif ( !this.linkAPI[flag] ) {\n\t\t\tthis.linkAPI[flag] = new LinkAPI(this);\n\t\t}\n\n\t\tvar linkInstance = new Link ( target, method, format || this.LinkDefaultFormatter );\n\n\t\t// Default the calling scope to the linked object.\n\t\tif ( !linkInstance.target ) {\n\t\t\tlinkInstance.target = $(this);\n\t\t}\n\n\t\t// If the Link requires creation of a new element,\n\t\t// Pass the element and request confirmation to get the changehandler.\n\t\t// Set the method to be called when a Link changes.\n\t\tlinkInstance.changeHandlerMethod = this.LinkConfirm( flag, linkInstance.el );\n\n\t\t// Store the linkInstance in the flagged list.\n\t\tthis.linkAPI[flag].push( linkInstance, linkInstance.el );\n\n\t\t// Now that Link have been connected, request an update.\n\t\tthis.LinkUpdate( flag );\n\t}\n\n\t/** @export */\n\t$.fn.Link = function( flag ){\n\n\t\tvar that = this;\n\n\t\t// Delete all linkAPI\n\t\tif ( flag === false ) {\n\n\t\t\treturn that.each(function(){\n\n\t\t\t\t// .Link(false) can be called on elements without Links.\n\t\t\t\t// When that happens, the objects can't be looped.\n\t\t\t\tif ( !this.linkAPI ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t$.map(this.linkAPI, function(api){\n\t\t\t\t\tapi.remove();\n\t\t\t\t});\n\n\t\t\t\tdelete this.linkAPI;\n\t\t\t});\n\t\t}\n\n\t\tif ( flag === undefined ) {\n\n\t\t\tflag = 0;\n\n\t\t} else if ( typeof flag !== 'string') {\n\n\t\t\tthrow new Error(\"Flag must be string.\");\n\t\t}\n\n\t\treturn {\n\t\t\tto: function( a, b, c ){\n\t\t\t\treturn that.each(function(){\n\t\t\t\t\tbinder.call(this, flag, a, b, c);\n\t\t\t\t});\n\t\t\t}\n\t\t};\n\t};\n\n}( window.jQuery || window.Zepto ));\n\n/*jslint browser: true */\n/*jslint white: true */\n\n(function( $ ){\n\n\t'use strict';\n\n\n\t// Removes duplicates from an array.\n\tfunction unique(array) {\n\t\treturn $.grep(array, function(el, index) {\n\t\t\treturn index === $.inArray(el, array);\n\t\t});\n\t}\n\n\t// Round a value to the closest 'to'.\n\tfunction closest ( value, to ) {\n\t\treturn Math.round(value / to) * to;\n\t}\n\n\t// Checks whether a value is numerical.\n\tfunction isNumeric ( a ) {\n\t\treturn typeof a === 'number' && !isNaN( a ) && isFinite( a );\n\t}\n\n\t// Rounds a number to 7 supported decimals.\n\tfunction accurateNumber( number ) {\n\t\tvar p = Math.pow(10, 7);\n\t\treturn Number((Math.round(number*p)/p).toFixed(7));\n\t}\n\n\t// Sets a class and removes it after [duration] ms.\n\tfunction addClassFor ( element, className, duration ) {\n\t\telement.addClass(className);\n\t\tsetTimeout(function(){\n\t\t\telement.removeClass(className);\n\t\t}, duration);\n\t}\n\n\t// Limits a value to 0 - 100\n\tfunction limit ( a ) {\n\t\treturn Math.max(Math.min(a, 100), 0);\n\t}\n\n\t// Wraps a variable as an array, if it isn't one yet.\n\tfunction asArray ( a ) {\n\t\treturn $.isArray(a) ? a : [a];\n\t}\n\n\t// Counts decimals\n\tfunction countDecimals ( numStr ) {\n\t\tvar pieces = numStr.split(\".\");\n\t\treturn pieces.length > 1 ? pieces[1].length : 0;\n\t}\n\n\n\tvar\n\t// Cache the document selector;\n\t/** @const */\n\tdoc = $(document),\n\t// Make a backup of the original jQuery/Zepto .val() method.\n\t/** @const */\n\t$val = $.fn.val,\n\t// Namespace for binding and unbinding slider events;\n\t/** @const */\n\tnamespace = '.nui',\n\t// Determine the events to bind. IE11 implements pointerEvents without\n\t// a prefix, which breaks compatibility with the IE10 implementation.\n\t/** @const */\n\tactions = window.navigator.pointerEnabled ? {\n\t\tstart: 'pointerdown',\n\t\tmove: 'pointermove',\n\t\tend: 'pointerup'\n\t} : window.navigator.msPointerEnabled ? {\n\t\tstart: 'MSPointerDown',\n\t\tmove: 'MSPointerMove',\n\t\tend: 'MSPointerUp'\n\t} : {\n\t\tstart: 'mousedown touchstart',\n\t\tmove: 'mousemove touchmove',\n\t\tend: 'mouseup touchend'\n\t},\n\t// Re-usable list of classes;\n\t/** @const */\n\tClasses = [\n/*  0 */  'noUi-target'\n/*  1 */ ,'noUi-base'\n/*  2 */ ,'noUi-origin'\n/*  3 */ ,'noUi-handle'\n/*  4 */ ,'noUi-horizontal'\n/*  5 */ ,'noUi-vertical'\n/*  6 */ ,'noUi-background'\n/*  7 */ ,'noUi-connect'\n/*  8 */ ,'noUi-ltr'\n/*  9 */ ,'noUi-rtl'\n/* 10 */ ,'noUi-dragable'\n/* 11 */ ,''\n/* 12 */ ,'noUi-state-drag'\n/* 13 */ ,''\n/* 14 */ ,'noUi-state-tap'\n/* 15 */ ,'noUi-active'\n/* 16 */ ,''\n/* 17 */ ,'noUi-stacking'\n\t];\n\n\n// Value calculation\n\n\t// Determine the size of a sub-range in relation to a full range.\n\tfunction subRangeRatio ( pa, pb ) {\n\t\treturn (100 / (pb - pa));\n\t}\n\n\t// (percentage) How many percent is this value of this range?\n\tfunction fromPercentage ( range, value ) {\n\t\treturn (value * 100) / ( range[1] - range[0] );\n\t}\n\n\t// (percentage) Where is this value on this range?\n\tfunction toPercentage ( range, value ) {\n\t\treturn fromPercentage( range, range[0] < 0 ?\n\t\t\tvalue + Math.abs(range[0]) :\n\t\t\t\tvalue - range[0] );\n\t}\n\n\t// (value) How much is this percentage on this range?\n\tfunction isPercentage ( range, value ) {\n\t\treturn ((value * ( range[1] - range[0] )) / 100) + range[0];\n\t}\n\n\n// Range conversion\n\n\tfunction getJ ( value, arr ) {\n\n\t\tvar j = 1;\n\n\t\twhile ( value >= arr[j] ){\n\t\t\tj += 1;\n\t\t}\n\n\t\treturn j;\n\t}\n\n\t// (percentage) Input a value, find where, on a scale of 0-100, it applies.\n\tfunction toStepping ( xVal, xPct, value ) {\n\n\t\tif ( value >= xVal.slice(-1)[0] ){\n\t\t\treturn 100;\n\t\t}\n\n\t\tvar j = getJ( value, xVal ), va, vb, pa, pb;\n\n\t\tva = xVal[j-1];\n\t\tvb = xVal[j];\n\t\tpa = xPct[j-1];\n\t\tpb = xPct[j];\n\n\t\treturn pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb));\n\t}\n\n\t// (value) Input a percentage, find where it is on the specified range.\n\tfunction fromStepping ( xVal, xPct, value ) {\n\n\t\t// There is no range group that fits 100\n\t\tif ( value >= 100 ){\n\t\t\treturn xVal.slice(-1)[0];\n\t\t}\n\n\t\tvar j = getJ( value, xPct ), va, vb, pa, pb;\n\n\t\tva = xVal[j-1];\n\t\tvb = xVal[j];\n\t\tpa = xPct[j-1];\n\t\tpb = xPct[j];\n\n\t\treturn isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb));\n\t}\n\n\t// (percentage) Get the step that applies at a certain value.\n\tfunction getStep ( xPct, xSteps, snap, value ) {\n\n\t\tif ( value === 100 ) {\n\t\t\treturn value;\n\t\t}\n\n\t\tvar j = getJ( value, xPct ), a, b;\n\n\t\t// If 'snap' is set, steps are used as fixed points on the slider.\n\t\tif ( snap ) {\n\n\t\t\ta = xPct[j-1];\n\t\t\tb = xPct[j];\n\n\t\t\t// Find the closest position, a or b.\n\t\t\tif ((value - a) > ((b-a)/2)){\n\t\t\t\treturn b;\n\t\t\t}\n\n\t\t\treturn a;\n\t\t}\n\n\t\tif ( !xSteps[j-1] ){\n\t\t\treturn value;\n\t\t}\n\n\t\treturn xPct[j-1] + closest(\n\t\t\tvalue - xPct[j-1],\n\t\t\txSteps[j-1]\n\t\t);\n\t}\n\n\n// Entry parsing\n\n\tfunction handleEntryPoint ( index, value, that ) {\n\n\t\tvar percentage;\n\n\t\t// Wrap numerical input in an array.\n\t\tif ( typeof value === \"number\" ) {\n\t\t\tvalue = [value];\n\t\t}\n\n\t\t// Reject any invalid input, by testing whether value is an array.\n\t\tif ( Object.prototype.toString.call( value ) !== '[object Array]' ){\n\t\t\tthrow new Error(\"noUiSlider: 'range' contains invalid value.\");\n\t\t}\n\n\t\t// Covert min/max syntax to 0 and 100.\n\t\tif ( index === 'min' ) {\n\t\t\tpercentage = 0;\n\t\t} else if ( index === 'max' ) {\n\t\t\tpercentage = 100;\n\t\t} else {\n\t\t\tpercentage = parseFloat( index );\n\t\t}\n\n\t\t// Check for correct input.\n\t\tif ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) {\n\t\t\tthrow new Error(\"noUiSlider: 'range' value isn't numeric.\");\n\t\t}\n\n\t\t// Store values.\n\t\tthat.xPct.push( percentage );\n\t\tthat.xVal.push( value[0] );\n\n\t\t// NaN will evaluate to false too, but to keep\n\t\t// logging clear, set step explicitly. Make sure\n\t\t// not to override the 'step' setting with false.\n\t\tif ( !percentage ) {\n\t\t\tif ( !isNaN( value[1] ) ) {\n\t\t\t\tthat.xSteps[0] = value[1];\n\t\t\t}\n\t\t} else {\n\t\t\tthat.xSteps.push( isNaN(value[1]) ? false : value[1] );\n\t\t}\n\t}\n\n\tfunction handleStepPoint ( i, n, that ) {\n\n\t\t// Ignore 'false' stepping.\n\t\tif ( !n ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Factor to range ratio\n\t\tthat.xSteps[i] = fromPercentage([\n\t\t\t that.xVal[i]\n\t\t\t,that.xVal[i+1]\n\t\t], n) / subRangeRatio (\n\t\t\tthat.xPct[i],\n\t\t\tthat.xPct[i+1] );\n\t}\n\n\n// Interface\n\n\t// The interface to Spectrum handles all direction-based\n\t// conversions, so the above values are unaware.\n\n\tfunction Spectrum ( entry, snap, direction, singleStep ) {\n\n\t\tthis.xPct = [];\n\t\tthis.xVal = [];\n\t\tthis.xSteps = [ singleStep || false ];\n\t\tthis.xNumSteps = [ false ];\n\n\t\tthis.snap = snap;\n\t\tthis.direction = direction;\n\n\t\tvar index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ];\n\n\t\t// Map the object keys to an array.\n\t\tfor ( index in entry ) {\n\t\t\tif ( entry.hasOwnProperty(index) ) {\n\t\t\t\tordered.push([entry[index], index]);\n\t\t\t}\n\t\t}\n\n\t\t// Sort all entries by value (numeric sort).\n\t\tordered.sort(function(a, b) { return a[0] - b[0]; });\n\n\t\t// Convert all entries to subranges.\n\t\tfor ( index = 0; index < ordered.length; index++ ) {\n\t\t\thandleEntryPoint(ordered[index][1], ordered[index][0], this);\n\t\t}\n\n\t\t// Store the actual step values.\n\t\t// xSteps is sorted in the same order as xPct and xVal.\n\t\tthis.xNumSteps = this.xSteps.slice(0);\n\n\t\t// Convert all numeric steps to the percentage of the subrange they represent.\n\t\tfor ( index = 0; index < this.xNumSteps.length; index++ ) {\n\t\t\thandleStepPoint(index, this.xNumSteps[index], this);\n\t\t}\n\t}\n\n\tSpectrum.prototype.getMargin = function ( value ) {\n\t\treturn this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false;\n\t};\n\n\tSpectrum.prototype.toStepping = function ( value ) {\n\n\t\tvalue = toStepping( this.xVal, this.xPct, value );\n\n\t\t// Invert the value if this is a right-to-left slider.\n\t\tif ( this.direction ) {\n\t\t\tvalue = 100 - value;\n\t\t}\n\n\t\treturn value;\n\t};\n\n\tSpectrum.prototype.fromStepping = function ( value ) {\n\n\t\t// Invert the value if this is a right-to-left slider.\n\t\tif ( this.direction ) {\n\t\t\tvalue = 100 - value;\n\t\t}\n\n\t\treturn accurateNumber(fromStepping( this.xVal, this.xPct, value ));\n\t};\n\n\tSpectrum.prototype.getStep = function ( value ) {\n\n\t\t// Find the proper step for rtl sliders by search in inverse direction.\n\t\t// Fixes issue #262.\n\t\tif ( this.direction ) {\n\t\t\tvalue = 100 - value;\n\t\t}\n\n\t\tvalue = getStep(this.xPct, this.xSteps, this.snap, value );\n\n\t\tif ( this.direction ) {\n\t\t\tvalue = 100 - value;\n\t\t}\n\n\t\treturn value;\n\t};\n\n\tSpectrum.prototype.getApplicableStep = function ( value ) {\n\n\t\t// If the value is 100%, return the negative step twice.\n\t\tvar j = getJ(value, this.xPct), offset = value === 100 ? 2 : 1;\n\t\treturn [this.xNumSteps[j-2], this.xVal[j-offset], this.xNumSteps[j-offset]];\n\t};\n\n\t// Outside testing\n\tSpectrum.prototype.convert = function ( value ) {\n\t\treturn this.getStep(this.toStepping(value));\n\t};\n\n/*\tEvery input option is tested and parsed. This'll prevent\n\tendless validation in internal methods. These tests are\n\tstructured with an item for every option available. An\n\toption can be marked as required by setting the 'r' flag.\n\tThe testing function is provided with three arguments:\n\t\t- The provided value for the option;\n\t\t- A reference to the options object;\n\t\t- The name for the option;\n\n\tThe testing function returns false when an error is detected,\n\tor true when everything is OK. It can also modify the option\n\tobject, to make sure all values can be correctly looped elsewhere. */\n\n\t/** @const */\n\tvar defaultFormatter = { 'to': function( value ){\n\t\treturn value.toFixed(2);\n\t}, 'from': Number };\n\n\tfunction testStep ( parsed, entry ) {\n\n\t\tif ( !isNumeric( entry ) ) {\n\t\t\tthrow new Error(\"noUiSlider: 'step' is not numeric.\");\n\t\t}\n\n\t\t// The step option can still be used to set stepping\n\t\t// for linear sliders. Overwritten if set in 'range'.\n\t\tparsed.singleStep = entry;\n\t}\n\n\tfunction testRange ( parsed, entry ) {\n\n\t\t// Filter incorrect input.\n\t\tif ( typeof entry !== 'object' || $.isArray(entry) ) {\n\t\t\tthrow new Error(\"noUiSlider: 'range' is not an object.\");\n\t\t}\n\n\t\t// Catch missing start or end.\n\t\tif ( entry.min === undefined || entry.max === undefined ) {\n\t\t\tthrow new Error(\"noUiSlider: Missing 'min' or 'max' in 'range'.\");\n\t\t}\n\n\t\tparsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep);\n\t}\n\n\tfunction testStart ( parsed, entry ) {\n\n\t\tentry = asArray(entry);\n\n\t\t// Validate input. Values aren't tested, as the public .val method\n\t\t// will always provide a valid location.\n\t\tif ( !$.isArray( entry ) || !entry.length || entry.length > 2 ) {\n\t\t\tthrow new Error(\"noUiSlider: 'start' option is incorrect.\");\n\t\t}\n\n\t\t// Store the number of handles.\n\t\tparsed.handles = entry.length;\n\n\t\t// When the slider is initialized, the .val method will\n\t\t// be called with the start options.\n\t\tparsed.start = entry;\n\t}\n\n\tfunction testSnap ( parsed, entry ) {\n\n\t\t// Enforce 100% stepping within subranges.\n\t\tparsed.snap = entry;\n\n\t\tif ( typeof entry !== 'boolean' ){\n\t\t\tthrow new Error(\"noUiSlider: 'snap' option must be a boolean.\");\n\t\t}\n\t}\n\n\tfunction testAnimate ( parsed, entry ) {\n\n\t\t// Enforce 100% stepping within subranges.\n\t\tparsed.animate = entry;\n\n\t\tif ( typeof entry !== 'boolean' ){\n\t\t\tthrow new Error(\"noUiSlider: 'animate' option must be a boolean.\");\n\t\t}\n\t}\n\n\tfunction testConnect ( parsed, entry ) {\n\n\t\tif ( entry === 'lower' && parsed.handles === 1 ) {\n\t\t\tparsed.connect = 1;\n\t\t} else if ( entry === 'upper' && parsed.handles === 1 ) {\n\t\t\tparsed.connect = 2;\n\t\t} else if ( entry === true && parsed.handles === 2 ) {\n\t\t\tparsed.connect = 3;\n\t\t} else if ( entry === false ) {\n\t\t\tparsed.connect = 0;\n\t\t} else {\n\t\t\tthrow new Error(\"noUiSlider: 'connect' option doesn't match handle count.\");\n\t\t}\n\t}\n\n\tfunction testOrientation ( parsed, entry ) {\n\n\t\t// Set orientation to an a numerical value for easy\n\t\t// array selection.\n\t\tswitch ( entry ){\n\t\t  case 'horizontal':\n\t\t\tparsed.ort = 0;\n\t\t\tbreak;\n\t\t  case 'vertical':\n\t\t\tparsed.ort = 1;\n\t\t\tbreak;\n\t\t  default:\n\t\t\tthrow new Error(\"noUiSlider: 'orientation' option is invalid.\");\n\t\t}\n\t}\n\n\tfunction testMargin ( parsed, entry ) {\n\n\t\tif ( !isNumeric(entry) ){\n\t\t\tthrow new Error(\"noUiSlider: 'margin' option must be numeric.\");\n\t\t}\n\n\t\tparsed.margin = parsed.spectrum.getMargin(entry);\n\n\t\tif ( !parsed.margin ) {\n\t\t\tthrow new Error(\"noUiSlider: 'margin' option is only supported on linear sliders.\");\n\t\t}\n\t}\n\n\tfunction testLimit ( parsed, entry ) {\n\n\t\tif ( !isNumeric(entry) ){\n\t\t\tthrow new Error(\"noUiSlider: 'limit' option must be numeric.\");\n\t\t}\n\n\t\tparsed.limit = parsed.spectrum.getMargin(entry);\n\n\t\tif ( !parsed.limit ) {\n\t\t\tthrow new Error(\"noUiSlider: 'limit' option is only supported on linear sliders.\");\n\t\t}\n\t}\n\n\tfunction testDirection ( parsed, entry ) {\n\n\t\t// Set direction as a numerical value for easy parsing.\n\t\t// Invert connection for RTL sliders, so that the proper\n\t\t// handles get the connect/background classes.\n\t\tswitch ( entry ) {\n\t\t  case 'ltr':\n\t\t\tparsed.dir = 0;\n\t\t\tbreak;\n\t\t  case 'rtl':\n\t\t\tparsed.dir = 1;\n\t\t\tparsed.connect = [0,2,1,3][parsed.connect];\n\t\t\tbreak;\n\t\t  default:\n\t\t\tthrow new Error(\"noUiSlider: 'direction' option was not recognized.\");\n\t\t}\n\t}\n\n\tfunction testBehaviour ( parsed, entry ) {\n\n\t\t// Make sure the input is a string.\n\t\tif ( typeof entry !== 'string' ) {\n\t\t\tthrow new Error(\"noUiSlider: 'behaviour' must be a string containing options.\");\n\t\t}\n\n\t\t// Check if the string contains any keywords.\n\t\t// None are required.\n\t\tvar tap = entry.indexOf('tap') >= 0,\n\t\t\tdrag = entry.indexOf('drag') >= 0,\n\t\t\tfixed = entry.indexOf('fixed') >= 0,\n\t\t\tsnap = entry.indexOf('snap') >= 0;\n\n\t\tparsed.events = {\n\t\t\ttap: tap || snap,\n\t\t\tdrag: drag,\n\t\t\tfixed: fixed,\n\t\t\tsnap: snap\n\t\t};\n\t}\n\n\tfunction testFormat ( parsed, entry ) {\n\n\t\tparsed.format = entry;\n\n\t\t// Any object with a to and from method is supported.\n\t\tif ( typeof entry.to === 'function' && typeof entry.from === 'function' ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tthrow new Error( \"noUiSlider: 'format' requires 'to' and 'from' methods.\");\n\t}\n\n\t// Test all developer settings and parse to assumption-safe values.\n\tfunction testOptions ( options ) {\n\n\t\tvar parsed = {\n\t\t\tmargin: 0,\n\t\t\tlimit: 0,\n\t\t\tanimate: true,\n\t\t\tformat: defaultFormatter\n\t\t}, tests;\n\n\t\t// Tests are executed in the order they are presented here.\n\t\ttests = {\n\t\t\t'step': { r: false, t: testStep },\n\t\t\t'start': { r: true, t: testStart },\n\t\t\t'connect': { r: true, t: testConnect },\n\t\t\t'direction': { r: true, t: testDirection },\n\t\t\t'snap': { r: false, t: testSnap },\n\t\t\t'animate': { r: false, t: testAnimate },\n\t\t\t'range': { r: true, t: testRange },\n\t\t\t'orientation': { r: false, t: testOrientation },\n\t\t\t'margin': { r: false, t: testMargin },\n\t\t\t'limit': { r: false, t: testLimit },\n\t\t\t'behaviour': { r: true, t: testBehaviour },\n\t\t\t'format': { r: false, t: testFormat }\n\t\t};\n\n\t\t// Set defaults where applicable.\n\t\toptions = $.extend({\n\t\t\t'connect': false,\n\t\t\t'direction': 'ltr',\n\t\t\t'behaviour': 'tap',\n\t\t\t'orientation': 'horizontal'\n\t\t}, options);\n\n\t\t// Run all options through a testing mechanism to ensure correct\n\t\t// input. It should be noted that options might get modified to\n\t\t// be handled properly. E.g. wrapping integers in arrays.\n\t\t$.each( tests, function( name, test ){\n\n\t\t\t// If the option isn't set, but it is required, throw an error.\n\t\t\tif ( options[name] === undefined ) {\n\n\t\t\t\tif ( test.r ) {\n\t\t\t\t\tthrow new Error(\"noUiSlider: '\" + name + \"' is required.\");\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\ttest.t( parsed, options[name] );\n\t\t});\n\n\t\t// Pre-define the styles.\n\t\tparsed.style = parsed.ort ? 'top' : 'left';\n\n\t\treturn parsed;\n\t}\n\n// Class handling\n\n\t// Delimit proposed values for handle positions.\n\tfunction getPositions ( a, b, delimit ) {\n\n\t\t// Add movement to current position.\n\t\tvar c = a + b[0], d = a + b[1];\n\n\t\t// Only alter the other position on drag,\n\t\t// not on standard sliding.\n\t\tif ( delimit ) {\n\t\t\tif ( c < 0 ) {\n\t\t\t\td += Math.abs(c);\n\t\t\t}\n\t\t\tif ( d > 100 ) {\n\t\t\t\tc -= ( d - 100 );\n\t\t\t}\n\n\t\t\t// Limit values to 0 and 100.\n\t\t\treturn [limit(c), limit(d)];\n\t\t}\n\n\t\treturn [c,d];\n\t}\n\n\n// Event handling\n\n\t// Provide a clean event with standardized offset values.\n\tfunction fixEvent ( e ) {\n\n\t\t// Prevent scrolling and panning on touch events, while\n\t\t// attempting to slide. The tap event also depends on this.\n\t\te.preventDefault();\n\n\t\t// Filter the event to register the type, which can be\n\t\t// touch, mouse or pointer. Offset changes need to be\n\t\t// made on an event specific basis.\n\t\tvar  touch = e.type.indexOf('touch') === 0\n\t\t\t,mouse = e.type.indexOf('mouse') === 0\n\t\t\t,pointer = e.type.indexOf('pointer') === 0\n\t\t\t,x,y, event = e;\n\n\t\t// IE10 implemented pointer events with a prefix;\n\t\tif ( e.type.indexOf('MSPointer') === 0 ) {\n\t\t\tpointer = true;\n\t\t}\n\n\t\t// Get the originalEvent, if the event has been wrapped\n\t\t// by jQuery. Zepto doesn't wrap the event.\n\t\tif ( e.originalEvent ) {\n\t\t\te = e.originalEvent;\n\t\t}\n\n\t\tif ( touch ) {\n\t\t\t// noUiSlider supports one movement at a time,\n\t\t\t// so we can select the first 'changedTouch'.\n\t\t\tx = e.changedTouches[0].pageX;\n\t\t\ty = e.changedTouches[0].pageY;\n\t\t}\n\n\t\tif ( mouse || pointer ) {\n\n\t\t\t// Polyfill the pageXOffset and pageYOffset\n\t\t\t// variables for IE7 and IE8;\n\t\t\tif( !pointer && window.pageXOffset === undefined ){\n\t\t\t\twindow.pageXOffset = document.documentElement.scrollLeft;\n\t\t\t\twindow.pageYOffset = document.documentElement.scrollTop;\n\t\t\t}\n\n\t\t\tx = e.clientX + window.pageXOffset;\n\t\t\ty = e.clientY + window.pageYOffset;\n\t\t}\n\n\t\tevent.points = [x, y];\n\t\tevent.cursor = mouse;\n\n\t\treturn event;\n\t}\n\n\n// DOM additions\n\n\t// Append a handle to the base.\n\tfunction addHandle ( direction, index ) {\n\n\t\tvar handle = $('<div><div/></div>').addClass( Classes[2] ),\n\t\t\tadditions = [ '-lower', '-upper' ];\n\n\t\tif ( direction ) {\n\t\t\tadditions.reverse();\n\t\t}\n\n\t\thandle.children().addClass(\n\t\t\tClasses[3] + \" \" + Classes[3]+additions[index]\n\t\t);\n\n\t\treturn handle;\n\t}\n\n\t// Add the proper connection classes.\n\tfunction addConnection ( connect, target, handles ) {\n\n\t\t// Apply the required connection classes to the elements\n\t\t// that need them. Some classes are made up for several\n\t\t// segments listed in the class list, to allow easy\n\t\t// renaming and provide a minor compression benefit.\n\t\tswitch ( connect ) {\n\t\t\tcase 1:\ttarget.addClass( Classes[7] );\n\t\t\t\t\thandles[0].addClass( Classes[6] );\n\t\t\t\t\tbreak;\n\t\t\tcase 3: handles[1].addClass( Classes[6] );\n\t\t\t\t\t/* falls through */\n\t\t\tcase 2: handles[0].addClass( Classes[7] );\n\t\t\t\t\t/* falls through */\n\t\t\tcase 0: target.addClass(Classes[6]);\n\t\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Add handles to the slider base.\n\tfunction addHandles ( nrHandles, direction, base ) {\n\n\t\tvar index, handles = [];\n\n\t\t// Append handles.\n\t\tfor ( index = 0; index < nrHandles; index += 1 ) {\n\n\t\t\t// Keep a list of all added handles.\n\t\t\thandles.push( addHandle( direction, index ).appendTo(base) );\n\t\t}\n\n\t\treturn handles;\n\t}\n\n\t// Initialize a single slider.\n\tfunction addSlider ( direction, orientation, target ) {\n\n\t\t// Apply classes and data to the target.\n\t\ttarget.addClass([\n\t\t\tClasses[0],\n\t\t\tClasses[8 + direction],\n\t\t\tClasses[4 + orientation]\n\t\t].join(' '));\n\n\t\treturn $('<div/>').appendTo(target).addClass( Classes[1] );\n\t}\n\nfunction closure ( target, options, originalOptions ){\n\n// Internal variables\n\n\t// All variables local to 'closure' are marked $.\n\tvar $Target = $(target),\n\t\t$Locations = [-1, -1],\n\t\t$Base,\n\t\t$Handles,\n\t\t$Spectrum = options.spectrum,\n\t\t$Values = [],\n\t// libLink. For rtl sliders, 'lower' and 'upper' should not be inverted\n\t// for one-handle sliders, so trim 'upper' it that case.\n\t\ttriggerPos = ['lower', 'upper'].slice(0, options.handles);\n\n\t// Invert the libLink connection for rtl sliders.\n\tif ( options.dir ) {\n\t\ttriggerPos.reverse();\n\t}\n\n// Helpers\n\n\t// Shorthand for base dimensions.\n\tfunction baseSize ( ) {\n\t\treturn $Base[['width', 'height'][options.ort]]();\n\t}\n\n\t// External event handling\n\tfunction fireEvents ( events ) {\n\n\t\t// Use the external api to get the values.\n\t\t// Wrap the values in an array, as .trigger takes\n\t\t// only one additional argument.\n\t\tvar index, values = [ $Target.val() ];\n\n\t\tfor ( index = 0; index < events.length; index += 1 ){\n\t\t\t$Target.trigger(events[index], values);\n\t\t}\n\t}\n\n\t// Returns the input array, respecting the slider direction configuration.\n\tfunction inSliderOrder ( values ) {\n\n\t\t// If only one handle is used, return a single value.\n\t\tif ( values.length === 1 ){\n\t\t\treturn values[0];\n\t\t}\n\n\t\tif ( options.dir ) {\n\t\t\treturn values.reverse();\n\t\t}\n\n\t\treturn values;\n\t}\n\n// libLink integration\n\n\t// Create a new function which calls .val on input change.\n\tfunction createChangeHandler ( trigger ) {\n\t\treturn function ( ignore, value ){\n\t\t\t// Determine which array position to 'null' based on 'trigger'.\n\t\t\t$Target.val( [ trigger ? null : value, trigger ? value : null ], true );\n\t\t};\n\t}\n\n\t// Called by libLink when it wants a set of links updated.\n\tfunction linkUpdate ( flag ) {\n\n\t\tvar trigger = $.inArray(flag, triggerPos);\n\n\t\t// The API might not have been set yet.\n\t\tif ( $Target[0].linkAPI && $Target[0].linkAPI[flag] ) {\n\t\t\t$Target[0].linkAPI[flag].change(\n\t\t\t\t$Values[trigger],\n\t\t\t\t$Handles[trigger].children(),\n\t\t\t\t$Target\n\t\t\t);\n\t\t}\n\t}\n\n\t// Called by libLink to append an element to the slider.\n\tfunction linkConfirm ( flag, element ) {\n\n\t\t// Find the trigger for the passed flag.\n\t\tvar trigger = $.inArray(flag, triggerPos);\n\n\t\t// If set, append the element to the handle it belongs to.\n\t\tif ( element ) {\n\t\t\telement.appendTo( $Handles[trigger].children() );\n\t\t}\n\n\t\t// The public API is reversed for rtl sliders, so the changeHandler\n\t\t// should not be aware of the inverted trigger positions.\n\t\t// On rtl slider with one handle, 'lower' should be used.\n\t\tif ( options.dir && options.handles > 1 ) {\n\t\t\ttrigger = trigger === 1 ? 0 : 1;\n\t\t}\n\n\t\treturn createChangeHandler( trigger );\n\t}\n\n\t// Place elements back on the slider.\n\tfunction reAppendLink ( ) {\n\n\t\tvar i, flag;\n\n\t\t// The API keeps a list of elements: we can re-append them on rebuild.\n\t\tfor ( i = 0; i < triggerPos.length; i += 1 ) {\n\t\t\tif ( this.linkAPI && this.linkAPI[(flag = triggerPos[i])] ) {\n\t\t\t\tthis.linkAPI[flag].reconfirm(flag);\n\t\t\t}\n\t\t}\n\t}\n\n\ttarget.LinkUpdate = linkUpdate;\n\ttarget.LinkConfirm = linkConfirm;\n\ttarget.LinkDefaultFormatter = options.format;\n\ttarget.LinkDefaultFlag = 'lower';\n\n\ttarget.reappend = reAppendLink;\n\n\n\t// Handler for attaching events trough a proxy.\n\tfunction attach ( events, element, callback, data ) {\n\n\t\t// This function can be used to 'filter' events to the slider.\n\n\t\t// Add the noUiSlider namespace to all events.\n\t\tevents = events.replace( /\\s/g, namespace + ' ' ) + namespace;\n\n\t\t// Bind a closure on the target.\n\t\treturn element.on( events, function( e ){\n\n\t\t\t// jQuery and Zepto (1) handle unset attributes differently,\n\t\t\t// but always falsy; #208\n\t\t\tif ( !!$Target.attr('disabled') ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Stop if an active 'tap' transition is taking place.\n\t\t\tif ( $Target.hasClass( Classes[14] ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\te = fixEvent(e);\n\t\t\te.calcPoint = e.points[ options.ort ];\n\n\t\t\t// Call the event handler with the event [ and additional data ].\n\t\t\tcallback ( e, data );\n\t\t});\n\t}\n\n\t// Handle movement on document for handle and range drag.\n\tfunction move ( event, data ) {\n\n\t\tvar handles = data.handles || $Handles, positions, state = false,\n\t\t\tproposal = ((event.calcPoint - data.start) * 100) / baseSize(),\n\t\t\th = handles[0][0] !== $Handles[0][0] ? 1 : 0;\n\n\t\t// Calculate relative positions for the handles.\n\t\tpositions = getPositions( proposal, data.positions, handles.length > 1);\n\n\t\tstate = setHandle ( handles[0], positions[h], handles.length === 1 );\n\n\t\tif ( handles.length > 1 ) {\n\t\t\tstate = setHandle ( handles[1], positions[h?0:1], false ) || state;\n\t\t}\n\n\t\t// Fire the 'slide' event if any handle moved.\n\t\tif ( state ) {\n\t\t\tfireEvents(['slide']);\n\t\t}\n\t}\n\n\t// Unbind move events on document, call callbacks.\n\tfunction end ( event ) {\n\n\t\t// The handle is no longer active, so remove the class.\n\t\t$('.' + Classes[15]).removeClass(Classes[15]);\n\n\t\t// Remove cursor styles and text-selection events bound to the body.\n\t\tif ( event.cursor ) {\n\t\t\t$('body').css('cursor', '').off( namespace );\n\t\t}\n\n\t\t// Unbind the move and end events, which are added on 'start'.\n\t\tdoc.off( namespace );\n\n\t\t// Remove dragging class.\n\t\t$Target.removeClass(Classes[12]);\n\n\t\t// Fire the change and set events.\n\t\tfireEvents(['set', 'change']);\n\t}\n\n\t// Bind move events on document.\n\tfunction start ( event, data ) {\n\n\t\t// Mark the handle as 'active' so it can be styled.\n\t\tif( data.handles.length === 1 ) {\n\t\t\tdata.handles[0].children().addClass(Classes[15]);\n\t\t}\n\n\t\t// A drag should never propagate up to the 'tap' event.\n\t\tevent.stopPropagation();\n\n\t\t// Attach the move event.\n\t\tattach ( actions.move, doc, move, {\n\t\t\tstart: event.calcPoint,\n\t\t\thandles: data.handles,\n\t\t\tpositions: [\n\t\t\t\t$Locations[0],\n\t\t\t\t$Locations[$Handles.length - 1]\n\t\t\t]\n\t\t});\n\n\t\t// Unbind all movement when the drag ends.\n\t\tattach ( actions.end, doc, end, null );\n\n\t\t// Text selection isn't an issue on touch devices,\n\t\t// so adding cursor styles can be skipped.\n\t\tif ( event.cursor ) {\n\n\t\t\t// Prevent the 'I' cursor and extend the range-drag cursor.\n\t\t\t$('body').css('cursor', $(event.target).css('cursor'));\n\n\t\t\t// Mark the target with a dragging state.\n\t\t\tif ( $Handles.length > 1 ) {\n\t\t\t\t$Target.addClass(Classes[12]);\n\t\t\t}\n\n\t\t\t// Prevent text selection when dragging the handles.\n\t\t\t$('body').on('selectstart' + namespace, false);\n\t\t}\n\t}\n\n\t// Move closest handle to tapped location.\n\tfunction tap ( event ) {\n\n\t\tvar location = event.calcPoint, total = 0, to;\n\n\t\t// The tap event shouldn't propagate up and cause 'edge' to run.\n\t\tevent.stopPropagation();\n\n\t\t// Add up the handle offsets.\n\t\t$.each( $Handles, function(){\n\t\t\ttotal += this.offset()[ options.style ];\n\t\t});\n\n\t\t// Find the handle closest to the tapped position.\n\t\ttotal = ( location < total/2 || $Handles.length === 1 ) ? 0 : 1;\n\n\t\tlocation -= $Base.offset()[ options.style ];\n\n\t\t// Calculate the new position.\n\t\tto = ( location * 100 ) / baseSize();\n\n\t\tif ( !options.events.snap ) {\n\t\t\t// Flag the slider as it is now in a transitional state.\n\t\t\t// Transition takes 300 ms, so re-enable the slider afterwards.\n\t\t\taddClassFor( $Target, Classes[14], 300 );\n\t\t}\n\n\t\t// Find the closest handle and calculate the tapped point.\n\t\t// The set handle to the new position.\n\t\tsetHandle( $Handles[total], to );\n\n\t\tfireEvents(['slide', 'set', 'change']);\n\n\t\tif ( options.events.snap ) {\n\t\t\tstart(event, { handles: [$Handles[total]] });\n\t\t}\n\t}\n\n\t// Attach events to several slider parts.\n\tfunction events ( behaviour ) {\n\n\t\tvar i, drag;\n\n\t\t// Attach the standard drag event to the handles.\n\t\tif ( !behaviour.fixed ) {\n\n\t\t\tfor ( i = 0; i < $Handles.length; i += 1 ) {\n\n\t\t\t\t// These events are only bound to the visual handle\n\t\t\t\t// element, not the 'real' origin element.\n\t\t\t\tattach ( actions.start, $Handles[i].children(), start, {\n\t\t\t\t\thandles: [ $Handles[i] ]\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Attach the tap event to the slider base.\n\t\tif ( behaviour.tap ) {\n\n\t\t\tattach ( actions.start, $Base, tap, {\n\t\t\t\thandles: $Handles\n\t\t\t});\n\t\t}\n\n\t\t// Make the range dragable.\n\t\tif ( behaviour.drag ){\n\n\t\t\tdrag = $Base.find( '.' + Classes[7] ).addClass( Classes[10] );\n\n\t\t\t// When the range is fixed, the entire range can\n\t\t\t// be dragged by the handles. The handle in the first\n\t\t\t// origin will propagate the start event upward,\n\t\t\t// but it needs to be bound manually on the other.\n\t\t\tif ( behaviour.fixed ) {\n\t\t\t\tdrag = drag.add($Base.children().not( drag ).children());\n\t\t\t}\n\n\t\t\tattach ( actions.start, drag, start, {\n\t\t\t\thandles: $Handles\n\t\t\t});\n\t\t}\n\t}\n\n\n\t// Test suggested values and apply margin, step.\n\tfunction setHandle ( handle, to, noLimitOption ) {\n\n\t\tvar trigger = handle[0] !== $Handles[0][0] ? 1 : 0,\n\t\t\tlowerMargin = $Locations[0] + options.margin,\n\t\t\tupperMargin = $Locations[1] - options.margin,\n\t\t\tlowerLimit = $Locations[0] + options.limit,\n\t\t\tupperLimit = $Locations[1] - options.limit;\n\n\t\t// For sliders with multiple handles,\n\t\t// limit movement to the other handle.\n\t\t// Apply the margin option by adding it to the handle positions.\n\t\tif ( $Handles.length > 1 ) {\n\t\t\tto = trigger ? Math.max( to, lowerMargin ) : Math.min( to, upperMargin );\n\t\t}\n\n\t\t// The limit option has the opposite effect, limiting handles to a\n\t\t// maximum distance from another. Limit must be > 0, as otherwise\n\t\t// handles would be unmoveable. 'noLimitOption' is set to 'false'\n\t\t// for the .val() method, except for pass 4/4.\n\t\tif ( noLimitOption !== false && options.limit && $Handles.length > 1 ) {\n\t\t\tto = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit );\n\t\t}\n\n\t\t// Handle the step option.\n\t\tto = $Spectrum.getStep( to );\n\n\t\t// Limit to 0/100 for .val input, trim anything beyond 7 digits, as\n\t\t// JavaScript has some issues in its floating point implementation.\n\t\tto = limit(parseFloat(to.toFixed(7)));\n\n\t\t// Return false if handle can't move.\n\t\tif ( to === $Locations[trigger] ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Set the handle to the new position.\n\t\thandle.css( options.style, to + '%' );\n\n\t\t// Force proper handle stacking\n\t\tif ( handle.is(':first-child') ) {\n\t\t\thandle.toggleClass(Classes[17], to > 50 );\n\t\t}\n\n\t\t// Update locations.\n\t\t$Locations[trigger] = to;\n\n\t\t// Convert the value to the slider stepping/range.\n\t\t$Values[trigger] = $Spectrum.fromStepping( to );\n\n\t\tlinkUpdate(triggerPos[trigger]);\n\n\t\treturn true;\n\t}\n\n\t// Loop values from value method and apply them.\n\tfunction setValues ( count, values ) {\n\n\t\tvar i, trigger, to;\n\n\t\t// With the limit option, we'll need another limiting pass.\n\t\tif ( options.limit ) {\n\t\t\tcount += 1;\n\t\t}\n\n\t\t// If there are multiple handles to be set run the setting\n\t\t// mechanism twice for the first handle, to make sure it\n\t\t// can be bounced of the second one properly.\n\t\tfor ( i = 0; i < count; i += 1 ) {\n\n\t\t\ttrigger = i%2;\n\n\t\t\t// Get the current argument from the array.\n\t\t\tto = values[trigger];\n\n\t\t\t// Setting with null indicates an 'ignore'.\n\t\t\t// Inputting 'false' is invalid.\n\t\t\tif ( to !== null && to !== false ) {\n\n\t\t\t\t// If a formatted number was passed, attemt to decode it.\n\t\t\t\tif ( typeof to === 'number' ) {\n\t\t\t\t\tto = String(to);\n\t\t\t\t}\n\n\t\t\t\tto = options.format.from( to );\n\n\t\t\t\t// Request an update for all links if the value was invalid.\n\t\t\t\t// Do so too if setting the handle fails.\n\t\t\t\tif ( to === false || isNaN(to) || setHandle( $Handles[trigger], $Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) {\n\n\t\t\t\t\tlinkUpdate(triggerPos[trigger]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the slider value.\n\tfunction valueSet ( input ) {\n\n\t\t// LibLink: don't accept new values when currently emitting changes.\n\t\tif ( $Target[0].LinkIsEmitting ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tvar count, values = asArray( input );\n\n\t\t// The RTL settings is implemented by reversing the front-end,\n\t\t// internal mechanisms are the same.\n\t\tif ( options.dir && options.handles > 1 ) {\n\t\t\tvalues.reverse();\n\t\t}\n\n\t\t// Animation is optional.\n\t\t// Make sure the initial values where set before using animated\n\t\t// placement. (no report, unit testing);\n\t\tif ( options.animate && $Locations[0] !== -1 ) {\n\t\t\taddClassFor( $Target, Classes[14], 300 );\n\t\t}\n\n\t\t// Determine how often to set the handles.\n\t\tcount = $Handles.length > 1 ? 3 : 1;\n\n\t\tif ( values.length === 1 ) {\n\t\t\tcount = 1;\n\t\t}\n\n\t\tsetValues ( count, values );\n\n\t\t// Fire the 'set' event. As of noUiSlider 7,\n\t\t// this is no longer optional.\n\t\tfireEvents(['set']);\n\n\t\treturn this;\n\t}\n\n\t// Get the slider value.\n\tfunction valueGet ( ) {\n\n\t\tvar i, retour = [];\n\n\t\t// Get the value from all handles.\n\t\tfor ( i = 0; i < options.handles; i += 1 ){\n\t\t\tretour[i] = options.format.to( $Values[i] );\n\t\t}\n\n\t\treturn inSliderOrder( retour );\n\t}\n\n\t// Destroy the slider and unbind all events.\n\tfunction destroyTarget ( ) {\n\n\t\t// Unbind events on the slider, remove all classes and child elements.\n\t\t$(this).off(namespace)\n\t\t\t.removeClass(Classes.join(' '))\n\t\t\t.empty();\n\n\t\tdelete this.LinkUpdate;\n\t\tdelete this.LinkConfirm;\n\t\tdelete this.LinkDefaultFormatter;\n\t\tdelete this.LinkDefaultFlag;\n\t\tdelete this.reappend;\n\t\tdelete this.vGet;\n\t\tdelete this.vSet;\n\t\tdelete this.getCurrentStep;\n\t\tdelete this.getInfo;\n\t\tdelete this.destroy;\n\n\t\t// Return the original options from the closure.\n\t\treturn originalOptions;\n\t}\n\n\t// Get the current step size for the slider.\n\tfunction getCurrentStep ( ) {\n\n\t\t// Check all locations, map them to their stepping point.\n\t\t// Get the step point, then find it in the input list.\n\t\tvar retour = $.map($Locations, function( location, index ){\n\n\t\t\tvar step = $Spectrum.getApplicableStep( location ),\n\n\t\t\t\t// As per #391, the comparison for the decrement step can have some rounding issues.\n\t\t\t\t// Round the value to the precision used in the step.\n\t\t\t\tstepDecimals = countDecimals(String(step[2])),\n\n\t\t\t\t// Get the current numeric value\n\t\t\t\tvalue = $Values[index],\n\n\t\t\t\t// To move the slider 'one step up', the current step value needs to be added.\n\t\t\t\t// Use null if we are at the maximum slider value.\n\t\t\t\tincrement = location === 100 ? null : step[2],\n\n\t\t\t\t// Going 'one step down' might put the slider in a different sub-range, so we\n\t\t\t\t// need to switch between the current or the previous step.\n\t\t\t\tprev = Number((value - step[2]).toFixed(stepDecimals)),\n\n\t\t\t\t// If the value fits the step, return the current step value. Otherwise, use the\n\t\t\t\t// previous step. Return null if the slider is at its minimum value.\n\t\t\t\tdecrement = location === 0 ? null : (prev >= step[1]) ? step[2] : (step[0] || false);\n\n\t\t\treturn [[decrement, increment]];\n\t\t});\n\n\t\t// Return values in the proper order.\n\t\treturn inSliderOrder( retour );\n\t}\n\n\t// Get the original set of options.\n\tfunction getOriginalOptions ( ) {\n\t\treturn originalOptions;\n\t}\n\n\n// Initialize slider\n\n\t// Throw an error if the slider was already initialized.\n\tif ( $Target.hasClass(Classes[0]) ) {\n\t\tthrow new Error('Slider was already initialized.');\n\t}\n\n\t// Create the base element, initialise HTML and set classes.\n\t// Add handles and links.\n\t$Base = addSlider( options.dir, options.ort, $Target );\n\t$Handles = addHandles( options.handles, options.dir, $Base );\n\n\t// Set the connect classes.\n\taddConnection ( options.connect, $Target, $Handles );\n\n\t// Attach user events.\n\tevents( options.events );\n\n// Methods\n\n\ttarget.vSet = valueSet;\n\ttarget.vGet = valueGet;\n\ttarget.destroy = destroyTarget;\n\n\ttarget.getCurrentStep = getCurrentStep;\n\ttarget.getOriginalOptions = getOriginalOptions;\n\n\ttarget.getInfo = function(){\n\t\treturn [\n\t\t\t$Spectrum,\n\t\t\toptions.style,\n\t\t\toptions.ort\n\t\t];\n\t};\n\n\t// Use the public value method to set the start values.\n\t$Target.val( options.start );\n\n}\n\n\n\t// Run the standard initializer\n\tfunction initialize ( originalOptions ) {\n\n\t\t// Test the options once, not for every slider.\n\t\tvar options = testOptions( originalOptions, this );\n\n\t\t// Loop all items, and provide a new closed-scope environment.\n\t\treturn this.each(function(){\n\t\t\tclosure(this, options, originalOptions);\n\t\t});\n\t}\n\n\t// Destroy the slider, then re-enter initialization.\n\tfunction rebuild ( options ) {\n\n\t\treturn this.each(function(){\n\n\t\t\t// The rebuild flag can be used if the slider wasn't initialized yet.\n\t\t\tif ( !this.destroy ) {\n\t\t\t\t$(this).noUiSlider( options );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Get the current values from the slider,\n\t\t\t// including the initialization options.\n\t\t\tvar values = $(this).val(), originalOptions = this.destroy(),\n\n\t\t\t\t// Extend the previous options with the newly provided ones.\n\t\t\t\tnewOptions = $.extend( {}, originalOptions, options );\n\n\t\t\t// Run the standard initializer.\n\t\t\t$(this).noUiSlider( newOptions );\n\n\t\t\t// Place Link elements back.\n\t\t\tthis.reappend();\n\n\t\t\t// If the start option hasn't changed,\n\t\t\t// reset the previous values.\n\t\t\tif ( originalOptions.start === newOptions.start ) {\n\t\t\t\t$(this).val(values);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Access the internal getting and setting methods based on argument count.\n\tfunction value ( ) {\n\t\treturn this[0][ !arguments.length ? 'vGet' : 'vSet' ].apply(this[0], arguments);\n\t}\n\n\t// Override the .val() method. Test every element. Is it a slider? Go to\n\t// the slider value handling. No? Use the standard method.\n\t// Note how $.fn.val expects 'this' to be an instance of $. For convenience,\n\t// the above 'value' function does too.\n\t$.fn.val = function ( arg ) {\n\n\t\t// this === instanceof $\n\n\t\tfunction valMethod( a ){\n\t\t\treturn a.hasClass(Classes[0]) ? value : $val;\n\t\t}\n\n\t\t// If no value is passed, this is 'get'.\n\t\tif ( !arguments.length ) {\n\t\t\tvar first = $(this[0]);\n\t\t\treturn valMethod(first).call(first);\n\t\t}\n\n\t\tvar isFunction = $.isFunction(arg);\n\n\t\t// Return the set so it remains chainable. Make sure not to break\n\t\t// jQuery's .val(function( index, value ){}) signature.\n\t\treturn this.each(function( i ){\n\n\t\t\tvar val = arg, $t = $(this);\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = arg.call(this, i, $t.val());\n\t\t\t}\n\n\t\t\tvalMethod($t).call($t, val);\n\t\t});\n\t};\n\n// Extend jQuery/Zepto with the noUiSlider method.\n\t$.fn.noUiSlider = function ( options, rebuildFlag ) {\n\n\t\tswitch ( options ) {\n\t\t\tcase 'step': return this[0].getCurrentStep();\n\t\t\tcase 'options': return this[0].getOriginalOptions();\n\t\t}\n\n\t\treturn ( rebuildFlag ? rebuild : initialize ).call(this, options);\n\t};\n\n\tfunction getGroup ( $Spectrum, mode, values, stepped ) {\n\n\t\t// Use the range.\n\t\tif ( mode === 'range' || mode === 'steps' ) {\n\t\t\treturn $Spectrum.xVal;\n\t\t}\n\n\t\tif ( mode === 'count' ) {\n\n\t\t\t// Divide 0 - 100 in 'count' parts.\n\t\t\tvar spread = ( 100 / (values-1) ), v, i = 0;\n\t\t\tvalues = [];\n\n\t\t\t// List these parts and have them handled as 'positions'.\n\t\t\twhile ((v=i++*spread) <= 100 ) {\n\t\t\t\tvalues.push(v);\n\t\t\t}\n\n\t\t\tmode = 'positions';\n\t\t}\n\n\t\tif ( mode === 'positions' ) {\n\n\t\t\t// Map all percentages to on-range values.\n\t\t\treturn $.map(values, function( value ){\n\t\t\t\treturn $Spectrum.fromStepping( stepped ? $Spectrum.getStep( value ) : value );\n\t\t\t});\n\t\t}\n\n\t\tif ( mode === 'values' ) {\n\n\t\t\t// If the value must be stepped, it needs to be converted to a percentage first.\n\t\t\tif ( stepped ) {\n\n\t\t\t\treturn $.map(values, function( value ){\n\n\t\t\t\t\t// Convert to percentage, apply step, return to value.\n\t\t\t\t\treturn $Spectrum.fromStepping( $Spectrum.getStep( $Spectrum.toStepping( value ) ) );\n\t\t\t\t});\n\n\t\t\t}\n\n\t\t\t// Otherwise, we can simply use the values.\n\t\t\treturn values;\n\t\t}\n\t}\n\n\tfunction generateSpread ( $Spectrum, density, mode, group ) {\n\n\t\tvar originalSpectrumDirection = $Spectrum.direction,\n\t\t\tindexes = {},\n\t\t\tfirstInRange = $Spectrum.xVal[0],\n\t\t\tlastInRange = $Spectrum.xVal[$Spectrum.xVal.length-1],\n\t\t\tignoreFirst = false,\n\t\t\tignoreLast = false,\n\t\t\tprevPct = 0;\n\n\t\t// This function loops the spectrum in an ltr linear fashion,\n\t\t// while the toStepping method is direction aware. Trick it into\n\t\t// believing it is ltr.\n\t\t$Spectrum.direction = 0;\n\n\t\t// Create a copy of the group, sort it and filter away all duplicates.\n\t\tgroup = unique(group.slice().sort(function(a, b){ return a - b; }));\n\n\t\t// Make sure the range starts with the first element.\n\t\tif ( group[0] !== firstInRange ) {\n\t\t\tgroup.unshift(firstInRange);\n\t\t\tignoreFirst = true;\n\t\t}\n\n\t\t// Likewise for the last one.\n\t\tif ( group[group.length - 1] !== lastInRange ) {\n\t\t\tgroup.push(lastInRange);\n\t\t\tignoreLast = true;\n\t\t}\n\n\t\t$.each(group, function ( index ) {\n\n\t\t\t// Get the current step and the lower + upper positions.\n\t\t\tvar step, i, q,\n\t\t\t\tlow = group[index],\n\t\t\t\thigh = group[index+1],\n\t\t\t\tnewPct, pctDifference, pctPos, type,\n\t\t\t\tsteps, realSteps, stepsize;\n\n\t\t\t// When using 'steps' mode, use the provided steps.\n\t\t\t// Otherwise, we'll step on to the next subrange.\n\t\t\tif ( mode === 'steps' ) {\n\t\t\t\tstep = $Spectrum.xNumSteps[ index ];\n\t\t\t}\n\n\t\t\t// Default to a 'full' step.\n\t\t\tif ( !step ) {\n\t\t\t\tstep = high-low;\n\t\t\t}\n\n\t\t\t// Low can be 0, so test for false. If high is undefined,\n\t\t\t// we are at the last subrange. Index 0 is already handled.\n\t\t\tif ( low === false || high === undefined ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Find all steps in the subrange.\n\t\t\tfor ( i = low; i <= high; i += step ) {\n\n\t\t\t\t// Get the percentage value for the current step,\n\t\t\t\t// calculate the size for the subrange.\n\t\t\t\tnewPct = $Spectrum.toStepping( i );\n\t\t\t\tpctDifference = newPct - prevPct;\n\n\t\t\t\tsteps = pctDifference / density;\n\t\t\t\trealSteps = Math.round(steps);\n\n\t\t\t\t// This ratio represents the ammount of percentage-space a point indicates.\n\t\t\t\t// For a density 1 the points/percentage = 1. For density 2, that percentage needs to be re-devided.\n\t\t\t\t// Round the percentage offset to an even number, then divide by two\n\t\t\t\t// to spread the offset on both sides of the range.\n\t\t\t\tstepsize = pctDifference/realSteps;\n\n\t\t\t\t// Divide all points evenly, adding the correct number to this subrange.\n\t\t\t\t// Run up to <= so that 100% gets a point, event if ignoreLast is set.\n\t\t\t\tfor ( q = 1; q <= realSteps; q += 1 ) {\n\n\t\t\t\t\t// The ratio between the rounded value and the actual size might be ~1% off.\n\t\t\t\t\t// Correct the percentage offset by the number of points\n\t\t\t\t\t// per subrange. density = 1 will result in 100 points on the\n\t\t\t\t\t// full range, 2 for 50, 4 for 25, etc.\n\t\t\t\t\tpctPos = prevPct + ( q * stepsize );\n\t\t\t\t\tindexes[pctPos.toFixed(5)] = ['x', 0];\n\t\t\t\t}\n\n\t\t\t\t// Determine the point type.\n\t\t\t\ttype = ($.inArray(i, group) > -1) ? 1 : ( mode === 'steps' ? 2 : 0 );\n\n\t\t\t\t// Enforce the 'ignoreFirst' option by overwriting the type for 0.\n\t\t\t\tif ( !index && ignoreFirst ) {\n\t\t\t\t\ttype = 0;\n\t\t\t\t}\n\n\t\t\t\tif ( !(i === high && ignoreLast)) {\n\t\t\t\t\t// Mark the 'type' of this point. 0 = plain, 1 = real value, 2 = step value.\n\t\t\t\t\tindexes[newPct.toFixed(5)] = [i, type];\n\t\t\t\t}\n\n\t\t\t\t// Update the percentage count.\n\t\t\t\tprevPct = newPct;\n\t\t\t}\n\t\t});\n\n\t\t// Reset the spectrum.\n\t\t$Spectrum.direction = originalSpectrumDirection;\n\n\t\treturn indexes;\n\t}\n\n\tfunction addMarking ( CSSstyle, orientation, direction, spread, filterFunc, formatter ) {\n\n\t\tvar style = ['horizontal', 'vertical'][orientation],\n\t\t\telement = $('<div/>');\n\n\t\telement.addClass('noUi-pips noUi-pips-'+style);\n\n\t\tfunction getSize( type, value ){\n\t\t\treturn [ '-normal', '-large', '-sub' ][type];\n\t\t}\n\n\t\tfunction getTags( offset, source, values ) {\n\t\t\treturn 'class=\"' + source + ' ' +\n\t\t\t\tsource + '-' + style + ' ' +\n\t\t\t\tsource + getSize(values[1], values[0]) +\n\t\t\t\t'\" style=\"' + CSSstyle + ': ' + offset + '%\"';\n\t\t}\n\n\t\tfunction addSpread ( offset, values ){\n\n\t\t\tif ( direction ) {\n\t\t\t\toffset = 100 - offset;\n\t\t\t}\n\n\t\t\t// Apply the filter function, if it is set.\n\t\t\tvalues[1] = (values[1] && filterFunc) ? filterFunc(values[0], values[1]) : values[1];\n\n\t\t\t// Add a marker for every point\n\t\t\telement.append('<div ' + getTags(offset, 'noUi-marker', values) + '></div>');\n\n\t\t\t// Values are only appended for points marked '1' or '2'.\n\t\t\tif ( values[1] ) {\n\t\t\t\telement.append('<div '+getTags(offset, 'noUi-value', values)+'>' + formatter.to(values[0]) + '</div>');\n\t\t\t}\n\t\t}\n\n\t\t// Append all points.\n\t\t$.each(spread, addSpread);\n\n\t\treturn element;\n\t}\n\n\t$.fn.noUiSlider_pips = function ( grid ) {\n\n\tvar mode = grid.mode,\n\t\tdensity = grid.density || 1,\n\t\tfilter = grid.filter || false,\n\t\tvalues = grid.values || false,\n\t\tformat = grid.format || {\n\t\t\tto: Math.round\n\t\t},\n\t\tstepped = grid.stepped || false;\n\n\t\treturn this.each(function(){\n\n\t\tvar info = this.getInfo(),\n\t\t\tgroup = getGroup( info[0], mode, values, stepped ),\n\t\t\tspread = generateSpread( info[0], density, mode, group );\n\n\t\t\treturn $(this).append(addMarking(\n\t\t\t\tinfo[1],\n\t\t\t\tinfo[2],\n\t\t\t\tinfo[0].direction,\n\t\t\t\tspread,\n\t\t\t\tfilter,\n\t\t\t\tformat\n\t\t\t));\n\t\t});\n\t};\n\n}( window.jQuery || window.Zepto ));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/nouislider/distribute/jquery.nouislider.js",
    "content": "/*! noUiSlider - 7.0.10 - 2014-12-27 14:50:46 */\n\n/*jslint browser: true */\n/*jslint white: true */\n\n(function( $ ){\n\n\t'use strict';\n\n\n\t// Removes duplicates from an array.\n\tfunction unique(array) {\n\t\treturn $.grep(array, function(el, index) {\n\t\t\treturn index === $.inArray(el, array);\n\t\t});\n\t}\n\n\t// Round a value to the closest 'to'.\n\tfunction closest ( value, to ) {\n\t\treturn Math.round(value / to) * to;\n\t}\n\n\t// Checks whether a value is numerical.\n\tfunction isNumeric ( a ) {\n\t\treturn typeof a === 'number' && !isNaN( a ) && isFinite( a );\n\t}\n\n\t// Rounds a number to 7 supported decimals.\n\tfunction accurateNumber( number ) {\n\t\tvar p = Math.pow(10, 7);\n\t\treturn Number((Math.round(number*p)/p).toFixed(7));\n\t}\n\n\t// Sets a class and removes it after [duration] ms.\n\tfunction addClassFor ( element, className, duration ) {\n\t\telement.addClass(className);\n\t\tsetTimeout(function(){\n\t\t\telement.removeClass(className);\n\t\t}, duration);\n\t}\n\n\t// Limits a value to 0 - 100\n\tfunction limit ( a ) {\n\t\treturn Math.max(Math.min(a, 100), 0);\n\t}\n\n\t// Wraps a variable as an array, if it isn't one yet.\n\tfunction asArray ( a ) {\n\t\treturn $.isArray(a) ? a : [a];\n\t}\n\n\t// Counts decimals\n\tfunction countDecimals ( numStr ) {\n\t\tvar pieces = numStr.split(\".\");\n\t\treturn pieces.length > 1 ? pieces[1].length : 0;\n\t}\n\n\n\tvar\n\t// Cache the document selector;\n\t/** @const */\n\tdoc = $(document),\n\t// Make a backup of the original jQuery/Zepto .val() method.\n\t/** @const */\n\t$val = $.fn.val,\n\t// Namespace for binding and unbinding slider events;\n\t/** @const */\n\tnamespace = '.nui',\n\t// Determine the events to bind. IE11 implements pointerEvents without\n\t// a prefix, which breaks compatibility with the IE10 implementation.\n\t/** @const */\n\tactions = window.navigator.pointerEnabled ? {\n\t\tstart: 'pointerdown',\n\t\tmove: 'pointermove',\n\t\tend: 'pointerup'\n\t} : window.navigator.msPointerEnabled ? {\n\t\tstart: 'MSPointerDown',\n\t\tmove: 'MSPointerMove',\n\t\tend: 'MSPointerUp'\n\t} : {\n\t\tstart: 'mousedown touchstart',\n\t\tmove: 'mousemove touchmove',\n\t\tend: 'mouseup touchend'\n\t},\n\t// Re-usable list of classes;\n\t/** @const */\n\tClasses = [\n/*  0 */  'noUi-target'\n/*  1 */ ,'noUi-base'\n/*  2 */ ,'noUi-origin'\n/*  3 */ ,'noUi-handle'\n/*  4 */ ,'noUi-horizontal'\n/*  5 */ ,'noUi-vertical'\n/*  6 */ ,'noUi-background'\n/*  7 */ ,'noUi-connect'\n/*  8 */ ,'noUi-ltr'\n/*  9 */ ,'noUi-rtl'\n/* 10 */ ,'noUi-dragable'\n/* 11 */ ,''\n/* 12 */ ,'noUi-state-drag'\n/* 13 */ ,''\n/* 14 */ ,'noUi-state-tap'\n/* 15 */ ,'noUi-active'\n/* 16 */ ,''\n/* 17 */ ,'noUi-stacking'\n\t];\n\n\n// Value calculation\n\n\t// Determine the size of a sub-range in relation to a full range.\n\tfunction subRangeRatio ( pa, pb ) {\n\t\treturn (100 / (pb - pa));\n\t}\n\n\t// (percentage) How many percent is this value of this range?\n\tfunction fromPercentage ( range, value ) {\n\t\treturn (value * 100) / ( range[1] - range[0] );\n\t}\n\n\t// (percentage) Where is this value on this range?\n\tfunction toPercentage ( range, value ) {\n\t\treturn fromPercentage( range, range[0] < 0 ?\n\t\t\tvalue + Math.abs(range[0]) :\n\t\t\t\tvalue - range[0] );\n\t}\n\n\t// (value) How much is this percentage on this range?\n\tfunction isPercentage ( range, value ) {\n\t\treturn ((value * ( range[1] - range[0] )) / 100) + range[0];\n\t}\n\n\n// Range conversion\n\n\tfunction getJ ( value, arr ) {\n\n\t\tvar j = 1;\n\n\t\twhile ( value >= arr[j] ){\n\t\t\tj += 1;\n\t\t}\n\n\t\treturn j;\n\t}\n\n\t// (percentage) Input a value, find where, on a scale of 0-100, it applies.\n\tfunction toStepping ( xVal, xPct, value ) {\n\n\t\tif ( value >= xVal.slice(-1)[0] ){\n\t\t\treturn 100;\n\t\t}\n\n\t\tvar j = getJ( value, xVal ), va, vb, pa, pb;\n\n\t\tva = xVal[j-1];\n\t\tvb = xVal[j];\n\t\tpa = xPct[j-1];\n\t\tpb = xPct[j];\n\n\t\treturn pa + (toPercentage([va, vb], value) / subRangeRatio (pa, pb));\n\t}\n\n\t// (value) Input a percentage, find where it is on the specified range.\n\tfunction fromStepping ( xVal, xPct, value ) {\n\n\t\t// There is no range group that fits 100\n\t\tif ( value >= 100 ){\n\t\t\treturn xVal.slice(-1)[0];\n\t\t}\n\n\t\tvar j = getJ( value, xPct ), va, vb, pa, pb;\n\n\t\tva = xVal[j-1];\n\t\tvb = xVal[j];\n\t\tpa = xPct[j-1];\n\t\tpb = xPct[j];\n\n\t\treturn isPercentage([va, vb], (value - pa) * subRangeRatio (pa, pb));\n\t}\n\n\t// (percentage) Get the step that applies at a certain value.\n\tfunction getStep ( xPct, xSteps, snap, value ) {\n\n\t\tif ( value === 100 ) {\n\t\t\treturn value;\n\t\t}\n\n\t\tvar j = getJ( value, xPct ), a, b;\n\n\t\t// If 'snap' is set, steps are used as fixed points on the slider.\n\t\tif ( snap ) {\n\n\t\t\ta = xPct[j-1];\n\t\t\tb = xPct[j];\n\n\t\t\t// Find the closest position, a or b.\n\t\t\tif ((value - a) > ((b-a)/2)){\n\t\t\t\treturn b;\n\t\t\t}\n\n\t\t\treturn a;\n\t\t}\n\n\t\tif ( !xSteps[j-1] ){\n\t\t\treturn value;\n\t\t}\n\n\t\treturn xPct[j-1] + closest(\n\t\t\tvalue - xPct[j-1],\n\t\t\txSteps[j-1]\n\t\t);\n\t}\n\n\n// Entry parsing\n\n\tfunction handleEntryPoint ( index, value, that ) {\n\n\t\tvar percentage;\n\n\t\t// Wrap numerical input in an array.\n\t\tif ( typeof value === \"number\" ) {\n\t\t\tvalue = [value];\n\t\t}\n\n\t\t// Reject any invalid input, by testing whether value is an array.\n\t\tif ( Object.prototype.toString.call( value ) !== '[object Array]' ){\n\t\t\tthrow new Error(\"noUiSlider: 'range' contains invalid value.\");\n\t\t}\n\n\t\t// Covert min/max syntax to 0 and 100.\n\t\tif ( index === 'min' ) {\n\t\t\tpercentage = 0;\n\t\t} else if ( index === 'max' ) {\n\t\t\tpercentage = 100;\n\t\t} else {\n\t\t\tpercentage = parseFloat( index );\n\t\t}\n\n\t\t// Check for correct input.\n\t\tif ( !isNumeric( percentage ) || !isNumeric( value[0] ) ) {\n\t\t\tthrow new Error(\"noUiSlider: 'range' value isn't numeric.\");\n\t\t}\n\n\t\t// Store values.\n\t\tthat.xPct.push( percentage );\n\t\tthat.xVal.push( value[0] );\n\n\t\t// NaN will evaluate to false too, but to keep\n\t\t// logging clear, set step explicitly. Make sure\n\t\t// not to override the 'step' setting with false.\n\t\tif ( !percentage ) {\n\t\t\tif ( !isNaN( value[1] ) ) {\n\t\t\t\tthat.xSteps[0] = value[1];\n\t\t\t}\n\t\t} else {\n\t\t\tthat.xSteps.push( isNaN(value[1]) ? false : value[1] );\n\t\t}\n\t}\n\n\tfunction handleStepPoint ( i, n, that ) {\n\n\t\t// Ignore 'false' stepping.\n\t\tif ( !n ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Factor to range ratio\n\t\tthat.xSteps[i] = fromPercentage([\n\t\t\t that.xVal[i]\n\t\t\t,that.xVal[i+1]\n\t\t], n) / subRangeRatio (\n\t\t\tthat.xPct[i],\n\t\t\tthat.xPct[i+1] );\n\t}\n\n\n// Interface\n\n\t// The interface to Spectrum handles all direction-based\n\t// conversions, so the above values are unaware.\n\n\tfunction Spectrum ( entry, snap, direction, singleStep ) {\n\n\t\tthis.xPct = [];\n\t\tthis.xVal = [];\n\t\tthis.xSteps = [ singleStep || false ];\n\t\tthis.xNumSteps = [ false ];\n\n\t\tthis.snap = snap;\n\t\tthis.direction = direction;\n\n\t\tvar index, ordered = [ /* [0, 'min'], [1, '50%'], [2, 'max'] */ ];\n\n\t\t// Map the object keys to an array.\n\t\tfor ( index in entry ) {\n\t\t\tif ( entry.hasOwnProperty(index) ) {\n\t\t\t\tordered.push([entry[index], index]);\n\t\t\t}\n\t\t}\n\n\t\t// Sort all entries by value (numeric sort).\n\t\tordered.sort(function(a, b) { return a[0] - b[0]; });\n\n\t\t// Convert all entries to subranges.\n\t\tfor ( index = 0; index < ordered.length; index++ ) {\n\t\t\thandleEntryPoint(ordered[index][1], ordered[index][0], this);\n\t\t}\n\n\t\t// Store the actual step values.\n\t\t// xSteps is sorted in the same order as xPct and xVal.\n\t\tthis.xNumSteps = this.xSteps.slice(0);\n\n\t\t// Convert all numeric steps to the percentage of the subrange they represent.\n\t\tfor ( index = 0; index < this.xNumSteps.length; index++ ) {\n\t\t\thandleStepPoint(index, this.xNumSteps[index], this);\n\t\t}\n\t}\n\n\tSpectrum.prototype.getMargin = function ( value ) {\n\t\treturn this.xPct.length === 2 ? fromPercentage(this.xVal, value) : false;\n\t};\n\n\tSpectrum.prototype.toStepping = function ( value ) {\n\n\t\tvalue = toStepping( this.xVal, this.xPct, value );\n\n\t\t// Invert the value if this is a right-to-left slider.\n\t\tif ( this.direction ) {\n\t\t\tvalue = 100 - value;\n\t\t}\n\n\t\treturn value;\n\t};\n\n\tSpectrum.prototype.fromStepping = function ( value ) {\n\n\t\t// Invert the value if this is a right-to-left slider.\n\t\tif ( this.direction ) {\n\t\t\tvalue = 100 - value;\n\t\t}\n\n\t\treturn accurateNumber(fromStepping( this.xVal, this.xPct, value ));\n\t};\n\n\tSpectrum.prototype.getStep = function ( value ) {\n\n\t\t// Find the proper step for rtl sliders by search in inverse direction.\n\t\t// Fixes issue #262.\n\t\tif ( this.direction ) {\n\t\t\tvalue = 100 - value;\n\t\t}\n\n\t\tvalue = getStep(this.xPct, this.xSteps, this.snap, value );\n\n\t\tif ( this.direction ) {\n\t\t\tvalue = 100 - value;\n\t\t}\n\n\t\treturn value;\n\t};\n\n\tSpectrum.prototype.getApplicableStep = function ( value ) {\n\n\t\t// If the value is 100%, return the negative step twice.\n\t\tvar j = getJ(value, this.xPct), offset = value === 100 ? 2 : 1;\n\t\treturn [this.xNumSteps[j-2], this.xVal[j-offset], this.xNumSteps[j-offset]];\n\t};\n\n\t// Outside testing\n\tSpectrum.prototype.convert = function ( value ) {\n\t\treturn this.getStep(this.toStepping(value));\n\t};\n\n/*\tEvery input option is tested and parsed. This'll prevent\n\tendless validation in internal methods. These tests are\n\tstructured with an item for every option available. An\n\toption can be marked as required by setting the 'r' flag.\n\tThe testing function is provided with three arguments:\n\t\t- The provided value for the option;\n\t\t- A reference to the options object;\n\t\t- The name for the option;\n\n\tThe testing function returns false when an error is detected,\n\tor true when everything is OK. It can also modify the option\n\tobject, to make sure all values can be correctly looped elsewhere. */\n\n\t/** @const */\n\tvar defaultFormatter = { 'to': function( value ){\n\t\treturn value.toFixed(2);\n\t}, 'from': Number };\n\n\tfunction testStep ( parsed, entry ) {\n\n\t\tif ( !isNumeric( entry ) ) {\n\t\t\tthrow new Error(\"noUiSlider: 'step' is not numeric.\");\n\t\t}\n\n\t\t// The step option can still be used to set stepping\n\t\t// for linear sliders. Overwritten if set in 'range'.\n\t\tparsed.singleStep = entry;\n\t}\n\n\tfunction testRange ( parsed, entry ) {\n\n\t\t// Filter incorrect input.\n\t\tif ( typeof entry !== 'object' || $.isArray(entry) ) {\n\t\t\tthrow new Error(\"noUiSlider: 'range' is not an object.\");\n\t\t}\n\n\t\t// Catch missing start or end.\n\t\tif ( entry.min === undefined || entry.max === undefined ) {\n\t\t\tthrow new Error(\"noUiSlider: Missing 'min' or 'max' in 'range'.\");\n\t\t}\n\n\t\tparsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep);\n\t}\n\n\tfunction testStart ( parsed, entry ) {\n\n\t\tentry = asArray(entry);\n\n\t\t// Validate input. Values aren't tested, as the public .val method\n\t\t// will always provide a valid location.\n\t\tif ( !$.isArray( entry ) || !entry.length || entry.length > 2 ) {\n\t\t\tthrow new Error(\"noUiSlider: 'start' option is incorrect.\");\n\t\t}\n\n\t\t// Store the number of handles.\n\t\tparsed.handles = entry.length;\n\n\t\t// When the slider is initialized, the .val method will\n\t\t// be called with the start options.\n\t\tparsed.start = entry;\n\t}\n\n\tfunction testSnap ( parsed, entry ) {\n\n\t\t// Enforce 100% stepping within subranges.\n\t\tparsed.snap = entry;\n\n\t\tif ( typeof entry !== 'boolean' ){\n\t\t\tthrow new Error(\"noUiSlider: 'snap' option must be a boolean.\");\n\t\t}\n\t}\n\n\tfunction testAnimate ( parsed, entry ) {\n\n\t\t// Enforce 100% stepping within subranges.\n\t\tparsed.animate = entry;\n\n\t\tif ( typeof entry !== 'boolean' ){\n\t\t\tthrow new Error(\"noUiSlider: 'animate' option must be a boolean.\");\n\t\t}\n\t}\n\n\tfunction testConnect ( parsed, entry ) {\n\n\t\tif ( entry === 'lower' && parsed.handles === 1 ) {\n\t\t\tparsed.connect = 1;\n\t\t} else if ( entry === 'upper' && parsed.handles === 1 ) {\n\t\t\tparsed.connect = 2;\n\t\t} else if ( entry === true && parsed.handles === 2 ) {\n\t\t\tparsed.connect = 3;\n\t\t} else if ( entry === false ) {\n\t\t\tparsed.connect = 0;\n\t\t} else {\n\t\t\tthrow new Error(\"noUiSlider: 'connect' option doesn't match handle count.\");\n\t\t}\n\t}\n\n\tfunction testOrientation ( parsed, entry ) {\n\n\t\t// Set orientation to an a numerical value for easy\n\t\t// array selection.\n\t\tswitch ( entry ){\n\t\t  case 'horizontal':\n\t\t\tparsed.ort = 0;\n\t\t\tbreak;\n\t\t  case 'vertical':\n\t\t\tparsed.ort = 1;\n\t\t\tbreak;\n\t\t  default:\n\t\t\tthrow new Error(\"noUiSlider: 'orientation' option is invalid.\");\n\t\t}\n\t}\n\n\tfunction testMargin ( parsed, entry ) {\n\n\t\tif ( !isNumeric(entry) ){\n\t\t\tthrow new Error(\"noUiSlider: 'margin' option must be numeric.\");\n\t\t}\n\n\t\tparsed.margin = parsed.spectrum.getMargin(entry);\n\n\t\tif ( !parsed.margin ) {\n\t\t\tthrow new Error(\"noUiSlider: 'margin' option is only supported on linear sliders.\");\n\t\t}\n\t}\n\n\tfunction testLimit ( parsed, entry ) {\n\n\t\tif ( !isNumeric(entry) ){\n\t\t\tthrow new Error(\"noUiSlider: 'limit' option must be numeric.\");\n\t\t}\n\n\t\tparsed.limit = parsed.spectrum.getMargin(entry);\n\n\t\tif ( !parsed.limit ) {\n\t\t\tthrow new Error(\"noUiSlider: 'limit' option is only supported on linear sliders.\");\n\t\t}\n\t}\n\n\tfunction testDirection ( parsed, entry ) {\n\n\t\t// Set direction as a numerical value for easy parsing.\n\t\t// Invert connection for RTL sliders, so that the proper\n\t\t// handles get the connect/background classes.\n\t\tswitch ( entry ) {\n\t\t  case 'ltr':\n\t\t\tparsed.dir = 0;\n\t\t\tbreak;\n\t\t  case 'rtl':\n\t\t\tparsed.dir = 1;\n\t\t\tparsed.connect = [0,2,1,3][parsed.connect];\n\t\t\tbreak;\n\t\t  default:\n\t\t\tthrow new Error(\"noUiSlider: 'direction' option was not recognized.\");\n\t\t}\n\t}\n\n\tfunction testBehaviour ( parsed, entry ) {\n\n\t\t// Make sure the input is a string.\n\t\tif ( typeof entry !== 'string' ) {\n\t\t\tthrow new Error(\"noUiSlider: 'behaviour' must be a string containing options.\");\n\t\t}\n\n\t\t// Check if the string contains any keywords.\n\t\t// None are required.\n\t\tvar tap = entry.indexOf('tap') >= 0,\n\t\t\tdrag = entry.indexOf('drag') >= 0,\n\t\t\tfixed = entry.indexOf('fixed') >= 0,\n\t\t\tsnap = entry.indexOf('snap') >= 0;\n\n\t\tparsed.events = {\n\t\t\ttap: tap || snap,\n\t\t\tdrag: drag,\n\t\t\tfixed: fixed,\n\t\t\tsnap: snap\n\t\t};\n\t}\n\n\tfunction testFormat ( parsed, entry ) {\n\n\t\tparsed.format = entry;\n\n\t\t// Any object with a to and from method is supported.\n\t\tif ( typeof entry.to === 'function' && typeof entry.from === 'function' ) {\n\t\t\treturn true;\n\t\t}\n\n\t\tthrow new Error( \"noUiSlider: 'format' requires 'to' and 'from' methods.\");\n\t}\n\n\t// Test all developer settings and parse to assumption-safe values.\n\tfunction testOptions ( options ) {\n\n\t\tvar parsed = {\n\t\t\tmargin: 0,\n\t\t\tlimit: 0,\n\t\t\tanimate: true,\n\t\t\tformat: defaultFormatter\n\t\t}, tests;\n\n\t\t// Tests are executed in the order they are presented here.\n\t\ttests = {\n\t\t\t'step': { r: false, t: testStep },\n\t\t\t'start': { r: true, t: testStart },\n\t\t\t'connect': { r: true, t: testConnect },\n\t\t\t'direction': { r: true, t: testDirection },\n\t\t\t'snap': { r: false, t: testSnap },\n\t\t\t'animate': { r: false, t: testAnimate },\n\t\t\t'range': { r: true, t: testRange },\n\t\t\t'orientation': { r: false, t: testOrientation },\n\t\t\t'margin': { r: false, t: testMargin },\n\t\t\t'limit': { r: false, t: testLimit },\n\t\t\t'behaviour': { r: true, t: testBehaviour },\n\t\t\t'format': { r: false, t: testFormat }\n\t\t};\n\n\t\t// Set defaults where applicable.\n\t\toptions = $.extend({\n\t\t\t'connect': false,\n\t\t\t'direction': 'ltr',\n\t\t\t'behaviour': 'tap',\n\t\t\t'orientation': 'horizontal'\n\t\t}, options);\n\n\t\t// Run all options through a testing mechanism to ensure correct\n\t\t// input. It should be noted that options might get modified to\n\t\t// be handled properly. E.g. wrapping integers in arrays.\n\t\t$.each( tests, function( name, test ){\n\n\t\t\t// If the option isn't set, but it is required, throw an error.\n\t\t\tif ( options[name] === undefined ) {\n\n\t\t\t\tif ( test.r ) {\n\t\t\t\t\tthrow new Error(\"noUiSlider: '\" + name + \"' is required.\");\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\ttest.t( parsed, options[name] );\n\t\t});\n\n\t\t// Pre-define the styles.\n\t\tparsed.style = parsed.ort ? 'top' : 'left';\n\n\t\treturn parsed;\n\t}\n\n// Class handling\n\n\t// Delimit proposed values for handle positions.\n\tfunction getPositions ( a, b, delimit ) {\n\n\t\t// Add movement to current position.\n\t\tvar c = a + b[0], d = a + b[1];\n\n\t\t// Only alter the other position on drag,\n\t\t// not on standard sliding.\n\t\tif ( delimit ) {\n\t\t\tif ( c < 0 ) {\n\t\t\t\td += Math.abs(c);\n\t\t\t}\n\t\t\tif ( d > 100 ) {\n\t\t\t\tc -= ( d - 100 );\n\t\t\t}\n\n\t\t\t// Limit values to 0 and 100.\n\t\t\treturn [limit(c), limit(d)];\n\t\t}\n\n\t\treturn [c,d];\n\t}\n\n\n// Event handling\n\n\t// Provide a clean event with standardized offset values.\n\tfunction fixEvent ( e ) {\n\n\t\t// Prevent scrolling and panning on touch events, while\n\t\t// attempting to slide. The tap event also depends on this.\n\t\te.preventDefault();\n\n\t\t// Filter the event to register the type, which can be\n\t\t// touch, mouse or pointer. Offset changes need to be\n\t\t// made on an event specific basis.\n\t\tvar  touch = e.type.indexOf('touch') === 0\n\t\t\t,mouse = e.type.indexOf('mouse') === 0\n\t\t\t,pointer = e.type.indexOf('pointer') === 0\n\t\t\t,x,y, event = e;\n\n\t\t// IE10 implemented pointer events with a prefix;\n\t\tif ( e.type.indexOf('MSPointer') === 0 ) {\n\t\t\tpointer = true;\n\t\t}\n\n\t\t// Get the originalEvent, if the event has been wrapped\n\t\t// by jQuery. Zepto doesn't wrap the event.\n\t\tif ( e.originalEvent ) {\n\t\t\te = e.originalEvent;\n\t\t}\n\n\t\tif ( touch ) {\n\t\t\t// noUiSlider supports one movement at a time,\n\t\t\t// so we can select the first 'changedTouch'.\n\t\t\tx = e.changedTouches[0].pageX;\n\t\t\ty = e.changedTouches[0].pageY;\n\t\t}\n\n\t\tif ( mouse || pointer ) {\n\n\t\t\t// Polyfill the pageXOffset and pageYOffset\n\t\t\t// variables for IE7 and IE8;\n\t\t\tif( !pointer && window.pageXOffset === undefined ){\n\t\t\t\twindow.pageXOffset = document.documentElement.scrollLeft;\n\t\t\t\twindow.pageYOffset = document.documentElement.scrollTop;\n\t\t\t}\n\n\t\t\tx = e.clientX + window.pageXOffset;\n\t\t\ty = e.clientY + window.pageYOffset;\n\t\t}\n\n\t\tevent.points = [x, y];\n\t\tevent.cursor = mouse;\n\n\t\treturn event;\n\t}\n\n\n// DOM additions\n\n\t// Append a handle to the base.\n\tfunction addHandle ( direction, index ) {\n\n\t\tvar handle = $('<div><div/></div>').addClass( Classes[2] ),\n\t\t\tadditions = [ '-lower', '-upper' ];\n\n\t\tif ( direction ) {\n\t\t\tadditions.reverse();\n\t\t}\n\n\t\thandle.children().addClass(\n\t\t\tClasses[3] + \" \" + Classes[3]+additions[index]\n\t\t);\n\n\t\treturn handle;\n\t}\n\n\t// Add the proper connection classes.\n\tfunction addConnection ( connect, target, handles ) {\n\n\t\t// Apply the required connection classes to the elements\n\t\t// that need them. Some classes are made up for several\n\t\t// segments listed in the class list, to allow easy\n\t\t// renaming and provide a minor compression benefit.\n\t\tswitch ( connect ) {\n\t\t\tcase 1:\ttarget.addClass( Classes[7] );\n\t\t\t\t\thandles[0].addClass( Classes[6] );\n\t\t\t\t\tbreak;\n\t\t\tcase 3: handles[1].addClass( Classes[6] );\n\t\t\t\t\t/* falls through */\n\t\t\tcase 2: handles[0].addClass( Classes[7] );\n\t\t\t\t\t/* falls through */\n\t\t\tcase 0: target.addClass(Classes[6]);\n\t\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Add handles to the slider base.\n\tfunction addHandles ( nrHandles, direction, base ) {\n\n\t\tvar index, handles = [];\n\n\t\t// Append handles.\n\t\tfor ( index = 0; index < nrHandles; index += 1 ) {\n\n\t\t\t// Keep a list of all added handles.\n\t\t\thandles.push( addHandle( direction, index ).appendTo(base) );\n\t\t}\n\n\t\treturn handles;\n\t}\n\n\t// Initialize a single slider.\n\tfunction addSlider ( direction, orientation, target ) {\n\n\t\t// Apply classes and data to the target.\n\t\ttarget.addClass([\n\t\t\tClasses[0],\n\t\t\tClasses[8 + direction],\n\t\t\tClasses[4 + orientation]\n\t\t].join(' '));\n\n\t\treturn $('<div/>').appendTo(target).addClass( Classes[1] );\n\t}\n\nfunction closure ( target, options, originalOptions ){\n\n// Internal variables\n\n\t// All variables local to 'closure' are marked $.\n\tvar $Target = $(target),\n\t\t$Locations = [-1, -1],\n\t\t$Base,\n\t\t$Handles,\n\t\t$Spectrum = options.spectrum,\n\t\t$Values = [],\n\t// libLink. For rtl sliders, 'lower' and 'upper' should not be inverted\n\t// for one-handle sliders, so trim 'upper' it that case.\n\t\ttriggerPos = ['lower', 'upper'].slice(0, options.handles);\n\n\t// Invert the libLink connection for rtl sliders.\n\tif ( options.dir ) {\n\t\ttriggerPos.reverse();\n\t}\n\n// Helpers\n\n\t// Shorthand for base dimensions.\n\tfunction baseSize ( ) {\n\t\treturn $Base[['width', 'height'][options.ort]]();\n\t}\n\n\t// External event handling\n\tfunction fireEvents ( events ) {\n\n\t\t// Use the external api to get the values.\n\t\t// Wrap the values in an array, as .trigger takes\n\t\t// only one additional argument.\n\t\tvar index, values = [ $Target.val() ];\n\n\t\tfor ( index = 0; index < events.length; index += 1 ){\n\t\t\t$Target.trigger(events[index], values);\n\t\t}\n\t}\n\n\t// Returns the input array, respecting the slider direction configuration.\n\tfunction inSliderOrder ( values ) {\n\n\t\t// If only one handle is used, return a single value.\n\t\tif ( values.length === 1 ){\n\t\t\treturn values[0];\n\t\t}\n\n\t\tif ( options.dir ) {\n\t\t\treturn values.reverse();\n\t\t}\n\n\t\treturn values;\n\t}\n\n// libLink integration\n\n\t// Create a new function which calls .val on input change.\n\tfunction createChangeHandler ( trigger ) {\n\t\treturn function ( ignore, value ){\n\t\t\t// Determine which array position to 'null' based on 'trigger'.\n\t\t\t$Target.val( [ trigger ? null : value, trigger ? value : null ], true );\n\t\t};\n\t}\n\n\t// Called by libLink when it wants a set of links updated.\n\tfunction linkUpdate ( flag ) {\n\n\t\tvar trigger = $.inArray(flag, triggerPos);\n\n\t\t// The API might not have been set yet.\n\t\tif ( $Target[0].linkAPI && $Target[0].linkAPI[flag] ) {\n\t\t\t$Target[0].linkAPI[flag].change(\n\t\t\t\t$Values[trigger],\n\t\t\t\t$Handles[trigger].children(),\n\t\t\t\t$Target\n\t\t\t);\n\t\t}\n\t}\n\n\t// Called by libLink to append an element to the slider.\n\tfunction linkConfirm ( flag, element ) {\n\n\t\t// Find the trigger for the passed flag.\n\t\tvar trigger = $.inArray(flag, triggerPos);\n\n\t\t// If set, append the element to the handle it belongs to.\n\t\tif ( element ) {\n\t\t\telement.appendTo( $Handles[trigger].children() );\n\t\t}\n\n\t\t// The public API is reversed for rtl sliders, so the changeHandler\n\t\t// should not be aware of the inverted trigger positions.\n\t\t// On rtl slider with one handle, 'lower' should be used.\n\t\tif ( options.dir && options.handles > 1 ) {\n\t\t\ttrigger = trigger === 1 ? 0 : 1;\n\t\t}\n\n\t\treturn createChangeHandler( trigger );\n\t}\n\n\t// Place elements back on the slider.\n\tfunction reAppendLink ( ) {\n\n\t\tvar i, flag;\n\n\t\t// The API keeps a list of elements: we can re-append them on rebuild.\n\t\tfor ( i = 0; i < triggerPos.length; i += 1 ) {\n\t\t\tif ( this.linkAPI && this.linkAPI[(flag = triggerPos[i])] ) {\n\t\t\t\tthis.linkAPI[flag].reconfirm(flag);\n\t\t\t}\n\t\t}\n\t}\n\n\ttarget.LinkUpdate = linkUpdate;\n\ttarget.LinkConfirm = linkConfirm;\n\ttarget.LinkDefaultFormatter = options.format;\n\ttarget.LinkDefaultFlag = 'lower';\n\n\ttarget.reappend = reAppendLink;\n\n\n\t// Handler for attaching events trough a proxy.\n\tfunction attach ( events, element, callback, data ) {\n\n\t\t// This function can be used to 'filter' events to the slider.\n\n\t\t// Add the noUiSlider namespace to all events.\n\t\tevents = events.replace( /\\s/g, namespace + ' ' ) + namespace;\n\n\t\t// Bind a closure on the target.\n\t\treturn element.on( events, function( e ){\n\n\t\t\t// jQuery and Zepto (1) handle unset attributes differently,\n\t\t\t// but always falsy; #208\n\t\t\tif ( !!$Target.attr('disabled') ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Stop if an active 'tap' transition is taking place.\n\t\t\tif ( $Target.hasClass( Classes[14] ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\te = fixEvent(e);\n\t\t\te.calcPoint = e.points[ options.ort ];\n\n\t\t\t// Call the event handler with the event [ and additional data ].\n\t\t\tcallback ( e, data );\n\t\t});\n\t}\n\n\t// Handle movement on document for handle and range drag.\n\tfunction move ( event, data ) {\n\n\t\tvar handles = data.handles || $Handles, positions, state = false,\n\t\t\tproposal = ((event.calcPoint - data.start) * 100) / baseSize(),\n\t\t\th = handles[0][0] !== $Handles[0][0] ? 1 : 0;\n\n\t\t// Calculate relative positions for the handles.\n\t\tpositions = getPositions( proposal, data.positions, handles.length > 1);\n\n\t\tstate = setHandle ( handles[0], positions[h], handles.length === 1 );\n\n\t\tif ( handles.length > 1 ) {\n\t\t\tstate = setHandle ( handles[1], positions[h?0:1], false ) || state;\n\t\t}\n\n\t\t// Fire the 'slide' event if any handle moved.\n\t\tif ( state ) {\n\t\t\tfireEvents(['slide']);\n\t\t}\n\t}\n\n\t// Unbind move events on document, call callbacks.\n\tfunction end ( event ) {\n\n\t\t// The handle is no longer active, so remove the class.\n\t\t$('.' + Classes[15]).removeClass(Classes[15]);\n\n\t\t// Remove cursor styles and text-selection events bound to the body.\n\t\tif ( event.cursor ) {\n\t\t\t$('body').css('cursor', '').off( namespace );\n\t\t}\n\n\t\t// Unbind the move and end events, which are added on 'start'.\n\t\tdoc.off( namespace );\n\n\t\t// Remove dragging class.\n\t\t$Target.removeClass(Classes[12]);\n\n\t\t// Fire the change and set events.\n\t\tfireEvents(['set', 'change']);\n\t}\n\n\t// Bind move events on document.\n\tfunction start ( event, data ) {\n\n\t\t// Mark the handle as 'active' so it can be styled.\n\t\tif( data.handles.length === 1 ) {\n\t\t\tdata.handles[0].children().addClass(Classes[15]);\n\t\t}\n\n\t\t// A drag should never propagate up to the 'tap' event.\n\t\tevent.stopPropagation();\n\n\t\t// Attach the move event.\n\t\tattach ( actions.move, doc, move, {\n\t\t\tstart: event.calcPoint,\n\t\t\thandles: data.handles,\n\t\t\tpositions: [\n\t\t\t\t$Locations[0],\n\t\t\t\t$Locations[$Handles.length - 1]\n\t\t\t]\n\t\t});\n\n\t\t// Unbind all movement when the drag ends.\n\t\tattach ( actions.end, doc, end, null );\n\n\t\t// Text selection isn't an issue on touch devices,\n\t\t// so adding cursor styles can be skipped.\n\t\tif ( event.cursor ) {\n\n\t\t\t// Prevent the 'I' cursor and extend the range-drag cursor.\n\t\t\t$('body').css('cursor', $(event.target).css('cursor'));\n\n\t\t\t// Mark the target with a dragging state.\n\t\t\tif ( $Handles.length > 1 ) {\n\t\t\t\t$Target.addClass(Classes[12]);\n\t\t\t}\n\n\t\t\t// Prevent text selection when dragging the handles.\n\t\t\t$('body').on('selectstart' + namespace, false);\n\t\t}\n\t}\n\n\t// Move closest handle to tapped location.\n\tfunction tap ( event ) {\n\n\t\tvar location = event.calcPoint, total = 0, to;\n\n\t\t// The tap event shouldn't propagate up and cause 'edge' to run.\n\t\tevent.stopPropagation();\n\n\t\t// Add up the handle offsets.\n\t\t$.each( $Handles, function(){\n\t\t\ttotal += this.offset()[ options.style ];\n\t\t});\n\n\t\t// Find the handle closest to the tapped position.\n\t\ttotal = ( location < total/2 || $Handles.length === 1 ) ? 0 : 1;\n\n\t\tlocation -= $Base.offset()[ options.style ];\n\n\t\t// Calculate the new position.\n\t\tto = ( location * 100 ) / baseSize();\n\n\t\tif ( !options.events.snap ) {\n\t\t\t// Flag the slider as it is now in a transitional state.\n\t\t\t// Transition takes 300 ms, so re-enable the slider afterwards.\n\t\t\taddClassFor( $Target, Classes[14], 300 );\n\t\t}\n\n\t\t// Find the closest handle and calculate the tapped point.\n\t\t// The set handle to the new position.\n\t\tsetHandle( $Handles[total], to );\n\n\t\tfireEvents(['slide', 'set', 'change']);\n\n\t\tif ( options.events.snap ) {\n\t\t\tstart(event, { handles: [$Handles[total]] });\n\t\t}\n\t}\n\n\t// Attach events to several slider parts.\n\tfunction events ( behaviour ) {\n\n\t\tvar i, drag;\n\n\t\t// Attach the standard drag event to the handles.\n\t\tif ( !behaviour.fixed ) {\n\n\t\t\tfor ( i = 0; i < $Handles.length; i += 1 ) {\n\n\t\t\t\t// These events are only bound to the visual handle\n\t\t\t\t// element, not the 'real' origin element.\n\t\t\t\tattach ( actions.start, $Handles[i].children(), start, {\n\t\t\t\t\thandles: [ $Handles[i] ]\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Attach the tap event to the slider base.\n\t\tif ( behaviour.tap ) {\n\n\t\t\tattach ( actions.start, $Base, tap, {\n\t\t\t\thandles: $Handles\n\t\t\t});\n\t\t}\n\n\t\t// Make the range dragable.\n\t\tif ( behaviour.drag ){\n\n\t\t\tdrag = $Base.find( '.' + Classes[7] ).addClass( Classes[10] );\n\n\t\t\t// When the range is fixed, the entire range can\n\t\t\t// be dragged by the handles. The handle in the first\n\t\t\t// origin will propagate the start event upward,\n\t\t\t// but it needs to be bound manually on the other.\n\t\t\tif ( behaviour.fixed ) {\n\t\t\t\tdrag = drag.add($Base.children().not( drag ).children());\n\t\t\t}\n\n\t\t\tattach ( actions.start, drag, start, {\n\t\t\t\thandles: $Handles\n\t\t\t});\n\t\t}\n\t}\n\n\n\t// Test suggested values and apply margin, step.\n\tfunction setHandle ( handle, to, noLimitOption ) {\n\n\t\tvar trigger = handle[0] !== $Handles[0][0] ? 1 : 0,\n\t\t\tlowerMargin = $Locations[0] + options.margin,\n\t\t\tupperMargin = $Locations[1] - options.margin,\n\t\t\tlowerLimit = $Locations[0] + options.limit,\n\t\t\tupperLimit = $Locations[1] - options.limit;\n\n\t\t// For sliders with multiple handles,\n\t\t// limit movement to the other handle.\n\t\t// Apply the margin option by adding it to the handle positions.\n\t\tif ( $Handles.length > 1 ) {\n\t\t\tto = trigger ? Math.max( to, lowerMargin ) : Math.min( to, upperMargin );\n\t\t}\n\n\t\t// The limit option has the opposite effect, limiting handles to a\n\t\t// maximum distance from another. Limit must be > 0, as otherwise\n\t\t// handles would be unmoveable. 'noLimitOption' is set to 'false'\n\t\t// for the .val() method, except for pass 4/4.\n\t\tif ( noLimitOption !== false && options.limit && $Handles.length > 1 ) {\n\t\t\tto = trigger ? Math.min ( to, lowerLimit ) : Math.max( to, upperLimit );\n\t\t}\n\n\t\t// Handle the step option.\n\t\tto = $Spectrum.getStep( to );\n\n\t\t// Limit to 0/100 for .val input, trim anything beyond 7 digits, as\n\t\t// JavaScript has some issues in its floating point implementation.\n\t\tto = limit(parseFloat(to.toFixed(7)));\n\n\t\t// Return false if handle can't move.\n\t\tif ( to === $Locations[trigger] ) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Set the handle to the new position.\n\t\thandle.css( options.style, to + '%' );\n\n\t\t// Force proper handle stacking\n\t\tif ( handle.is(':first-child') ) {\n\t\t\thandle.toggleClass(Classes[17], to > 50 );\n\t\t}\n\n\t\t// Update locations.\n\t\t$Locations[trigger] = to;\n\n\t\t// Convert the value to the slider stepping/range.\n\t\t$Values[trigger] = $Spectrum.fromStepping( to );\n\n\t\tlinkUpdate(triggerPos[trigger]);\n\n\t\treturn true;\n\t}\n\n\t// Loop values from value method and apply them.\n\tfunction setValues ( count, values ) {\n\n\t\tvar i, trigger, to;\n\n\t\t// With the limit option, we'll need another limiting pass.\n\t\tif ( options.limit ) {\n\t\t\tcount += 1;\n\t\t}\n\n\t\t// If there are multiple handles to be set run the setting\n\t\t// mechanism twice for the first handle, to make sure it\n\t\t// can be bounced of the second one properly.\n\t\tfor ( i = 0; i < count; i += 1 ) {\n\n\t\t\ttrigger = i%2;\n\n\t\t\t// Get the current argument from the array.\n\t\t\tto = values[trigger];\n\n\t\t\t// Setting with null indicates an 'ignore'.\n\t\t\t// Inputting 'false' is invalid.\n\t\t\tif ( to !== null && to !== false ) {\n\n\t\t\t\t// If a formatted number was passed, attemt to decode it.\n\t\t\t\tif ( typeof to === 'number' ) {\n\t\t\t\t\tto = String(to);\n\t\t\t\t}\n\n\t\t\t\tto = options.format.from( to );\n\n\t\t\t\t// Request an update for all links if the value was invalid.\n\t\t\t\t// Do so too if setting the handle fails.\n\t\t\t\tif ( to === false || isNaN(to) || setHandle( $Handles[trigger], $Spectrum.toStepping( to ), i === (3 - options.dir) ) === false ) {\n\n\t\t\t\t\tlinkUpdate(triggerPos[trigger]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Set the slider value.\n\tfunction valueSet ( input ) {\n\n\t\t// LibLink: don't accept new values when currently emitting changes.\n\t\tif ( $Target[0].LinkIsEmitting ) {\n\t\t\treturn this;\n\t\t}\n\n\t\tvar count, values = asArray( input );\n\n\t\t// The RTL settings is implemented by reversing the front-end,\n\t\t// internal mechanisms are the same.\n\t\tif ( options.dir && options.handles > 1 ) {\n\t\t\tvalues.reverse();\n\t\t}\n\n\t\t// Animation is optional.\n\t\t// Make sure the initial values where set before using animated\n\t\t// placement. (no report, unit testing);\n\t\tif ( options.animate && $Locations[0] !== -1 ) {\n\t\t\taddClassFor( $Target, Classes[14], 300 );\n\t\t}\n\n\t\t// Determine how often to set the handles.\n\t\tcount = $Handles.length > 1 ? 3 : 1;\n\n\t\tif ( values.length === 1 ) {\n\t\t\tcount = 1;\n\t\t}\n\n\t\tsetValues ( count, values );\n\n\t\t// Fire the 'set' event. As of noUiSlider 7,\n\t\t// this is no longer optional.\n\t\tfireEvents(['set']);\n\n\t\treturn this;\n\t}\n\n\t// Get the slider value.\n\tfunction valueGet ( ) {\n\n\t\tvar i, retour = [];\n\n\t\t// Get the value from all handles.\n\t\tfor ( i = 0; i < options.handles; i += 1 ){\n\t\t\tretour[i] = options.format.to( $Values[i] );\n\t\t}\n\n\t\treturn inSliderOrder( retour );\n\t}\n\n\t// Destroy the slider and unbind all events.\n\tfunction destroyTarget ( ) {\n\n\t\t// Unbind events on the slider, remove all classes and child elements.\n\t\t$(this).off(namespace)\n\t\t\t.removeClass(Classes.join(' '))\n\t\t\t.empty();\n\n\t\tdelete this.LinkUpdate;\n\t\tdelete this.LinkConfirm;\n\t\tdelete this.LinkDefaultFormatter;\n\t\tdelete this.LinkDefaultFlag;\n\t\tdelete this.reappend;\n\t\tdelete this.vGet;\n\t\tdelete this.vSet;\n\t\tdelete this.getCurrentStep;\n\t\tdelete this.getInfo;\n\t\tdelete this.destroy;\n\n\t\t// Return the original options from the closure.\n\t\treturn originalOptions;\n\t}\n\n\t// Get the current step size for the slider.\n\tfunction getCurrentStep ( ) {\n\n\t\t// Check all locations, map them to their stepping point.\n\t\t// Get the step point, then find it in the input list.\n\t\tvar retour = $.map($Locations, function( location, index ){\n\n\t\t\tvar step = $Spectrum.getApplicableStep( location ),\n\n\t\t\t\t// As per #391, the comparison for the decrement step can have some rounding issues.\n\t\t\t\t// Round the value to the precision used in the step.\n\t\t\t\tstepDecimals = countDecimals(String(step[2])),\n\n\t\t\t\t// Get the current numeric value\n\t\t\t\tvalue = $Values[index],\n\n\t\t\t\t// To move the slider 'one step up', the current step value needs to be added.\n\t\t\t\t// Use null if we are at the maximum slider value.\n\t\t\t\tincrement = location === 100 ? null : step[2],\n\n\t\t\t\t// Going 'one step down' might put the slider in a different sub-range, so we\n\t\t\t\t// need to switch between the current or the previous step.\n\t\t\t\tprev = Number((value - step[2]).toFixed(stepDecimals)),\n\n\t\t\t\t// If the value fits the step, return the current step value. Otherwise, use the\n\t\t\t\t// previous step. Return null if the slider is at its minimum value.\n\t\t\t\tdecrement = location === 0 ? null : (prev >= step[1]) ? step[2] : (step[0] || false);\n\n\t\t\treturn [[decrement, increment]];\n\t\t});\n\n\t\t// Return values in the proper order.\n\t\treturn inSliderOrder( retour );\n\t}\n\n\t// Get the original set of options.\n\tfunction getOriginalOptions ( ) {\n\t\treturn originalOptions;\n\t}\n\n\n// Initialize slider\n\n\t// Throw an error if the slider was already initialized.\n\tif ( $Target.hasClass(Classes[0]) ) {\n\t\tthrow new Error('Slider was already initialized.');\n\t}\n\n\t// Create the base element, initialise HTML and set classes.\n\t// Add handles and links.\n\t$Base = addSlider( options.dir, options.ort, $Target );\n\t$Handles = addHandles( options.handles, options.dir, $Base );\n\n\t// Set the connect classes.\n\taddConnection ( options.connect, $Target, $Handles );\n\n\t// Attach user events.\n\tevents( options.events );\n\n// Methods\n\n\ttarget.vSet = valueSet;\n\ttarget.vGet = valueGet;\n\ttarget.destroy = destroyTarget;\n\n\ttarget.getCurrentStep = getCurrentStep;\n\ttarget.getOriginalOptions = getOriginalOptions;\n\n\ttarget.getInfo = function(){\n\t\treturn [\n\t\t\t$Spectrum,\n\t\t\toptions.style,\n\t\t\toptions.ort\n\t\t];\n\t};\n\n\t// Use the public value method to set the start values.\n\t$Target.val( options.start );\n\n}\n\n\n\t// Run the standard initializer\n\tfunction initialize ( originalOptions ) {\n\n\t\t// Test the options once, not for every slider.\n\t\tvar options = testOptions( originalOptions, this );\n\n\t\t// Loop all items, and provide a new closed-scope environment.\n\t\treturn this.each(function(){\n\t\t\tclosure(this, options, originalOptions);\n\t\t});\n\t}\n\n\t// Destroy the slider, then re-enter initialization.\n\tfunction rebuild ( options ) {\n\n\t\treturn this.each(function(){\n\n\t\t\t// The rebuild flag can be used if the slider wasn't initialized yet.\n\t\t\tif ( !this.destroy ) {\n\t\t\t\t$(this).noUiSlider( options );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Get the current values from the slider,\n\t\t\t// including the initialization options.\n\t\t\tvar values = $(this).val(), originalOptions = this.destroy(),\n\n\t\t\t\t// Extend the previous options with the newly provided ones.\n\t\t\t\tnewOptions = $.extend( {}, originalOptions, options );\n\n\t\t\t// Run the standard initializer.\n\t\t\t$(this).noUiSlider( newOptions );\n\n\t\t\t// Place Link elements back.\n\t\t\tthis.reappend();\n\n\t\t\t// If the start option hasn't changed,\n\t\t\t// reset the previous values.\n\t\t\tif ( originalOptions.start === newOptions.start ) {\n\t\t\t\t$(this).val(values);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Access the internal getting and setting methods based on argument count.\n\tfunction value ( ) {\n\t\treturn this[0][ !arguments.length ? 'vGet' : 'vSet' ].apply(this[0], arguments);\n\t}\n\n\t// Override the .val() method. Test every element. Is it a slider? Go to\n\t// the slider value handling. No? Use the standard method.\n\t// Note how $.fn.val expects 'this' to be an instance of $. For convenience,\n\t// the above 'value' function does too.\n\t$.fn.val = function ( arg ) {\n\n\t\t// this === instanceof $\n\n\t\tfunction valMethod( a ){\n\t\t\treturn a.hasClass(Classes[0]) ? value : $val;\n\t\t}\n\n\t\t// If no value is passed, this is 'get'.\n\t\tif ( !arguments.length ) {\n\t\t\tvar first = $(this[0]);\n\t\t\treturn valMethod(first).call(first);\n\t\t}\n\n\t\tvar isFunction = $.isFunction(arg);\n\n\t\t// Return the set so it remains chainable. Make sure not to break\n\t\t// jQuery's .val(function( index, value ){}) signature.\n\t\treturn this.each(function( i ){\n\n\t\t\tvar val = arg, $t = $(this);\n\n\t\t\tif ( isFunction ) {\n\t\t\t\tval = arg.call(this, i, $t.val());\n\t\t\t}\n\n\t\t\tvalMethod($t).call($t, val);\n\t\t});\n\t};\n\n// Extend jQuery/Zepto with the noUiSlider method.\n\t$.fn.noUiSlider = function ( options, rebuildFlag ) {\n\n\t\tswitch ( options ) {\n\t\t\tcase 'step': return this[0].getCurrentStep();\n\t\t\tcase 'options': return this[0].getOriginalOptions();\n\t\t}\n\n\t\treturn ( rebuildFlag ? rebuild : initialize ).call(this, options);\n\t};\n\n}( window.jQuery || window.Zepto ));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/summernote/dist/summernote-bs3.css",
    "content": ".note-editor {\n  /*! normalize.css v2.1.3 | MIT License | git.io/normalize */\n\n}\n.note-editor article,\n.note-editor aside,\n.note-editor details,\n.note-editor figcaption,\n.note-editor figure,\n.note-editor footer,\n.note-editor header,\n.note-editor hgroup,\n.note-editor main,\n.note-editor nav,\n.note-editor section,\n.note-editor summary {\n  display: block;\n}\n.note-editor audio,\n.note-editor canvas,\n.note-editor video {\n  display: inline-block;\n}\n.note-editor audio:not([controls]) {\n  display: none;\n  height: 0;\n}\n.note-editor [hidden],\n.note-editor template {\n  display: none;\n}\n.note-editor html {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\n.note-editor body {\n  margin: 0;\n}\n.note-editor a {\n  background: transparent;\n}\n.note-editor a:focus {\n  outline: thin dotted;\n}\n.note-editor a:active,\n.note-editor a:hover {\n  outline: 0;\n}\n.note-editor h1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n.note-editor abbr[title] {\n  border-bottom: 1px dotted;\n}\n.note-editor b,\n.note-editor strong {\n  font-weight: bold;\n}\n.note-editor dfn {\n  font-style: italic;\n}\n.note-editor hr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n.note-editor mark {\n  background: #ff0;\n  color: #000;\n}\n.note-editor code,\n.note-editor kbd,\n.note-editor pre,\n.note-editor samp {\n  font-family: monospace, serif;\n  font-size: 1em;\n}\n.note-editor pre {\n  white-space: pre-wrap;\n}\n.note-editor q {\n  quotes: \"\\201C\" \"\\201D\" \"\\2018\" \"\\2019\";\n}\n.note-editor small {\n  font-size: 80%;\n}\n.note-editor sub,\n.note-editor sup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n.note-editor sup {\n  top: -0.5em;\n}\n.note-editor sub {\n  bottom: -0.25em;\n}\n.note-editor img {\n  border: 0;\n}\n.note-editor svg:not(:root) {\n  overflow: hidden;\n}\n.note-editor figure {\n  margin: 0;\n}\n.note-editor fieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n.note-editor legend {\n  border: 0;\n  padding: 0;\n}\n.note-editor button,\n.note-editor input,\n.note-editor select,\n.note-editor textarea {\n  font-family: inherit;\n  font-size: 100%;\n  margin: 0;\n}\n.note-editor button,\n.note-editor input {\n  line-height: normal;\n}\n.note-editor button,\n.note-editor select {\n  text-transform: none;\n}\n.note-editor button,\n.note-editor html input[type=\"button\"],\n.note-editor input[type=\"reset\"],\n.note-editor input[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\n.note-editor button[disabled],\n.note-editor html input[disabled] {\n  cursor: default;\n}\n.note-editor input[type=\"checkbox\"],\n.note-editor input[type=\"radio\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\n.note-editor input[type=\"search\"] {\n  -webkit-appearance: textfield;\n  -moz-box-sizing: content-box;\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n.note-editor input[type=\"search\"]::-webkit-search-cancel-button,\n.note-editor input[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n.note-editor button::-moz-focus-inner,\n.note-editor input::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n.note-editor textarea {\n  overflow: auto;\n  vertical-align: top;\n}\n.note-editor table {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n@media print {\n  .note-editor * {\n    text-shadow: none !important;\n    color: #000 !important;\n    background: transparent !important;\n    box-shadow: none !important;\n  }\n  .note-editor a,\n  .note-editor a:visited {\n    text-decoration: underline;\n  }\n  .note-editor a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  .note-editor abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  .note-editor .ir a:after,\n  .note-editor a[href^=\"javascript:\"]:after,\n  .note-editor a[href^=\"#\"]:after {\n    content: \"\";\n  }\n  .note-editor pre,\n  .note-editor blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n  .note-editor thead {\n    display: table-header-group;\n  }\n  .note-editor tr,\n  .note-editor img {\n    page-break-inside: avoid;\n  }\n  .note-editor img {\n    max-width: 100% !important;\n  }\n  @page  {\n    margin: 2cm .5cm;\n  }\n  .note-editor p,\n  .note-editor h2,\n  .note-editor h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  .note-editor h2,\n  .note-editor h3 {\n    page-break-after: avoid;\n  }\n  .note-editor .navbar {\n    display: none;\n  }\n  .note-editor .table td,\n  .note-editor .table th {\n    background-color: #fff !important;\n  }\n  .note-editor .btn > .caret,\n  .note-editor .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .note-editor .label {\n    border: 1px solid #000;\n  }\n  .note-editor .table {\n    border-collapse: collapse !important;\n  }\n  .note-editor .table-bordered th,\n  .note-editor .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n.note-editor *,\n.note-editor *:before,\n.note-editor *:after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n.note-editor html {\n  font-size: 62.5%;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n.note-editor body {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #333333;\n  background-color: #ffffff;\n}\n.note-editor input,\n.note-editor button,\n.note-editor select,\n.note-editor textarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n.note-editor a {\n  color: #428bca;\n  text-decoration: none;\n}\n.note-editor a:hover,\n.note-editor a:focus {\n  color: #2a6496;\n  text-decoration: underline;\n}\n.note-editor a:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.note-editor img {\n  vertical-align: middle;\n}\n.note-editor .img-responsive {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.note-editor .img-rounded {\n  border-radius: 6px;\n}\n.note-editor .img-thumbnail {\n  padding: 4px;\n  line-height: 1.428571429;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n}\n.note-editor .img-circle {\n  border-radius: 50%;\n}\n.note-editor hr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n}\n.note-editor .sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.note-editor p {\n  margin: 0 0 10px;\n}\n.note-editor .lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 200;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .note-editor .lead {\n    font-size: 21px;\n  }\n}\n.note-editor small,\n.note-editor .small {\n  font-size: 85%;\n}\n.note-editor cite {\n  font-style: normal;\n}\n.note-editor .text-muted {\n  color: #999999;\n}\n.note-editor .text-primary {\n  color: #428bca;\n}\n.note-editor .text-primary:hover {\n  color: #3071a9;\n}\n.note-editor .text-warning {\n  color: #c09853;\n}\n.note-editor .text-warning:hover {\n  color: #a47e3c;\n}\n.note-editor .text-danger {\n  color: #b94a48;\n}\n.note-editor .text-danger:hover {\n  color: #953b39;\n}\n.note-editor .text-success {\n  color: #468847;\n}\n.note-editor .text-success:hover {\n  color: #356635;\n}\n.note-editor .text-info {\n  color: #3a87ad;\n}\n.note-editor .text-info:hover {\n  color: #2d6987;\n}\n.note-editor .text-left {\n  text-align: left;\n}\n.note-editor .text-right {\n  text-align: right;\n}\n.note-editor .text-center {\n  text-align: center;\n}\n.note-editor h1,\n.note-editor h2,\n.note-editor h3,\n.note-editor h4,\n.note-editor h5,\n.note-editor h6,\n.note-editor .h1,\n.note-editor .h2,\n.note-editor .h3,\n.note-editor .h4,\n.note-editor .h5,\n.note-editor .h6 {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\n.note-editor h1 small,\n.note-editor h2 small,\n.note-editor h3 small,\n.note-editor h4 small,\n.note-editor h5 small,\n.note-editor h6 small,\n.note-editor .h1 small,\n.note-editor .h2 small,\n.note-editor .h3 small,\n.note-editor .h4 small,\n.note-editor .h5 small,\n.note-editor .h6 small,\n.note-editor h1 .small,\n.note-editor h2 .small,\n.note-editor h3 .small,\n.note-editor h4 .small,\n.note-editor h5 .small,\n.note-editor h6 .small,\n.note-editor .h1 .small,\n.note-editor .h2 .small,\n.note-editor .h3 .small,\n.note-editor .h4 .small,\n.note-editor .h5 .small,\n.note-editor .h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #999999;\n}\n.note-editor h1,\n.note-editor h2,\n.note-editor h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\n.note-editor h1 small,\n.note-editor h2 small,\n.note-editor h3 small,\n.note-editor h1 .small,\n.note-editor h2 .small,\n.note-editor h3 .small {\n  font-size: 65%;\n}\n.note-editor h4,\n.note-editor h5,\n.note-editor h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.note-editor h4 small,\n.note-editor h5 small,\n.note-editor h6 small,\n.note-editor h4 .small,\n.note-editor h5 .small,\n.note-editor h6 .small {\n  font-size: 75%;\n}\n.note-editor h1,\n.note-editor .h1 {\n  font-size: 36px;\n}\n.note-editor h2,\n.note-editor .h2 {\n  font-size: 30px;\n}\n.note-editor h3,\n.note-editor .h3 {\n  font-size: 24px;\n}\n.note-editor h4,\n.note-editor .h4 {\n  font-size: 18px;\n}\n.note-editor h5,\n.note-editor .h5 {\n  font-size: 14px;\n}\n.note-editor h6,\n.note-editor .h6 {\n  font-size: 12px;\n}\n.note-editor .page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eeeeee;\n}\n.note-editor ul,\n.note-editor ol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\n.note-editor ul ul,\n.note-editor ol ul,\n.note-editor ul ol,\n.note-editor ol ol {\n  margin-bottom: 0;\n}\n.note-editor .list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.note-editor .list-inline {\n  padding-left: 0;\n  list-style: none;\n}\n.note-editor .list-inline > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\n.note-editor dl {\n  margin-bottom: 20px;\n}\n.note-editor dt,\n.note-editor dd {\n  line-height: 1.428571429;\n}\n.note-editor dt {\n  font-weight: bold;\n}\n.note-editor dd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .note-editor .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    clear: left;\n    text-align: right;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .note-editor .dl-horizontal dd {\n    margin-left: 180px;\n  }\n  .note-editor .dl-horizontal dd:before,\n  .note-editor .dl-horizontal dd:after {\n    content: \" \";\n    /* 1 */\n  \n    display: table;\n    /* 2 */\n  \n  }\n  .note-editor .dl-horizontal dd:after {\n    clear: both;\n  }\n  .note-editor .dl-horizontal dd:before,\n  .note-editor .dl-horizontal dd:after {\n    content: \" \";\n    /* 1 */\n  \n    display: table;\n    /* 2 */\n  \n  }\n  .note-editor .dl-horizontal dd:after {\n    clear: both;\n  }\n}\n.note-editor abbr[title],\n.note-editor abbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #999999;\n}\n.note-editor abbr.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n.note-editor blockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  border-left: 5px solid #eeeeee;\n}\n.note-editor blockquote p {\n  font-size: 17.5px;\n  font-weight: 300;\n  line-height: 1.25;\n}\n.note-editor blockquote p:last-child {\n  margin-bottom: 0;\n}\n.note-editor blockquote small {\n  display: block;\n  line-height: 1.428571429;\n  color: #999999;\n}\n.note-editor blockquote small:before {\n  content: '\\2014 \\00A0';\n}\n.note-editor blockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n}\n.note-editor blockquote.pull-right p,\n.note-editor blockquote.pull-right small,\n.note-editor blockquote.pull-right .small {\n  text-align: right;\n}\n.note-editor blockquote.pull-right small:before,\n.note-editor blockquote.pull-right .small:before {\n  content: '';\n}\n.note-editor blockquote.pull-right small:after,\n.note-editor blockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\n.note-editor blockquote:before,\n.note-editor blockquote:after {\n  content: \"\";\n}\n.note-editor address {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.428571429;\n}\n.note-editor code,\n.note-editor kdb,\n.note-editor pre,\n.note-editor samp {\n  font-family: Monaco, Menlo, Consolas, \"Courier New\", monospace;\n}\n.note-editor code {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  white-space: nowrap;\n  border-radius: 4px;\n}\n.note-editor pre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.428571429;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: #333333;\n  background-color: #f5f5f5;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\n.note-editor pre 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.note-editor .pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.note-editor .container {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.note-editor .container:before,\n.note-editor .container:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .container:after {\n  clear: both;\n}\n.note-editor .container:before,\n.note-editor .container:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .container:after {\n  clear: both;\n}\n.note-editor .row {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.note-editor .row:before,\n.note-editor .row:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .row:after {\n  clear: both;\n}\n.note-editor .row:before,\n.note-editor .row:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .row:after {\n  clear: both;\n}\n.note-editor .col-xs-1, \n.note-editor .col-sm-1, \n.note-editor .col-md-1, \n.note-editor .col-lg-1, \n.note-editor .col-xs-2, \n.note-editor .col-sm-2, \n.note-editor .col-md-2, \n.note-editor .col-lg-2, \n.note-editor .col-xs-3, \n.note-editor .col-sm-3, \n.note-editor .col-md-3, \n.note-editor .col-lg-3, \n.note-editor .col-xs-4, \n.note-editor .col-sm-4, \n.note-editor .col-md-4, \n.note-editor .col-lg-4, \n.note-editor .col-xs-5, \n.note-editor .col-sm-5, \n.note-editor .col-md-5, \n.note-editor .col-lg-5, \n.note-editor .col-xs-6, \n.note-editor .col-sm-6, \n.note-editor .col-md-6, \n.note-editor .col-lg-6, \n.note-editor .col-xs-7, \n.note-editor .col-sm-7, \n.note-editor .col-md-7, \n.note-editor .col-lg-7, \n.note-editor .col-xs-8, \n.note-editor .col-sm-8, \n.note-editor .col-md-8, \n.note-editor .col-lg-8, \n.note-editor .col-xs-9, \n.note-editor .col-sm-9, \n.note-editor .col-md-9, \n.note-editor .col-lg-9, \n.note-editor .col-xs-10, \n.note-editor .col-sm-10, \n.note-editor .col-md-10, \n.note-editor .col-lg-10, \n.note-editor .col-xs-11, \n.note-editor .col-sm-11, \n.note-editor .col-md-11, \n.note-editor .col-lg-11, \n.note-editor .col-xs-12, \n.note-editor .col-sm-12, \n.note-editor .col-md-12, \n.note-editor .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.note-editor .col-xs-1, \n.note-editor .col-xs-2, \n.note-editor .col-xs-3, \n.note-editor .col-xs-4, \n.note-editor .col-xs-5, \n.note-editor .col-xs-6, \n.note-editor .col-xs-7, \n.note-editor .col-xs-8, \n.note-editor .col-xs-9, \n.note-editor .col-xs-10, \n.note-editor .col-xs-11 {\n  float: left;\n}\n.note-editor .col-xs-12 {\n  width: 100%;\n}\n.note-editor .col-xs-11 {\n  width: 91.66666666666666%;\n}\n.note-editor .col-xs-10 {\n  width: 83.33333333333334%;\n}\n.note-editor .col-xs-9 {\n  width: 75%;\n}\n.note-editor .col-xs-8 {\n  width: 66.66666666666666%;\n}\n.note-editor .col-xs-7 {\n  width: 58.333333333333336%;\n}\n.note-editor .col-xs-6 {\n  width: 50%;\n}\n.note-editor .col-xs-5 {\n  width: 41.66666666666667%;\n}\n.note-editor .col-xs-4 {\n  width: 33.33333333333333%;\n}\n.note-editor .col-xs-3 {\n  width: 25%;\n}\n.note-editor .col-xs-2 {\n  width: 16.666666666666664%;\n}\n.note-editor .col-xs-1 {\n  width: 8.333333333333332%;\n}\n.note-editor .col-xs-pull-12 {\n  right: 100%;\n}\n.note-editor .col-xs-pull-11 {\n  right: 91.66666666666666%;\n}\n.note-editor .col-xs-pull-10 {\n  right: 83.33333333333334%;\n}\n.note-editor .col-xs-pull-9 {\n  right: 75%;\n}\n.note-editor .col-xs-pull-8 {\n  right: 66.66666666666666%;\n}\n.note-editor .col-xs-pull-7 {\n  right: 58.333333333333336%;\n}\n.note-editor .col-xs-pull-6 {\n  right: 50%;\n}\n.note-editor .col-xs-pull-5 {\n  right: 41.66666666666667%;\n}\n.note-editor .col-xs-pull-4 {\n  right: 33.33333333333333%;\n}\n.note-editor .col-xs-pull-3 {\n  right: 25%;\n}\n.note-editor .col-xs-pull-2 {\n  right: 16.666666666666664%;\n}\n.note-editor .col-xs-pull-1 {\n  right: 8.333333333333332%;\n}\n.note-editor .col-xs-push-12 {\n  left: 100%;\n}\n.note-editor .col-xs-push-11 {\n  left: 91.66666666666666%;\n}\n.note-editor .col-xs-push-10 {\n  left: 83.33333333333334%;\n}\n.note-editor .col-xs-push-9 {\n  left: 75%;\n}\n.note-editor .col-xs-push-8 {\n  left: 66.66666666666666%;\n}\n.note-editor .col-xs-push-7 {\n  left: 58.333333333333336%;\n}\n.note-editor .col-xs-push-6 {\n  left: 50%;\n}\n.note-editor .col-xs-push-5 {\n  left: 41.66666666666667%;\n}\n.note-editor .col-xs-push-4 {\n  left: 33.33333333333333%;\n}\n.note-editor .col-xs-push-3 {\n  left: 25%;\n}\n.note-editor .col-xs-push-2 {\n  left: 16.666666666666664%;\n}\n.note-editor .col-xs-push-1 {\n  left: 8.333333333333332%;\n}\n.note-editor .col-xs-offset-12 {\n  margin-left: 100%;\n}\n.note-editor .col-xs-offset-11 {\n  margin-left: 91.66666666666666%;\n}\n.note-editor .col-xs-offset-10 {\n  margin-left: 83.33333333333334%;\n}\n.note-editor .col-xs-offset-9 {\n  margin-left: 75%;\n}\n.note-editor .col-xs-offset-8 {\n  margin-left: 66.66666666666666%;\n}\n.note-editor .col-xs-offset-7 {\n  margin-left: 58.333333333333336%;\n}\n.note-editor .col-xs-offset-6 {\n  margin-left: 50%;\n}\n.note-editor .col-xs-offset-5 {\n  margin-left: 41.66666666666667%;\n}\n.note-editor .col-xs-offset-4 {\n  margin-left: 33.33333333333333%;\n}\n.note-editor .col-xs-offset-3 {\n  margin-left: 25%;\n}\n.note-editor .col-xs-offset-2 {\n  margin-left: 16.666666666666664%;\n}\n.note-editor .col-xs-offset-1 {\n  margin-left: 8.333333333333332%;\n}\n@media (min-width: 768px) {\n  .note-editor .container {\n    width: 750px;\n  }\n  .note-editor .col-sm-1, \n  .note-editor .col-sm-2, \n  .note-editor .col-sm-3, \n  .note-editor .col-sm-4, \n  .note-editor .col-sm-5, \n  .note-editor .col-sm-6, \n  .note-editor .col-sm-7, \n  .note-editor .col-sm-8, \n  .note-editor .col-sm-9, \n  .note-editor .col-sm-10, \n  .note-editor .col-sm-11 {\n    float: left;\n  }\n  .note-editor .col-sm-12 {\n    width: 100%;\n  }\n  .note-editor .col-sm-11 {\n    width: 91.66666666666666%;\n  }\n  .note-editor .col-sm-10 {\n    width: 83.33333333333334%;\n  }\n  .note-editor .col-sm-9 {\n    width: 75%;\n  }\n  .note-editor .col-sm-8 {\n    width: 66.66666666666666%;\n  }\n  .note-editor .col-sm-7 {\n    width: 58.333333333333336%;\n  }\n  .note-editor .col-sm-6 {\n    width: 50%;\n  }\n  .note-editor .col-sm-5 {\n    width: 41.66666666666667%;\n  }\n  .note-editor .col-sm-4 {\n    width: 33.33333333333333%;\n  }\n  .note-editor .col-sm-3 {\n    width: 25%;\n  }\n  .note-editor .col-sm-2 {\n    width: 16.666666666666664%;\n  }\n  .note-editor .col-sm-1 {\n    width: 8.333333333333332%;\n  }\n  .note-editor .col-sm-pull-12 {\n    right: 100%;\n  }\n  .note-editor .col-sm-pull-11 {\n    right: 91.66666666666666%;\n  }\n  .note-editor .col-sm-pull-10 {\n    right: 83.33333333333334%;\n  }\n  .note-editor .col-sm-pull-9 {\n    right: 75%;\n  }\n  .note-editor .col-sm-pull-8 {\n    right: 66.66666666666666%;\n  }\n  .note-editor .col-sm-pull-7 {\n    right: 58.333333333333336%;\n  }\n  .note-editor .col-sm-pull-6 {\n    right: 50%;\n  }\n  .note-editor .col-sm-pull-5 {\n    right: 41.66666666666667%;\n  }\n  .note-editor .col-sm-pull-4 {\n    right: 33.33333333333333%;\n  }\n  .note-editor .col-sm-pull-3 {\n    right: 25%;\n  }\n  .note-editor .col-sm-pull-2 {\n    right: 16.666666666666664%;\n  }\n  .note-editor .col-sm-pull-1 {\n    right: 8.333333333333332%;\n  }\n  .note-editor .col-sm-push-12 {\n    left: 100%;\n  }\n  .note-editor .col-sm-push-11 {\n    left: 91.66666666666666%;\n  }\n  .note-editor .col-sm-push-10 {\n    left: 83.33333333333334%;\n  }\n  .note-editor .col-sm-push-9 {\n    left: 75%;\n  }\n  .note-editor .col-sm-push-8 {\n    left: 66.66666666666666%;\n  }\n  .note-editor .col-sm-push-7 {\n    left: 58.333333333333336%;\n  }\n  .note-editor .col-sm-push-6 {\n    left: 50%;\n  }\n  .note-editor .col-sm-push-5 {\n    left: 41.66666666666667%;\n  }\n  .note-editor .col-sm-push-4 {\n    left: 33.33333333333333%;\n  }\n  .note-editor .col-sm-push-3 {\n    left: 25%;\n  }\n  .note-editor .col-sm-push-2 {\n    left: 16.666666666666664%;\n  }\n  .note-editor .col-sm-push-1 {\n    left: 8.333333333333332%;\n  }\n  .note-editor .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .note-editor .col-sm-offset-11 {\n    margin-left: 91.66666666666666%;\n  }\n  .note-editor .col-sm-offset-10 {\n    margin-left: 83.33333333333334%;\n  }\n  .note-editor .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .note-editor .col-sm-offset-8 {\n    margin-left: 66.66666666666666%;\n  }\n  .note-editor .col-sm-offset-7 {\n    margin-left: 58.333333333333336%;\n  }\n  .note-editor .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .note-editor .col-sm-offset-5 {\n    margin-left: 41.66666666666667%;\n  }\n  .note-editor .col-sm-offset-4 {\n    margin-left: 33.33333333333333%;\n  }\n  .note-editor .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .note-editor .col-sm-offset-2 {\n    margin-left: 16.666666666666664%;\n  }\n  .note-editor .col-sm-offset-1 {\n    margin-left: 8.333333333333332%;\n  }\n}\n@media (min-width: 992px) {\n  .note-editor .container {\n    width: 970px;\n  }\n  .note-editor .col-md-1, \n  .note-editor .col-md-2, \n  .note-editor .col-md-3, \n  .note-editor .col-md-4, \n  .note-editor .col-md-5, \n  .note-editor .col-md-6, \n  .note-editor .col-md-7, \n  .note-editor .col-md-8, \n  .note-editor .col-md-9, \n  .note-editor .col-md-10, \n  .note-editor .col-md-11 {\n    float: left;\n  }\n  .note-editor .col-md-12 {\n    width: 100%;\n  }\n  .note-editor .col-md-11 {\n    width: 91.66666666666666%;\n  }\n  .note-editor .col-md-10 {\n    width: 83.33333333333334%;\n  }\n  .note-editor .col-md-9 {\n    width: 75%;\n  }\n  .note-editor .col-md-8 {\n    width: 66.66666666666666%;\n  }\n  .note-editor .col-md-7 {\n    width: 58.333333333333336%;\n  }\n  .note-editor .col-md-6 {\n    width: 50%;\n  }\n  .note-editor .col-md-5 {\n    width: 41.66666666666667%;\n  }\n  .note-editor .col-md-4 {\n    width: 33.33333333333333%;\n  }\n  .note-editor .col-md-3 {\n    width: 25%;\n  }\n  .note-editor .col-md-2 {\n    width: 16.666666666666664%;\n  }\n  .note-editor .col-md-1 {\n    width: 8.333333333333332%;\n  }\n  .note-editor .col-md-pull-12 {\n    right: 100%;\n  }\n  .note-editor .col-md-pull-11 {\n    right: 91.66666666666666%;\n  }\n  .note-editor .col-md-pull-10 {\n    right: 83.33333333333334%;\n  }\n  .note-editor .col-md-pull-9 {\n    right: 75%;\n  }\n  .note-editor .col-md-pull-8 {\n    right: 66.66666666666666%;\n  }\n  .note-editor .col-md-pull-7 {\n    right: 58.333333333333336%;\n  }\n  .note-editor .col-md-pull-6 {\n    right: 50%;\n  }\n  .note-editor .col-md-pull-5 {\n    right: 41.66666666666667%;\n  }\n  .note-editor .col-md-pull-4 {\n    right: 33.33333333333333%;\n  }\n  .note-editor .col-md-pull-3 {\n    right: 25%;\n  }\n  .note-editor .col-md-pull-2 {\n    right: 16.666666666666664%;\n  }\n  .note-editor .col-md-pull-1 {\n    right: 8.333333333333332%;\n  }\n  .note-editor .col-md-push-12 {\n    left: 100%;\n  }\n  .note-editor .col-md-push-11 {\n    left: 91.66666666666666%;\n  }\n  .note-editor .col-md-push-10 {\n    left: 83.33333333333334%;\n  }\n  .note-editor .col-md-push-9 {\n    left: 75%;\n  }\n  .note-editor .col-md-push-8 {\n    left: 66.66666666666666%;\n  }\n  .note-editor .col-md-push-7 {\n    left: 58.333333333333336%;\n  }\n  .note-editor .col-md-push-6 {\n    left: 50%;\n  }\n  .note-editor .col-md-push-5 {\n    left: 41.66666666666667%;\n  }\n  .note-editor .col-md-push-4 {\n    left: 33.33333333333333%;\n  }\n  .note-editor .col-md-push-3 {\n    left: 25%;\n  }\n  .note-editor .col-md-push-2 {\n    left: 16.666666666666664%;\n  }\n  .note-editor .col-md-push-1 {\n    left: 8.333333333333332%;\n  }\n  .note-editor .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .note-editor .col-md-offset-11 {\n    margin-left: 91.66666666666666%;\n  }\n  .note-editor .col-md-offset-10 {\n    margin-left: 83.33333333333334%;\n  }\n  .note-editor .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .note-editor .col-md-offset-8 {\n    margin-left: 66.66666666666666%;\n  }\n  .note-editor .col-md-offset-7 {\n    margin-left: 58.333333333333336%;\n  }\n  .note-editor .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .note-editor .col-md-offset-5 {\n    margin-left: 41.66666666666667%;\n  }\n  .note-editor .col-md-offset-4 {\n    margin-left: 33.33333333333333%;\n  }\n  .note-editor .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .note-editor .col-md-offset-2 {\n    margin-left: 16.666666666666664%;\n  }\n  .note-editor .col-md-offset-1 {\n    margin-left: 8.333333333333332%;\n  }\n}\n@media (min-width: 1200px) {\n  .note-editor .container {\n    width: 1170px;\n  }\n  .note-editor .col-lg-1, \n  .note-editor .col-lg-2, \n  .note-editor .col-lg-3, \n  .note-editor .col-lg-4, \n  .note-editor .col-lg-5, \n  .note-editor .col-lg-6, \n  .note-editor .col-lg-7, \n  .note-editor .col-lg-8, \n  .note-editor .col-lg-9, \n  .note-editor .col-lg-10, \n  .note-editor .col-lg-11 {\n    float: left;\n  }\n  .note-editor .col-lg-12 {\n    width: 100%;\n  }\n  .note-editor .col-lg-11 {\n    width: 91.66666666666666%;\n  }\n  .note-editor .col-lg-10 {\n    width: 83.33333333333334%;\n  }\n  .note-editor .col-lg-9 {\n    width: 75%;\n  }\n  .note-editor .col-lg-8 {\n    width: 66.66666666666666%;\n  }\n  .note-editor .col-lg-7 {\n    width: 58.333333333333336%;\n  }\n  .note-editor .col-lg-6 {\n    width: 50%;\n  }\n  .note-editor .col-lg-5 {\n    width: 41.66666666666667%;\n  }\n  .note-editor .col-lg-4 {\n    width: 33.33333333333333%;\n  }\n  .note-editor .col-lg-3 {\n    width: 25%;\n  }\n  .note-editor .col-lg-2 {\n    width: 16.666666666666664%;\n  }\n  .note-editor .col-lg-1 {\n    width: 8.333333333333332%;\n  }\n  .note-editor .col-lg-pull-12 {\n    right: 100%;\n  }\n  .note-editor .col-lg-pull-11 {\n    right: 91.66666666666666%;\n  }\n  .note-editor .col-lg-pull-10 {\n    right: 83.33333333333334%;\n  }\n  .note-editor .col-lg-pull-9 {\n    right: 75%;\n  }\n  .note-editor .col-lg-pull-8 {\n    right: 66.66666666666666%;\n  }\n  .note-editor .col-lg-pull-7 {\n    right: 58.333333333333336%;\n  }\n  .note-editor .col-lg-pull-6 {\n    right: 50%;\n  }\n  .note-editor .col-lg-pull-5 {\n    right: 41.66666666666667%;\n  }\n  .note-editor .col-lg-pull-4 {\n    right: 33.33333333333333%;\n  }\n  .note-editor .col-lg-pull-3 {\n    right: 25%;\n  }\n  .note-editor .col-lg-pull-2 {\n    right: 16.666666666666664%;\n  }\n  .note-editor .col-lg-pull-1 {\n    right: 8.333333333333332%;\n  }\n  .note-editor .col-lg-push-12 {\n    left: 100%;\n  }\n  .note-editor .col-lg-push-11 {\n    left: 91.66666666666666%;\n  }\n  .note-editor .col-lg-push-10 {\n    left: 83.33333333333334%;\n  }\n  .note-editor .col-lg-push-9 {\n    left: 75%;\n  }\n  .note-editor .col-lg-push-8 {\n    left: 66.66666666666666%;\n  }\n  .note-editor .col-lg-push-7 {\n    left: 58.333333333333336%;\n  }\n  .note-editor .col-lg-push-6 {\n    left: 50%;\n  }\n  .note-editor .col-lg-push-5 {\n    left: 41.66666666666667%;\n  }\n  .note-editor .col-lg-push-4 {\n    left: 33.33333333333333%;\n  }\n  .note-editor .col-lg-push-3 {\n    left: 25%;\n  }\n  .note-editor .col-lg-push-2 {\n    left: 16.666666666666664%;\n  }\n  .note-editor .col-lg-push-1 {\n    left: 8.333333333333332%;\n  }\n  .note-editor .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .note-editor .col-lg-offset-11 {\n    margin-left: 91.66666666666666%;\n  }\n  .note-editor .col-lg-offset-10 {\n    margin-left: 83.33333333333334%;\n  }\n  .note-editor .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .note-editor .col-lg-offset-8 {\n    margin-left: 66.66666666666666%;\n  }\n  .note-editor .col-lg-offset-7 {\n    margin-left: 58.333333333333336%;\n  }\n  .note-editor .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .note-editor .col-lg-offset-5 {\n    margin-left: 41.66666666666667%;\n  }\n  .note-editor .col-lg-offset-4 {\n    margin-left: 33.33333333333333%;\n  }\n  .note-editor .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .note-editor .col-lg-offset-2 {\n    margin-left: 16.666666666666664%;\n  }\n  .note-editor .col-lg-offset-1 {\n    margin-left: 8.333333333333332%;\n  }\n}\n.note-editor table {\n  max-width: 100%;\n  background-color: transparent;\n}\n.note-editor th {\n  text-align: left;\n}\n.note-editor .table {\n  width: 100%;\n  margin-bottom: 20px;\n}\n.note-editor .table > thead > tr > th,\n.note-editor .table > tbody > tr > th,\n.note-editor .table > tfoot > tr > th,\n.note-editor .table > thead > tr > td,\n.note-editor .table > tbody > tr > td,\n.note-editor .table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.428571429;\n  vertical-align: top;\n  border-top: 1px solid #dddddd;\n}\n.note-editor .table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #dddddd;\n}\n.note-editor .table > caption + thead > tr:first-child > th,\n.note-editor .table > colgroup + thead > tr:first-child > th,\n.note-editor .table > thead:first-child > tr:first-child > th,\n.note-editor .table > caption + thead > tr:first-child > td,\n.note-editor .table > colgroup + thead > tr:first-child > td,\n.note-editor .table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.note-editor .table > tbody + tbody {\n  border-top: 2px solid #dddddd;\n}\n.note-editor .table .table {\n  background-color: #ffffff;\n}\n.note-editor .table-condensed > thead > tr > th,\n.note-editor .table-condensed > tbody > tr > th,\n.note-editor .table-condensed > tfoot > tr > th,\n.note-editor .table-condensed > thead > tr > td,\n.note-editor .table-condensed > tbody > tr > td,\n.note-editor .table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.note-editor .table-bordered {\n  border: 1px solid #dddddd;\n}\n.note-editor .table-bordered > thead > tr > th,\n.note-editor .table-bordered > tbody > tr > th,\n.note-editor .table-bordered > tfoot > tr > th,\n.note-editor .table-bordered > thead > tr > td,\n.note-editor .table-bordered > tbody > tr > td,\n.note-editor .table-bordered > tfoot > tr > td {\n  border: 1px solid #dddddd;\n}\n.note-editor .table-bordered > thead > tr > th,\n.note-editor .table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.note-editor .table-striped > tbody > tr:nth-child(odd) > td,\n.note-editor .table-striped > tbody > tr:nth-child(odd) > th {\n  background-color: #f9f9f9;\n}\n.note-editor .table-hover > tbody > tr:hover > td,\n.note-editor .table-hover > tbody > tr:hover > th {\n  background-color: #f5f5f5;\n}\n.note-editor table col[class*=\"col-\"] {\n  float: none;\n  display: table-column;\n}\n.note-editor table td[class*=\"col-\"],\n.note-editor table th[class*=\"col-\"] {\n  float: none;\n  display: table-cell;\n}\n.note-editor .table > thead > tr > td.active,\n.note-editor .table > tbody > tr > td.active,\n.note-editor .table > tfoot > tr > td.active,\n.note-editor .table > thead > tr > th.active,\n.note-editor .table > tbody > tr > th.active,\n.note-editor .table > tfoot > tr > th.active,\n.note-editor .table > thead > tr.active > td,\n.note-editor .table > tbody > tr.active > td,\n.note-editor .table > tfoot > tr.active > td,\n.note-editor .table > thead > tr.active > th,\n.note-editor .table > tbody > tr.active > th,\n.note-editor .table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.note-editor .table > thead > tr > td.success,\n.note-editor .table > tbody > tr > td.success,\n.note-editor .table > tfoot > tr > td.success,\n.note-editor .table > thead > tr > th.success,\n.note-editor .table > tbody > tr > th.success,\n.note-editor .table > tfoot > tr > th.success,\n.note-editor .table > thead > tr.success > td,\n.note-editor .table > tbody > tr.success > td,\n.note-editor .table > tfoot > tr.success > td,\n.note-editor .table > thead > tr.success > th,\n.note-editor .table > tbody > tr.success > th,\n.note-editor .table > tfoot > tr.success > th {\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.note-editor .table-hover > tbody > tr > td.success:hover,\n.note-editor .table-hover > tbody > tr > th.success:hover,\n.note-editor .table-hover > tbody > tr.success:hover > td,\n.note-editor .table-hover > tbody > tr.success:hover > th {\n  background-color: #d0e9c6;\n  border-color: #c9e2b3;\n}\n.note-editor .table > thead > tr > td.danger,\n.note-editor .table > tbody > tr > td.danger,\n.note-editor .table > tfoot > tr > td.danger,\n.note-editor .table > thead > tr > th.danger,\n.note-editor .table > tbody > tr > th.danger,\n.note-editor .table > tfoot > tr > th.danger,\n.note-editor .table > thead > tr.danger > td,\n.note-editor .table > tbody > tr.danger > td,\n.note-editor .table > tfoot > tr.danger > td,\n.note-editor .table > thead > tr.danger > th,\n.note-editor .table > tbody > tr.danger > th,\n.note-editor .table > tfoot > tr.danger > th {\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.note-editor .table-hover > tbody > tr > td.danger:hover,\n.note-editor .table-hover > tbody > tr > th.danger:hover,\n.note-editor .table-hover > tbody > tr.danger:hover > td,\n.note-editor .table-hover > tbody > tr.danger:hover > th {\n  background-color: #ebcccc;\n  border-color: #e4b9c0;\n}\n.note-editor .table > thead > tr > td.warning,\n.note-editor .table > tbody > tr > td.warning,\n.note-editor .table > tfoot > tr > td.warning,\n.note-editor .table > thead > tr > th.warning,\n.note-editor .table > tbody > tr > th.warning,\n.note-editor .table > tfoot > tr > th.warning,\n.note-editor .table > thead > tr.warning > td,\n.note-editor .table > tbody > tr.warning > td,\n.note-editor .table > tfoot > tr.warning > td,\n.note-editor .table > thead > tr.warning > th,\n.note-editor .table > tbody > tr.warning > th,\n.note-editor .table > tfoot > tr.warning > th {\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.note-editor .table-hover > tbody > tr > td.warning:hover,\n.note-editor .table-hover > tbody > tr > th.warning:hover,\n.note-editor .table-hover > tbody > tr.warning:hover > td,\n.note-editor .table-hover > tbody > tr.warning:hover > th {\n  background-color: #faf2cc;\n  border-color: #f7e1b5;\n}\n@media (max-width: 767px) {\n  .note-editor .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    overflow-x: scroll;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #dddddd;\n    -webkit-overflow-scrolling: touch;\n  }\n  .note-editor .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .note-editor .table-responsive > .table > thead > tr > th,\n  .note-editor .table-responsive > .table > tbody > tr > th,\n  .note-editor .table-responsive > .table > tfoot > tr > th,\n  .note-editor .table-responsive > .table > thead > tr > td,\n  .note-editor .table-responsive > .table > tbody > tr > td,\n  .note-editor .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .note-editor .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .note-editor .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .note-editor .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .note-editor .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .note-editor .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .note-editor .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .note-editor .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .note-editor .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .note-editor .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .note-editor .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .note-editor .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\n.note-editor fieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n.note-editor legend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\n.note-editor label {\n  display: inline-block;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n.note-editor input[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n.note-editor input[type=\"radio\"],\n.note-editor input[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  /* IE8-9 */\n\n  line-height: normal;\n}\n.note-editor input[type=\"file\"] {\n  display: block;\n}\n.note-editor select[multiple],\n.note-editor select[size] {\n  height: auto;\n}\n.note-editor select optgroup {\n  font-size: inherit;\n  font-style: inherit;\n  font-family: inherit;\n}\n.note-editor input[type=\"file\"]:focus,\n.note-editor input[type=\"radio\"]:focus,\n.note-editor input[type=\"checkbox\"]:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.note-editor input[type=\"number\"]::-webkit-outer-spin-button,\n.note-editor input[type=\"number\"]::-webkit-inner-spin-button {\n  height: auto;\n}\n.note-editor output {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #555555;\n  vertical-align: middle;\n}\n.note-editor .form-control:-moz-placeholder {\n  color: #999999;\n}\n.note-editor .form-control::-moz-placeholder {\n  color: #999999;\n}\n.note-editor .form-control:-ms-input-placeholder {\n  color: #999999;\n}\n.note-editor .form-control::-webkit-input-placeholder {\n  color: #999999;\n}\n.note-editor .form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #555555;\n  vertical-align: middle;\n  background-color: #ffffff;\n  background-image: none;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-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.note-editor .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, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.note-editor .form-control[disabled],\n.note-editor .form-control[readonly],\nfieldset[disabled] .note-editor .form-control {\n  cursor: not-allowed;\n  background-color: #eeeeee;\n}\ntextarea.note-editor .form-control {\n  height: auto;\n}\n.note-editor .form-group {\n  margin-bottom: 15px;\n}\n.note-editor .radio,\n.note-editor .checkbox {\n  display: block;\n  min-height: 20px;\n  margin-top: 10px;\n  margin-bottom: 10px;\n  padding-left: 20px;\n  vertical-align: middle;\n}\n.note-editor .radio label,\n.note-editor .checkbox label {\n  display: inline;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.note-editor .radio input[type=\"radio\"],\n.note-editor .radio-inline input[type=\"radio\"],\n.note-editor .checkbox input[type=\"checkbox\"],\n.note-editor .checkbox-inline input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -20px;\n}\n.note-editor .radio + .radio,\n.note-editor .checkbox + .checkbox {\n  margin-top: -5px;\n}\n.note-editor .radio-inline,\n.note-editor .checkbox-inline {\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.note-editor .radio-inline + .radio-inline,\n.note-editor .checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\n.note-editor input[type=\"radio\"][disabled],\n.note-editor input[type=\"checkbox\"][disabled],\n.note-editor .radio[disabled],\n.note-editor .radio-inline[disabled],\n.note-editor .checkbox[disabled],\n.note-editor .checkbox-inline[disabled],\nfieldset[disabled] .note-editor input[type=\"radio\"],\nfieldset[disabled] .note-editor input[type=\"checkbox\"],\nfieldset[disabled] .note-editor .radio,\nfieldset[disabled] .note-editor .radio-inline,\nfieldset[disabled] .note-editor .checkbox,\nfieldset[disabled] .note-editor .checkbox-inline {\n  cursor: not-allowed;\n}\n.note-editor .input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.note-editor .input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.note-editor .input-sm {\n  height: auto;\n}\n.note-editor .input-lg {\n  height: 45px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\nselect.note-editor .input-lg {\n  height: 45px;\n  line-height: 45px;\n}\ntextarea.note-editor .input-lg {\n  height: auto;\n}\n.note-editor .has-warning .help-block,\n.note-editor .has-warning .control-label {\n  color: #c09853;\n}\n.note-editor .has-warning .form-control {\n  border-color: #c09853;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.note-editor .has-warning .form-control:focus {\n  border-color: #a47e3c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;\n}\n.note-editor .has-warning .input-group-addon {\n  color: #c09853;\n  border-color: #c09853;\n  background-color: #fcf8e3;\n}\n.note-editor .has-error .help-block,\n.note-editor .has-error .control-label {\n  color: #b94a48;\n}\n.note-editor .has-error .form-control {\n  border-color: #b94a48;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.note-editor .has-error .form-control:focus {\n  border-color: #953b39;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;\n}\n.note-editor .has-error .input-group-addon {\n  color: #b94a48;\n  border-color: #b94a48;\n  background-color: #f2dede;\n}\n.note-editor .has-success .help-block,\n.note-editor .has-success .control-label {\n  color: #468847;\n}\n.note-editor .has-success .form-control {\n  border-color: #468847;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.note-editor .has-success .form-control:focus {\n  border-color: #356635;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;\n}\n.note-editor .has-success .input-group-addon {\n  color: #468847;\n  border-color: #468847;\n  background-color: #dff0d8;\n}\n.note-editor .form-control-static {\n  margin-bottom: 0;\n}\n.note-editor .help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .note-editor .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .note-editor .form-inline .form-control {\n    display: inline-block;\n  }\n  .note-editor .form-inline .radio,\n  .note-editor .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-left: 0;\n  }\n  .note-editor .form-inline .radio input[type=\"radio\"],\n  .note-editor .form-inline .checkbox input[type=\"checkbox\"] {\n    float: none;\n    margin-left: 0;\n  }\n}\n.note-editor .form-horizontal .control-label,\n.note-editor .form-horizontal .radio,\n.note-editor .form-horizontal .checkbox,\n.note-editor .form-horizontal .radio-inline,\n.note-editor .form-horizontal .checkbox-inline {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 7px;\n}\n.note-editor .form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.note-editor .form-horizontal .form-group:before,\n.note-editor .form-horizontal .form-group:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .form-horizontal .form-group:after {\n  clear: both;\n}\n.note-editor .form-horizontal .form-group:before,\n.note-editor .form-horizontal .form-group:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .form-horizontal .form-group:after {\n  clear: both;\n}\n.note-editor .form-horizontal .form-control-static {\n  padding-top: 7px;\n}\n@media (min-width: 768px) {\n  .note-editor .form-horizontal .control-label {\n    text-align: right;\n  }\n}\n.note-editor .btn {\n  display: inline-block;\n  margin-bottom: 0;\n  font-weight: normal;\n  text-align: center;\n  vertical-align: middle;\n  cursor: pointer;\n  background-image: none;\n  border: 1px solid transparent;\n  white-space: nowrap;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  border-radius: 4px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  -o-user-select: none;\n  user-select: none;\n}\n.note-editor .btn:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.note-editor .btn:hover,\n.note-editor .btn:focus {\n  color: #333333;\n  text-decoration: none;\n}\n.note-editor .btn:active,\n.note-editor .btn.active {\n  outline: 0;\n  background-image: none;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.note-editor .btn.disabled,\n.note-editor .btn[disabled],\nfieldset[disabled] .note-editor .btn {\n  cursor: not-allowed;\n  pointer-events: none;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.note-editor .btn-default {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.note-editor .btn-default:hover,\n.note-editor .btn-default:focus,\n.note-editor .btn-default:active,\n.note-editor .btn-default.active,\n.open .dropdown-toggle.note-editor .btn-default {\n  color: #333333;\n  background-color: #ebebeb;\n  border-color: #adadad;\n}\n.note-editor .btn-default:active,\n.note-editor .btn-default.active,\n.open .dropdown-toggle.note-editor .btn-default {\n  background-image: none;\n}\n.note-editor .btn-default.disabled,\n.note-editor .btn-default[disabled],\nfieldset[disabled] .note-editor .btn-default,\n.note-editor .btn-default.disabled:hover,\n.note-editor .btn-default[disabled]:hover,\nfieldset[disabled] .note-editor .btn-default:hover,\n.note-editor .btn-default.disabled:focus,\n.note-editor .btn-default[disabled]:focus,\nfieldset[disabled] .note-editor .btn-default:focus,\n.note-editor .btn-default.disabled:active,\n.note-editor .btn-default[disabled]:active,\nfieldset[disabled] .note-editor .btn-default:active,\n.note-editor .btn-default.disabled.active,\n.note-editor .btn-default[disabled].active,\nfieldset[disabled] .note-editor .btn-default.active {\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.note-editor .btn-primary {\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.note-editor .btn-primary:hover,\n.note-editor .btn-primary:focus,\n.note-editor .btn-primary:active,\n.note-editor .btn-primary.active,\n.open .dropdown-toggle.note-editor .btn-primary {\n  color: #ffffff;\n  background-color: #3276b1;\n  border-color: #285e8e;\n}\n.note-editor .btn-primary:active,\n.note-editor .btn-primary.active,\n.open .dropdown-toggle.note-editor .btn-primary {\n  background-image: none;\n}\n.note-editor .btn-primary.disabled,\n.note-editor .btn-primary[disabled],\nfieldset[disabled] .note-editor .btn-primary,\n.note-editor .btn-primary.disabled:hover,\n.note-editor .btn-primary[disabled]:hover,\nfieldset[disabled] .note-editor .btn-primary:hover,\n.note-editor .btn-primary.disabled:focus,\n.note-editor .btn-primary[disabled]:focus,\nfieldset[disabled] .note-editor .btn-primary:focus,\n.note-editor .btn-primary.disabled:active,\n.note-editor .btn-primary[disabled]:active,\nfieldset[disabled] .note-editor .btn-primary:active,\n.note-editor .btn-primary.disabled.active,\n.note-editor .btn-primary[disabled].active,\nfieldset[disabled] .note-editor .btn-primary.active {\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.note-editor .btn-warning {\n  color: #ffffff;\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.note-editor .btn-warning:hover,\n.note-editor .btn-warning:focus,\n.note-editor .btn-warning:active,\n.note-editor .btn-warning.active,\n.open .dropdown-toggle.note-editor .btn-warning {\n  color: #ffffff;\n  background-color: #ed9c28;\n  border-color: #d58512;\n}\n.note-editor .btn-warning:active,\n.note-editor .btn-warning.active,\n.open .dropdown-toggle.note-editor .btn-warning {\n  background-image: none;\n}\n.note-editor .btn-warning.disabled,\n.note-editor .btn-warning[disabled],\nfieldset[disabled] .note-editor .btn-warning,\n.note-editor .btn-warning.disabled:hover,\n.note-editor .btn-warning[disabled]:hover,\nfieldset[disabled] .note-editor .btn-warning:hover,\n.note-editor .btn-warning.disabled:focus,\n.note-editor .btn-warning[disabled]:focus,\nfieldset[disabled] .note-editor .btn-warning:focus,\n.note-editor .btn-warning.disabled:active,\n.note-editor .btn-warning[disabled]:active,\nfieldset[disabled] .note-editor .btn-warning:active,\n.note-editor .btn-warning.disabled.active,\n.note-editor .btn-warning[disabled].active,\nfieldset[disabled] .note-editor .btn-warning.active {\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.note-editor .btn-danger {\n  color: #ffffff;\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.note-editor .btn-danger:hover,\n.note-editor .btn-danger:focus,\n.note-editor .btn-danger:active,\n.note-editor .btn-danger.active,\n.open .dropdown-toggle.note-editor .btn-danger {\n  color: #ffffff;\n  background-color: #d2322d;\n  border-color: #ac2925;\n}\n.note-editor .btn-danger:active,\n.note-editor .btn-danger.active,\n.open .dropdown-toggle.note-editor .btn-danger {\n  background-image: none;\n}\n.note-editor .btn-danger.disabled,\n.note-editor .btn-danger[disabled],\nfieldset[disabled] .note-editor .btn-danger,\n.note-editor .btn-danger.disabled:hover,\n.note-editor .btn-danger[disabled]:hover,\nfieldset[disabled] .note-editor .btn-danger:hover,\n.note-editor .btn-danger.disabled:focus,\n.note-editor .btn-danger[disabled]:focus,\nfieldset[disabled] .note-editor .btn-danger:focus,\n.note-editor .btn-danger.disabled:active,\n.note-editor .btn-danger[disabled]:active,\nfieldset[disabled] .note-editor .btn-danger:active,\n.note-editor .btn-danger.disabled.active,\n.note-editor .btn-danger[disabled].active,\nfieldset[disabled] .note-editor .btn-danger.active {\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.note-editor .btn-success {\n  color: #ffffff;\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.note-editor .btn-success:hover,\n.note-editor .btn-success:focus,\n.note-editor .btn-success:active,\n.note-editor .btn-success.active,\n.open .dropdown-toggle.note-editor .btn-success {\n  color: #ffffff;\n  background-color: #47a447;\n  border-color: #398439;\n}\n.note-editor .btn-success:active,\n.note-editor .btn-success.active,\n.open .dropdown-toggle.note-editor .btn-success {\n  background-image: none;\n}\n.note-editor .btn-success.disabled,\n.note-editor .btn-success[disabled],\nfieldset[disabled] .note-editor .btn-success,\n.note-editor .btn-success.disabled:hover,\n.note-editor .btn-success[disabled]:hover,\nfieldset[disabled] .note-editor .btn-success:hover,\n.note-editor .btn-success.disabled:focus,\n.note-editor .btn-success[disabled]:focus,\nfieldset[disabled] .note-editor .btn-success:focus,\n.note-editor .btn-success.disabled:active,\n.note-editor .btn-success[disabled]:active,\nfieldset[disabled] .note-editor .btn-success:active,\n.note-editor .btn-success.disabled.active,\n.note-editor .btn-success[disabled].active,\nfieldset[disabled] .note-editor .btn-success.active {\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.note-editor .btn-info {\n  color: #ffffff;\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.note-editor .btn-info:hover,\n.note-editor .btn-info:focus,\n.note-editor .btn-info:active,\n.note-editor .btn-info.active,\n.open .dropdown-toggle.note-editor .btn-info {\n  color: #ffffff;\n  background-color: #39b3d7;\n  border-color: #269abc;\n}\n.note-editor .btn-info:active,\n.note-editor .btn-info.active,\n.open .dropdown-toggle.note-editor .btn-info {\n  background-image: none;\n}\n.note-editor .btn-info.disabled,\n.note-editor .btn-info[disabled],\nfieldset[disabled] .note-editor .btn-info,\n.note-editor .btn-info.disabled:hover,\n.note-editor .btn-info[disabled]:hover,\nfieldset[disabled] .note-editor .btn-info:hover,\n.note-editor .btn-info.disabled:focus,\n.note-editor .btn-info[disabled]:focus,\nfieldset[disabled] .note-editor .btn-info:focus,\n.note-editor .btn-info.disabled:active,\n.note-editor .btn-info[disabled]:active,\nfieldset[disabled] .note-editor .btn-info:active,\n.note-editor .btn-info.disabled.active,\n.note-editor .btn-info[disabled].active,\nfieldset[disabled] .note-editor .btn-info.active {\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.note-editor .btn-link {\n  color: #428bca;\n  font-weight: normal;\n  cursor: pointer;\n  border-radius: 0;\n}\n.note-editor .btn-link,\n.note-editor .btn-link:active,\n.note-editor .btn-link[disabled],\nfieldset[disabled] .note-editor .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.note-editor .btn-link,\n.note-editor .btn-link:hover,\n.note-editor .btn-link:focus,\n.note-editor .btn-link:active {\n  border-color: transparent;\n}\n.note-editor .btn-link:hover,\n.note-editor .btn-link:focus {\n  color: #2a6496;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.note-editor .btn-link[disabled]:hover,\nfieldset[disabled] .note-editor .btn-link:hover,\n.note-editor .btn-link[disabled]:focus,\nfieldset[disabled] .note-editor .btn-link:focus {\n  color: #999999;\n  text-decoration: none;\n}\n.note-editor .btn-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\n.note-editor .btn-sm,\n.note-editor .btn-xs {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.note-editor .btn-xs {\n  padding: 1px 5px;\n}\n.note-editor .btn-block {\n  display: block;\n  width: 100%;\n  padding-left: 0;\n  padding-right: 0;\n}\n.note-editor .btn-block + .btn-block {\n  margin-top: 5px;\n}\n.note-editor input[type=\"submit\"].btn-block,\n.note-editor input[type=\"reset\"].btn-block,\n.note-editor input[type=\"button\"].btn-block {\n  width: 100%;\n}\n.note-editor .fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n  transition: opacity 0.15s linear;\n}\n.note-editor .fade.in {\n  opacity: 1;\n}\n.note-editor .collapse {\n  display: none;\n}\n.note-editor .collapse.in {\n  display: block;\n}\n.note-editor .collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition: height 0.35s ease;\n  transition: height 0.35s ease;\n}\n.note-editor .caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px solid #000000;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n  border-bottom: 0 dotted;\n}\n.note-editor .dropdown {\n  position: relative;\n}\n.note-editor .dropdown-toggle:focus {\n  outline: 0;\n}\n.note-editor .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  list-style: none;\n  font-size: 14px;\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  background-clip: padding-box;\n}\n.note-editor .dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.note-editor .dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.note-editor .dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.428571429;\n  color: #333333;\n  white-space: nowrap;\n}\n.note-editor .dropdown-menu > li > a:hover,\n.note-editor .dropdown-menu > li > a:focus {\n  text-decoration: none;\n  color: #262626;\n  background-color: #f5f5f5;\n}\n.note-editor .dropdown-menu > .active > a,\n.note-editor .dropdown-menu > .active > a:hover,\n.note-editor .dropdown-menu > .active > a:focus {\n  color: #ffffff;\n  text-decoration: none;\n  outline: 0;\n  background-color: #428bca;\n}\n.note-editor .dropdown-menu > .disabled > a,\n.note-editor .dropdown-menu > .disabled > a:hover,\n.note-editor .dropdown-menu > .disabled > a:focus {\n  color: #999999;\n}\n.note-editor .dropdown-menu > .disabled > a:hover,\n.note-editor .dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  cursor: not-allowed;\n}\n.note-editor .open > .dropdown-menu {\n  display: block;\n}\n.note-editor .open > a {\n  outline: 0;\n}\n.note-editor .dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.428571429;\n  color: #999999;\n}\n.note-editor .dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: 990;\n}\n.note-editor .pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.note-editor .dropup .caret,\n.note-editor .navbar-fixed-bottom .dropdown .caret {\n  border-top: 0 dotted;\n  border-bottom: 4px solid #000000;\n  content: \"\";\n}\n.note-editor .dropup .dropdown-menu,\n.note-editor .navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 1px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-right .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n}\n.btn-default .note-editor .caret {\n  border-top-color: #333333;\n}\n.btn-primary .note-editor .caret,\n.btn-success .note-editor .caret,\n.btn-warning .note-editor .caret,\n.btn-danger .note-editor .caret,\n.btn-info .note-editor .caret {\n  border-top-color: #fff;\n}\n.note-editor .dropup .btn-default .caret {\n  border-bottom-color: #333333;\n}\n.note-editor .dropup .btn-primary .caret,\n.note-editor .dropup .btn-success .caret,\n.note-editor .dropup .btn-warning .caret,\n.note-editor .dropup .btn-danger .caret,\n.note-editor .dropup .btn-info .caret {\n  border-bottom-color: #fff;\n}\n.note-editor .btn-group,\n.note-editor .btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.note-editor .btn-group > .btn,\n.note-editor .btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.note-editor .btn-group > .btn:hover,\n.note-editor .btn-group-vertical > .btn:hover,\n.note-editor .btn-group > .btn:focus,\n.note-editor .btn-group-vertical > .btn:focus,\n.note-editor .btn-group > .btn:active,\n.note-editor .btn-group-vertical > .btn:active,\n.note-editor .btn-group > .btn.active,\n.note-editor .btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.note-editor .btn-group > .btn:focus,\n.note-editor .btn-group-vertical > .btn:focus {\n  outline: none;\n}\n.note-editor .btn-group .btn + .btn,\n.note-editor .btn-group .btn + .btn-group,\n.note-editor .btn-group .btn-group + .btn,\n.note-editor .btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.note-editor .btn-toolbar:before,\n.note-editor .btn-toolbar:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .btn-toolbar:after {\n  clear: both;\n}\n.note-editor .btn-toolbar:before,\n.note-editor .btn-toolbar:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .btn-toolbar:after {\n  clear: both;\n}\n.note-editor .btn-toolbar .btn-group {\n  float: left;\n}\n.note-editor .btn-toolbar > .btn + .btn,\n.note-editor .btn-toolbar > .btn-group + .btn,\n.note-editor .btn-toolbar > .btn + .btn-group,\n.note-editor .btn-toolbar > .btn-group + .btn-group {\n  margin-left: 5px;\n}\n.note-editor .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.note-editor .btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.note-editor .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.note-editor .btn-group > .btn:last-child:not(:first-child),\n.note-editor .btn-group > .dropdown-toggle:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .btn-group > .btn-group {\n  float: left;\n}\n.note-editor .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.note-editor .btn-group > .btn-group:first-child > .btn:last-child,\n.note-editor .btn-group > .btn-group:first-child > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.note-editor .btn-group > .btn-group:last-child > .btn:first-child {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .btn-group .dropdown-toggle:active,\n.note-editor .btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.note-editor .btn-group-xs > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n  padding: 1px 5px;\n}\n.note-editor .btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.note-editor .btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\n.note-editor .btn-group > .btn + .dropdown-toggle {\n  padding-left: 5px;\n  padding-right: 5px;\n}\n.note-editor .btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n.note-editor .btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.note-editor .btn .caret {\n  margin-left: 0;\n}\n.note-editor .btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.note-editor .dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.note-editor .btn-group-vertical > .btn,\n.note-editor .btn-group-vertical > .btn-group {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.note-editor .btn-group-vertical > .btn-group:before,\n.note-editor .btn-group-vertical > .btn-group:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .btn-group-vertical > .btn-group:after {\n  clear: both;\n}\n.note-editor .btn-group-vertical > .btn-group:before,\n.note-editor .btn-group-vertical > .btn-group:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .btn-group-vertical > .btn-group:after {\n  clear: both;\n}\n.note-editor .btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.note-editor .btn-group-vertical > .btn + .btn,\n.note-editor .btn-group-vertical > .btn + .btn-group,\n.note-editor .btn-group-vertical > .btn-group + .btn,\n.note-editor .btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.note-editor .btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-bottom-left-radius: 4px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn-group:first-child > .btn:last-child,\n.note-editor .btn-group-vertical > .btn-group:first-child > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn-group:last-child > .btn:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.note-editor .btn-group-justified .btn {\n  float: none;\n  display: table-cell;\n  width: 1%;\n}\n.note-editor [data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n.note-editor [data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n  display: none;\n}\n.note-editor .input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.note-editor .input-group.col {\n  float: none;\n  padding-left: 0;\n  padding-right: 0;\n}\n.note-editor .input-group .form-control {\n  width: 100%;\n  margin-bottom: 0;\n}\n.note-editor .input-group-lg > .form-control,\n.note-editor .input-group-lg > .input-group-addon,\n.note-editor .input-group-lg > .input-group-btn > .btn {\n  height: 45px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\nselect.note-editor .input-group-lg > .form-control,\nselect.note-editor .input-group-lg > .input-group-addon,\nselect.note-editor .input-group-lg > .input-group-btn > .btn {\n  height: 45px;\n  line-height: 45px;\n}\ntextarea.note-editor .input-group-lg > .form-control,\ntextarea.note-editor .input-group-lg > .input-group-addon,\ntextarea.note-editor .input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.note-editor .input-group-sm > .form-control,\n.note-editor .input-group-sm > .input-group-addon,\n.note-editor .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.note-editor .input-group-sm > .form-control,\nselect.note-editor .input-group-sm > .input-group-addon,\nselect.note-editor .input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.note-editor .input-group-sm > .form-control,\ntextarea.note-editor .input-group-sm > .input-group-addon,\ntextarea.note-editor .input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.note-editor .input-group-addon,\n.note-editor .input-group-btn,\n.note-editor .input-group .form-control {\n  display: table-cell;\n}\n.note-editor .input-group-addon:not(:first-child):not(:last-child),\n.note-editor .input-group-btn:not(:first-child):not(:last-child),\n.note-editor .input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.note-editor .input-group-addon,\n.note-editor .input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.note-editor .input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555555;\n  text-align: center;\n  background-color: #eeeeee;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\n.note-editor .input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.note-editor .input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.note-editor .input-group-addon input[type=\"radio\"],\n.note-editor .input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.note-editor .input-group .form-control:first-child,\n.note-editor .input-group-addon:first-child,\n.note-editor .input-group-btn:first-child > .btn,\n.note-editor .input-group-btn:first-child > .dropdown-toggle,\n.note-editor .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.note-editor .input-group-addon:first-child {\n  border-right: 0;\n}\n.note-editor .input-group .form-control:last-child,\n.note-editor .input-group-addon:last-child,\n.note-editor .input-group-btn:last-child > .btn,\n.note-editor .input-group-btn:last-child > .dropdown-toggle,\n.note-editor .input-group-btn:first-child > .btn:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .input-group-addon:last-child {\n  border-left: 0;\n}\n.note-editor .input-group-btn {\n  position: relative;\n  white-space: nowrap;\n}\n.note-editor .input-group-btn:first-child > .btn {\n  margin-right: -1px;\n}\n.note-editor .input-group-btn:last-child > .btn {\n  margin-left: -1px;\n}\n.note-editor .input-group-btn > .btn {\n  position: relative;\n}\n.note-editor .input-group-btn > .btn + .btn {\n  margin-left: -4px;\n}\n.note-editor .input-group-btn > .btn:hover,\n.note-editor .input-group-btn > .btn:active {\n  z-index: 2;\n}\n.note-editor .nav {\n  margin-bottom: 0;\n  padding-left: 0;\n  list-style: none;\n}\n.note-editor .nav:before,\n.note-editor .nav:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .nav:after {\n  clear: both;\n}\n.note-editor .nav:before,\n.note-editor .nav:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .nav:after {\n  clear: both;\n}\n.note-editor .nav > li {\n  position: relative;\n  display: block;\n}\n.note-editor .nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.note-editor .nav > li > a:hover,\n.note-editor .nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.note-editor .nav > li.disabled > a {\n  color: #999999;\n}\n.note-editor .nav > li.disabled > a:hover,\n.note-editor .nav > li.disabled > a:focus {\n  color: #999999;\n  text-decoration: none;\n  background-color: transparent;\n  cursor: not-allowed;\n}\n.note-editor .nav .open > a,\n.note-editor .nav .open > a:hover,\n.note-editor .nav .open > a:focus {\n  background-color: #eeeeee;\n  border-color: #428bca;\n}\n.note-editor .nav .open > a .caret,\n.note-editor .nav .open > a:hover .caret,\n.note-editor .nav .open > a:focus .caret {\n  border-top-color: #2a6496;\n  border-bottom-color: #2a6496;\n}\n.note-editor .nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.note-editor .nav > li > a > img {\n  max-width: none;\n}\n.note-editor .nav-tabs {\n  border-bottom: 1px solid #dddddd;\n}\n.note-editor .nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.note-editor .nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.428571429;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.note-editor .nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #dddddd;\n}\n.note-editor .nav-tabs > li.active > a,\n.note-editor .nav-tabs > li.active > a:hover,\n.note-editor .nav-tabs > li.active > a:focus {\n  color: #555555;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-bottom-color: transparent;\n  cursor: default;\n}\n.note-editor .nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.note-editor .nav-tabs.nav-justified > li {\n  float: none;\n}\n.note-editor .nav-tabs.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n@media (min-width: 768px) {\n  .note-editor .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .note-editor .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.note-editor .nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.note-editor .nav-tabs.nav-justified > .active > a,\n.note-editor .nav-tabs.nav-justified > .active > a:hover,\n.note-editor .nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .note-editor .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .note-editor .nav-tabs.nav-justified > .active > a,\n  .note-editor .nav-tabs.nav-justified > .active > a:hover,\n  .note-editor .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #ffffff;\n  }\n}\n.note-editor .nav-pills > li {\n  float: left;\n}\n.note-editor .nav-pills > li > a {\n  border-radius: 4px;\n}\n.note-editor .nav-pills > li + li {\n  margin-left: 2px;\n}\n.note-editor .nav-pills > li.active > a,\n.note-editor .nav-pills > li.active > a:hover,\n.note-editor .nav-pills > li.active > a:focus {\n  color: #ffffff;\n  background-color: #428bca;\n}\n.note-editor .nav-pills > li.active > a .caret,\n.note-editor .nav-pills > li.active > a:hover .caret,\n.note-editor .nav-pills > li.active > a:focus .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n.note-editor .nav-stacked > li {\n  float: none;\n}\n.note-editor .nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.note-editor .nav-justified {\n  width: 100%;\n}\n.note-editor .nav-justified > li {\n  float: none;\n}\n.note-editor .nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n@media (min-width: 768px) {\n  .note-editor .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .note-editor .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.note-editor .nav-tabs-justified {\n  border-bottom: 0;\n}\n.note-editor .nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.note-editor .nav-tabs-justified > .active > a,\n.note-editor .nav-tabs-justified > .active > a:hover,\n.note-editor .nav-tabs-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .note-editor .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .note-editor .nav-tabs-justified > .active > a,\n  .note-editor .nav-tabs-justified > .active > a:hover,\n  .note-editor .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #ffffff;\n  }\n}\n.note-editor .tab-content > .tab-pane {\n  display: none;\n}\n.note-editor .tab-content > .active {\n  display: block;\n}\n.note-editor .nav .caret {\n  border-top-color: #428bca;\n  border-bottom-color: #428bca;\n}\n.note-editor .nav a:hover .caret {\n  border-top-color: #2a6496;\n  border-bottom-color: #2a6496;\n}\n.note-editor .nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .navbar {\n  position: relative;\n  z-index: 1000;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n.note-editor .navbar:before,\n.note-editor .navbar:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar:after {\n  clear: both;\n}\n.note-editor .navbar:before,\n.note-editor .navbar:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar {\n    border-radius: 4px;\n  }\n}\n.note-editor .navbar-header:before,\n.note-editor .navbar-header:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar-header:after {\n  clear: both;\n}\n.note-editor .navbar-header:before,\n.note-editor .navbar-header:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar-header:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-header {\n    float: left;\n  }\n}\n.note-editor .navbar-collapse {\n  max-height: 340px;\n  overflow-x: visible;\n  padding-right: 15px;\n  padding-left: 15px;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n  -webkit-overflow-scrolling: touch;\n}\n.note-editor .navbar-collapse:before,\n.note-editor .navbar-collapse:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar-collapse:after {\n  clear: both;\n}\n.note-editor .navbar-collapse:before,\n.note-editor .navbar-collapse:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar-collapse:after {\n  clear: both;\n}\n.note-editor .navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n  }\n  .note-editor .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .note-editor .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .note-editor .navbar-collapse .navbar-nav.navbar-left:first-child {\n    margin-left: -15px;\n  }\n  .note-editor .navbar-collapse .navbar-nav.navbar-right:last-child {\n    margin-right: -15px;\n  }\n  .note-editor .navbar-collapse .navbar-text:last-child {\n    margin-right: 0;\n  }\n}\n.note-editor .container > .navbar-header,\n.note-editor .container > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .note-editor .container > .navbar-header,\n  .note-editor .container > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.note-editor .navbar-static-top {\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.note-editor .navbar-fixed-top,\n.note-editor .navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-fixed-top,\n  .note-editor .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.note-editor .navbar-fixed-top {\n  z-index: 1030;\n  top: 0;\n}\n.note-editor .navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n}\n.note-editor .navbar-brand {\n  float: left;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n}\n.note-editor .navbar-brand:hover,\n.note-editor .navbar-brand:focus {\n  text-decoration: none;\n}\n@media (min-width: 768px) {\n  .navbar > .container .note-editor .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.note-editor .navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: 15px;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.note-editor .navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.note-editor .navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-toggle {\n    display: none;\n  }\n}\n.note-editor .navbar-nav {\n  margin: 7.5px -15px;\n}\n.note-editor .navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .note-editor .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    box-shadow: none;\n  }\n  .note-editor .navbar-nav .open .dropdown-menu > li > a,\n  .note-editor .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .note-editor .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .note-editor .navbar-nav .open .dropdown-menu > li > a:hover,\n  .note-editor .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .note-editor .navbar-nav > li {\n    float: left;\n  }\n  .note-editor .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-left {\n    float: left !important;\n  }\n  .note-editor .navbar-right {\n    float: right !important;\n  }\n}\n.note-editor .navbar-form {\n  margin-left: -15px;\n  margin-right: -15px;\n  padding: 10px 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, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .note-editor .navbar-form .form-control {\n    display: inline-block;\n  }\n  .note-editor .navbar-form .radio,\n  .note-editor .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-left: 0;\n  }\n  .note-editor .navbar-form .radio input[type=\"radio\"],\n  .note-editor .navbar-form .checkbox input[type=\"checkbox\"] {\n    float: none;\n    margin-left: 0;\n  }\n}\n@media (max-width: 767px) {\n  .note-editor .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-form {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n}\n.note-editor .navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.note-editor .navbar-nav.pull-right > li > .dropdown-menu,\n.note-editor .navbar-nav > li > .dropdown-menu.pull-right {\n  left: auto;\n  right: 0;\n}\n.note-editor .navbar-btn {\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n.note-editor .navbar-text {\n  float: left;\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-text {\n    margin-left: 15px;\n    margin-right: 15px;\n  }\n}\n.note-editor .navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.note-editor .navbar-default .navbar-brand {\n  color: #777777;\n}\n.note-editor .navbar-default .navbar-brand:hover,\n.note-editor .navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.note-editor .navbar-default .navbar-text {\n  color: #777777;\n}\n.note-editor .navbar-default .navbar-nav > li > a {\n  color: #777777;\n}\n.note-editor .navbar-default .navbar-nav > li > a:hover,\n.note-editor .navbar-default .navbar-nav > li > a:focus {\n  color: #333333;\n  background-color: transparent;\n}\n.note-editor .navbar-default .navbar-nav > .active > a,\n.note-editor .navbar-default .navbar-nav > .active > a:hover,\n.note-editor .navbar-default .navbar-nav > .active > a:focus {\n  color: #555555;\n  background-color: #e7e7e7;\n}\n.note-editor .navbar-default .navbar-nav > .disabled > a,\n.note-editor .navbar-default .navbar-nav > .disabled > a:hover,\n.note-editor .navbar-default .navbar-nav > .disabled > a:focus {\n  color: #cccccc;\n  background-color: transparent;\n}\n.note-editor .navbar-default .navbar-toggle {\n  border-color: #dddddd;\n}\n.note-editor .navbar-default .navbar-toggle:hover,\n.note-editor .navbar-default .navbar-toggle:focus {\n  background-color: #dddddd;\n}\n.note-editor .navbar-default .navbar-toggle .icon-bar {\n  background-color: #cccccc;\n}\n.note-editor .navbar-default .navbar-collapse,\n.note-editor .navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.note-editor .navbar-default .navbar-nav > .dropdown > a:hover .caret,\n.note-editor .navbar-default .navbar-nav > .dropdown > a:focus .caret {\n  border-top-color: #333333;\n  border-bottom-color: #333333;\n}\n.note-editor .navbar-default .navbar-nav > .open > a,\n.note-editor .navbar-default .navbar-nav > .open > a:hover,\n.note-editor .navbar-default .navbar-nav > .open > a:focus {\n  background-color: #e7e7e7;\n  color: #555555;\n}\n.note-editor .navbar-default .navbar-nav > .open > a .caret,\n.note-editor .navbar-default .navbar-nav > .open > a:hover .caret,\n.note-editor .navbar-default .navbar-nav > .open > a:focus .caret {\n  border-top-color: #555555;\n  border-bottom-color: #555555;\n}\n.note-editor .navbar-default .navbar-nav > .dropdown > a .caret {\n  border-top-color: #777777;\n  border-bottom-color: #777777;\n}\n@media (max-width: 767px) {\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777777;\n  }\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333333;\n    background-color: transparent;\n  }\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #555555;\n    background-color: #e7e7e7;\n  }\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #cccccc;\n    background-color: transparent;\n  }\n}\n.note-editor .navbar-default .navbar-link {\n  color: #777777;\n}\n.note-editor .navbar-default .navbar-link:hover {\n  color: #333333;\n}\n.note-editor .navbar-inverse {\n  background-color: #222222;\n  border-color: #080808;\n}\n.note-editor .navbar-inverse .navbar-brand {\n  color: #999999;\n}\n.note-editor .navbar-inverse .navbar-brand:hover,\n.note-editor .navbar-inverse .navbar-brand:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.note-editor .navbar-inverse .navbar-text {\n  color: #999999;\n}\n.note-editor .navbar-inverse .navbar-nav > li > a {\n  color: #999999;\n}\n.note-editor .navbar-inverse .navbar-nav > li > a:hover,\n.note-editor .navbar-inverse .navbar-nav > li > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.note-editor .navbar-inverse .navbar-nav > .active > a,\n.note-editor .navbar-inverse .navbar-nav > .active > a:hover,\n.note-editor .navbar-inverse .navbar-nav > .active > a:focus {\n  color: #ffffff;\n  background-color: #080808;\n}\n.note-editor .navbar-inverse .navbar-nav > .disabled > a,\n.note-editor .navbar-inverse .navbar-nav > .disabled > a:hover,\n.note-editor .navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444444;\n  background-color: transparent;\n}\n.note-editor .navbar-inverse .navbar-toggle {\n  border-color: #333333;\n}\n.note-editor .navbar-inverse .navbar-toggle:hover,\n.note-editor .navbar-inverse .navbar-toggle:focus {\n  background-color: #333333;\n}\n.note-editor .navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #ffffff;\n}\n.note-editor .navbar-inverse .navbar-collapse,\n.note-editor .navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.note-editor .navbar-inverse .navbar-nav > .open > a,\n.note-editor .navbar-inverse .navbar-nav > .open > a:hover,\n.note-editor .navbar-inverse .navbar-nav > .open > a:focus {\n  background-color: #080808;\n  color: #ffffff;\n}\n.note-editor .navbar-inverse .navbar-nav > .dropdown > a:hover .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n.note-editor .navbar-inverse .navbar-nav > .dropdown > a .caret {\n  border-top-color: #999999;\n  border-bottom-color: #999999;\n}\n.note-editor .navbar-inverse .navbar-nav > .open > a .caret,\n.note-editor .navbar-inverse .navbar-nav > .open > a:hover .caret,\n.note-editor .navbar-inverse .navbar-nav > .open > a:focus .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n@media (max-width: 767px) {\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #999999;\n  }\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #ffffff;\n    background-color: transparent;\n  }\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #ffffff;\n    background-color: #080808;\n  }\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444444;\n    background-color: transparent;\n  }\n}\n.note-editor .navbar-inverse .navbar-link {\n  color: #999999;\n}\n.note-editor .navbar-inverse .navbar-link:hover {\n  color: #ffffff;\n}\n.note-editor .breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.note-editor .breadcrumb > li {\n  display: inline-block;\n}\n.note-editor .breadcrumb > li + li:before {\n  content: \"/\\00a0\";\n  padding: 0 5px;\n  color: #cccccc;\n}\n.note-editor .breadcrumb > .active {\n  color: #999999;\n}\n.note-editor .pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.note-editor .pagination > li {\n  display: inline;\n}\n.note-editor .pagination > li > a,\n.note-editor .pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  line-height: 1.428571429;\n  text-decoration: none;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  margin-left: -1px;\n}\n.note-editor .pagination > li:first-child > a,\n.note-editor .pagination > li:first-child > span {\n  margin-left: 0;\n  border-bottom-left-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.note-editor .pagination > li:last-child > a,\n.note-editor .pagination > li:last-child > span {\n  border-bottom-right-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.note-editor .pagination > li > a:hover,\n.note-editor .pagination > li > span:hover,\n.note-editor .pagination > li > a:focus,\n.note-editor .pagination > li > span:focus {\n  background-color: #eeeeee;\n}\n.note-editor .pagination > .active > a,\n.note-editor .pagination > .active > span,\n.note-editor .pagination > .active > a:hover,\n.note-editor .pagination > .active > span:hover,\n.note-editor .pagination > .active > a:focus,\n.note-editor .pagination > .active > span:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n  cursor: default;\n}\n.note-editor .pagination > .disabled > span,\n.note-editor .pagination > .disabled > span:hover,\n.note-editor .pagination > .disabled > span:focus,\n.note-editor .pagination > .disabled > a,\n.note-editor .pagination > .disabled > a:hover,\n.note-editor .pagination > .disabled > a:focus {\n  color: #999999;\n  background-color: #ffffff;\n  border-color: #dddddd;\n  cursor: not-allowed;\n}\n.note-editor .pagination-lg > li > a,\n.note-editor .pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n}\n.note-editor .pagination-lg > li:first-child > a,\n.note-editor .pagination-lg > li:first-child > span {\n  border-bottom-left-radius: 6px;\n  border-top-left-radius: 6px;\n}\n.note-editor .pagination-lg > li:last-child > a,\n.note-editor .pagination-lg > li:last-child > span {\n  border-bottom-right-radius: 6px;\n  border-top-right-radius: 6px;\n}\n.note-editor .pagination-sm > li > a,\n.note-editor .pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n}\n.note-editor .pagination-sm > li:first-child > a,\n.note-editor .pagination-sm > li:first-child > span {\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.note-editor .pagination-sm > li:last-child > a,\n.note-editor .pagination-sm > li:last-child > span {\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.note-editor .pager {\n  padding-left: 0;\n  margin: 20px 0;\n  list-style: none;\n  text-align: center;\n}\n.note-editor .pager:before,\n.note-editor .pager:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .pager:after {\n  clear: both;\n}\n.note-editor .pager:before,\n.note-editor .pager:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .pager:after {\n  clear: both;\n}\n.note-editor .pager li {\n  display: inline;\n}\n.note-editor .pager li > a,\n.note-editor .pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 15px;\n}\n.note-editor .pager li > a:hover,\n.note-editor .pager li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.note-editor .pager .next > a,\n.note-editor .pager .next > span {\n  float: right;\n}\n.note-editor .pager .previous > a,\n.note-editor .pager .previous > span {\n  float: left;\n}\n.note-editor .pager .disabled > a,\n.note-editor .pager .disabled > a:hover,\n.note-editor .pager .disabled > a:focus,\n.note-editor .pager .disabled > span {\n  color: #999999;\n  background-color: #ffffff;\n  cursor: not-allowed;\n}\n.note-editor .label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #ffffff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\n.note-editor .label[href]:hover,\n.note-editor .label[href]:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.note-editor .label:empty {\n  display: none;\n}\n.note-editor .label-default {\n  background-color: #999999;\n}\n.note-editor .label-default[href]:hover,\n.note-editor .label-default[href]:focus {\n  background-color: #808080;\n}\n.note-editor .label-primary {\n  background-color: #428bca;\n}\n.note-editor .label-primary[href]:hover,\n.note-editor .label-primary[href]:focus {\n  background-color: #3071a9;\n}\n.note-editor .label-success {\n  background-color: #5cb85c;\n}\n.note-editor .label-success[href]:hover,\n.note-editor .label-success[href]:focus {\n  background-color: #449d44;\n}\n.note-editor .label-info {\n  background-color: #5bc0de;\n}\n.note-editor .label-info[href]:hover,\n.note-editor .label-info[href]:focus {\n  background-color: #31b0d5;\n}\n.note-editor .label-warning {\n  background-color: #f0ad4e;\n}\n.note-editor .label-warning[href]:hover,\n.note-editor .label-warning[href]:focus {\n  background-color: #ec971f;\n}\n.note-editor .label-danger {\n  background-color: #d9534f;\n}\n.note-editor .label-danger[href]:hover,\n.note-editor .label-danger[href]:focus {\n  background-color: #c9302c;\n}\n.note-editor .badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  color: #ffffff;\n  line-height: 1;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: #999999;\n  border-radius: 10px;\n}\n.note-editor .badge:empty {\n  display: none;\n}\n.note-editor a.badge:hover,\n.note-editor a.badge:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.note-editor .btn .badge {\n  position: relative;\n  top: -1px;\n}\n.note-editor a.list-group-item.active > .badge,\n.note-editor .nav-pills > .active > a > .badge {\n  color: #428bca;\n  background-color: #ffffff;\n}\n.note-editor .nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.note-editor .jumbotron {\n  padding: 30px;\n  margin-bottom: 30px;\n  font-size: 21px;\n  font-weight: 200;\n  line-height: 2.1428571435;\n  color: inherit;\n  background-color: #eeeeee;\n}\n.note-editor .jumbotron h1 {\n  line-height: 1;\n  color: inherit;\n}\n.note-editor .jumbotron p {\n  line-height: 1.4;\n}\n.container .note-editor .jumbotron {\n  border-radius: 6px;\n}\n@media screen and (min-width: 768px) {\n  .note-editor .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .note-editor .jumbotron {\n    padding-left: 60px;\n    padding-right: 60px;\n  }\n  .note-editor .jumbotron h1 {\n    font-size: 63px;\n  }\n}\n.note-editor .thumbnail {\n  padding: 4px;\n  line-height: 1.428571429;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n  display: block;\n  margin-bottom: 20px;\n}\n.note-editor .thumbnail > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.note-editor a.thumbnail:hover,\n.note-editor a.thumbnail:focus,\n.note-editor a.thumbnail.active {\n  border-color: #428bca;\n}\n.note-editor .thumbnail > img {\n  margin-left: auto;\n  margin-right: auto;\n}\n.note-editor .thumbnail .caption {\n  padding: 9px;\n  color: #333333;\n}\n.note-editor .alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.note-editor .alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.note-editor .alert .alert-link {\n  font-weight: bold;\n}\n.note-editor .alert > p,\n.note-editor .alert > ul {\n  margin-bottom: 0;\n}\n.note-editor .alert > p + p {\n  margin-top: 5px;\n}\n.note-editor .alert-dismissable {\n  padding-right: 35px;\n}\n.note-editor .alert-dismissable .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.note-editor .alert-success {\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n  color: #468847;\n}\n.note-editor .alert-success hr {\n  border-top-color: #c9e2b3;\n}\n.note-editor .alert-success .alert-link {\n  color: #356635;\n}\n.note-editor .alert-info {\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n  color: #3a87ad;\n}\n.note-editor .alert-info hr {\n  border-top-color: #a6e1ec;\n}\n.note-editor .alert-info .alert-link {\n  color: #2d6987;\n}\n.note-editor .alert-warning {\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n  color: #c09853;\n}\n.note-editor .alert-warning hr {\n  border-top-color: #f7e1b5;\n}\n.note-editor .alert-warning .alert-link {\n  color: #a47e3c;\n}\n.note-editor .alert-danger {\n  background-color: #f2dede;\n  border-color: #ebccd1;\n  color: #b94a48;\n}\n.note-editor .alert-danger hr {\n  border-top-color: #e4b9c0;\n}\n.note-editor .alert-danger .alert-link {\n  color: #953b39;\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@-moz-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: 0 0;\n  }\n  to {\n    background-position: 40px 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.note-editor .progress {\n  overflow: hidden;\n  height: 20px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.note-editor .progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #428bca;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n.note-editor .progress-striped .progress-bar {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-size: 40px 40px;\n}\n.note-editor .progress.active .progress-bar {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n  -moz-animation: progress-bar-stripes 2s linear infinite;\n  -ms-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.note-editor .progress-bar-success {\n  background-color: #5cb85c;\n}\n.progress-striped .note-editor .progress-bar-success {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.note-editor .progress-bar-info {\n  background-color: #5bc0de;\n}\n.progress-striped .note-editor .progress-bar-info {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.note-editor .progress-bar-warning {\n  background-color: #f0ad4e;\n}\n.progress-striped .note-editor .progress-bar-warning {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.note-editor .progress-bar-danger {\n  background-color: #d9534f;\n}\n.progress-striped .note-editor .progress-bar-danger {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.note-editor .media,\n.note-editor .media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n.note-editor .media,\n.note-editor .media .media {\n  margin-top: 15px;\n}\n.note-editor .media:first-child {\n  margin-top: 0;\n}\n.note-editor .media-object {\n  display: block;\n}\n.note-editor .media-heading {\n  margin: 0 0 5px;\n}\n.note-editor .media > .pull-left {\n  margin-right: 10px;\n}\n.note-editor .media > .pull-right {\n  margin-left: 10px;\n}\n.note-editor .media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.note-editor .list-group {\n  margin-bottom: 20px;\n  padding-left: 0;\n}\n.note-editor .list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n}\n.note-editor .list-group-item:first-child {\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.note-editor .list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.note-editor .list-group-item > .badge {\n  float: right;\n}\n.note-editor .list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.note-editor a.list-group-item {\n  color: #555555;\n}\n.note-editor a.list-group-item .list-group-item-heading {\n  color: #333333;\n}\n.note-editor a.list-group-item:hover,\n.note-editor a.list-group-item:focus {\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.note-editor a.list-group-item.active,\n.note-editor a.list-group-item.active:hover,\n.note-editor a.list-group-item.active:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.note-editor a.list-group-item.active .list-group-item-heading,\n.note-editor a.list-group-item.active:hover .list-group-item-heading,\n.note-editor a.list-group-item.active:focus .list-group-item-heading {\n  color: inherit;\n}\n.note-editor a.list-group-item.active .list-group-item-text,\n.note-editor a.list-group-item.active:hover .list-group-item-text,\n.note-editor a.list-group-item.active:focus .list-group-item-text {\n  color: #e1edf7;\n}\n.note-editor .list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.note-editor .list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.note-editor .panel {\n  margin-bottom: 20px;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.note-editor .panel-body {\n  padding: 15px;\n}\n.note-editor .panel-body:before,\n.note-editor .panel-body:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .panel-body:after {\n  clear: both;\n}\n.note-editor .panel-body:before,\n.note-editor .panel-body:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .panel-body:after {\n  clear: both;\n}\n.note-editor .panel > .list-group {\n  margin-bottom: 0;\n}\n.note-editor .panel > .list-group .list-group-item {\n  border-width: 1px 0;\n}\n.note-editor .panel > .list-group .list-group-item:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .panel > .list-group .list-group-item:last-child {\n  border-bottom: 0;\n}\n.note-editor .panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.note-editor .panel > .table,\n.note-editor .panel > .table-responsive {\n  margin-bottom: 0;\n}\n.note-editor .panel > .panel-body + .table,\n.note-editor .panel > .panel-body + .table-responsive {\n  border-top: 1px solid #dddddd;\n}\n.note-editor .panel > .table-bordered,\n.note-editor .panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.note-editor .panel > .table-bordered > thead > tr > th:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.note-editor .panel > .table-bordered > tbody > tr > th:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.note-editor .panel > .table-bordered > tfoot > tr > th:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.note-editor .panel > .table-bordered > thead > tr > td:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.note-editor .panel > .table-bordered > tbody > tr > td:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.note-editor .panel > .table-bordered > tfoot > tr > td:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.note-editor .panel > .table-bordered > thead > tr > th:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.note-editor .panel > .table-bordered > tbody > tr > th:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.note-editor .panel > .table-bordered > tfoot > tr > th:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.note-editor .panel > .table-bordered > thead > tr > td:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.note-editor .panel > .table-bordered > tbody > tr > td:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.note-editor .panel > .table-bordered > tfoot > tr > td:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.note-editor .panel > .table-bordered > thead > tr:last-child > th,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr:last-child > th,\n.note-editor .panel > .table-bordered > tbody > tr:last-child > th,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.note-editor .panel > .table-bordered > tfoot > tr:last-child > th,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n.note-editor .panel > .table-bordered > thead > tr:last-child > td,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr:last-child > td,\n.note-editor .panel > .table-bordered > tbody > tr:last-child > td,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.note-editor .panel > .table-bordered > tfoot > tr:last-child > td,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n  border-bottom: 0;\n}\n.note-editor .panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.note-editor .panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n}\n.note-editor .panel-title > a {\n  color: inherit;\n}\n.note-editor .panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #dddddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.note-editor .panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n  overflow: hidden;\n}\n.note-editor .panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.note-editor .panel-group .panel-heading {\n  border-bottom: 0;\n}\n.note-editor .panel-group .panel-heading + .panel-collapse .panel-body {\n  border-top: 1px solid #dddddd;\n}\n.note-editor .panel-group .panel-footer {\n  border-top: 0;\n}\n.note-editor .panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #dddddd;\n}\n.note-editor .panel-default {\n  border-color: #dddddd;\n}\n.note-editor .panel-default > .panel-heading {\n  color: #333333;\n  background-color: #f5f5f5;\n  border-color: #dddddd;\n}\n.note-editor .panel-default > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #dddddd;\n}\n.note-editor .panel-default > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #dddddd;\n}\n.note-editor .panel-primary {\n  border-color: #428bca;\n}\n.note-editor .panel-primary > .panel-heading {\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.note-editor .panel-primary > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #428bca;\n}\n.note-editor .panel-primary > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #428bca;\n}\n.note-editor .panel-success {\n  border-color: #d6e9c6;\n}\n.note-editor .panel-success > .panel-heading {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.note-editor .panel-success > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #d6e9c6;\n}\n.note-editor .panel-success > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #d6e9c6;\n}\n.note-editor .panel-warning {\n  border-color: #faebcc;\n}\n.note-editor .panel-warning > .panel-heading {\n  color: #c09853;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.note-editor .panel-warning > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #faebcc;\n}\n.note-editor .panel-warning > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #faebcc;\n}\n.note-editor .panel-danger {\n  border-color: #ebccd1;\n}\n.note-editor .panel-danger > .panel-heading {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.note-editor .panel-danger > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #ebccd1;\n}\n.note-editor .panel-danger > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #ebccd1;\n}\n.note-editor .panel-info {\n  border-color: #bce8f1;\n}\n.note-editor .panel-info > .panel-heading {\n  color: #3a87ad;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.note-editor .panel-info > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #bce8f1;\n}\n.note-editor .panel-info > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #bce8f1;\n}\n.note-editor .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, 0.05);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.note-editor .well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n.note-editor .well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.note-editor .well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.note-editor .close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n.note-editor .close:hover,\n.note-editor .close:focus {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\nbutton.note-editor .close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  display: none;\n  overflow: auto;\n  overflow-y: scroll;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n}\n.modal.fade .modal-dialog {\n  -webkit-transform: translate(0, -25%);\n  -ms-transform: translate(0, -25%);\n  transform: translate(0, -25%);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -moz-transition: -moz-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n  -ms-transform: translate(0, 0);\n  transform: translate(0, 0);\n}\n.modal-dialog {\n  margin-left: auto;\n  margin-right: auto;\n  width: auto;\n  padding: 10px;\n  z-index: 1050;\n}\n.modal-content {\n  position: relative;\n  background-color: #ffffff;\n  border: 1px solid #999999;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  background-clip: padding-box;\n  outline: none;\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1030;\n  background-color: #000000;\n}\n.modal-backdrop.fade {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n  min-height: 16.428571429px;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.428571429;\n}\n.modal-body {\n  position: relative;\n  padding: 20px;\n}\n.modal-footer {\n  margin-top: 15px;\n  padding: 19px 20px 20px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer:before,\n.modal-footer:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.modal-footer:after {\n  clear: both;\n}\n.modal-footer:before,\n.modal-footer:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.modal-footer:after {\n  clear: both;\n}\n.modal-footer .btn + .btn {\n  margin-left: 5px;\n  margin-bottom: 0;\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@media screen and (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    padding-top: 30px;\n    padding-bottom: 30px;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1030;\n  display: block;\n  visibility: visible;\n  font-size: 12px;\n  line-height: 1.4;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.tooltip.in {\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.tooltip.top {\n  margin-top: -3px;\n  padding: 5px 0;\n}\n.tooltip.right {\n  margin-left: 3px;\n  padding: 0 5px;\n}\n.tooltip.bottom {\n  margin-top: 3px;\n  padding: 5px 0;\n}\n.tooltip.left {\n  margin-left: -3px;\n  padding: 0 5px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  text-decoration: none;\n  background-color: #000000;\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: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  right: 5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\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: #000000;\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: #000000;\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: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1010;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  text-align: left;\n  background-color: #ffffff;\n  background-clip: padding-box;\n  border: 1px solid #cccccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  white-space: normal;\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  margin: 0;\n  padding: 8px 14px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 18px;\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  border-width: 10px;\n  content: \"\";\n}\n.popover.top .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-width: 0;\n  border-top-color: #999999;\n  border-top-color: rgba(0, 0, 0, 0.25);\n  bottom: -11px;\n}\n.popover.top .arrow:after {\n  content: \" \";\n  bottom: 1px;\n  margin-left: -10px;\n  border-bottom-width: 0;\n  border-top-color: #ffffff;\n}\n.popover.right .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-left-width: 0;\n  border-right-color: #999999;\n  border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right .arrow:after {\n  content: \" \";\n  left: 1px;\n  bottom: -10px;\n  border-left-width: 0;\n  border-right-color: #ffffff;\n}\n.popover.bottom .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999999;\n  border-bottom-color: rgba(0, 0, 0, 0.25);\n  top: -11px;\n}\n.popover.bottom .arrow:after {\n  content: \" \";\n  top: 1px;\n  margin-left: -10px;\n  border-top-width: 0;\n  border-bottom-color: #ffffff;\n}\n.popover.left .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999999;\n  border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left .arrow:after {\n  content: \" \";\n  right: 1px;\n  border-right-width: 0;\n  border-left-color: #ffffff;\n  bottom: -10px;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n.carousel-inner > .item {\n  display: none;\n  position: relative;\n  -webkit-transition: 0.6s ease-in-out left;\n  transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n  line-height: 1;\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  left: 0;\n  bottom: 0;\n  width: 15%;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-size: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n  background-image: -webkit-gradient(linear, 0% top, 100% top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001)));\n  background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0%), color-stop(rgba(0, 0, 0, 0.0001) 100%));\n  background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n  left: auto;\n  right: 0;\n  background-image: -webkit-gradient(linear, 0% top, 100% top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5)));\n  background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0%), color-stop(rgba(0, 0, 0, 0.5) 100%));\n  background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\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}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  margin-top: -10px;\n  margin-left: -10px;\n  font-family: serif;\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  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  border: 1px solid #ffffff;\n  border-radius: 10px;\n  cursor: pointer;\n}\n.carousel-indicators .active {\n  margin: 0;\n  width: 12px;\n  height: 12px;\n  background-color: #ffffff;\n}\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicons-chevron-left,\n  .carousel-control .glyphicons-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -15px;\n    margin-left: -15px;\n    font-size: 30px;\n  }\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.clearfix:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-left: auto;\n  margin-right: 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  visibility: hidden !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\ntr.visible-xs,\nth.visible-xs,\ntd.visible-xs {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !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 (min-width: 768px) and (max-width: 991px) {\n  .visible-xs.visible-sm {\n    display: block !important;\n  }\n  tr.visible-xs.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-xs.visible-sm,\n  td.visible-xs.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-xs.visible-md {\n    display: block !important;\n  }\n  tr.visible-xs.visible-md {\n    display: table-row !important;\n  }\n  th.visible-xs.visible-md,\n  td.visible-xs.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-xs.visible-lg {\n    display: block !important;\n  }\n  tr.visible-xs.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-xs.visible-lg,\n  td.visible-xs.visible-lg {\n    display: table-cell !important;\n  }\n}\n.visible-sm,\ntr.visible-sm,\nth.visible-sm,\ntd.visible-sm {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-sm.visible-xs {\n    display: block !important;\n  }\n  tr.visible-sm.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-sm.visible-xs,\n  td.visible-sm.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !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: 992px) and (max-width: 1199px) {\n  .visible-sm.visible-md {\n    display: block !important;\n  }\n  tr.visible-sm.visible-md {\n    display: table-row !important;\n  }\n  th.visible-sm.visible-md,\n  td.visible-sm.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-sm.visible-lg {\n    display: block !important;\n  }\n  tr.visible-sm.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-sm.visible-lg,\n  td.visible-sm.visible-lg {\n    display: table-cell !important;\n  }\n}\n.visible-md,\ntr.visible-md,\nth.visible-md,\ntd.visible-md {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-md.visible-xs {\n    display: block !important;\n  }\n  tr.visible-md.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-md.visible-xs,\n  td.visible-md.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-md.visible-sm {\n    display: block !important;\n  }\n  tr.visible-md.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-md.visible-sm,\n  td.visible-md.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !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: 1200px) {\n  .visible-md.visible-lg {\n    display: block !important;\n  }\n  tr.visible-md.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-md.visible-lg,\n  td.visible-md.visible-lg {\n    display: table-cell !important;\n  }\n}\n.visible-lg,\ntr.visible-lg,\nth.visible-lg,\ntd.visible-lg {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-lg.visible-xs {\n    display: block !important;\n  }\n  tr.visible-lg.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-lg.visible-xs,\n  td.visible-lg.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-lg.visible-sm {\n    display: block !important;\n  }\n  tr.visible-lg.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-lg.visible-sm,\n  td.visible-lg.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-lg.visible-md {\n    display: block !important;\n  }\n  tr.visible-lg.visible-md {\n    display: table-row !important;\n  }\n  th.visible-lg.visible-md,\n  td.visible-lg.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !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.hidden-xs {\n  display: block !important;\n}\ntr.hidden-xs {\n  display: table-row !important;\n}\nth.hidden-xs,\ntd.hidden-xs {\n  display: table-cell !important;\n}\n@media (max-width: 767px) {\n  .hidden-xs,\n  tr.hidden-xs,\n  th.hidden-xs,\n  td.hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-xs.hidden-sm,\n  tr.hidden-xs.hidden-sm,\n  th.hidden-xs.hidden-sm,\n  td.hidden-xs.hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-xs.hidden-md,\n  tr.hidden-xs.hidden-md,\n  th.hidden-xs.hidden-md,\n  td.hidden-xs.hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-xs.hidden-lg,\n  tr.hidden-xs.hidden-lg,\n  th.hidden-xs.hidden-lg,\n  td.hidden-xs.hidden-lg {\n    display: none !important;\n  }\n}\n.hidden-sm {\n  display: block !important;\n}\ntr.hidden-sm {\n  display: table-row !important;\n}\nth.hidden-sm,\ntd.hidden-sm {\n  display: table-cell !important;\n}\n@media (max-width: 767px) {\n  .hidden-sm.hidden-xs,\n  tr.hidden-sm.hidden-xs,\n  th.hidden-sm.hidden-xs,\n  td.hidden-sm.hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm,\n  tr.hidden-sm,\n  th.hidden-sm,\n  td.hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-sm.hidden-md,\n  tr.hidden-sm.hidden-md,\n  th.hidden-sm.hidden-md,\n  td.hidden-sm.hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-sm.hidden-lg,\n  tr.hidden-sm.hidden-lg,\n  th.hidden-sm.hidden-lg,\n  td.hidden-sm.hidden-lg {\n    display: none !important;\n  }\n}\n.hidden-md {\n  display: block !important;\n}\ntr.hidden-md {\n  display: table-row !important;\n}\nth.hidden-md,\ntd.hidden-md {\n  display: table-cell !important;\n}\n@media (max-width: 767px) {\n  .hidden-md.hidden-xs,\n  tr.hidden-md.hidden-xs,\n  th.hidden-md.hidden-xs,\n  td.hidden-md.hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-md.hidden-sm,\n  tr.hidden-md.hidden-sm,\n  th.hidden-md.hidden-sm,\n  td.hidden-md.hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md,\n  tr.hidden-md,\n  th.hidden-md,\n  td.hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-md.hidden-lg,\n  tr.hidden-md.hidden-lg,\n  th.hidden-md.hidden-lg,\n  td.hidden-md.hidden-lg {\n    display: none !important;\n  }\n}\n.hidden-lg {\n  display: block !important;\n}\ntr.hidden-lg {\n  display: table-row !important;\n}\nth.hidden-lg,\ntd.hidden-lg {\n  display: table-cell !important;\n}\n@media (max-width: 767px) {\n  .hidden-lg.hidden-xs,\n  tr.hidden-lg.hidden-xs,\n  th.hidden-lg.hidden-xs,\n  td.hidden-lg.hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-lg.hidden-sm,\n  tr.hidden-lg.hidden-sm,\n  th.hidden-lg.hidden-sm,\n  td.hidden-lg.hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-lg.hidden-md,\n  tr.hidden-lg.hidden-md,\n  th.hidden-lg.hidden-md,\n  td.hidden-lg.hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg,\n  tr.hidden-lg,\n  th.hidden-lg,\n  td.hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print,\ntr.visible-print,\nth.visible-print,\ntd.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !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  .hidden-print,\n  tr.hidden-print,\n  th.hidden-print,\n  td.hidden-print {\n    display: none !important;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/summernote/dist/summernote.css",
    "content": ".note-editor{position:relative;overflow:hidden;border:1px solid #a9a9a9}.note-editor .note-dropzone{position:absolute;z-index:100;display:none;color:#87cefa;background-color:white;opacity:.95;pointer-event:none}.note-editor .note-dropzone .note-dropzone-message{display:table-cell;font-size:28px;font-weight:bold;text-align:center;vertical-align:middle}.note-editor .note-dropzone.hover{color:#098ddf}.note-editor.dragover .note-dropzone{display:table}.note-editor.codeview .note-editing-area .note-editable{display:none}.note-editor.codeview .note-editing-area .note-codable{display:block}.note-editor.fullscreen{position:fixed;top:0;left:0;z-index:1050;width:100%}.note-editor.fullscreen .note-editable{background-color:white}.note-editor.fullscreen .note-resizebar{display:none}.note-editor .note-editing-area{position:relative;overflow:hidden}.note-editor .note-editing-area .note-editable{padding:10px;overflow:auto;color:#000;background-color:#fff;outline:0}.note-editor .note-editing-area .note-editable[contenteditable=true]:empty:not(:focus):before{content:attr(data-placeholder)}.note-editor .note-editing-area .note-editable[contenteditable=\"false\"]{background-color:#e5e5e5}.note-editor .note-editing-area .note-codable{display:none;width:100%;padding:10px;margin-bottom:0;font-family:Menlo,Monaco,monospace,sans-serif;font-size:14px;color:#ccc;background-color:#222;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;box-shadow:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;resize:none}.note-editor .note-statusbar{background-color:#f5f5f5}.note-editor .note-statusbar .note-resizebar{width:100%;height:8px;padding-top:1px;cursor:ns-resize}.note-editor .note-statusbar .note-resizebar .note-icon-bar{width:20px;margin:1px auto;border-top:1px solid #a9a9a9}.note-air-editor{outline:0}.note-popover .popover{max-width:none}.note-popover .popover .popover-content a{display:inline-block;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.note-popover .popover .arrow{left:20px}.note-popover .popover .popover-content,.panel-heading.note-toolbar{padding:0 0 5px 5px;margin:0}.note-popover .popover .popover-content>.btn-group,.panel-heading.note-toolbar>.btn-group{margin-top:5px;margin-right:5px;margin-left:0}.note-popover .popover .popover-content .btn-group .note-table,.panel-heading.note-toolbar .btn-group .note-table{min-width:0;padding:5px}.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker{font-size:18px}.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher{position:absolute!important;z-index:3;width:10em;height:10em;cursor:pointer}.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted{position:relative!important;z-index:1;width:5em;height:5em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted{position:absolute!important;z-index:2;width:1em;height:1em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-popover .popover .popover-content .note-style h1,.panel-heading.note-toolbar .note-style h1,.note-popover .popover .popover-content .note-style h2,.panel-heading.note-toolbar .note-style h2,.note-popover .popover .popover-content .note-style h3,.panel-heading.note-toolbar .note-style h3,.note-popover .popover .popover-content .note-style h4,.panel-heading.note-toolbar .note-style h4,.note-popover .popover .popover-content .note-style h5,.panel-heading.note-toolbar .note-style h5,.note-popover .popover .popover-content .note-style h6,.panel-heading.note-toolbar .note-style h6,.note-popover .popover .popover-content .note-style blockquote,.panel-heading.note-toolbar .note-style blockquote{margin:0}.note-popover .popover .popover-content .note-color .dropdown-toggle,.panel-heading.note-toolbar .note-color .dropdown-toggle{width:20px;padding-left:5px}.note-popover .popover .popover-content .note-color .dropdown-menu,.panel-heading.note-toolbar .note-color .dropdown-menu{min-width:340px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group{margin:0}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group:first-child,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group:first-child{margin:0 5px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-palette-title,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title{margin:2px 7px;font-size:12px;text-align:center;border-bottom:1px solid #eee}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset{padding:0 3px;margin:3px;font-size:11px;cursor:pointer;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-row,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-row{height:20px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset:hover,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover{background:#eee}.note-popover .popover .popover-content .note-para .dropdown-menu,.panel-heading.note-toolbar .note-para .dropdown-menu{min-width:216px;padding:5px}.note-popover .popover .popover-content .note-para .dropdown-menu>div:first-child,.panel-heading.note-toolbar .note-para .dropdown-menu>div:first-child{margin-right:5px}.note-popover .popover .popover-content .dropdown-menu,.panel-heading.note-toolbar .dropdown-menu{min-width:90px}.note-popover .popover .popover-content .dropdown-menu.right,.panel-heading.note-toolbar .dropdown-menu.right{right:0;left:auto}.note-popover .popover .popover-content .dropdown-menu.right::before,.panel-heading.note-toolbar .dropdown-menu.right::before{right:9px;left:auto!important}.note-popover .popover .popover-content .dropdown-menu.right::after,.panel-heading.note-toolbar .dropdown-menu.right::after{right:10px;left:auto!important}.note-popover .popover .popover-content .dropdown-menu.note-check li a i,.panel-heading.note-toolbar .dropdown-menu.note-check li a i{color:deepskyblue;visibility:hidden}.note-popover .popover .popover-content .dropdown-menu.note-check li a.checked i,.panel-heading.note-toolbar .dropdown-menu.note-check li a.checked i{visibility:visible}.note-popover .popover .popover-content .note-fontsize-10,.panel-heading.note-toolbar .note-fontsize-10{font-size:10px}.note-popover .popover .popover-content .note-color-palette,.panel-heading.note-toolbar .note-color-palette{line-height:1}.note-popover .popover .popover-content .note-color-palette div .note-color-btn,.panel-heading.note-toolbar .note-color-palette div .note-color-btn{width:20px;height:20px;padding:0;margin:0;border:1px solid #fff}.note-popover .popover .popover-content .note-color-palette div .note-color-btn:hover,.panel-heading.note-toolbar .note-color-palette div .note-color-btn:hover{border:1px solid #000}.note-dialog>div{display:none}.note-dialog .form-group{margin-right:0;margin-left:0}.note-dialog .note-modal-form{margin:0}.note-dialog .note-image-dialog .note-dropzone{min-height:100px;margin-bottom:10px;font-size:30px;line-height:4;color:lightgray;text-align:center;border:4px dashed lightgray}.note-dialog .note-help-dialog{font-size:12px;color:#ccc;background:transparent;background-color:#222!important;border:0;-webkit-opacity:.9;-khtml-opacity:.9;-moz-opacity:.9;opacity:.9;-ms-filter:alpha(opacity=90);filter:alpha(opacity=90)}.note-dialog .note-help-dialog .modal-content{background:transparent;border:1px solid white;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.note-dialog .note-help-dialog a{font-size:12px;color:white}.note-dialog .note-help-dialog .title{padding-bottom:5px;margin-bottom:10px;font-size:14px;font-weight:bold;color:white;border-bottom:white 1px solid}.note-dialog .note-help-dialog .modal-close{font-size:14px;color:#dd0;cursor:pointer}.note-dialog .note-help-dialog .text-center{margin:10px 0 0}.note-dialog .note-help-dialog .note-shortcut{padding-top:8px;padding-bottom:8px}.note-dialog .note-help-dialog .note-shortcut-row{margin-right:-5px;margin-left:-5px}.note-dialog .note-help-dialog .note-shortcut-col{padding-right:5px;padding-left:5px}.note-dialog .note-help-dialog .note-shortcut-title{font-size:13px;font-weight:bold;color:#dd0}.note-dialog .note-help-dialog .note-shortcut-key{font-family:\"Courier New\";color:#dd0;text-align:right}.note-handle .note-control-selection{position:absolute;display:none;border:1px solid black}.note-handle .note-control-selection>div{position:absolute}.note-handle .note-control-selection .note-control-selection-bg{width:100%;height:100%;background-color:black;-webkit-opacity:.3;-khtml-opacity:.3;-moz-opacity:.3;opacity:.3;-ms-filter:alpha(opacity=30);filter:alpha(opacity=30)}.note-handle .note-control-selection .note-control-handle{width:7px;height:7px;border:1px solid black}.note-handle .note-control-selection .note-control-holder{width:7px;height:7px;border:1px solid black}.note-handle .note-control-selection .note-control-sizing{width:7px;height:7px;background-color:white;border:1px solid black}.note-handle .note-control-selection .note-control-nw{top:-5px;left:-5px;border-right:0;border-bottom:0}.note-handle .note-control-selection .note-control-ne{top:-5px;right:-5px;border-bottom:0;border-left:none}.note-handle .note-control-selection .note-control-sw{bottom:-5px;left:-5px;border-top:0;border-right:0}.note-handle .note-control-selection .note-control-se{right:-5px;bottom:-5px;cursor:se-resize}.note-handle .note-control-selection .note-control-se.note-control-holder{cursor:default;border-top:0;border-left:none}.note-handle .note-control-selection .note-control-selection-info{right:0;bottom:0;padding:5px;margin:5px;font-size:12px;color:white;background-color:black;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-opacity:.7;-khtml-opacity:.7;-moz-opacity:.7;opacity:.7;-ms-filter:alpha(opacity=70);filter:alpha(opacity=70)}"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/bower_components/summernote/dist/summernote.js",
    "content": "/**\n * Super simple wysiwyg editor on Bootstrap v0.6.16\n * http://summernote.org/\n *\n * summernote.js\n * Copyright 2013-2015 Alan Hong. and other contributors\n * summernote may be freely distributed under the MIT license./\n *\n * Date: 2015-08-03T16:41Z\n */\n(function (factory) {\n  /* global define */\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module.\n    define(['jquery'], factory);\n  } else {\n    // Browser globals: jQuery\n    factory(window.jQuery);\n  }\n}(function ($) {\n  \n\n\n  if (!Array.prototype.reduce) {\n    /**\n     * Array.prototype.reduce polyfill\n     *\n     * @param {Function} callback\n     * @param {Value} [initialValue]\n     * @return {Value}\n     *\n     * @see http://goo.gl/WNriQD\n     */\n    Array.prototype.reduce = function (callback) {\n      var t = Object(this), len = t.length >>> 0, k = 0, value;\n      if (arguments.length === 2) {\n        value = arguments[1];\n      } else {\n        while (k < len && !(k in t)) {\n          k++;\n        }\n        if (k >= len) {\n          throw new TypeError('Reduce of empty array with no initial value');\n        }\n        value = t[k++];\n      }\n      for (; k < len; k++) {\n        if (k in t) {\n          value = callback(value, t[k], k, t);\n        }\n      }\n      return value;\n    };\n  }\n\n  if ('function' !== typeof Array.prototype.filter) {\n    /**\n     * Array.prototype.filter polyfill\n     *\n     * @param {Function} func\n     * @return {Array}\n     *\n     * @see http://goo.gl/T1KFnq\n     */\n    Array.prototype.filter = function (func) {\n      var t = Object(this), len = t.length >>> 0;\n\n      var res = [];\n      var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n      for (var i = 0; i < len; i++) {\n        if (i in t) {\n          var val = t[i];\n          if (func.call(thisArg, val, i, t)) {\n            res.push(val);\n          }\n        }\n      }\n  \n      return res;\n    };\n  }\n\n  if (!Array.prototype.map) {\n    /**\n     * Array.prototype.map polyfill\n     *\n     * @param {Function} callback\n     * @return {Array}\n     *\n     * @see https://goo.gl/SMWaMK\n     */\n    Array.prototype.map = function (callback, thisArg) {\n      var T, A, k;\n      if (this === null) {\n        throw new TypeError(' this is null or not defined');\n      }\n\n      var O = Object(this);\n      var len = O.length >>> 0;\n      if (typeof callback !== 'function') {\n        throw new TypeError(callback + ' is not a function');\n      }\n  \n      if (arguments.length > 1) {\n        T = thisArg;\n      }\n  \n      A = new Array(len);\n      k = 0;\n  \n      while (k < len) {\n        var kValue, mappedValue;\n        if (k in O) {\n          kValue = O[k];\n          mappedValue = callback.call(T, kValue, k, O);\n          A[k] = mappedValue;\n        }\n        k++;\n      }\n      return A;\n    };\n  }\n\n  var isSupportAmd = typeof define === 'function' && define.amd;\n\n  /**\n   * returns whether font is installed or not.\n   *\n   * @param {String} fontName\n   * @return {Boolean}\n   */\n  var isFontInstalled = function (fontName) {\n    var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';\n    var $tester = $('<div>').css({\n      position: 'absolute',\n      left: '-9999px',\n      top: '-9999px',\n      fontSize: '200px'\n    }).text('mmmmmmmmmwwwwwww').appendTo(document.body);\n\n    var originalWidth = $tester.css('fontFamily', testFontName).width();\n    var width = $tester.css('fontFamily', fontName + ',' + testFontName).width();\n\n    $tester.remove();\n\n    return originalWidth !== width;\n  };\n\n  var userAgent = navigator.userAgent;\n  var isMSIE = /MSIE|Trident/i.test(userAgent);\n  var browserVersion;\n  if (isMSIE) {\n    var matches = /MSIE (\\d+[.]\\d+)/.exec(userAgent);\n    if (matches) {\n      browserVersion = parseFloat(matches[1]);\n    }\n    matches = /Trident\\/.*rv:([0-9]{1,}[\\.0-9]{0,})/.exec(userAgent);\n    if (matches) {\n      browserVersion = parseFloat(matches[1]);\n    }\n  }\n\n  /**\n   * @class core.agent\n   *\n   * Object which check platform and agent\n   *\n   * @singleton\n   * @alternateClassName agent\n   */\n  var agent = {\n    /** @property {Boolean} [isMac=false] true if this agent is Mac  */\n    isMac: navigator.appVersion.indexOf('Mac') > -1,\n    /** @property {Boolean} [isMSIE=false] true if this agent is a Internet Explorer  */\n    isMSIE: isMSIE,\n    /** @property {Boolean} [isFF=false] true if this agent is a Firefox  */\n    isFF: /firefox/i.test(userAgent),\n    isWebkit: /webkit/i.test(userAgent),\n    /** @property {Boolean} [isSafari=false] true if this agent is a Safari  */\n    isSafari: /safari/i.test(userAgent),\n    /** @property {Float} browserVersion current browser version  */\n    browserVersion: browserVersion,\n    /** @property {String} jqueryVersion current jQuery version string  */\n    jqueryVersion: parseFloat($.fn.jquery),\n    isSupportAmd: isSupportAmd,\n    hasCodeMirror: isSupportAmd ? require.specified('CodeMirror') : !!window.CodeMirror,\n    isFontInstalled: isFontInstalled,\n    isW3CRangeSupport: !!document.createRange\n  };\n\n  /**\n   * @class core.func\n   *\n   * func utils (for high-order func's arg)\n   *\n   * @singleton\n   * @alternateClassName func\n   */\n  var func = (function () {\n    var eq = function (itemA) {\n      return function (itemB) {\n        return itemA === itemB;\n      };\n    };\n\n    var eq2 = function (itemA, itemB) {\n      return itemA === itemB;\n    };\n\n    var peq2 = function (propName) {\n      return function (itemA, itemB) {\n        return itemA[propName] === itemB[propName];\n      };\n    };\n\n    var ok = function () {\n      return true;\n    };\n\n    var fail = function () {\n      return false;\n    };\n\n    var not = function (f) {\n      return function () {\n        return !f.apply(f, arguments);\n      };\n    };\n\n    var and = function (fA, fB) {\n      return function (item) {\n        return fA(item) && fB(item);\n      };\n    };\n\n    var self = function (a) {\n      return a;\n    };\n\n    var idCounter = 0;\n\n    /**\n     * generate a globally-unique id\n     *\n     * @param {String} [prefix]\n     */\n    var uniqueId = function (prefix) {\n      var id = ++idCounter + '';\n      return prefix ? prefix + id : id;\n    };\n\n    /**\n     * returns bnd (bounds) from rect\n     *\n     * - IE Compatability Issue: http://goo.gl/sRLOAo\n     * - Scroll Issue: http://goo.gl/sNjUc\n     *\n     * @param {Rect} rect\n     * @return {Object} bounds\n     * @return {Number} bounds.top\n     * @return {Number} bounds.left\n     * @return {Number} bounds.width\n     * @return {Number} bounds.height\n     */\n    var rect2bnd = function (rect) {\n      var $document = $(document);\n      return {\n        top: rect.top + $document.scrollTop(),\n        left: rect.left + $document.scrollLeft(),\n        width: rect.right - rect.left,\n        height: rect.bottom - rect.top\n      };\n    };\n\n    /**\n     * returns a copy of the object where the keys have become the values and the values the keys.\n     * @param {Object} obj\n     * @return {Object}\n     */\n    var invertObject = function (obj) {\n      var inverted = {};\n      for (var key in obj) {\n        if (obj.hasOwnProperty(key)) {\n          inverted[obj[key]] = key;\n        }\n      }\n      return inverted;\n    };\n\n    /**\n     * @param {String} namespace\n     * @param {String} [prefix]\n     * @return {String}\n     */\n    var namespaceToCamel = function (namespace, prefix) {\n      prefix = prefix || '';\n      return prefix + namespace.split('.').map(function (name) {\n        return name.substring(0, 1).toUpperCase() + name.substring(1);\n      }).join('');\n    };\n\n    return {\n      eq: eq,\n      eq2: eq2,\n      peq2: peq2,\n      ok: ok,\n      fail: fail,\n      self: self,\n      not: not,\n      and: and,\n      uniqueId: uniqueId,\n      rect2bnd: rect2bnd,\n      invertObject: invertObject,\n      namespaceToCamel: namespaceToCamel\n    };\n  })();\n\n  /**\n   * @class core.list\n   *\n   * list utils\n   *\n   * @singleton\n   * @alternateClassName list\n   */\n  var list = (function () {\n    /**\n     * returns the first item of an array.\n     *\n     * @param {Array} array\n     */\n    var head = function (array) {\n      return array[0];\n    };\n\n    /**\n     * returns the last item of an array.\n     *\n     * @param {Array} array\n     */\n    var last = function (array) {\n      return array[array.length - 1];\n    };\n\n    /**\n     * returns everything but the last entry of the array.\n     *\n     * @param {Array} array\n     */\n    var initial = function (array) {\n      return array.slice(0, array.length - 1);\n    };\n\n    /**\n     * returns the rest of the items in an array.\n     *\n     * @param {Array} array\n     */\n    var tail = function (array) {\n      return array.slice(1);\n    };\n\n    /**\n     * returns item of array\n     */\n    var find = function (array, pred) {\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        var item = array[idx];\n        if (pred(item)) {\n          return item;\n        }\n      }\n    };\n\n    /**\n     * returns true if all of the values in the array pass the predicate truth test.\n     */\n    var all = function (array, pred) {\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (!pred(array[idx])) {\n          return false;\n        }\n      }\n      return true;\n    };\n\n    /**\n     * returns index of item\n     */\n    var indexOf = function (array, item) {\n      return $.inArray(item, array);\n    };\n\n    /**\n     * returns true if the value is present in the list.\n     */\n    var contains = function (array, item) {\n      return indexOf(array, item) !== -1;\n    };\n\n    /**\n     * get sum from a list\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - iterator\n     */\n    var sum = function (array, fn) {\n      fn = fn || func.self;\n      return array.reduce(function (memo, v) {\n        return memo + fn(v);\n      }, 0);\n    };\n  \n    /**\n     * returns a copy of the collection with array type.\n     * @param {Collection} collection - collection eg) node.childNodes, ...\n     */\n    var from = function (collection) {\n      var result = [], idx = -1, length = collection.length;\n      while (++idx < length) {\n        result[idx] = collection[idx];\n      }\n      return result;\n    };\n  \n    /**\n     * cluster elements by predicate function.\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - predicate function for cluster rule\n     * @param {Array[]}\n     */\n    var clusterBy = function (array, fn) {\n      if (!array.length) { return []; }\n      var aTail = tail(array);\n      return aTail.reduce(function (memo, v) {\n        var aLast = last(memo);\n        if (fn(last(aLast), v)) {\n          aLast[aLast.length] = v;\n        } else {\n          memo[memo.length] = [v];\n        }\n        return memo;\n      }, [[head(array)]]);\n    };\n  \n    /**\n     * returns a copy of the array with all falsy values removed\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - predicate function for cluster rule\n     */\n    var compact = function (array) {\n      var aResult = [];\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (array[idx]) { aResult.push(array[idx]); }\n      }\n      return aResult;\n    };\n\n    /**\n     * produces a duplicate-free version of the array\n     *\n     * @param {Array} array\n     */\n    var unique = function (array) {\n      var results = [];\n\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (!contains(results, array[idx])) {\n          results.push(array[idx]);\n        }\n      }\n\n      return results;\n    };\n\n    /**\n     * returns next item.\n     * @param {Array} array\n     */\n    var next = function (array, item) {\n      var idx = indexOf(array, item);\n      if (idx === -1) { return null; }\n\n      return array[idx + 1];\n    };\n\n    /**\n     * returns prev item.\n     * @param {Array} array\n     */\n    var prev = function (array, item) {\n      var idx = indexOf(array, item);\n      if (idx === -1) { return null; }\n\n      return array[idx - 1];\n    };\n  \n    return { head: head, last: last, initial: initial, tail: tail,\n             prev: prev, next: next, find: find, contains: contains,\n             all: all, sum: sum, from: from,\n             clusterBy: clusterBy, compact: compact, unique: unique };\n  })();\n\n\n  var NBSP_CHAR = String.fromCharCode(160);\n  var ZERO_WIDTH_NBSP_CHAR = '\\ufeff';\n\n  /**\n   * @class core.dom\n   *\n   * Dom functions\n   *\n   * @singleton\n   * @alternateClassName dom\n   */\n  var dom = (function () {\n    /**\n     * @method isEditable\n     *\n     * returns whether node is `note-editable` or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isEditable = function (node) {\n      return node && $(node).hasClass('note-editable');\n    };\n\n    /**\n     * @method isControlSizing\n     *\n     * returns whether node is `note-control-sizing` or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isControlSizing = function (node) {\n      return node && $(node).hasClass('note-control-sizing');\n    };\n\n    /**\n     * @method  buildLayoutInfo\n     *\n     * build layoutInfo from $editor(.note-editor)\n     *\n     * @param {jQuery} $editor\n     * @return {Object}\n     * @return {Function} return.editor\n     * @return {Node} return.dropzone\n     * @return {Node} return.toolbar\n     * @return {Node} return.editable\n     * @return {Node} return.codable\n     * @return {Node} return.popover\n     * @return {Node} return.handle\n     * @return {Node} return.dialog\n     */\n    var buildLayoutInfo = function ($editor) {\n      var makeFinder;\n\n      // air mode\n      if ($editor.hasClass('note-air-editor')) {\n        var id = list.last($editor.attr('id').split('-'));\n        makeFinder = function (sIdPrefix) {\n          return function () { return $(sIdPrefix + id); };\n        };\n\n        return {\n          editor: function () { return $editor; },\n          holder : function () { return $editor.data('holder'); },\n          editable: function () { return $editor; },\n          popover: makeFinder('#note-popover-'),\n          handle: makeFinder('#note-handle-'),\n          dialog: makeFinder('#note-dialog-')\n        };\n\n        // frame mode\n      } else {\n        makeFinder = function (className, $base) {\n          $base = $base || $editor;\n          return function () { return $base.find(className); };\n        };\n\n        var options = $editor.data('options');\n        var $dialogHolder = (options && options.dialogsInBody) ? $(document.body) : null;\n\n        return {\n          editor: function () { return $editor; },\n          holder : function () { return $editor.data('holder'); },\n          dropzone: makeFinder('.note-dropzone'),\n          toolbar: makeFinder('.note-toolbar'),\n          editable: makeFinder('.note-editable'),\n          codable: makeFinder('.note-codable'),\n          statusbar: makeFinder('.note-statusbar'),\n          popover: makeFinder('.note-popover'),\n          handle: makeFinder('.note-handle'),\n          dialog: makeFinder('.note-dialog', $dialogHolder)\n        };\n      }\n    };\n\n    /**\n     * returns makeLayoutInfo from editor's descendant node.\n     *\n     * @private\n     * @param {Node} descendant\n     * @return {Object}\n     */\n    var makeLayoutInfo = function (descendant) {\n      var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout');\n\n      if (!$target.length) {\n        return null;\n      }\n\n      var $editor;\n      if ($target.is('.note-editor, .note-air-editor')) {\n        $editor = $target;\n      } else {\n        $editor = $('#note-editor-' + list.last($target.attr('id').split('-')));\n      }\n\n      return buildLayoutInfo($editor);\n    };\n\n    /**\n     * @method makePredByNodeName\n     *\n     * returns predicate which judge whether nodeName is same\n     *\n     * @param {String} nodeName\n     * @return {Function}\n     */\n    var makePredByNodeName = function (nodeName) {\n      nodeName = nodeName.toUpperCase();\n      return function (node) {\n        return node && node.nodeName.toUpperCase() === nodeName;\n      };\n    };\n\n    /**\n     * @method isText\n     *\n     *\n     *\n     * @param {Node} node\n     * @return {Boolean} true if node's type is text(3)\n     */\n    var isText = function (node) {\n      return node && node.nodeType === 3;\n    };\n\n    /**\n     * ex) br, col, embed, hr, img, input, ...\n     * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements\n     */\n    var isVoid = function (node) {\n      return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON/.test(node.nodeName.toUpperCase());\n    };\n\n    var isPara = function (node) {\n      if (isEditable(node)) {\n        return false;\n      }\n\n      // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph\n      return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());\n    };\n\n    var isLi = makePredByNodeName('LI');\n\n    var isPurePara = function (node) {\n      return isPara(node) && !isLi(node);\n    };\n\n    var isTable = makePredByNodeName('TABLE');\n\n    var isInline = function (node) {\n      return !isBodyContainer(node) &&\n             !isList(node) &&\n             !isHr(node) &&\n             !isPara(node) &&\n             !isTable(node) &&\n             !isBlockquote(node);\n    };\n\n    var isList = function (node) {\n      return node && /^UL|^OL/.test(node.nodeName.toUpperCase());\n    };\n\n    var isHr = makePredByNodeName('HR');\n\n    var isCell = function (node) {\n      return node && /^TD|^TH/.test(node.nodeName.toUpperCase());\n    };\n\n    var isBlockquote = makePredByNodeName('BLOCKQUOTE');\n\n    var isBodyContainer = function (node) {\n      return isCell(node) || isBlockquote(node) || isEditable(node);\n    };\n\n    var isAnchor = makePredByNodeName('A');\n\n    var isParaInline = function (node) {\n      return isInline(node) && !!ancestor(node, isPara);\n    };\n\n    var isBodyInline = function (node) {\n      return isInline(node) && !ancestor(node, isPara);\n    };\n\n    var isBody = makePredByNodeName('BODY');\n\n    /**\n     * returns whether nodeB is closest sibling of nodeA\n     *\n     * @param {Node} nodeA\n     * @param {Node} nodeB\n     * @return {Boolean}\n     */\n    var isClosestSibling = function (nodeA, nodeB) {\n      return nodeA.nextSibling === nodeB ||\n             nodeA.previousSibling === nodeB;\n    };\n\n    /**\n     * returns array of closest siblings with node\n     *\n     * @param {Node} node\n     * @param {function} [pred] - predicate function\n     * @return {Node[]}\n     */\n    var withClosestSiblings = function (node, pred) {\n      pred = pred || func.ok;\n\n      var siblings = [];\n      if (node.previousSibling && pred(node.previousSibling)) {\n        siblings.push(node.previousSibling);\n      }\n      siblings.push(node);\n      if (node.nextSibling && pred(node.nextSibling)) {\n        siblings.push(node.nextSibling);\n      }\n      return siblings;\n    };\n\n    /**\n     * blank HTML for cursor position\n     * - [workaround] old IE only works with &nbsp;\n     * - [workaround] IE11 and other browser works with bogus br\n     */\n    var blankHTML = agent.isMSIE && agent.browserVersion < 11 ? '&nbsp;' : '<br>';\n\n    /**\n     * @method nodeLength\n     *\n     * returns #text's text size or element's childNodes size\n     *\n     * @param {Node} node\n     */\n    var nodeLength = function (node) {\n      if (isText(node)) {\n        return node.nodeValue.length;\n      }\n\n      return node.childNodes.length;\n    };\n\n    /**\n     * returns whether node is empty or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isEmpty = function (node) {\n      var len = nodeLength(node);\n\n      if (len === 0) {\n        return true;\n      } else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) {\n        // ex) <p><br></p>, <span><br></span>\n        return true;\n      } else if (list.all(node.childNodes, isText) && node.innerHTML === '') {\n        // ex) <p></p>, <span></span>\n        return true;\n      }\n\n      return false;\n    };\n\n    /**\n     * padding blankHTML if node is empty (for cursor position)\n     */\n    var paddingBlankHTML = function (node) {\n      if (!isVoid(node) && !nodeLength(node)) {\n        node.innerHTML = blankHTML;\n      }\n    };\n\n    /**\n     * find nearest ancestor predicate hit\n     *\n     * @param {Node} node\n     * @param {Function} pred - predicate function\n     */\n    var ancestor = function (node, pred) {\n      while (node) {\n        if (pred(node)) { return node; }\n        if (isEditable(node)) { break; }\n\n        node = node.parentNode;\n      }\n      return null;\n    };\n\n    /**\n     * find nearest ancestor only single child blood line and predicate hit\n     *\n     * @param {Node} node\n     * @param {Function} pred - predicate function\n     */\n    var singleChildAncestor = function (node, pred) {\n      node = node.parentNode;\n\n      while (node) {\n        if (nodeLength(node) !== 1) { break; }\n        if (pred(node)) { return node; }\n        if (isEditable(node)) { break; }\n\n        node = node.parentNode;\n      }\n      return null;\n    };\n\n    /**\n     * returns new array of ancestor nodes (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [optional] pred - predicate function\n     */\n    var listAncestor = function (node, pred) {\n      pred = pred || func.fail;\n\n      var ancestors = [];\n      ancestor(node, function (el) {\n        if (!isEditable(el)) {\n          ancestors.push(el);\n        }\n\n        return pred(el);\n      });\n      return ancestors;\n    };\n\n    /**\n     * find farthest ancestor predicate hit\n     */\n    var lastAncestor = function (node, pred) {\n      var ancestors = listAncestor(node);\n      return list.last(ancestors.filter(pred));\n    };\n\n    /**\n     * returns common ancestor node between two nodes.\n     *\n     * @param {Node} nodeA\n     * @param {Node} nodeB\n     */\n    var commonAncestor = function (nodeA, nodeB) {\n      var ancestors = listAncestor(nodeA);\n      for (var n = nodeB; n; n = n.parentNode) {\n        if ($.inArray(n, ancestors) > -1) { return n; }\n      }\n      return null; // difference document area\n    };\n\n    /**\n     * listing all previous siblings (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [optional] pred - predicate function\n     */\n    var listPrev = function (node, pred) {\n      pred = pred || func.fail;\n\n      var nodes = [];\n      while (node) {\n        if (pred(node)) { break; }\n        nodes.push(node);\n        node = node.previousSibling;\n      }\n      return nodes;\n    };\n\n    /**\n     * listing next siblings (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [pred] - predicate function\n     */\n    var listNext = function (node, pred) {\n      pred = pred || func.fail;\n\n      var nodes = [];\n      while (node) {\n        if (pred(node)) { break; }\n        nodes.push(node);\n        node = node.nextSibling;\n      }\n      return nodes;\n    };\n\n    /**\n     * listing descendant nodes\n     *\n     * @param {Node} node\n     * @param {Function} [pred] - predicate function\n     */\n    var listDescendant = function (node, pred) {\n      var descendents = [];\n      pred = pred || func.ok;\n\n      // start DFS(depth first search) with node\n      (function fnWalk(current) {\n        if (node !== current && pred(current)) {\n          descendents.push(current);\n        }\n        for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {\n          fnWalk(current.childNodes[idx]);\n        }\n      })(node);\n\n      return descendents;\n    };\n\n    /**\n     * wrap node with new tag.\n     *\n     * @param {Node} node\n     * @param {Node} tagName of wrapper\n     * @return {Node} - wrapper\n     */\n    var wrap = function (node, wrapperName) {\n      var parent = node.parentNode;\n      var wrapper = $('<' + wrapperName + '>')[0];\n\n      parent.insertBefore(wrapper, node);\n      wrapper.appendChild(node);\n\n      return wrapper;\n    };\n\n    /**\n     * insert node after preceding\n     *\n     * @param {Node} node\n     * @param {Node} preceding - predicate function\n     */\n    var insertAfter = function (node, preceding) {\n      var next = preceding.nextSibling, parent = preceding.parentNode;\n      if (next) {\n        parent.insertBefore(node, next);\n      } else {\n        parent.appendChild(node);\n      }\n      return node;\n    };\n\n    /**\n     * append elements.\n     *\n     * @param {Node} node\n     * @param {Collection} aChild\n     */\n    var appendChildNodes = function (node, aChild) {\n      $.each(aChild, function (idx, child) {\n        node.appendChild(child);\n      });\n      return node;\n    };\n\n    /**\n     * returns whether boundaryPoint is left edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isLeftEdgePoint = function (point) {\n      return point.offset === 0;\n    };\n\n    /**\n     * returns whether boundaryPoint is right edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isRightEdgePoint = function (point) {\n      return point.offset === nodeLength(point.node);\n    };\n\n    /**\n     * returns whether boundaryPoint is edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isEdgePoint = function (point) {\n      return isLeftEdgePoint(point) || isRightEdgePoint(point);\n    };\n\n    /**\n     * returns wheter node is left edge of ancestor or not.\n     *\n     * @param {Node} node\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isLeftEdgeOf = function (node, ancestor) {\n      while (node && node !== ancestor) {\n        if (position(node) !== 0) {\n          return false;\n        }\n        node = node.parentNode;\n      }\n\n      return true;\n    };\n\n    /**\n     * returns whether node is right edge of ancestor or not.\n     *\n     * @param {Node} node\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isRightEdgeOf = function (node, ancestor) {\n      while (node && node !== ancestor) {\n        if (position(node) !== nodeLength(node.parentNode) - 1) {\n          return false;\n        }\n        node = node.parentNode;\n      }\n\n      return true;\n    };\n\n    /**\n     * returns whether point is left edge of ancestor or not.\n     * @param {BoundaryPoint} point\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isLeftEdgePointOf = function (point, ancestor) {\n      return isLeftEdgePoint(point) && isLeftEdgeOf(point.node, ancestor);\n    };\n\n    /**\n     * returns whether point is right edge of ancestor or not.\n     * @param {BoundaryPoint} point\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isRightEdgePointOf = function (point, ancestor) {\n      return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor);\n    };\n\n    /**\n     * returns offset from parent.\n     *\n     * @param {Node} node\n     */\n    var position = function (node) {\n      var offset = 0;\n      while ((node = node.previousSibling)) {\n        offset += 1;\n      }\n      return offset;\n    };\n\n    var hasChildren = function (node) {\n      return !!(node && node.childNodes && node.childNodes.length);\n    };\n\n    /**\n     * returns previous boundaryPoint\n     *\n     * @param {BoundaryPoint} point\n     * @param {Boolean} isSkipInnerOffset\n     * @return {BoundaryPoint}\n     */\n    var prevPoint = function (point, isSkipInnerOffset) {\n      var node, offset;\n\n      if (point.offset === 0) {\n        if (isEditable(point.node)) {\n          return null;\n        }\n\n        node = point.node.parentNode;\n        offset = position(point.node);\n      } else if (hasChildren(point.node)) {\n        node = point.node.childNodes[point.offset - 1];\n        offset = nodeLength(node);\n      } else {\n        node = point.node;\n        offset = isSkipInnerOffset ? 0 : point.offset - 1;\n      }\n\n      return {\n        node: node,\n        offset: offset\n      };\n    };\n\n    /**\n     * returns next boundaryPoint\n     *\n     * @param {BoundaryPoint} point\n     * @param {Boolean} isSkipInnerOffset\n     * @return {BoundaryPoint}\n     */\n    var nextPoint = function (point, isSkipInnerOffset) {\n      var node, offset;\n\n      if (nodeLength(point.node) === point.offset) {\n        if (isEditable(point.node)) {\n          return null;\n        }\n\n        node = point.node.parentNode;\n        offset = position(point.node) + 1;\n      } else if (hasChildren(point.node)) {\n        node = point.node.childNodes[point.offset];\n        offset = 0;\n      } else {\n        node = point.node;\n        offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;\n      }\n\n      return {\n        node: node,\n        offset: offset\n      };\n    };\n\n    /**\n     * returns whether pointA and pointB is same or not.\n     *\n     * @param {BoundaryPoint} pointA\n     * @param {BoundaryPoint} pointB\n     * @return {Boolean}\n     */\n    var isSamePoint = function (pointA, pointB) {\n      return pointA.node === pointB.node && pointA.offset === pointB.offset;\n    };\n\n    /**\n     * returns whether point is visible (can set cursor) or not.\n     * \n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isVisiblePoint = function (point) {\n      if (isText(point.node) || !hasChildren(point.node) || isEmpty(point.node)) {\n        return true;\n      }\n\n      var leftNode = point.node.childNodes[point.offset - 1];\n      var rightNode = point.node.childNodes[point.offset];\n      if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) {\n        return true;\n      }\n\n      return false;\n    };\n\n    /**\n     * @method prevPointUtil\n     *\n     * @param {BoundaryPoint} point\n     * @param {Function} pred\n     * @return {BoundaryPoint}\n     */\n    var prevPointUntil = function (point, pred) {\n      while (point) {\n        if (pred(point)) {\n          return point;\n        }\n\n        point = prevPoint(point);\n      }\n\n      return null;\n    };\n\n    /**\n     * @method nextPointUntil\n     *\n     * @param {BoundaryPoint} point\n     * @param {Function} pred\n     * @return {BoundaryPoint}\n     */\n    var nextPointUntil = function (point, pred) {\n      while (point) {\n        if (pred(point)) {\n          return point;\n        }\n\n        point = nextPoint(point);\n      }\n\n      return null;\n    };\n\n    /**\n     * returns whether point has character or not.\n     *\n     * @param {Point} point\n     * @return {Boolean}\n     */\n    var isCharPoint = function (point) {\n      if (!isText(point.node)) {\n        return false;\n      }\n\n      var ch = point.node.nodeValue.charAt(point.offset - 1);\n      return ch && (ch !== ' ' && ch !== NBSP_CHAR);\n    };\n\n    /**\n     * @method walkPoint\n     *\n     * @param {BoundaryPoint} startPoint\n     * @param {BoundaryPoint} endPoint\n     * @param {Function} handler\n     * @param {Boolean} isSkipInnerOffset\n     */\n    var walkPoint = function (startPoint, endPoint, handler, isSkipInnerOffset) {\n      var point = startPoint;\n\n      while (point) {\n        handler(point);\n\n        if (isSamePoint(point, endPoint)) {\n          break;\n        }\n\n        var isSkipOffset = isSkipInnerOffset &&\n                           startPoint.node !== point.node &&\n                           endPoint.node !== point.node;\n        point = nextPoint(point, isSkipOffset);\n      }\n    };\n\n    /**\n     * @method makeOffsetPath\n     *\n     * return offsetPath(array of offset) from ancestor\n     *\n     * @param {Node} ancestor - ancestor node\n     * @param {Node} node\n     */\n    var makeOffsetPath = function (ancestor, node) {\n      var ancestors = listAncestor(node, func.eq(ancestor));\n      return ancestors.map(position).reverse();\n    };\n\n    /**\n     * @method fromOffsetPath\n     *\n     * return element from offsetPath(array of offset)\n     *\n     * @param {Node} ancestor - ancestor node\n     * @param {array} offsets - offsetPath\n     */\n    var fromOffsetPath = function (ancestor, offsets) {\n      var current = ancestor;\n      for (var i = 0, len = offsets.length; i < len; i++) {\n        if (current.childNodes.length <= offsets[i]) {\n          current = current.childNodes[current.childNodes.length - 1];\n        } else {\n          current = current.childNodes[offsets[i]];\n        }\n      }\n      return current;\n    };\n\n    /**\n     * @method splitNode\n     *\n     * split element or #text\n     *\n     * @param {BoundaryPoint} point\n     * @param {Object} [options]\n     * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false\n     * @param {Boolean} [options.isNotSplitEdgePoint] - default: false\n     * @return {Node} right node of boundaryPoint\n     */\n    var splitNode = function (point, options) {\n      var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;\n      var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;\n\n      // edge case\n      if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {\n        if (isLeftEdgePoint(point)) {\n          return point.node;\n        } else if (isRightEdgePoint(point)) {\n          return point.node.nextSibling;\n        }\n      }\n\n      // split #text\n      if (isText(point.node)) {\n        return point.node.splitText(point.offset);\n      } else {\n        var childNode = point.node.childNodes[point.offset];\n        var clone = insertAfter(point.node.cloneNode(false), point.node);\n        appendChildNodes(clone, listNext(childNode));\n\n        if (!isSkipPaddingBlankHTML) {\n          paddingBlankHTML(point.node);\n          paddingBlankHTML(clone);\n        }\n\n        return clone;\n      }\n    };\n\n    /**\n     * @method splitTree\n     *\n     * split tree by point\n     *\n     * @param {Node} root - split root\n     * @param {BoundaryPoint} point\n     * @param {Object} [options]\n     * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false\n     * @param {Boolean} [options.isNotSplitEdgePoint] - default: false\n     * @return {Node} right node of boundaryPoint\n     */\n    var splitTree = function (root, point, options) {\n      // ex) [#text, <span>, <p>]\n      var ancestors = listAncestor(point.node, func.eq(root));\n\n      if (!ancestors.length) {\n        return null;\n      } else if (ancestors.length === 1) {\n        return splitNode(point, options);\n      }\n\n      return ancestors.reduce(function (node, parent) {\n        if (node === point.node) {\n          node = splitNode(point, options);\n        }\n\n        return splitNode({\n          node: parent,\n          offset: node ? dom.position(node) : nodeLength(parent)\n        }, options);\n      });\n    };\n\n    /**\n     * split point\n     *\n     * @param {Point} point\n     * @param {Boolean} isInline\n     * @return {Object}\n     */\n    var splitPoint = function (point, isInline) {\n      // find splitRoot, container\n      //  - inline: splitRoot is a child of paragraph\n      //  - block: splitRoot is a child of bodyContainer\n      var pred = isInline ? isPara : isBodyContainer;\n      var ancestors = listAncestor(point.node, pred);\n      var topAncestor = list.last(ancestors) || point.node;\n\n      var splitRoot, container;\n      if (pred(topAncestor)) {\n        splitRoot = ancestors[ancestors.length - 2];\n        container = topAncestor;\n      } else {\n        splitRoot = topAncestor;\n        container = splitRoot.parentNode;\n      }\n\n      // if splitRoot is exists, split with splitTree\n      var pivot = splitRoot && splitTree(splitRoot, point, {\n        isSkipPaddingBlankHTML: isInline,\n        isNotSplitEdgePoint: isInline\n      });\n\n      // if container is point.node, find pivot with point.offset\n      if (!pivot && container === point.node) {\n        pivot = point.node.childNodes[point.offset];\n      }\n\n      return {\n        rightNode: pivot,\n        container: container\n      };\n    };\n\n    var create = function (nodeName) {\n      return document.createElement(nodeName);\n    };\n\n    var createText = function (text) {\n      return document.createTextNode(text);\n    };\n\n    /**\n     * @method remove\n     *\n     * remove node, (isRemoveChild: remove child or not)\n     *\n     * @param {Node} node\n     * @param {Boolean} isRemoveChild\n     */\n    var remove = function (node, isRemoveChild) {\n      if (!node || !node.parentNode) { return; }\n      if (node.removeNode) { return node.removeNode(isRemoveChild); }\n\n      var parent = node.parentNode;\n      if (!isRemoveChild) {\n        var nodes = [];\n        var i, len;\n        for (i = 0, len = node.childNodes.length; i < len; i++) {\n          nodes.push(node.childNodes[i]);\n        }\n\n        for (i = 0, len = nodes.length; i < len; i++) {\n          parent.insertBefore(nodes[i], node);\n        }\n      }\n\n      parent.removeChild(node);\n    };\n\n    /**\n     * @method removeWhile\n     *\n     * @param {Node} node\n     * @param {Function} pred\n     */\n    var removeWhile = function (node, pred) {\n      while (node) {\n        if (isEditable(node) || !pred(node)) {\n          break;\n        }\n\n        var parent = node.parentNode;\n        remove(node);\n        node = parent;\n      }\n    };\n\n    /**\n     * @method replace\n     *\n     * replace node with provided nodeName\n     *\n     * @param {Node} node\n     * @param {String} nodeName\n     * @return {Node} - new node\n     */\n    var replace = function (node, nodeName) {\n      if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {\n        return node;\n      }\n\n      var newNode = create(nodeName);\n\n      if (node.style.cssText) {\n        newNode.style.cssText = node.style.cssText;\n      }\n\n      appendChildNodes(newNode, list.from(node.childNodes));\n      insertAfter(newNode, node);\n      remove(node);\n\n      return newNode;\n    };\n\n    var isTextarea = makePredByNodeName('TEXTAREA');\n\n    /**\n     * @param {jQuery} $node\n     * @param {Boolean} [stripLinebreaks] - default: false\n     */\n    var value = function ($node, stripLinebreaks) {\n      var val = isTextarea($node[0]) ? $node.val() : $node.html();\n      if (stripLinebreaks) {\n        return val.replace(/[\\n\\r]/g, '');\n      }\n      return val;\n    };\n\n    /**\n     * @method html\n     *\n     * get the HTML contents of node\n     *\n     * @param {jQuery} $node\n     * @param {Boolean} [isNewlineOnBlock]\n     */\n    var html = function ($node, isNewlineOnBlock) {\n      var markup = value($node);\n\n      if (isNewlineOnBlock) {\n        var regexTag = /<(\\/?)(\\b(?!!)[^>\\s]*)(.*?)(\\s*\\/?>)/g;\n        markup = markup.replace(regexTag, function (match, endSlash, name) {\n          name = name.toUpperCase();\n          var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) &&\n                                       !!endSlash;\n          var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);\n\n          return match + ((isEndOfInlineContainer || isBlockNode) ? '\\n' : '');\n        });\n        markup = $.trim(markup);\n      }\n\n      return markup;\n    };\n\n    return {\n      /** @property {String} NBSP_CHAR */\n      NBSP_CHAR: NBSP_CHAR,\n      /** @property {String} ZERO_WIDTH_NBSP_CHAR */\n      ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,\n      /** @property {String} blank */\n      blank: blankHTML,\n      /** @property {String} emptyPara */\n      emptyPara: '<p>' + blankHTML + '</p>',\n      makePredByNodeName: makePredByNodeName,\n      isEditable: isEditable,\n      isControlSizing: isControlSizing,\n      buildLayoutInfo: buildLayoutInfo,\n      makeLayoutInfo: makeLayoutInfo,\n      isText: isText,\n      isVoid: isVoid,\n      isPara: isPara,\n      isPurePara: isPurePara,\n      isInline: isInline,\n      isBlock: func.not(isInline),\n      isBodyInline: isBodyInline,\n      isBody: isBody,\n      isParaInline: isParaInline,\n      isList: isList,\n      isTable: isTable,\n      isCell: isCell,\n      isBlockquote: isBlockquote,\n      isBodyContainer: isBodyContainer,\n      isAnchor: isAnchor,\n      isDiv: makePredByNodeName('DIV'),\n      isLi: isLi,\n      isBR: makePredByNodeName('BR'),\n      isSpan: makePredByNodeName('SPAN'),\n      isB: makePredByNodeName('B'),\n      isU: makePredByNodeName('U'),\n      isS: makePredByNodeName('S'),\n      isI: makePredByNodeName('I'),\n      isImg: makePredByNodeName('IMG'),\n      isTextarea: isTextarea,\n      isEmpty: isEmpty,\n      isEmptyAnchor: func.and(isAnchor, isEmpty),\n      isClosestSibling: isClosestSibling,\n      withClosestSiblings: withClosestSiblings,\n      nodeLength: nodeLength,\n      isLeftEdgePoint: isLeftEdgePoint,\n      isRightEdgePoint: isRightEdgePoint,\n      isEdgePoint: isEdgePoint,\n      isLeftEdgeOf: isLeftEdgeOf,\n      isRightEdgeOf: isRightEdgeOf,\n      isLeftEdgePointOf: isLeftEdgePointOf,\n      isRightEdgePointOf: isRightEdgePointOf,\n      prevPoint: prevPoint,\n      nextPoint: nextPoint,\n      isSamePoint: isSamePoint,\n      isVisiblePoint: isVisiblePoint,\n      prevPointUntil: prevPointUntil,\n      nextPointUntil: nextPointUntil,\n      isCharPoint: isCharPoint,\n      walkPoint: walkPoint,\n      ancestor: ancestor,\n      singleChildAncestor: singleChildAncestor,\n      listAncestor: listAncestor,\n      lastAncestor: lastAncestor,\n      listNext: listNext,\n      listPrev: listPrev,\n      listDescendant: listDescendant,\n      commonAncestor: commonAncestor,\n      wrap: wrap,\n      insertAfter: insertAfter,\n      appendChildNodes: appendChildNodes,\n      position: position,\n      hasChildren: hasChildren,\n      makeOffsetPath: makeOffsetPath,\n      fromOffsetPath: fromOffsetPath,\n      splitTree: splitTree,\n      splitPoint: splitPoint,\n      create: create,\n      createText: createText,\n      remove: remove,\n      removeWhile: removeWhile,\n      replace: replace,\n      html: html,\n      value: value\n    };\n  })();\n\n\n  var range = (function () {\n\n    /**\n     * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js\n     *\n     * @param {TextRange} textRange\n     * @param {Boolean} isStart\n     * @return {BoundaryPoint}\n     *\n     * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx\n     */\n    var textRangeToPoint = function (textRange, isStart) {\n      var container = textRange.parentElement(), offset;\n  \n      var tester = document.body.createTextRange(), prevContainer;\n      var childNodes = list.from(container.childNodes);\n      for (offset = 0; offset < childNodes.length; offset++) {\n        if (dom.isText(childNodes[offset])) {\n          continue;\n        }\n        tester.moveToElementText(childNodes[offset]);\n        if (tester.compareEndPoints('StartToStart', textRange) >= 0) {\n          break;\n        }\n        prevContainer = childNodes[offset];\n      }\n  \n      if (offset !== 0 && dom.isText(childNodes[offset - 1])) {\n        var textRangeStart = document.body.createTextRange(), curTextNode = null;\n        textRangeStart.moveToElementText(prevContainer || container);\n        textRangeStart.collapse(!prevContainer);\n        curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;\n  \n        var pointTester = textRange.duplicate();\n        pointTester.setEndPoint('StartToStart', textRangeStart);\n        var textCount = pointTester.text.replace(/[\\r\\n]/g, '').length;\n  \n        while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {\n          textCount -= curTextNode.nodeValue.length;\n          curTextNode = curTextNode.nextSibling;\n        }\n  \n        /* jshint ignore:start */\n        var dummy = curTextNode.nodeValue; // enforce IE to re-reference curTextNode, hack\n        /* jshint ignore:end */\n  \n        if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) &&\n            textCount === curTextNode.nodeValue.length) {\n          textCount -= curTextNode.nodeValue.length;\n          curTextNode = curTextNode.nextSibling;\n        }\n  \n        container = curTextNode;\n        offset = textCount;\n      }\n  \n      return {\n        cont: container,\n        offset: offset\n      };\n    };\n    \n    /**\n     * return TextRange from boundary point (inspired by google closure-library)\n     * @param {BoundaryPoint} point\n     * @return {TextRange}\n     */\n    var pointToTextRange = function (point) {\n      var textRangeInfo = function (container, offset) {\n        var node, isCollapseToStart;\n  \n        if (dom.isText(container)) {\n          var prevTextNodes = dom.listPrev(container, func.not(dom.isText));\n          var prevContainer = list.last(prevTextNodes).previousSibling;\n          node =  prevContainer || container.parentNode;\n          offset += list.sum(list.tail(prevTextNodes), dom.nodeLength);\n          isCollapseToStart = !prevContainer;\n        } else {\n          node = container.childNodes[offset] || container;\n          if (dom.isText(node)) {\n            return textRangeInfo(node, 0);\n          }\n  \n          offset = 0;\n          isCollapseToStart = false;\n        }\n  \n        return {\n          node: node,\n          collapseToStart: isCollapseToStart,\n          offset: offset\n        };\n      };\n  \n      var textRange = document.body.createTextRange();\n      var info = textRangeInfo(point.node, point.offset);\n  \n      textRange.moveToElementText(info.node);\n      textRange.collapse(info.collapseToStart);\n      textRange.moveStart('character', info.offset);\n      return textRange;\n    };\n    \n    /**\n     * Wrapped Range\n     *\n     * @constructor\n     * @param {Node} sc - start container\n     * @param {Number} so - start offset\n     * @param {Node} ec - end container\n     * @param {Number} eo - end offset\n     */\n    var WrappedRange = function (sc, so, ec, eo) {\n      this.sc = sc;\n      this.so = so;\n      this.ec = ec;\n      this.eo = eo;\n  \n      // nativeRange: get nativeRange from sc, so, ec, eo\n      var nativeRange = function () {\n        if (agent.isW3CRangeSupport) {\n          var w3cRange = document.createRange();\n          w3cRange.setStart(sc, so);\n          w3cRange.setEnd(ec, eo);\n\n          return w3cRange;\n        } else {\n          var textRange = pointToTextRange({\n            node: sc,\n            offset: so\n          });\n\n          textRange.setEndPoint('EndToEnd', pointToTextRange({\n            node: ec,\n            offset: eo\n          }));\n\n          return textRange;\n        }\n      };\n\n      this.getPoints = function () {\n        return {\n          sc: sc,\n          so: so,\n          ec: ec,\n          eo: eo\n        };\n      };\n\n      this.getStartPoint = function () {\n        return {\n          node: sc,\n          offset: so\n        };\n      };\n\n      this.getEndPoint = function () {\n        return {\n          node: ec,\n          offset: eo\n        };\n      };\n\n      /**\n       * select update visible range\n       */\n      this.select = function () {\n        var nativeRng = nativeRange();\n        if (agent.isW3CRangeSupport) {\n          var selection = document.getSelection();\n          if (selection.rangeCount > 0) {\n            selection.removeAllRanges();\n          }\n          selection.addRange(nativeRng);\n        } else {\n          nativeRng.select();\n        }\n        \n        return this;\n      };\n\n      /**\n       * @return {WrappedRange}\n       */\n      this.normalize = function () {\n\n        /**\n         * @param {BoundaryPoint} point\n         * @param {Boolean} isLeftToRight\n         * @return {BoundaryPoint}\n         */\n        var getVisiblePoint = function (point, isLeftToRight) {\n          if ((dom.isVisiblePoint(point) && !dom.isEdgePoint(point)) ||\n              (dom.isVisiblePoint(point) && dom.isRightEdgePoint(point) && !isLeftToRight) ||\n              (dom.isVisiblePoint(point) && dom.isLeftEdgePoint(point) && isLeftToRight) ||\n              (dom.isVisiblePoint(point) && dom.isBlock(point.node) && dom.isEmpty(point.node))) {\n            return point;\n          }\n\n          // point on block's edge\n          var block = dom.ancestor(point.node, dom.isBlock);\n          if (((dom.isLeftEdgePointOf(point, block) || dom.isVoid(dom.prevPoint(point).node)) && !isLeftToRight) ||\n              ((dom.isRightEdgePointOf(point, block) || dom.isVoid(dom.nextPoint(point).node)) && isLeftToRight)) {\n\n            // returns point already on visible point\n            if (dom.isVisiblePoint(point)) {\n              return point;\n            }\n            // reverse direction \n            isLeftToRight = !isLeftToRight;\n          }\n\n          var nextPoint = isLeftToRight ? dom.nextPointUntil(dom.nextPoint(point), dom.isVisiblePoint) :\n                                          dom.prevPointUntil(dom.prevPoint(point), dom.isVisiblePoint);\n          return nextPoint || point;\n        };\n\n        var endPoint = getVisiblePoint(this.getEndPoint(), false);\n        var startPoint = this.isCollapsed() ? endPoint : getVisiblePoint(this.getStartPoint(), true);\n\n        return new WrappedRange(\n          startPoint.node,\n          startPoint.offset,\n          endPoint.node,\n          endPoint.offset\n        );\n      };\n\n      /**\n       * returns matched nodes on range\n       *\n       * @param {Function} [pred] - predicate function\n       * @param {Object} [options]\n       * @param {Boolean} [options.includeAncestor]\n       * @param {Boolean} [options.fullyContains]\n       * @return {Node[]}\n       */\n      this.nodes = function (pred, options) {\n        pred = pred || func.ok;\n\n        var includeAncestor = options && options.includeAncestor;\n        var fullyContains = options && options.fullyContains;\n\n        // TODO compare points and sort\n        var startPoint = this.getStartPoint();\n        var endPoint = this.getEndPoint();\n\n        var nodes = [];\n        var leftEdgeNodes = [];\n\n        dom.walkPoint(startPoint, endPoint, function (point) {\n          if (dom.isEditable(point.node)) {\n            return;\n          }\n\n          var node;\n          if (fullyContains) {\n            if (dom.isLeftEdgePoint(point)) {\n              leftEdgeNodes.push(point.node);\n            }\n            if (dom.isRightEdgePoint(point) && list.contains(leftEdgeNodes, point.node)) {\n              node = point.node;\n            }\n          } else if (includeAncestor) {\n            node = dom.ancestor(point.node, pred);\n          } else {\n            node = point.node;\n          }\n\n          if (node && pred(node)) {\n            nodes.push(node);\n          }\n        }, true);\n\n        return list.unique(nodes);\n      };\n\n      /**\n       * returns commonAncestor of range\n       * @return {Element} - commonAncestor\n       */\n      this.commonAncestor = function () {\n        return dom.commonAncestor(sc, ec);\n      };\n\n      /**\n       * returns expanded range by pred\n       *\n       * @param {Function} pred - predicate function\n       * @return {WrappedRange}\n       */\n      this.expand = function (pred) {\n        var startAncestor = dom.ancestor(sc, pred);\n        var endAncestor = dom.ancestor(ec, pred);\n\n        if (!startAncestor && !endAncestor) {\n          return new WrappedRange(sc, so, ec, eo);\n        }\n\n        var boundaryPoints = this.getPoints();\n\n        if (startAncestor) {\n          boundaryPoints.sc = startAncestor;\n          boundaryPoints.so = 0;\n        }\n\n        if (endAncestor) {\n          boundaryPoints.ec = endAncestor;\n          boundaryPoints.eo = dom.nodeLength(endAncestor);\n        }\n\n        return new WrappedRange(\n          boundaryPoints.sc,\n          boundaryPoints.so,\n          boundaryPoints.ec,\n          boundaryPoints.eo\n        );\n      };\n\n      /**\n       * @param {Boolean} isCollapseToStart\n       * @return {WrappedRange}\n       */\n      this.collapse = function (isCollapseToStart) {\n        if (isCollapseToStart) {\n          return new WrappedRange(sc, so, sc, so);\n        } else {\n          return new WrappedRange(ec, eo, ec, eo);\n        }\n      };\n\n      /**\n       * splitText on range\n       */\n      this.splitText = function () {\n        var isSameContainer = sc === ec;\n        var boundaryPoints = this.getPoints();\n\n        if (dom.isText(ec) && !dom.isEdgePoint(this.getEndPoint())) {\n          ec.splitText(eo);\n        }\n\n        if (dom.isText(sc) && !dom.isEdgePoint(this.getStartPoint())) {\n          boundaryPoints.sc = sc.splitText(so);\n          boundaryPoints.so = 0;\n\n          if (isSameContainer) {\n            boundaryPoints.ec = boundaryPoints.sc;\n            boundaryPoints.eo = eo - so;\n          }\n        }\n\n        return new WrappedRange(\n          boundaryPoints.sc,\n          boundaryPoints.so,\n          boundaryPoints.ec,\n          boundaryPoints.eo\n        );\n      };\n\n      /**\n       * delete contents on range\n       * @return {WrappedRange}\n       */\n      this.deleteContents = function () {\n        if (this.isCollapsed()) {\n          return this;\n        }\n\n        var rng = this.splitText();\n        var nodes = rng.nodes(null, {\n          fullyContains: true\n        });\n\n        // find new cursor point\n        var point = dom.prevPointUntil(rng.getStartPoint(), function (point) {\n          return !list.contains(nodes, point.node);\n        });\n\n        var emptyParents = [];\n        $.each(nodes, function (idx, node) {\n          // find empty parents\n          var parent = node.parentNode;\n          if (point.node !== parent && dom.nodeLength(parent) === 1) {\n            emptyParents.push(parent);\n          }\n          dom.remove(node, false);\n        });\n\n        // remove empty parents\n        $.each(emptyParents, function (idx, node) {\n          dom.remove(node, false);\n        });\n\n        return new WrappedRange(\n          point.node,\n          point.offset,\n          point.node,\n          point.offset\n        ).normalize();\n      };\n      \n      /**\n       * makeIsOn: return isOn(pred) function\n       */\n      var makeIsOn = function (pred) {\n        return function () {\n          var ancestor = dom.ancestor(sc, pred);\n          return !!ancestor && (ancestor === dom.ancestor(ec, pred));\n        };\n      };\n  \n      // isOnEditable: judge whether range is on editable or not\n      this.isOnEditable = makeIsOn(dom.isEditable);\n      // isOnList: judge whether range is on list node or not\n      this.isOnList = makeIsOn(dom.isList);\n      // isOnAnchor: judge whether range is on anchor node or not\n      this.isOnAnchor = makeIsOn(dom.isAnchor);\n      // isOnAnchor: judge whether range is on cell node or not\n      this.isOnCell = makeIsOn(dom.isCell);\n\n      /**\n       * @param {Function} pred\n       * @return {Boolean}\n       */\n      this.isLeftEdgeOf = function (pred) {\n        if (!dom.isLeftEdgePoint(this.getStartPoint())) {\n          return false;\n        }\n\n        var node = dom.ancestor(this.sc, pred);\n        return node && dom.isLeftEdgeOf(this.sc, node);\n      };\n\n      /**\n       * returns whether range was collapsed or not\n       */\n      this.isCollapsed = function () {\n        return sc === ec && so === eo;\n      };\n\n      /**\n       * wrap inline nodes which children of body with paragraph\n       *\n       * @return {WrappedRange}\n       */\n      this.wrapBodyInlineWithPara = function () {\n        if (dom.isBodyContainer(sc) && dom.isEmpty(sc)) {\n          sc.innerHTML = dom.emptyPara;\n          return new WrappedRange(sc.firstChild, 0, sc.firstChild, 0);\n        }\n\n        /**\n         * [workaround] firefox often create range on not visible point. so normalize here.\n         *  - firefox: |<p>text</p>|\n         *  - chrome: <p>|text|</p>\n         */\n        var rng = this.normalize();\n        if (dom.isParaInline(sc) || dom.isPara(sc)) {\n          return rng;\n        }\n\n        // find inline top ancestor\n        var topAncestor;\n        if (dom.isInline(rng.sc)) {\n          var ancestors = dom.listAncestor(rng.sc, func.not(dom.isInline));\n          topAncestor = list.last(ancestors);\n          if (!dom.isInline(topAncestor)) {\n            topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];\n          }\n        } else {\n          topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];\n        }\n\n        // siblings not in paragraph\n        var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();\n        inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline));\n\n        // wrap with paragraph\n        if (inlineSiblings.length) {\n          var para = dom.wrap(list.head(inlineSiblings), 'p');\n          dom.appendChildNodes(para, list.tail(inlineSiblings));\n        }\n\n        return this.normalize();\n      };\n\n      /**\n       * insert node at current cursor\n       *\n       * @param {Node} node\n       * @return {Node}\n       */\n      this.insertNode = function (node) {\n        var rng = this.wrapBodyInlineWithPara().deleteContents();\n        var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));\n\n        if (info.rightNode) {\n          info.rightNode.parentNode.insertBefore(node, info.rightNode);\n        } else {\n          info.container.appendChild(node);\n        }\n\n        return node;\n      };\n\n      /**\n       * insert html at current cursor\n       */\n      this.pasteHTML = function (markup) {\n        var contentsContainer = $('<div></div>').html(markup)[0];\n        var childNodes = list.from(contentsContainer.childNodes);\n\n        var rng = this.wrapBodyInlineWithPara().deleteContents();\n\n        return childNodes.reverse().map(function (childNode) {\n          return rng.insertNode(childNode);\n        }).reverse();\n      };\n  \n      /**\n       * returns text in range\n       *\n       * @return {String}\n       */\n      this.toString = function () {\n        var nativeRng = nativeRange();\n        return agent.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;\n      };\n\n      /**\n       * returns range for word before cursor\n       *\n       * @param {Boolean} [findAfter] - find after cursor, default: false\n       * @return {WrappedRange}\n       */\n      this.getWordRange = function (findAfter) {\n        var endPoint = this.getEndPoint();\n\n        if (!dom.isCharPoint(endPoint)) {\n          return this;\n        }\n\n        var startPoint = dom.prevPointUntil(endPoint, function (point) {\n          return !dom.isCharPoint(point);\n        });\n\n        if (findAfter) {\n          endPoint = dom.nextPointUntil(endPoint, function (point) {\n            return !dom.isCharPoint(point);\n          });\n        }\n\n        return new WrappedRange(\n          startPoint.node,\n          startPoint.offset,\n          endPoint.node,\n          endPoint.offset\n        );\n      };\n  \n      /**\n       * create offsetPath bookmark\n       *\n       * @param {Node} editable\n       */\n      this.bookmark = function (editable) {\n        return {\n          s: {\n            path: dom.makeOffsetPath(editable, sc),\n            offset: so\n          },\n          e: {\n            path: dom.makeOffsetPath(editable, ec),\n            offset: eo\n          }\n        };\n      };\n\n      /**\n       * create offsetPath bookmark base on paragraph\n       *\n       * @param {Node[]} paras\n       */\n      this.paraBookmark = function (paras) {\n        return {\n          s: {\n            path: list.tail(dom.makeOffsetPath(list.head(paras), sc)),\n            offset: so\n          },\n          e: {\n            path: list.tail(dom.makeOffsetPath(list.last(paras), ec)),\n            offset: eo\n          }\n        };\n      };\n\n      /**\n       * getClientRects\n       * @return {Rect[]}\n       */\n      this.getClientRects = function () {\n        var nativeRng = nativeRange();\n        return nativeRng.getClientRects();\n      };\n    };\n\n  /**\n   * @class core.range\n   *\n   * Data structure\n   *  * BoundaryPoint: a point of dom tree\n   *  * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range\n   *\n   * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position\n   *\n   * @singleton\n   * @alternateClassName range\n   */\n    return {\n      /**\n       * @method\n       * \n       * create Range Object From arguments or Browser Selection\n       *\n       * @param {Node} sc - start container\n       * @param {Number} so - start offset\n       * @param {Node} ec - end container\n       * @param {Number} eo - end offset\n       * @return {WrappedRange}\n       */\n      create : function (sc, so, ec, eo) {\n        if (!arguments.length) { // from Browser Selection\n          if (agent.isW3CRangeSupport) {\n            var selection = document.getSelection();\n            if (!selection || selection.rangeCount === 0) {\n              return null;\n            } else if (dom.isBody(selection.anchorNode)) {\n              // Firefox: returns entire body as range on initialization. We won't never need it.\n              return null;\n            }\n  \n            var nativeRng = selection.getRangeAt(0);\n            sc = nativeRng.startContainer;\n            so = nativeRng.startOffset;\n            ec = nativeRng.endContainer;\n            eo = nativeRng.endOffset;\n          } else { // IE8: TextRange\n            var textRange = document.selection.createRange();\n            var textRangeEnd = textRange.duplicate();\n            textRangeEnd.collapse(false);\n            var textRangeStart = textRange;\n            textRangeStart.collapse(true);\n  \n            var startPoint = textRangeToPoint(textRangeStart, true),\n            endPoint = textRangeToPoint(textRangeEnd, false);\n\n            // same visible point case: range was collapsed.\n            if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) &&\n                dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) &&\n                endPoint.node.nextSibling === startPoint.node) {\n              startPoint = endPoint;\n            }\n\n            sc = startPoint.cont;\n            so = startPoint.offset;\n            ec = endPoint.cont;\n            eo = endPoint.offset;\n          }\n        } else if (arguments.length === 2) { //collapsed\n          ec = sc;\n          eo = so;\n        }\n        return new WrappedRange(sc, so, ec, eo);\n      },\n\n      /**\n       * @method \n       * \n       * create WrappedRange from node\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNode: function (node) {\n        var sc = node;\n        var so = 0;\n        var ec = node;\n        var eo = dom.nodeLength(ec);\n\n        // browsers can't target a picture or void node\n        if (dom.isVoid(sc)) {\n          so = dom.listPrev(sc).length - 1;\n          sc = sc.parentNode;\n        }\n        if (dom.isBR(ec)) {\n          eo = dom.listPrev(ec).length - 1;\n          ec = ec.parentNode;\n        } else if (dom.isVoid(ec)) {\n          eo = dom.listPrev(ec).length;\n          ec = ec.parentNode;\n        }\n\n        return this.create(sc, so, ec, eo);\n      },\n\n      /**\n       * create WrappedRange from node after position\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNodeBefore: function (node) {\n        return this.createFromNode(node).collapse(true);\n      },\n\n      /**\n       * create WrappedRange from node after position\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNodeAfter: function (node) {\n        return this.createFromNode(node).collapse();\n      },\n\n      /**\n       * @method \n       * \n       * create WrappedRange from bookmark\n       *\n       * @param {Node} editable\n       * @param {Object} bookmark\n       * @return {WrappedRange}\n       */\n      createFromBookmark : function (editable, bookmark) {\n        var sc = dom.fromOffsetPath(editable, bookmark.s.path);\n        var so = bookmark.s.offset;\n        var ec = dom.fromOffsetPath(editable, bookmark.e.path);\n        var eo = bookmark.e.offset;\n        return new WrappedRange(sc, so, ec, eo);\n      },\n\n      /**\n       * @method \n       *\n       * create WrappedRange from paraBookmark\n       *\n       * @param {Object} bookmark\n       * @param {Node[]} paras\n       * @return {WrappedRange}\n       */\n      createFromParaBookmark: function (bookmark, paras) {\n        var so = bookmark.s.offset;\n        var eo = bookmark.e.offset;\n        var sc = dom.fromOffsetPath(list.head(paras), bookmark.s.path);\n        var ec = dom.fromOffsetPath(list.last(paras), bookmark.e.path);\n\n        return new WrappedRange(sc, so, ec, eo);\n      }\n    };\n  })();\n\n  /**\n   * @class defaults \n   * \n   * @singleton\n   */\n  var defaults = {\n    /** @property */\n    version: '0.6.16',\n\n    /**\n     * \n     * for event options, reference to EventHandler.attach\n     * \n     * @property {Object} options \n     * @property {String/Number} [options.width=null] set editor width \n     * @property {String/Number} [options.height=null] set editor height, ex) 300\n     * @property {String/Number} options.minHeight set minimum height of editor\n     * @property {String/Number} options.maxHeight\n     * @property {String/Number} options.focus \n     * @property {Number} options.tabsize \n     * @property {Boolean} options.styleWithSpan\n     * @property {Object} options.codemirror\n     * @property {Object} [options.codemirror.mode='text/html']\n     * @property {Object} [options.codemirror.htmlMode=true]\n     * @property {Object} [options.codemirror.lineNumbers=true]\n     * @property {String} [options.lang=en-US] language 'en-US', 'ko-KR', ...\n     * @property {String} [options.direction=null] text direction, ex) 'rtl'\n     * @property {Array} [options.toolbar]\n     * @property {Boolean} [options.airMode=false]\n     * @property {Array} [options.airPopover]\n     * @property {Fucntion} [options.onInit] initialize\n     * @property {Fucntion} [options.onsubmit]\n     */\n    options: {\n      width: null,                  // set editor width\n      height: null,                 // set editor height, ex) 300\n\n      minHeight: null,              // set minimum height of editor\n      maxHeight: null,              // set maximum height of editor\n\n      focus: false,                 // set focus to editable area after initializing summernote\n\n      tabsize: 4,                   // size of tab ex) 2 or 4\n      styleWithSpan: true,          // style with span (Chrome and FF only)\n\n      disableLinkTarget: false,     // hide link Target Checkbox\n      disableDragAndDrop: false,    // disable drag and drop event\n      disableResizeEditor: false,   // disable resizing editor\n      disableResizeImage: false,    // disable resizing image\n\n      shortcuts: true,              // enable keyboard shortcuts\n\n      textareaAutoSync: true,       // enable textarea auto sync\n\n      placeholder: false,           // enable placeholder text\n      prettifyHtml: true,           // enable prettifying html while toggling codeview\n\n      iconPrefix: 'fa fa-',         // prefix for css icon classes\n\n      icons: {\n        font: {\n          bold: 'bold',\n          italic: 'italic',\n          underline: 'underline',\n          clear: 'eraser',\n          height: 'text-height',\n          strikethrough: 'strikethrough',\n          superscript: 'superscript',\n          subscript: 'subscript'\n        },\n        image: {\n          image: 'picture-o',\n          floatLeft: 'align-left',\n          floatRight: 'align-right',\n          floatNone: 'align-justify',\n          shapeRounded: 'square',\n          shapeCircle: 'circle-o',\n          shapeThumbnail: 'picture-o',\n          shapeNone: 'times',\n          remove: 'trash-o'\n        },\n        link: {\n          link: 'link',\n          unlink: 'unlink',\n          edit: 'edit'\n        },\n        table: {\n          table: 'table'\n        },\n        hr: {\n          insert: 'minus'\n        },\n        style: {\n          style: 'magic'\n        },\n        lists: {\n          unordered: 'list-ul',\n          ordered: 'list-ol'\n        },\n        options: {\n          help: 'question',\n          fullscreen: 'arrows-alt',\n          codeview: 'code'\n        },\n        paragraph: {\n          paragraph: 'align-left',\n          outdent: 'outdent',\n          indent: 'indent',\n          left: 'align-left',\n          center: 'align-center',\n          right: 'align-right',\n          justify: 'align-justify'\n        },\n        color: {\n          recent: 'font'\n        },\n        history: {\n          undo: 'undo',\n          redo: 'repeat'\n        },\n        misc: {\n          check: 'check'\n        }\n      },\n\n      dialogsInBody: false,          // false will add dialogs into editor\n\n      codemirror: {                 // codemirror options\n        mode: 'text/html',\n        htmlMode: true,\n        lineNumbers: true\n      },\n\n      // language\n      lang: 'en-US',                // language 'en-US', 'ko-KR', ...\n      direction: null,              // text direction, ex) 'rtl'\n\n      // toolbar\n      toolbar: [\n        ['style', ['style']],\n        ['font', ['bold', 'italic', 'underline', 'clear']],\n        // ['font', ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']],\n        ['fontname', ['fontname']],\n        ['fontsize', ['fontsize']],\n        ['color', ['color']],\n        ['para', ['ul', 'ol', 'paragraph']],\n        ['height', ['height']],\n        ['table', ['table']],\n        ['insert', ['link', 'picture', 'hr']],\n        ['view', ['fullscreen', 'codeview']],\n        ['help', ['help']]\n      ],\n\n      plugin : { },\n\n      // air mode: inline editor\n      airMode: false,\n      // airPopover: [\n      //   ['style', ['style']],\n      //   ['font', ['bold', 'italic', 'underline', 'clear']],\n      //   ['fontname', ['fontname']],\n      //   ['color', ['color']],\n      //   ['para', ['ul', 'ol', 'paragraph']],\n      //   ['height', ['height']],\n      //   ['table', ['table']],\n      //   ['insert', ['link', 'picture']],\n      //   ['help', ['help']]\n      // ],\n      airPopover: [\n        ['color', ['color']],\n        ['font', ['bold', 'underline', 'clear']],\n        ['para', ['ul', 'paragraph']],\n        ['table', ['table']],\n        ['insert', ['link', 'picture']]\n      ],\n\n      // style tag\n      styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n\n      // default fontName\n      defaultFontName: 'Helvetica Neue',\n\n      // fontName\n      fontNames: [\n        'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',\n        'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande',\n        'Tahoma', 'Times New Roman', 'Verdana'\n      ],\n      fontNamesIgnoreCheck: [],\n\n      fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],\n\n      // pallete colors(n x n)\n      colors: [\n        ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'],\n        ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],\n        ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],\n        ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],\n        ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],\n        ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],\n        ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],\n        ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']\n      ],\n\n      // lineHeight\n      lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],\n\n      // insertTable max size\n      insertTableMaxSize: {\n        col: 10,\n        row: 10\n      },\n\n      // image\n      maximumImageFileSize: null, // size in bytes, null = no limit\n\n      // callbacks\n      oninit: null,             // initialize\n      onfocus: null,            // editable has focus\n      onblur: null,             // editable out of focus\n      onenter: null,            // enter key pressed\n      onkeyup: null,            // keyup\n      onkeydown: null,          // keydown\n      onImageUpload: null,      // imageUpload\n      onImageUploadError: null, // imageUploadError\n      onMediaDelete: null,      // media delete\n      onToolbarClick: null,\n      onsubmit: null,\n\n      /**\n       * manipulate link address when user create link\n       * @param {String} sLinkUrl\n       * @return {String}\n       */\n      onCreateLink: function (sLinkUrl) {\n        if (sLinkUrl.indexOf('@') !== -1 && sLinkUrl.indexOf(':') === -1) {\n          sLinkUrl =  'mailto:' + sLinkUrl;\n        }\n\n        return sLinkUrl;\n      },\n\n      keyMap: {\n        pc: {\n          'ENTER': 'insertParagraph',\n          'CTRL+Z': 'undo',\n          'CTRL+Y': 'redo',\n          'TAB': 'tab',\n          'SHIFT+TAB': 'untab',\n          'CTRL+B': 'bold',\n          'CTRL+I': 'italic',\n          'CTRL+U': 'underline',\n          'CTRL+SHIFT+S': 'strikethrough',\n          'CTRL+BACKSLASH': 'removeFormat',\n          'CTRL+SHIFT+L': 'justifyLeft',\n          'CTRL+SHIFT+E': 'justifyCenter',\n          'CTRL+SHIFT+R': 'justifyRight',\n          'CTRL+SHIFT+J': 'justifyFull',\n          'CTRL+SHIFT+NUM7': 'insertUnorderedList',\n          'CTRL+SHIFT+NUM8': 'insertOrderedList',\n          'CTRL+LEFTBRACKET': 'outdent',\n          'CTRL+RIGHTBRACKET': 'indent',\n          'CTRL+NUM0': 'formatPara',\n          'CTRL+NUM1': 'formatH1',\n          'CTRL+NUM2': 'formatH2',\n          'CTRL+NUM3': 'formatH3',\n          'CTRL+NUM4': 'formatH4',\n          'CTRL+NUM5': 'formatH5',\n          'CTRL+NUM6': 'formatH6',\n          'CTRL+ENTER': 'insertHorizontalRule',\n          'CTRL+K': 'showLinkDialog'\n        },\n\n        mac: {\n          'ENTER': 'insertParagraph',\n          'CMD+Z': 'undo',\n          'CMD+SHIFT+Z': 'redo',\n          'TAB': 'tab',\n          'SHIFT+TAB': 'untab',\n          'CMD+B': 'bold',\n          'CMD+I': 'italic',\n          'CMD+U': 'underline',\n          'CMD+SHIFT+S': 'strikethrough',\n          'CMD+BACKSLASH': 'removeFormat',\n          'CMD+SHIFT+L': 'justifyLeft',\n          'CMD+SHIFT+E': 'justifyCenter',\n          'CMD+SHIFT+R': 'justifyRight',\n          'CMD+SHIFT+J': 'justifyFull',\n          'CMD+SHIFT+NUM7': 'insertUnorderedList',\n          'CMD+SHIFT+NUM8': 'insertOrderedList',\n          'CMD+LEFTBRACKET': 'outdent',\n          'CMD+RIGHTBRACKET': 'indent',\n          'CMD+NUM0': 'formatPara',\n          'CMD+NUM1': 'formatH1',\n          'CMD+NUM2': 'formatH2',\n          'CMD+NUM3': 'formatH3',\n          'CMD+NUM4': 'formatH4',\n          'CMD+NUM5': 'formatH5',\n          'CMD+NUM6': 'formatH6',\n          'CMD+ENTER': 'insertHorizontalRule',\n          'CMD+K': 'showLinkDialog'\n        }\n      }\n    },\n\n    // default language: en-US\n    lang: {\n      'en-US': {\n        font: {\n          bold: 'Bold',\n          italic: 'Italic',\n          underline: 'Underline',\n          clear: 'Remove Font Style',\n          height: 'Line Height',\n          name: 'Font Family',\n          strikethrough: 'Strikethrough',\n          subscript: 'Subscript',\n          superscript: 'Superscript',\n          size: 'Font Size'\n        },\n        image: {\n          image: 'Picture',\n          insert: 'Insert Image',\n          resizeFull: 'Resize Full',\n          resizeHalf: 'Resize Half',\n          resizeQuarter: 'Resize Quarter',\n          floatLeft: 'Float Left',\n          floatRight: 'Float Right',\n          floatNone: 'Float None',\n          shapeRounded: 'Shape: Rounded',\n          shapeCircle: 'Shape: Circle',\n          shapeThumbnail: 'Shape: Thumbnail',\n          shapeNone: 'Shape: None',\n          dragImageHere: 'Drag image or text here',\n          dropImage: 'Drop image or Text',\n          selectFromFiles: 'Select from files',\n          maximumFileSize: 'Maximum file size',\n          maximumFileSizeError: 'Maximum file size exceeded.',\n          url: 'Image URL',\n          remove: 'Remove Image'\n        },\n        link: {\n          link: 'Link',\n          insert: 'Insert Link',\n          unlink: 'Unlink',\n          edit: 'Edit',\n          textToDisplay: 'Text to display',\n          url: 'To what URL should this link go?',\n          openInNewWindow: 'Open in new window'\n        },\n        table: {\n          table: 'Table'\n        },\n        hr: {\n          insert: 'Insert Horizontal Rule'\n        },\n        style: {\n          style: 'Style',\n          normal: 'Normal',\n          blockquote: 'Quote',\n          pre: 'Code',\n          h1: 'Header 1',\n          h2: 'Header 2',\n          h3: 'Header 3',\n          h4: 'Header 4',\n          h5: 'Header 5',\n          h6: 'Header 6'\n        },\n        lists: {\n          unordered: 'Unordered list',\n          ordered: 'Ordered list'\n        },\n        options: {\n          help: 'Help',\n          fullscreen: 'Full Screen',\n          codeview: 'Code View'\n        },\n        paragraph: {\n          paragraph: 'Paragraph',\n          outdent: 'Outdent',\n          indent: 'Indent',\n          left: 'Align left',\n          center: 'Align center',\n          right: 'Align right',\n          justify: 'Justify full'\n        },\n        color: {\n          recent: 'Recent Color',\n          more: 'More Color',\n          background: 'Background Color',\n          foreground: 'Foreground Color',\n          transparent: 'Transparent',\n          setTransparent: 'Set transparent',\n          reset: 'Reset',\n          resetToDefault: 'Reset to default'\n        },\n        shortcut: {\n          shortcuts: 'Keyboard shortcuts',\n          close: 'Close',\n          textFormatting: 'Text formatting',\n          action: 'Action',\n          paragraphFormatting: 'Paragraph formatting',\n          documentStyle: 'Document Style',\n          extraKeys: 'Extra keys'\n        },\n        history: {\n          undo: 'Undo',\n          redo: 'Redo'\n        }\n      }\n    }\n  };\n\n  /**\n   * @class core.async\n   *\n   * Async functions which returns `Promise`\n   *\n   * @singleton\n   * @alternateClassName async\n   */\n  var async = (function () {\n    /**\n     * @method readFileAsDataURL\n     *\n     * read contents of file as representing URL\n     *\n     * @param {File} file\n     * @return {Promise} - then: sDataUrl\n     */\n    var readFileAsDataURL = function (file) {\n      return $.Deferred(function (deferred) {\n        $.extend(new FileReader(), {\n          onload: function (e) {\n            var sDataURL = e.target.result;\n            deferred.resolve(sDataURL);\n          },\n          onerror: function () {\n            deferred.reject(this);\n          }\n        }).readAsDataURL(file);\n      }).promise();\n    };\n  \n    /**\n     * @method createImage\n     *\n     * create `<image>` from url string\n     *\n     * @param {String} sUrl\n     * @param {String} filename\n     * @return {Promise} - then: $image\n     */\n    var createImage = function (sUrl, filename) {\n      return $.Deferred(function (deferred) {\n        var $img = $('<img>');\n\n        $img.one('load', function () {\n          $img.off('error abort');\n          deferred.resolve($img);\n        }).one('error abort', function () {\n          $img.off('load').detach();\n          deferred.reject($img);\n        }).css({\n          display: 'none'\n        }).appendTo(document.body).attr({\n          'src': sUrl,\n          'data-filename': filename\n        });\n      }).promise();\n    };\n\n    return {\n      readFileAsDataURL: readFileAsDataURL,\n      createImage: createImage\n    };\n  })();\n\n  /**\n   * @class core.key\n   *\n   * Object for keycodes.\n   *\n   * @singleton\n   * @alternateClassName key\n   */\n  var key = (function () {\n    var keyMap = {\n      'BACKSPACE': 8,\n      'TAB': 9,\n      'ENTER': 13,\n      'SPACE': 32,\n\n      // Number: 0-9\n      'NUM0': 48,\n      'NUM1': 49,\n      'NUM2': 50,\n      'NUM3': 51,\n      'NUM4': 52,\n      'NUM5': 53,\n      'NUM6': 54,\n      'NUM7': 55,\n      'NUM8': 56,\n\n      // Alphabet: a-z\n      'B': 66,\n      'E': 69,\n      'I': 73,\n      'J': 74,\n      'K': 75,\n      'L': 76,\n      'R': 82,\n      'S': 83,\n      'U': 85,\n      'V': 86,\n      'Y': 89,\n      'Z': 90,\n\n      'SLASH': 191,\n      'LEFTBRACKET': 219,\n      'BACKSLASH': 220,\n      'RIGHTBRACKET': 221\n    };\n\n    return {\n      /**\n       * @method isEdit\n       *\n       * @param {Number} keyCode\n       * @return {Boolean}\n       */\n      isEdit: function (keyCode) {\n        return list.contains([8, 9, 13, 32], keyCode);\n      },\n      /**\n       * @method isMove\n       *\n       * @param {Number} keyCode\n       * @return {Boolean}\n       */\n      isMove: function (keyCode) {\n        return list.contains([37, 38, 39, 40], keyCode);\n      },\n      /**\n       * @property {Object} nameFromCode\n       * @property {String} nameFromCode.8 \"BACKSPACE\"\n       */\n      nameFromCode: func.invertObject(keyMap),\n      code: keyMap\n    };\n  })();\n\n  /**\n   * @class editing.History\n   *\n   * Editor History\n   *\n   */\n  var History = function ($editable) {\n    var stack = [], stackOffset = -1;\n    var editable = $editable[0];\n\n    var makeSnapshot = function () {\n      var rng = range.create();\n      var emptyBookmark = {s: {path: [], offset: 0}, e: {path: [], offset: 0}};\n\n      return {\n        contents: $editable.html(),\n        bookmark: (rng ? rng.bookmark(editable) : emptyBookmark)\n      };\n    };\n\n    var applySnapshot = function (snapshot) {\n      if (snapshot.contents !== null) {\n        $editable.html(snapshot.contents);\n      }\n      if (snapshot.bookmark !== null) {\n        range.createFromBookmark(editable, snapshot.bookmark).select();\n      }\n    };\n\n    /**\n     * undo\n     */\n    this.undo = function () {\n      // Create snap shot if not yet recorded\n      if ($editable.html() !== stack[stackOffset].contents) {\n        this.recordUndo();\n      }\n\n      if (0 < stackOffset) {\n        stackOffset--;\n        applySnapshot(stack[stackOffset]);\n      }\n    };\n\n    /**\n     * redo\n     */\n    this.redo = function () {\n      if (stack.length - 1 > stackOffset) {\n        stackOffset++;\n        applySnapshot(stack[stackOffset]);\n      }\n    };\n\n    /**\n     * recorded undo\n     */\n    this.recordUndo = function () {\n      stackOffset++;\n\n      // Wash out stack after stackOffset\n      if (stack.length > stackOffset) {\n        stack = stack.slice(0, stackOffset);\n      }\n\n      // Create new snapshot and push it to the end\n      stack.push(makeSnapshot());\n    };\n\n    // Create first undo stack\n    this.recordUndo();\n  };\n\n  /**\n   * @class editing.Style\n   *\n   * Style\n   *\n   */\n  var Style = function () {\n    /**\n     * @method jQueryCSS\n     *\n     * [workaround] for old jQuery\n     * passing an array of style properties to .css()\n     * will result in an object of property-value pairs.\n     * (compability with version < 1.9)\n     *\n     * @private\n     * @param  {jQuery} $obj\n     * @param  {Array} propertyNames - An array of one or more CSS properties.\n     * @return {Object}\n     */\n    var jQueryCSS = function ($obj, propertyNames) {\n      if (agent.jqueryVersion < 1.9) {\n        var result = {};\n        $.each(propertyNames, function (idx, propertyName) {\n          result[propertyName] = $obj.css(propertyName);\n        });\n        return result;\n      }\n      return $obj.css.call($obj, propertyNames);\n    };\n\n    /**\n     * returns style object from node\n     *\n     * @param {jQuery} $node\n     * @return {Object}\n     */\n    this.fromNode = function ($node) {\n      var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];\n      var styleInfo = jQueryCSS($node, properties) || {};\n      styleInfo['font-size'] = parseInt(styleInfo['font-size'], 10);\n      return styleInfo;\n    };\n\n    /**\n     * paragraph level style\n     *\n     * @param {WrappedRange} rng\n     * @param {Object} styleInfo\n     */\n    this.stylePara = function (rng, styleInfo) {\n      $.each(rng.nodes(dom.isPara, {\n        includeAncestor: true\n      }), function (idx, para) {\n        $(para).css(styleInfo);\n      });\n    };\n\n    /**\n     * insert and returns styleNodes on range.\n     *\n     * @param {WrappedRange} rng\n     * @param {Object} [options] - options for styleNodes\n     * @param {String} [options.nodeName] - default: `SPAN`\n     * @param {Boolean} [options.expandClosestSibling] - default: `false`\n     * @param {Boolean} [options.onlyPartialContains] - default: `false`\n     * @return {Node[]}\n     */\n    this.styleNodes = function (rng, options) {\n      rng = rng.splitText();\n\n      var nodeName = options && options.nodeName || 'SPAN';\n      var expandClosestSibling = !!(options && options.expandClosestSibling);\n      var onlyPartialContains = !!(options && options.onlyPartialContains);\n\n      if (rng.isCollapsed()) {\n        return [rng.insertNode(dom.create(nodeName))];\n      }\n\n      var pred = dom.makePredByNodeName(nodeName);\n      var nodes = rng.nodes(dom.isText, {\n        fullyContains: true\n      }).map(function (text) {\n        return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);\n      });\n\n      if (expandClosestSibling) {\n        if (onlyPartialContains) {\n          var nodesInRange = rng.nodes();\n          // compose with partial contains predication\n          pred = func.and(pred, function (node) {\n            return list.contains(nodesInRange, node);\n          });\n        }\n\n        return nodes.map(function (node) {\n          var siblings = dom.withClosestSiblings(node, pred);\n          var head = list.head(siblings);\n          var tails = list.tail(siblings);\n          $.each(tails, function (idx, elem) {\n            dom.appendChildNodes(head, elem.childNodes);\n            dom.remove(elem);\n          });\n          return list.head(siblings);\n        });\n      } else {\n        return nodes;\n      }\n    };\n\n    /**\n     * get current style on cursor\n     *\n     * @param {WrappedRange} rng\n     * @return {Object} - object contains style properties.\n     */\n    this.current = function (rng) {\n      var $cont = $(dom.isText(rng.sc) ? rng.sc.parentNode : rng.sc);\n      var styleInfo = this.fromNode($cont);\n\n      // document.queryCommandState for toggle state\n      styleInfo['font-bold'] = document.queryCommandState('bold') ? 'bold' : 'normal';\n      styleInfo['font-italic'] = document.queryCommandState('italic') ? 'italic' : 'normal';\n      styleInfo['font-underline'] = document.queryCommandState('underline') ? 'underline' : 'normal';\n      styleInfo['font-strikethrough'] = document.queryCommandState('strikeThrough') ? 'strikethrough' : 'normal';\n      styleInfo['font-superscript'] = document.queryCommandState('superscript') ? 'superscript' : 'normal';\n      styleInfo['font-subscript'] = document.queryCommandState('subscript') ? 'subscript' : 'normal';\n\n      // list-style-type to list-style(unordered, ordered)\n      if (!rng.isOnList()) {\n        styleInfo['list-style'] = 'none';\n      } else {\n        var aOrderedType = ['circle', 'disc', 'disc-leading-zero', 'square'];\n        var isUnordered = $.inArray(styleInfo['list-style-type'], aOrderedType) > -1;\n        styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';\n      }\n\n      var para = dom.ancestor(rng.sc, dom.isPara);\n      if (para && para.style['line-height']) {\n        styleInfo['line-height'] = para.style.lineHeight;\n      } else {\n        var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);\n        styleInfo['line-height'] = lineHeight.toFixed(1);\n      }\n\n      styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);\n      styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);\n      styleInfo.range = rng;\n\n      return styleInfo;\n    };\n  };\n\n\n  /**\n   * @class editing.Bullet\n   *\n   * @alternateClassName Bullet\n   */\n  var Bullet = function () {\n    /**\n     * @method insertOrderedList\n     *\n     * toggle ordered list\n     *\n     * @type command\n     */\n    this.insertOrderedList = function () {\n      this.toggleList('OL');\n    };\n\n    /**\n     * @method insertUnorderedList\n     *\n     * toggle unordered list\n     *\n     * @type command\n     */\n    this.insertUnorderedList = function () {\n      this.toggleList('UL');\n    };\n\n    /**\n     * @method indent\n     *\n     * indent\n     *\n     * @type command\n     */\n    this.indent = function () {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        if (dom.isLi(head)) {\n          self.wrapList(paras, head.parentNode.nodeName);\n        } else {\n          $.each(paras, function (idx, para) {\n            $(para).css('marginLeft', function (idx, val) {\n              return (parseInt(val, 10) || 0) + 25;\n            });\n          });\n        }\n      });\n\n      rng.select();\n    };\n\n    /**\n     * @method outdent\n     *\n     * outdent\n     *\n     * @type command\n     */\n    this.outdent = function () {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        if (dom.isLi(head)) {\n          self.releaseList([paras]);\n        } else {\n          $.each(paras, function (idx, para) {\n            $(para).css('marginLeft', function (idx, val) {\n              val = (parseInt(val, 10) || 0);\n              return val > 25 ? val - 25 : '';\n            });\n          });\n        }\n      });\n\n      rng.select();\n    };\n\n    /**\n     * @method toggleList\n     *\n     * toggle list\n     *\n     * @param {String} listName - OL or UL\n     */\n    this.toggleList = function (listName) {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var bookmark = rng.paraBookmark(paras);\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      // paragraph to list\n      if (list.find(paras, dom.isPurePara)) {\n        var wrappedParas = [];\n        $.each(clustereds, function (idx, paras) {\n          wrappedParas = wrappedParas.concat(self.wrapList(paras, listName));\n        });\n        paras = wrappedParas;\n      // list to paragraph or change list style\n      } else {\n        var diffLists = rng.nodes(dom.isList, {\n          includeAncestor: true\n        }).filter(function (listNode) {\n          return !$.nodeName(listNode, listName);\n        });\n\n        if (diffLists.length) {\n          $.each(diffLists, function (idx, listNode) {\n            dom.replace(listNode, listName);\n          });\n        } else {\n          paras = this.releaseList(clustereds, true);\n        }\n      }\n\n      range.createFromParaBookmark(bookmark, paras).select();\n    };\n\n    /**\n     * @method wrapList\n     *\n     * @param {Node[]} paras\n     * @param {String} listName\n     * @return {Node[]}\n     */\n    this.wrapList = function (paras, listName) {\n      var head = list.head(paras);\n      var last = list.last(paras);\n\n      var prevList = dom.isList(head.previousSibling) && head.previousSibling;\n      var nextList = dom.isList(last.nextSibling) && last.nextSibling;\n\n      var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last);\n\n      // P to LI\n      paras = paras.map(function (para) {\n        return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;\n      });\n\n      // append to list(<ul>, <ol>)\n      dom.appendChildNodes(listNode, paras);\n\n      if (nextList) {\n        dom.appendChildNodes(listNode, list.from(nextList.childNodes));\n        dom.remove(nextList);\n      }\n\n      return paras;\n    };\n\n    /**\n     * @method releaseList\n     *\n     * @param {Array[]} clustereds\n     * @param {Boolean} isEscapseToBody\n     * @return {Node[]}\n     */\n    this.releaseList = function (clustereds, isEscapseToBody) {\n      var releasedParas = [];\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        var last = list.last(paras);\n\n        var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) :\n                                         head.parentNode;\n        var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {\n          node: last.parentNode,\n          offset: dom.position(last) + 1\n        }, {\n          isSkipPaddingBlankHTML: true\n        }) : null;\n\n        var middleList = dom.splitTree(headList, {\n          node: head.parentNode,\n          offset: dom.position(head)\n        }, {\n          isSkipPaddingBlankHTML: true\n        });\n\n        paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) :\n                                  list.from(middleList.childNodes).filter(dom.isLi);\n\n        // LI to P\n        if (isEscapseToBody || !dom.isList(headList.parentNode)) {\n          paras = paras.map(function (para) {\n            return dom.replace(para, 'P');\n          });\n        }\n\n        $.each(list.from(paras).reverse(), function (idx, para) {\n          dom.insertAfter(para, headList);\n        });\n\n        // remove empty lists\n        var rootLists = list.compact([headList, middleList, lastList]);\n        $.each(rootLists, function (idx, rootList) {\n          var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));\n          $.each(listNodes.reverse(), function (idx, listNode) {\n            if (!dom.nodeLength(listNode)) {\n              dom.remove(listNode, true);\n            }\n          });\n        });\n\n        releasedParas = releasedParas.concat(paras);\n      });\n\n      return releasedParas;\n    };\n  };\n\n\n  /**\n   * @class editing.Typing\n   *\n   * Typing\n   *\n   */\n  var Typing = function () {\n\n    // a Bullet instance to toggle lists off\n    var bullet = new Bullet();\n\n    /**\n     * insert tab\n     *\n     * @param {jQuery} $editable\n     * @param {WrappedRange} rng\n     * @param {Number} tabsize\n     */\n    this.insertTab = function ($editable, rng, tabsize) {\n      var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));\n      rng = rng.deleteContents();\n      rng.insertNode(tab, true);\n\n      rng = range.create(tab, tabsize);\n      rng.select();\n    };\n\n    /**\n     * insert paragraph\n     */\n    this.insertParagraph = function () {\n      var rng = range.create();\n\n      // deleteContents on range.\n      rng = rng.deleteContents();\n\n      // Wrap range if it needs to be wrapped by paragraph\n      rng = rng.wrapBodyInlineWithPara();\n\n      // finding paragraph\n      var splitRoot = dom.ancestor(rng.sc, dom.isPara);\n\n      var nextPara;\n      // on paragraph: split paragraph\n      if (splitRoot) {\n        // if it is an empty line with li\n        if (dom.isEmpty(splitRoot) && dom.isLi(splitRoot)) {\n          // disable UL/OL and escape!\n          bullet.toggleList(splitRoot.parentNode.nodeName);\n          return;\n        // if new line has content (not a line break)\n        } else {\n          nextPara = dom.splitTree(splitRoot, rng.getStartPoint());\n\n          var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);\n          emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));\n\n          $.each(emptyAnchors, function (idx, anchor) {\n            dom.remove(anchor);\n          });\n        }\n      // no paragraph: insert empty paragraph\n      } else {\n        var next = rng.sc.childNodes[rng.so];\n        nextPara = $(dom.emptyPara)[0];\n        if (next) {\n          rng.sc.insertBefore(nextPara, next);\n        } else {\n          rng.sc.appendChild(nextPara);\n        }\n      }\n\n      range.create(nextPara, 0).normalize().select();\n\n    };\n\n  };\n\n  /**\n   * @class editing.Table\n   *\n   * Table\n   *\n   */\n  var Table = function () {\n    /**\n     * handle tab key\n     *\n     * @param {WrappedRange} rng\n     * @param {Boolean} isShift\n     */\n    this.tab = function (rng, isShift) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      var table = dom.ancestor(cell, dom.isTable);\n      var cells = dom.listDescendant(table, dom.isCell);\n\n      var nextCell = list[isShift ? 'prev' : 'next'](cells, cell);\n      if (nextCell) {\n        range.create(nextCell, 0).select();\n      }\n    };\n\n    /**\n     * create empty table element\n     *\n     * @param {Number} rowCount\n     * @param {Number} colCount\n     * @return {Node}\n     */\n    this.createTable = function (colCount, rowCount) {\n      var tds = [], tdHTML;\n      for (var idxCol = 0; idxCol < colCount; idxCol++) {\n        tds.push('<td>' + dom.blank + '</td>');\n      }\n      tdHTML = tds.join('');\n\n      var trs = [], trHTML;\n      for (var idxRow = 0; idxRow < rowCount; idxRow++) {\n        trs.push('<tr>' + tdHTML + '</tr>');\n      }\n      trHTML = trs.join('');\n      return $('<table class=\"table table-bordered\">' + trHTML + '</table>')[0];\n    };\n  };\n\n\n  var KEY_BOGUS = 'bogus';\n\n  /**\n   * @class editing.Editor\n   *\n   * Editor\n   *\n   */\n  var Editor = function (handler) {\n\n    var self = this;\n    var style = new Style();\n    var table = new Table();\n    var typing = new Typing();\n    var bullet = new Bullet();\n\n    /**\n     * @method createRange\n     *\n     * create range\n     *\n     * @param {jQuery} $editable\n     * @return {WrappedRange}\n     */\n    this.createRange = function ($editable) {\n      this.focus($editable);\n      return range.create();\n    };\n\n    /**\n     * @method saveRange\n     *\n     * save current range\n     *\n     * @param {jQuery} $editable\n     * @param {Boolean} [thenCollapse=false]\n     */\n    this.saveRange = function ($editable, thenCollapse) {\n      this.focus($editable);\n      $editable.data('range', range.create());\n      if (thenCollapse) {\n        range.create().collapse().select();\n      }\n    };\n\n    /**\n     * @method saveRange\n     *\n     * save current node list to $editable.data('childNodes')\n     *\n     * @param {jQuery} $editable\n     */\n    this.saveNode = function ($editable) {\n      // copy child node reference\n      var copy = [];\n      for (var key  = 0, len = $editable[0].childNodes.length; key < len; key++) {\n        copy.push($editable[0].childNodes[key]);\n      }\n      $editable.data('childNodes', copy);\n    };\n\n    /**\n     * @method restoreRange\n     *\n     * restore lately range\n     *\n     * @param {jQuery} $editable\n     */\n    this.restoreRange = function ($editable) {\n      var rng = $editable.data('range');\n      if (rng) {\n        rng.select();\n        this.focus($editable);\n      }\n    };\n\n    /**\n     * @method restoreNode\n     *\n     * restore lately node list\n     *\n     * @param {jQuery} $editable\n     */\n    this.restoreNode = function ($editable) {\n      $editable.html('');\n      var child = $editable.data('childNodes');\n      for (var index = 0, len = child.length; index < len; index++) {\n        $editable[0].appendChild(child[index]);\n      }\n    };\n\n    /**\n     * @method currentStyle\n     *\n     * current style\n     *\n     * @param {Node} target\n     * @return {Object|Boolean} unfocus\n     */\n    this.currentStyle = function (target) {\n      var rng = range.create();\n      var styleInfo =  rng && rng.isOnEditable() ? style.current(rng.normalize()) : {};\n      if (dom.isImg(target)) {\n        styleInfo.image = target;\n      }\n      return styleInfo;\n    };\n\n    /**\n     * style from node\n     *\n     * @param {jQuery} $node\n     * @return {Object}\n     */\n    this.styleFromNode = function ($node) {\n      return style.fromNode($node);\n    };\n\n    var triggerOnBeforeChange = function ($editable) {\n      var $holder = dom.makeLayoutInfo($editable).holder();\n      handler.bindCustomEvent(\n        $holder, $editable.data('callbacks'), 'before.command'\n      )($editable.html(), $editable);\n    };\n\n    var triggerOnChange = function ($editable) {\n      var $holder = dom.makeLayoutInfo($editable).holder();\n      handler.bindCustomEvent(\n        $holder, $editable.data('callbacks'), 'change'\n      )($editable.html(), $editable);\n    };\n\n    /**\n     * @method undo\n     * undo\n     * @param {jQuery} $editable\n     */\n    this.undo = function ($editable) {\n      triggerOnBeforeChange($editable);\n      $editable.data('NoteHistory').undo();\n      triggerOnChange($editable);\n    };\n\n    /**\n     * @method redo\n     * redo\n     * @param {jQuery} $editable\n     */\n    this.redo = function ($editable) {\n      triggerOnBeforeChange($editable);\n      $editable.data('NoteHistory').redo();\n      triggerOnChange($editable);\n    };\n\n    /**\n     * @method beforeCommand\n     * before command\n     * @param {jQuery} $editable\n     */\n    var beforeCommand = this.beforeCommand = function ($editable) {\n      triggerOnBeforeChange($editable);\n      // keep focus on editable before command execution\n      self.focus($editable);\n    };\n\n    /**\n     * @method afterCommand\n     * after command\n     * @param {jQuery} $editable\n     * @param {Boolean} isPreventTrigger\n     */\n    var afterCommand = this.afterCommand = function ($editable, isPreventTrigger) {\n      $editable.data('NoteHistory').recordUndo();\n      if (!isPreventTrigger) {\n        triggerOnChange($editable);\n      }\n    };\n\n    /**\n     * @method bold\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method italic\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method underline\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method strikethrough\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method formatBlock\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method superscript\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method subscript\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyLeft\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyCenter\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyRight\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyFull\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method formatBlock\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method removeFormat\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method backColor\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method foreColor\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method insertHorizontalRule\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method fontName\n     *\n     * change font name\n     *\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /* jshint ignore:start */\n    // native commands(with execCommand), generate function for execCommand\n    var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript',\n                    'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull',\n                    'formatBlock', 'removeFormat',\n                    'backColor', 'foreColor', 'fontName'];\n\n    for (var idx = 0, len = commands.length; idx < len; idx ++) {\n      this[commands[idx]] = (function (sCmd) {\n        return function ($editable, value) {\n          beforeCommand($editable);\n\n          document.execCommand(sCmd, false, value);\n\n          afterCommand($editable, true);\n        };\n      })(commands[idx]);\n    }\n    /* jshint ignore:end */\n\n    /**\n     * @method tab\n     *\n     * handle tab key\n     *\n     * @param {jQuery} $editable\n     * @param {Object} options\n     */\n    this.tab = function ($editable, options) {\n      var rng = this.createRange($editable);\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        table.tab(rng);\n      } else {\n        beforeCommand($editable);\n        typing.insertTab($editable, rng, options.tabsize);\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * @method untab\n     *\n     * handle shift+tab key\n     *\n     */\n    this.untab = function ($editable) {\n      var rng = this.createRange($editable);\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        table.tab(rng, true);\n      }\n    };\n\n    /**\n     * @method insertParagraph\n     *\n     * insert paragraph\n     *\n     * @param {Node} $editable\n     */\n    this.insertParagraph = function ($editable) {\n      beforeCommand($editable);\n      typing.insertParagraph($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @method insertOrderedList\n     *\n     * @param {jQuery} $editable\n     */\n    this.insertOrderedList = function ($editable) {\n      beforeCommand($editable);\n      bullet.insertOrderedList($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.insertUnorderedList = function ($editable) {\n      beforeCommand($editable);\n      bullet.insertUnorderedList($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.indent = function ($editable) {\n      beforeCommand($editable);\n      bullet.indent($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.outdent = function ($editable) {\n      beforeCommand($editable);\n      bullet.outdent($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * insert image\n     *\n     * @param {jQuery} $editable\n     * @param {String} sUrl\n     */\n    this.insertImage = function ($editable, sUrl, filename) {\n      async.createImage(sUrl, filename).then(function ($image) {\n        beforeCommand($editable);\n        $image.css({\n          display: '',\n          width: Math.min($editable.width(), $image.width())\n        });\n        range.create().insertNode($image[0]);\n        range.createFromNodeAfter($image[0]).select();\n        afterCommand($editable);\n      }).fail(function () {\n        var $holder = dom.makeLayoutInfo($editable).holder();\n        handler.bindCustomEvent(\n          $holder, $editable.data('callbacks'), 'image.upload.error'\n        )();\n      });\n    };\n\n    /**\n     * @method insertNode\n     * insert node\n     * @param {Node} $editable\n     * @param {Node} node\n     */\n    this.insertNode = function ($editable, node) {\n      beforeCommand($editable);\n      range.create().insertNode(node);\n      range.createFromNodeAfter(node).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * insert text\n     * @param {Node} $editable\n     * @param {String} text\n     */\n    this.insertText = function ($editable, text) {\n      beforeCommand($editable);\n      var textNode = range.create().insertNode(dom.createText(text));\n      range.create(textNode, dom.nodeLength(textNode)).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * paste HTML\n     * @param {Node} $editable\n     * @param {String} markup\n     */\n    this.pasteHTML = function ($editable, markup) {\n      beforeCommand($editable);\n      var contents = range.create().pasteHTML(markup);\n      range.createFromNodeAfter(list.last(contents)).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * formatBlock\n     *\n     * @param {jQuery} $editable\n     * @param {String} tagName\n     */\n    this.formatBlock = function ($editable, tagName) {\n      beforeCommand($editable);\n      // [workaround] for MSIE, IE need `<`\n      tagName = agent.isMSIE ? '<' + tagName + '>' : tagName;\n      document.execCommand('FormatBlock', false, tagName);\n      afterCommand($editable);\n    };\n\n    this.formatPara = function ($editable) {\n      beforeCommand($editable);\n      this.formatBlock($editable, 'P');\n      afterCommand($editable);\n    };\n\n    /* jshint ignore:start */\n    for (var idx = 1; idx <= 6; idx ++) {\n      this['formatH' + idx] = function (idx) {\n        return function ($editable) {\n          this.formatBlock($editable, 'H' + idx);\n        };\n      }(idx);\n    };\n    /* jshint ignore:end */\n\n    /**\n     * fontSize\n     *\n     * @param {jQuery} $editable\n     * @param {String} value - px\n     */\n    this.fontSize = function ($editable, value) {\n      var rng = range.create();\n\n      if (rng.isCollapsed()) {\n        var spans = style.styleNodes(rng);\n        var firstSpan = list.head(spans);\n\n        $(spans).css({\n          'font-size': value + 'px'\n        });\n\n        // [workaround] added styled bogus span for style\n        //  - also bogus character needed for cursor position\n        if (firstSpan && !dom.nodeLength(firstSpan)) {\n          firstSpan.innerHTML = dom.ZERO_WIDTH_NBSP_CHAR;\n          range.createFromNodeAfter(firstSpan.firstChild).select();\n          $editable.data(KEY_BOGUS, firstSpan);\n        }\n      } else {\n        beforeCommand($editable);\n        $(style.styleNodes(rng)).css({\n          'font-size': value + 'px'\n        });\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * insert horizontal rule\n     * @param {jQuery} $editable\n     */\n    this.insertHorizontalRule = function ($editable) {\n      beforeCommand($editable);\n\n      var rng = range.create();\n      var hrNode = rng.insertNode($('<HR/>')[0]);\n      if (hrNode.nextSibling) {\n        range.create(hrNode.nextSibling, 0).normalize().select();\n      }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * remove bogus node and character\n     */\n    this.removeBogus = function ($editable) {\n      var bogusNode = $editable.data(KEY_BOGUS);\n      if (!bogusNode) {\n        return;\n      }\n\n      var textNode = list.find(list.from(bogusNode.childNodes), dom.isText);\n\n      var bogusCharIdx = textNode.nodeValue.indexOf(dom.ZERO_WIDTH_NBSP_CHAR);\n      if (bogusCharIdx !== -1) {\n        textNode.deleteData(bogusCharIdx, 1);\n      }\n\n      if (dom.isEmpty(bogusNode)) {\n        dom.remove(bogusNode);\n      }\n\n      $editable.removeData(KEY_BOGUS);\n    };\n\n    /**\n     * lineHeight\n     * @param {jQuery} $editable\n     * @param {String} value\n     */\n    this.lineHeight = function ($editable, value) {\n      beforeCommand($editable);\n      style.stylePara(range.create(), {\n        lineHeight: value\n      });\n      afterCommand($editable);\n    };\n\n    /**\n     * unlink\n     *\n     * @type command\n     *\n     * @param {jQuery} $editable\n     */\n    this.unlink = function ($editable) {\n      var rng = this.createRange($editable);\n      if (rng.isOnAnchor()) {\n        var anchor = dom.ancestor(rng.sc, dom.isAnchor);\n        rng = range.createFromNode(anchor);\n        rng.select();\n\n        beforeCommand($editable);\n        document.execCommand('unlink');\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * create link (command)\n     *\n     * @param {jQuery} $editable\n     * @param {Object} linkInfo\n     * @param {Object} options\n     */\n    this.createLink = function ($editable, linkInfo, options) {\n      var linkUrl = linkInfo.url;\n      var linkText = linkInfo.text;\n      var isNewWindow = linkInfo.isNewWindow;\n      var rng = linkInfo.range || this.createRange($editable);\n      var isTextChanged = rng.toString() !== linkText;\n\n      options = options || dom.makeLayoutInfo($editable).editor().data('options');\n\n      beforeCommand($editable);\n\n      if (options.onCreateLink) {\n        linkUrl = options.onCreateLink(linkUrl);\n      }\n\n      var anchors = [];\n      if (isTextChanged) {\n        // Create a new link when text changed.\n        var anchor = rng.insertNode($('<A>' + linkText + '</A>')[0]);\n        anchors.push(anchor);\n      } else {\n        anchors = style.styleNodes(rng, {\n          nodeName: 'A',\n          expandClosestSibling: true,\n          onlyPartialContains: true\n        });\n      }\n\n      $.each(anchors, function (idx, anchor) {\n        $(anchor).attr('href', linkUrl);\n        if (isNewWindow) {\n          $(anchor).attr('target', '_blank');\n        } else {\n          $(anchor).removeAttr('target');\n        }\n      });\n\n      var startRange = range.createFromNodeBefore(list.head(anchors));\n      var startPoint = startRange.getStartPoint();\n      var endRange = range.createFromNodeAfter(list.last(anchors));\n      var endPoint = endRange.getEndPoint();\n\n      range.create(\n        startPoint.node,\n        startPoint.offset,\n        endPoint.node,\n        endPoint.offset\n      ).select();\n\n      afterCommand($editable);\n    };\n\n    /**\n     * returns link info\n     *\n     * @return {Object}\n     * @return {WrappedRange} return.range\n     * @return {String} return.text\n     * @return {Boolean} [return.isNewWindow=true]\n     * @return {String} [return.url=\"\"]\n     */\n    this.getLinkInfo = function ($editable) {\n      this.focus($editable);\n\n      var rng = range.create().expand(dom.isAnchor);\n\n      // Get the first anchor on range(for edit).\n      var $anchor = $(list.head(rng.nodes(dom.isAnchor)));\n\n      return {\n        range: rng,\n        text: rng.toString(),\n        isNewWindow: $anchor.length ? $anchor.attr('target') === '_blank' : false,\n        url: $anchor.length ? $anchor.attr('href') : ''\n      };\n    };\n\n    /**\n     * setting color\n     *\n     * @param {Node} $editable\n     * @param {Object} sObjColor  color code\n     * @param {String} sObjColor.foreColor foreground color\n     * @param {String} sObjColor.backColor background color\n     */\n    this.color = function ($editable, sObjColor) {\n      var oColor = JSON.parse(sObjColor);\n      var foreColor = oColor.foreColor, backColor = oColor.backColor;\n\n      beforeCommand($editable);\n\n      if (foreColor) { document.execCommand('foreColor', false, foreColor); }\n      if (backColor) { document.execCommand('backColor', false, backColor); }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * insert Table\n     *\n     * @param {Node} $editable\n     * @param {String} sDim dimension of table (ex : \"5x5\")\n     */\n    this.insertTable = function ($editable, sDim) {\n      var dimension = sDim.split('x');\n      beforeCommand($editable);\n\n      var rng = range.create().deleteContents();\n      rng.insertNode(table.createTable(dimension[0], dimension[1]));\n      afterCommand($editable);\n    };\n\n    /**\n     * float me\n     *\n     * @param {jQuery} $editable\n     * @param {String} value\n     * @param {jQuery} $target\n     */\n    this.floatMe = function ($editable, value, $target) {\n      beforeCommand($editable);\n      // bootstrap\n      $target.removeClass('pull-left pull-right');\n      if (value && value !== 'none') {\n        $target.addClass('pull-' + value);\n      }\n\n      // fallback for non-bootstrap\n      $target.css('float', value);\n      afterCommand($editable);\n    };\n\n    /**\n     * change image shape\n     *\n     * @param {jQuery} $editable\n     * @param {String} value css class\n     * @param {Node} $target\n     */\n    this.imageShape = function ($editable, value, $target) {\n      beforeCommand($editable);\n\n      $target.removeClass('img-rounded img-circle img-thumbnail');\n\n      if (value) {\n        $target.addClass(value);\n      }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * resize overlay element\n     * @param {jQuery} $editable\n     * @param {String} value\n     * @param {jQuery} $target - target element\n     */\n    this.resize = function ($editable, value, $target) {\n      beforeCommand($editable);\n\n      $target.css({\n        width: value * 100 + '%',\n        height: ''\n      });\n\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {Position} pos\n     * @param {jQuery} $target - target element\n     * @param {Boolean} [bKeepRatio] - keep ratio\n     */\n    this.resizeTo = function (pos, $target, bKeepRatio) {\n      var imageSize;\n      if (bKeepRatio) {\n        var newRatio = pos.y / pos.x;\n        var ratio = $target.data('ratio');\n        imageSize = {\n          width: ratio > newRatio ? pos.x : pos.y / ratio,\n          height: ratio > newRatio ? pos.x * ratio : pos.y\n        };\n      } else {\n        imageSize = {\n          width: pos.x,\n          height: pos.y\n        };\n      }\n\n      $target.css(imageSize);\n    };\n\n    /**\n     * remove media object\n     *\n     * @param {jQuery} $editable\n     * @param {String} value - dummy argument (for keep interface)\n     * @param {jQuery} $target - target element\n     */\n    this.removeMedia = function ($editable, value, $target) {\n      beforeCommand($editable);\n      $target.detach();\n\n      handler.bindCustomEvent(\n        $(), $editable.data('callbacks'), 'media.delete'\n      )($target, $editable);\n\n      afterCommand($editable);\n    };\n\n    /**\n     * set focus\n     *\n     * @param $editable\n     */\n    this.focus = function ($editable) {\n      $editable.focus();\n\n      // [workaround] for firefox bug http://goo.gl/lVfAaI\n      if (agent.isFF && !range.create().isOnEditable()) {\n        range.createFromNode($editable[0])\n             .normalize()\n             .collapse()\n             .select();\n      }\n    };\n\n    /**\n     * returns whether contents is empty or not.\n     *\n     * @param {jQuery} $editable\n     * @return {Boolean}\n     */\n    this.isEmpty = function ($editable) {\n      return dom.isEmpty($editable[0]) || dom.emptyPara === $editable.html();\n    };\n  };\n\n  /**\n   * @class module.Button\n   *\n   * Button\n   */\n  var Button = function () {\n    /**\n     * update button status\n     *\n     * @param {jQuery} $container\n     * @param {Object} styleInfo\n     */\n    this.update = function ($container, styleInfo) {\n      /**\n       * handle dropdown's check mark (for fontname, fontsize, lineHeight).\n       * @param {jQuery} $btn\n       * @param {Number} value\n       */\n      var checkDropdownMenu = function ($btn, value) {\n        $btn.find('.dropdown-menu li a').each(function () {\n          // always compare string to avoid creating another func.\n          var isChecked = ($(this).data('value') + '') === (value + '');\n          this.className = isChecked ? 'checked' : '';\n        });\n      };\n\n      /**\n       * update button state(active or not).\n       *\n       * @private\n       * @param {String} selector\n       * @param {Function} pred\n       */\n      var btnState = function (selector, pred) {\n        var $btn = $container.find(selector);\n        $btn.toggleClass('active', pred());\n      };\n\n      if (styleInfo.image) {\n        var $img = $(styleInfo.image);\n\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-rounded\"]', function () {\n          return $img.hasClass('img-rounded');\n        });\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-circle\"]', function () {\n          return $img.hasClass('img-circle');\n        });\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-thumbnail\"]', function () {\n          return $img.hasClass('img-thumbnail');\n        });\n        btnState('button[data-event=\"imageShape\"]:not([data-value])', function () {\n          return !$img.is('.img-rounded, .img-circle, .img-thumbnail');\n        });\n\n        var imgFloat = $img.css('float');\n        btnState('button[data-event=\"floatMe\"][data-value=\"left\"]', function () {\n          return imgFloat === 'left';\n        });\n        btnState('button[data-event=\"floatMe\"][data-value=\"right\"]', function () {\n          return imgFloat === 'right';\n        });\n        btnState('button[data-event=\"floatMe\"][data-value=\"none\"]', function () {\n          return imgFloat !== 'left' && imgFloat !== 'right';\n        });\n\n        var style = $img.attr('style');\n        btnState('button[data-event=\"resize\"][data-value=\"1\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*100%/.test(style);\n        });\n        btnState('button[data-event=\"resize\"][data-value=\"0.5\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*50%/.test(style);\n        });\n        btnState('button[data-event=\"resize\"][data-value=\"0.25\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*25%/.test(style);\n        });\n        return;\n      }\n\n      // fontname\n      var $fontname = $container.find('.note-fontname');\n      if ($fontname.length) {\n        var selectedFont = styleInfo['font-family'];\n        if (!!selectedFont) {\n\n          var list = selectedFont.split(',');\n          for (var i = 0, len = list.length; i < len; i++) {\n            selectedFont = list[i].replace(/[\\'\\\"]/g, '').replace(/\\s+$/, '').replace(/^\\s+/, '');\n            if (agent.isFontInstalled(selectedFont)) {\n              break;\n            }\n          }\n          \n          $fontname.find('.note-current-fontname').text(selectedFont);\n          checkDropdownMenu($fontname, selectedFont);\n\n        }\n      }\n\n      // fontsize\n      var $fontsize = $container.find('.note-fontsize');\n      $fontsize.find('.note-current-fontsize').text(styleInfo['font-size']);\n      checkDropdownMenu($fontsize, parseFloat(styleInfo['font-size']));\n\n      // lineheight\n      var $lineHeight = $container.find('.note-height');\n      checkDropdownMenu($lineHeight, parseFloat(styleInfo['line-height']));\n\n      btnState('button[data-event=\"bold\"]', function () {\n        return styleInfo['font-bold'] === 'bold';\n      });\n      btnState('button[data-event=\"italic\"]', function () {\n        return styleInfo['font-italic'] === 'italic';\n      });\n      btnState('button[data-event=\"underline\"]', function () {\n        return styleInfo['font-underline'] === 'underline';\n      });\n      btnState('button[data-event=\"strikethrough\"]', function () {\n        return styleInfo['font-strikethrough'] === 'strikethrough';\n      });\n      btnState('button[data-event=\"superscript\"]', function () {\n        return styleInfo['font-superscript'] === 'superscript';\n      });\n      btnState('button[data-event=\"subscript\"]', function () {\n        return styleInfo['font-subscript'] === 'subscript';\n      });\n      btnState('button[data-event=\"justifyLeft\"]', function () {\n        return styleInfo['text-align'] === 'left' || styleInfo['text-align'] === 'start';\n      });\n      btnState('button[data-event=\"justifyCenter\"]', function () {\n        return styleInfo['text-align'] === 'center';\n      });\n      btnState('button[data-event=\"justifyRight\"]', function () {\n        return styleInfo['text-align'] === 'right';\n      });\n      btnState('button[data-event=\"justifyFull\"]', function () {\n        return styleInfo['text-align'] === 'justify';\n      });\n      btnState('button[data-event=\"insertUnorderedList\"]', function () {\n        return styleInfo['list-style'] === 'unordered';\n      });\n      btnState('button[data-event=\"insertOrderedList\"]', function () {\n        return styleInfo['list-style'] === 'ordered';\n      });\n    };\n\n    /**\n     * update recent color\n     *\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {Mixed} value\n     */\n    this.updateRecentColor = function (button, eventName, value) {\n      var $color = $(button).closest('.note-color');\n      var $recentColor = $color.find('.note-recent-color');\n      var colorInfo = JSON.parse($recentColor.attr('data-value'));\n      colorInfo[eventName] = value;\n      $recentColor.attr('data-value', JSON.stringify(colorInfo));\n      var sKey = eventName === 'backColor' ? 'background-color' : 'color';\n      $recentColor.find('i').css(sKey, value);\n    };\n  };\n\n  /**\n   * @class module.Toolbar\n   *\n   * Toolbar\n   */\n  var Toolbar = function () {\n    var button = new Button();\n\n    this.update = function ($toolbar, styleInfo) {\n      button.update($toolbar, styleInfo);\n    };\n\n    /**\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {String} value\n     */\n    this.updateRecentColor = function (buttonNode, eventName, value) {\n      button.updateRecentColor(buttonNode, eventName, value);\n    };\n\n    /**\n     * activate buttons exclude codeview\n     * @param {jQuery} $toolbar\n     */\n    this.activate = function ($toolbar) {\n      $toolbar.find('button')\n              .not('button[data-event=\"codeview\"]')\n              .removeClass('disabled');\n    };\n\n    /**\n     * deactivate buttons exclude codeview\n     * @param {jQuery} $toolbar\n     */\n    this.deactivate = function ($toolbar) {\n      $toolbar.find('button')\n              .not('button[data-event=\"codeview\"]')\n              .addClass('disabled');\n    };\n\n    /**\n     * @param {jQuery} $container\n     * @param {Boolean} [bFullscreen=false]\n     */\n    this.updateFullscreen = function ($container, bFullscreen) {\n      var $btn = $container.find('button[data-event=\"fullscreen\"]');\n      $btn.toggleClass('active', bFullscreen);\n    };\n\n    /**\n     * @param {jQuery} $container\n     * @param {Boolean} [isCodeview=false]\n     */\n    this.updateCodeview = function ($container, isCodeview) {\n      var $btn = $container.find('button[data-event=\"codeview\"]');\n      $btn.toggleClass('active', isCodeview);\n\n      if (isCodeview) {\n        this.deactivate($container);\n      } else {\n        this.activate($container);\n      }\n    };\n\n    /**\n     * get button in toolbar \n     *\n     * @param {jQuery} $editable\n     * @param {String} name\n     * @return {jQuery}\n     */\n    this.get = function ($editable, name) {\n      var $toolbar = dom.makeLayoutInfo($editable).toolbar();\n\n      return $toolbar.find('[data-name=' + name + ']');\n    };\n\n    /**\n     * set button state\n     * @param {jQuery} $editable\n     * @param {String} name\n     * @param {Boolean} [isActive=true]\n     */\n    this.setButtonState = function ($editable, name, isActive) {\n      isActive = (isActive === false) ? false : true;\n\n      var $button = this.get($editable, name);\n      $button.toggleClass('active', isActive);\n    };\n  };\n\n  var EDITABLE_PADDING = 24;\n\n  var Statusbar = function () {\n    var $document = $(document);\n\n    this.attach = function (layoutInfo, options) {\n      if (!options.disableResizeEditor) {\n        layoutInfo.statusbar().on('mousedown', hStatusbarMousedown);\n      }\n    };\n\n    /**\n     * `mousedown` event handler on statusbar\n     *\n     * @param {MouseEvent} event\n     */\n    var hStatusbarMousedown = function (event) {\n      event.preventDefault();\n      event.stopPropagation();\n\n      var $editable = dom.makeLayoutInfo(event.target).editable();\n      var editableTop = $editable.offset().top - $document.scrollTop();\n\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      var options = layoutInfo.editor().data('options');\n\n      $document.on('mousemove', function (event) {\n        var nHeight = event.clientY - (editableTop + EDITABLE_PADDING);\n\n        nHeight = (options.minHeight > 0) ? Math.max(nHeight, options.minHeight) : nHeight;\n        nHeight = (options.maxHeight > 0) ? Math.min(nHeight, options.maxHeight) : nHeight;\n\n        $editable.height(nHeight);\n      }).one('mouseup', function () {\n        $document.off('mousemove');\n      });\n    };\n  };\n\n  /**\n   * @class module.Popover\n   *\n   * Popover (http://getbootstrap.com/javascript/#popovers)\n   *\n   */\n  var Popover = function () {\n    var button = new Button();\n\n    /**\n     * returns position from placeholder\n     *\n     * @private\n     * @param {Node} placeholder\n     * @param {Object} options\n     * @param {Boolean} options.isAirMode\n     * @return {Position}\n     */\n    var posFromPlaceholder = function (placeholder, options) {\n      var isAirMode = options && options.isAirMode;\n      var isLeftTop = options && options.isLeftTop;\n\n      var $placeholder = $(placeholder);\n      var pos = isAirMode ? $placeholder.offset() : $placeholder.position();\n      var height = isLeftTop ? 0 : $placeholder.outerHeight(true); // include margin\n\n      // popover below placeholder.\n      return {\n        left: pos.left,\n        top: pos.top + height\n      };\n    };\n\n    /**\n     * show popover\n     *\n     * @private\n     * @param {jQuery} popover\n     * @param {Position} pos\n     */\n    var showPopover = function ($popover, pos) {\n      $popover.css({\n        display: 'block',\n        left: pos.left,\n        top: pos.top\n      });\n    };\n\n    var PX_POPOVER_ARROW_OFFSET_X = 20;\n\n    /**\n     * update current state\n     * @param {jQuery} $popover - popover container\n     * @param {Object} styleInfo - style object\n     * @param {Boolean} isAirMode\n     */\n    this.update = function ($popover, styleInfo, isAirMode) {\n      button.update($popover, styleInfo);\n\n      var $linkPopover = $popover.find('.note-link-popover');\n      if (styleInfo.anchor) {\n        var $anchor = $linkPopover.find('a');\n        var href = $(styleInfo.anchor).attr('href');\n        var target = $(styleInfo.anchor).attr('target');\n        $anchor.attr('href', href).html(href);\n        if (!target) {\n          $anchor.removeAttr('target');\n        } else {\n          $anchor.attr('target', '_blank');\n        }\n        showPopover($linkPopover, posFromPlaceholder(styleInfo.anchor, {\n          isAirMode: isAirMode\n        }));\n      } else {\n        $linkPopover.hide();\n      }\n\n      var $imagePopover = $popover.find('.note-image-popover');\n      if (styleInfo.image) {\n        showPopover($imagePopover, posFromPlaceholder(styleInfo.image, {\n          isAirMode: isAirMode,\n          isLeftTop: true\n        }));\n      } else {\n        $imagePopover.hide();\n      }\n\n      var $airPopover = $popover.find('.note-air-popover');\n      if (isAirMode && styleInfo.range && !styleInfo.range.isCollapsed()) {\n        var rect = list.last(styleInfo.range.getClientRects());\n        if (rect) {\n          var bnd = func.rect2bnd(rect);\n          showPopover($airPopover, {\n            left: Math.max(bnd.left + bnd.width / 2 - PX_POPOVER_ARROW_OFFSET_X, 0),\n            top: bnd.top + bnd.height\n          });\n        }\n      } else {\n        $airPopover.hide();\n      }\n    };\n\n    /**\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {String} value\n     */\n    this.updateRecentColor = function (button, eventName, value) {\n      button.updateRecentColor(button, eventName, value);\n    };\n\n    /**\n     * hide all popovers\n     * @param {jQuery} $popover - popover container\n     */\n    this.hide = function ($popover) {\n      $popover.children().hide();\n    };\n  };\n\n  /**\n   * @class module.Handle\n   *\n   * Handle\n   */\n  var Handle = function (handler) {\n    var $document = $(document);\n\n    /**\n     * `mousedown` event handler on $handle\n     *  - controlSizing: resize image\n     *\n     * @param {MouseEvent} event\n     */\n    var hHandleMousedown = function (event) {\n      if (dom.isControlSizing(event.target)) {\n        event.preventDefault();\n        event.stopPropagation();\n\n        var layoutInfo = dom.makeLayoutInfo(event.target),\n            $handle = layoutInfo.handle(),\n            $popover = layoutInfo.popover(),\n            $editable = layoutInfo.editable(),\n            $editor = layoutInfo.editor();\n\n        var target = $handle.find('.note-control-selection').data('target'),\n            $target = $(target), posStart = $target.offset(),\n            scrollTop = $document.scrollTop();\n\n        var isAirMode = $editor.data('options').airMode;\n\n        $document.on('mousemove', function (event) {\n          handler.invoke('editor.resizeTo', {\n            x: event.clientX - posStart.left,\n            y: event.clientY - (posStart.top - scrollTop)\n          }, $target, !event.shiftKey);\n\n          handler.invoke('handle.update', $handle, {image: target}, isAirMode);\n          handler.invoke('popover.update', $popover, {image: target}, isAirMode);\n        }).one('mouseup', function () {\n          $document.off('mousemove');\n          handler.invoke('editor.afterCommand', $editable);\n        });\n\n        if (!$target.data('ratio')) { // original ratio.\n          $target.data('ratio', $target.height() / $target.width());\n        }\n      }\n    };\n\n    this.attach = function (layoutInfo) {\n      layoutInfo.handle().on('mousedown', hHandleMousedown);\n    };\n\n    /**\n     * update handle\n     * @param {jQuery} $handle\n     * @param {Object} styleInfo\n     * @param {Boolean} isAirMode\n     */\n    this.update = function ($handle, styleInfo, isAirMode) {\n      var $selection = $handle.find('.note-control-selection');\n      if (styleInfo.image) {\n        var $image = $(styleInfo.image);\n        var pos = isAirMode ? $image.offset() : $image.position();\n\n        // include margin\n        var imageSize = {\n          w: $image.outerWidth(true),\n          h: $image.outerHeight(true)\n        };\n\n        $selection.css({\n          display: 'block',\n          left: pos.left,\n          top: pos.top,\n          width: imageSize.w,\n          height: imageSize.h\n        }).data('target', styleInfo.image); // save current image element.\n        var sizingText = imageSize.w + 'x' + imageSize.h;\n        $selection.find('.note-control-selection-info').text(sizingText);\n      } else {\n        $selection.hide();\n      }\n    };\n\n    /**\n     * hide\n     *\n     * @param {jQuery} $handle\n     */\n    this.hide = function ($handle) {\n      $handle.children().hide();\n    };\n  };\n\n  var Fullscreen = function (handler) {\n    var $window = $(window);\n    var $scrollbar = $('html, body');\n\n    /**\n     * toggle fullscreen\n     *\n     * @param {Object} layoutInfo\n     */\n    this.toggle = function (layoutInfo) {\n\n      var $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable();\n\n      var resize = function (size) {\n        $editable.css('height', size.h);\n        $codable.css('height', size.h);\n        if ($codable.data('cmeditor')) {\n          $codable.data('cmeditor').setsize(null, size.h);\n        }\n      };\n\n      $editor.toggleClass('fullscreen');\n      var isFullscreen = $editor.hasClass('fullscreen');\n      if (isFullscreen) {\n        $editable.data('orgheight', $editable.css('height'));\n\n        $window.on('resize', function () {\n          resize({\n            h: $window.height() - $toolbar.outerHeight()\n          });\n        }).trigger('resize');\n\n        $scrollbar.css('overflow', 'hidden');\n      } else {\n        $window.off('resize');\n        resize({\n          h: $editable.data('orgheight')\n        });\n        $scrollbar.css('overflow', 'visible');\n      }\n\n      handler.invoke('toolbar.updateFullscreen', $toolbar, isFullscreen);\n    };\n  };\n\n\n  var CodeMirror;\n  if (agent.hasCodeMirror) {\n    if (agent.isSupportAmd) {\n      require(['CodeMirror'], function (cm) {\n        CodeMirror = cm;\n      });\n    } else {\n      CodeMirror = window.CodeMirror;\n    }\n  }\n\n  /**\n   * @class Codeview\n   */\n  var Codeview = function (handler) {\n\n    this.sync = function (layoutInfo) {\n      var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);\n      if (isCodeview && agent.hasCodeMirror) {\n        layoutInfo.codable().data('cmEditor').save();\n      }\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     * @return {Boolean}\n     */\n    this.isActivated = function (layoutInfo) {\n      var $editor = layoutInfo.editor();\n      return $editor.hasClass('codeview');\n    };\n\n    /**\n     * toggle codeview\n     *\n     * @param {Object} layoutInfo\n     */\n    this.toggle = function (layoutInfo) {\n      if (this.isActivated(layoutInfo)) {\n        this.deactivate(layoutInfo);\n      } else {\n        this.activate(layoutInfo);\n      }\n    };\n\n    /**\n     * activate code view\n     *\n     * @param {Object} layoutInfo\n     */\n    this.activate = function (layoutInfo) {\n      var $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable(),\n          $popover = layoutInfo.popover(),\n          $handle = layoutInfo.handle();\n\n      var options = $editor.data('options');\n\n      $codable.val(dom.html($editable, options.prettifyHtml));\n      $codable.height($editable.height());\n\n      handler.invoke('toolbar.updateCodeview', $toolbar, true);\n      handler.invoke('popover.hide', $popover);\n      handler.invoke('handle.hide', $handle);\n\n      $editor.addClass('codeview');\n\n      $codable.focus();\n\n      // activate CodeMirror as codable\n      if (agent.hasCodeMirror) {\n        var cmEditor = CodeMirror.fromTextArea($codable[0], options.codemirror);\n\n        // CodeMirror TernServer\n        if (options.codemirror.tern) {\n          var server = new CodeMirror.TernServer(options.codemirror.tern);\n          cmEditor.ternServer = server;\n          cmEditor.on('cursorActivity', function (cm) {\n            server.updateArgHints(cm);\n          });\n        }\n\n        // CodeMirror hasn't Padding.\n        cmEditor.setSize(null, $editable.outerHeight());\n        $codable.data('cmEditor', cmEditor);\n      }\n    };\n\n    /**\n     * deactivate code view\n     *\n     * @param {Object} layoutInfo\n     */\n    this.deactivate = function (layoutInfo) {\n      var $holder = layoutInfo.holder(),\n          $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable();\n\n      var options = $editor.data('options');\n\n      // deactivate CodeMirror as codable\n      if (agent.hasCodeMirror) {\n        var cmEditor = $codable.data('cmEditor');\n        $codable.val(cmEditor.getValue());\n        cmEditor.toTextArea();\n      }\n\n      var value = dom.value($codable, options.prettifyHtml) || dom.emptyPara;\n      var isChange = $editable.html() !== value;\n\n      $editable.html(value);\n      $editable.height(options.height ? $codable.height() : 'auto');\n      $editor.removeClass('codeview');\n\n      if (isChange) {\n        handler.bindCustomEvent(\n          $holder, $editable.data('callbacks'), 'change'\n        )($editable.html(), $editable);\n      }\n\n      $editable.focus();\n\n      handler.invoke('toolbar.updateCodeview', $toolbar, false);\n    };\n  };\n\n  var DragAndDrop = function (handler) {\n    var $document = $(document);\n\n    /**\n     * attach Drag and Drop Events\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options\n     */\n    this.attach = function (layoutInfo, options) {\n      if (options.airMode || options.disableDragAndDrop) {\n        // prevent default drop event\n        $document.on('drop', function (e) {\n          e.preventDefault();\n        });\n      } else {\n        this.attachDragAndDropEvent(layoutInfo, options);\n      }\n    };\n\n    /**\n     * attach Drag and Drop Events\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options\n     */\n    this.attachDragAndDropEvent = function (layoutInfo, options) {\n      var collection = $(),\n          $editor = layoutInfo.editor(),\n          $dropzone = layoutInfo.dropzone(),\n          $dropzoneMessage = $dropzone.find('.note-dropzone-message');\n\n      // show dropzone on dragenter when dragging a object to document\n      // -but only if the editor is visible, i.e. has a positive width and height\n      $document.on('dragenter', function (e) {\n        var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);\n        var hasEditorSize = $editor.width() > 0 && $editor.height() > 0;\n        if (!isCodeview && !collection.length && hasEditorSize) {\n          $editor.addClass('dragover');\n          $dropzone.width($editor.width());\n          $dropzone.height($editor.height());\n          $dropzoneMessage.text(options.langInfo.image.dragImageHere);\n        }\n        collection = collection.add(e.target);\n      }).on('dragleave', function (e) {\n        collection = collection.not(e.target);\n        if (!collection.length) {\n          $editor.removeClass('dragover');\n        }\n      }).on('drop', function () {\n        collection = $();\n        $editor.removeClass('dragover');\n      });\n\n      // change dropzone's message on hover.\n      $dropzone.on('dragenter', function () {\n        $dropzone.addClass('hover');\n        $dropzoneMessage.text(options.langInfo.image.dropImage);\n      }).on('dragleave', function () {\n        $dropzone.removeClass('hover');\n        $dropzoneMessage.text(options.langInfo.image.dragImageHere);\n      });\n\n      // attach dropImage\n      $dropzone.on('drop', function (event) {\n\n        var dataTransfer = event.originalEvent.dataTransfer;\n        var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n\n        if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {\n          event.preventDefault();\n          layoutInfo.editable().focus();\n          handler.insertImages(layoutInfo, dataTransfer.files);\n        } else {\n          var insertNodefunc = function () {\n            layoutInfo.holder().summernote('insertNode', this);\n          };\n\n          for (var i = 0, len = dataTransfer.types.length; i < len; i++) {\n            var type = dataTransfer.types[i];\n            var content = dataTransfer.getData(type);\n\n            if (type.toLowerCase().indexOf('text') > -1) {\n              layoutInfo.holder().summernote('pasteHTML', content);\n            } else {\n              $(content).each(insertNodefunc);\n            }\n          }\n        }\n      }).on('dragover', false); // prevent default dragover event\n    };\n  };\n\n  var Clipboard = function (handler) {\n    var $paste;\n\n    this.attach = function (layoutInfo) {\n      // [workaround] getting image from clipboard\n      //  - IE11 and Firefox: CTRL+v hook\n      //  - Webkit: event.clipboardData\n      if ((agent.isMSIE && agent.browserVersion > 10) || agent.isFF) {\n        $paste = $('<div />').attr('contenteditable', true).css({\n          position : 'absolute',\n          left : -100000,\n          opacity : 0\n        });\n\n        layoutInfo.editable().on('keydown', function (e) {\n          if (e.ctrlKey && e.keyCode === key.code.V) {\n            handler.invoke('saveRange', layoutInfo.editable());\n            $paste.focus();\n\n            setTimeout(function () {\n              pasteByHook(layoutInfo);\n            }, 0);\n          }\n        });\n\n        layoutInfo.editable().before($paste);\n      } else {\n        layoutInfo.editable().on('paste', pasteByEvent);\n      }\n    };\n\n    var pasteByHook = function (layoutInfo) {\n      var $editable = layoutInfo.editable();\n      var node = $paste[0].firstChild;\n\n      if (dom.isImg(node)) {\n        var dataURI = node.src;\n        var decodedData = atob(dataURI.split(',')[1]);\n        var array = new Uint8Array(decodedData.length);\n        for (var i = 0; i < decodedData.length; i++) {\n          array[i] = decodedData.charCodeAt(i);\n        }\n\n        var blob = new Blob([array], { type : 'image/png' });\n        blob.name = 'clipboard.png';\n\n        handler.invoke('restoreRange', $editable);\n        handler.invoke('focus', $editable);\n        handler.insertImages(layoutInfo, [blob]);\n      } else {\n        var pasteContent = $('<div />').html($paste.html()).html();\n        handler.invoke('restoreRange', $editable);\n        handler.invoke('focus', $editable);\n\n        if (pasteContent) {\n          handler.invoke('pasteHTML', $editable, pasteContent);\n        }\n      }\n\n      $paste.empty();\n    };\n\n    /**\n     * paste by clipboard event\n     *\n     * @param {Event} event\n     */\n    var pasteByEvent = function (event) {\n      var clipboardData = event.originalEvent.clipboardData;\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      var $editable = layoutInfo.editable();\n\n      if (clipboardData && clipboardData.items && clipboardData.items.length) {\n        var item = list.head(clipboardData.items);\n        if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {\n          handler.insertImages(layoutInfo, [item.getAsFile()]);\n        }\n        handler.invoke('editor.afterCommand', $editable);\n      }\n    };\n  };\n\n  var LinkDialog = function (handler) {\n\n    /**\n     * toggle button status\n     *\n     * @private\n     * @param {jQuery} $btn\n     * @param {Boolean} isEnable\n     */\n    var toggleBtn = function ($btn, isEnable) {\n      $btn.toggleClass('disabled', !isEnable);\n      $btn.attr('disabled', !isEnable);\n    };\n\n    /**\n     * bind enter key\n     *\n     * @private\n     * @param {jQuery} $input\n     * @param {jQuery} $btn\n     */\n    var bindEnterKey = function ($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          $btn.trigger('click');\n        }\n      });\n    };\n\n    /**\n     * Show link dialog and set event handlers on dialog controls.\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @param {Object} linkInfo\n     * @return {Promise}\n     */\n    this.showLinkDialog = function ($editable, $dialog, linkInfo) {\n      return $.Deferred(function (deferred) {\n        var $linkDialog = $dialog.find('.note-link-dialog');\n\n        var $linkText = $linkDialog.find('.note-link-text'),\n        $linkUrl = $linkDialog.find('.note-link-url'),\n        $linkBtn = $linkDialog.find('.note-link-btn'),\n        $openInNewWindow = $linkDialog.find('input[type=checkbox]');\n\n        $linkDialog.one('shown.bs.modal', function () {\n          $linkText.val(linkInfo.text);\n\n          $linkText.on('input', function () {\n            toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());\n            // if linktext was modified by keyup,\n            // stop cloning text from linkUrl\n            linkInfo.text = $linkText.val();\n          });\n\n          // if no url was given, copy text to url\n          if (!linkInfo.url) {\n            linkInfo.url = linkInfo.text || 'http://';\n            toggleBtn($linkBtn, linkInfo.text);\n          }\n\n          $linkUrl.on('input', function () {\n            toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());\n            // display same link on `Text to display` input\n            // when create a new link\n            if (!linkInfo.text) {\n              $linkText.val($linkUrl.val());\n            }\n          }).val(linkInfo.url).trigger('focus').trigger('select');\n\n          bindEnterKey($linkUrl, $linkBtn);\n          bindEnterKey($linkText, $linkBtn);\n\n          $openInNewWindow.prop('checked', linkInfo.isNewWindow);\n\n          $linkBtn.one('click', function (event) {\n            event.preventDefault();\n\n            deferred.resolve({\n              range: linkInfo.range,\n              url: $linkUrl.val(),\n              text: $linkText.val(),\n              isNewWindow: $openInNewWindow.is(':checked')\n            });\n            $linkDialog.modal('hide');\n          });\n        }).one('hidden.bs.modal', function () {\n          // detach events\n          $linkText.off('input keypress');\n          $linkUrl.off('input keypress');\n          $linkBtn.off('click');\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        }).modal('show');\n      }).promise();\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     */\n    this.show = function (layoutInfo) {\n      var $editor = layoutInfo.editor(),\n          $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable(),\n          $popover = layoutInfo.popover(),\n          linkInfo = handler.invoke('editor.getLinkInfo', $editable);\n\n      var options = $editor.data('options');\n\n      handler.invoke('editor.saveRange', $editable);\n      this.showLinkDialog($editable, $dialog, linkInfo).then(function (linkInfo) {\n        handler.invoke('editor.restoreRange', $editable);\n        handler.invoke('editor.createLink', $editable, linkInfo, options);\n        // hide popover after creating link\n        handler.invoke('popover.hide', $popover);\n      }).fail(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n  };\n\n  var ImageDialog = function (handler) {\n    /**\n     * toggle button status\n     *\n     * @private\n     * @param {jQuery} $btn\n     * @param {Boolean} isEnable\n     */\n    var toggleBtn = function ($btn, isEnable) {\n      $btn.toggleClass('disabled', !isEnable);\n      $btn.attr('disabled', !isEnable);\n    };\n\n    /**\n     * bind enter key\n     *\n     * @private\n     * @param {jQuery} $input\n     * @param {jQuery} $btn\n     */\n    var bindEnterKey = function ($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          $btn.trigger('click');\n        }\n      });\n    };\n\n    this.show = function (layoutInfo) {\n      var $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable();\n\n      handler.invoke('editor.saveRange', $editable);\n      this.showImageDialog($editable, $dialog).then(function (data) {\n        handler.invoke('editor.restoreRange', $editable);\n\n        if (typeof data === 'string') {\n          // image url\n          handler.invoke('editor.insertImage', $editable, data);\n        } else {\n          // array of files\n          handler.insertImages(layoutInfo, data);\n        }\n      }).fail(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n\n    /**\n     * show image dialog\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @return {Promise}\n     */\n    this.showImageDialog = function ($editable, $dialog) {\n      return $.Deferred(function (deferred) {\n        var $imageDialog = $dialog.find('.note-image-dialog');\n\n        var $imageInput = $dialog.find('.note-image-input'),\n            $imageUrl = $dialog.find('.note-image-url'),\n            $imageBtn = $dialog.find('.note-image-btn');\n\n        $imageDialog.one('shown.bs.modal', function () {\n          // Cloning imageInput to clear element.\n          $imageInput.replaceWith($imageInput.clone()\n            .on('change', function () {\n              deferred.resolve(this.files || this.value);\n              $imageDialog.modal('hide');\n            })\n            .val('')\n          );\n\n          $imageBtn.click(function (event) {\n            event.preventDefault();\n\n            deferred.resolve($imageUrl.val());\n            $imageDialog.modal('hide');\n          });\n\n          $imageUrl.on('keyup paste', function (event) {\n            var url;\n            \n            if (event.type === 'paste') {\n              url = event.originalEvent.clipboardData.getData('text');\n            } else {\n              url = $imageUrl.val();\n            }\n            \n            toggleBtn($imageBtn, url);\n          }).val('').trigger('focus');\n          bindEnterKey($imageUrl, $imageBtn);\n        }).one('hidden.bs.modal', function () {\n          $imageInput.off('change');\n          $imageUrl.off('keyup paste keypress');\n          $imageBtn.off('click');\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        }).modal('show');\n      });\n    };\n  };\n\n  var HelpDialog = function (handler) {\n    /**\n     * show help dialog\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @return {Promise}\n     */\n    this.showHelpDialog = function ($editable, $dialog) {\n      return $.Deferred(function (deferred) {\n        var $helpDialog = $dialog.find('.note-help-dialog');\n\n        $helpDialog.one('hidden.bs.modal', function () {\n          deferred.resolve();\n        }).modal('show');\n      }).promise();\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     */\n    this.show = function (layoutInfo) {\n      var $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable();\n\n      handler.invoke('editor.saveRange', $editable, true);\n      this.showHelpDialog($editable, $dialog).then(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n  };\n\n\n  /**\n   * @class EventHandler\n   *\n   * EventHandler\n   *  - TODO: new instance per a editor\n   */\n  var EventHandler = function () {\n    var self = this;\n\n    /**\n     * Modules\n     */\n    var modules = this.modules = {\n      editor: new Editor(this),\n      toolbar: new Toolbar(this),\n      statusbar: new Statusbar(this),\n      popover: new Popover(this),\n      handle: new Handle(this),\n      fullscreen: new Fullscreen(this),\n      codeview: new Codeview(this),\n      dragAndDrop: new DragAndDrop(this),\n      clipboard: new Clipboard(this),\n      linkDialog: new LinkDialog(this),\n      imageDialog: new ImageDialog(this),\n      helpDialog: new HelpDialog(this)\n    };\n\n    /**\n     * invoke module's method\n     *\n     * @param {String} moduleAndMethod - ex) 'editor.redo'\n     * @param {...*} arguments - arguments of method\n     * @return {*}\n     */\n    this.invoke = function () {\n      var moduleAndMethod = list.head(list.from(arguments));\n      var args = list.tail(list.from(arguments));\n\n      var splits = moduleAndMethod.split('.');\n      var hasSeparator = splits.length > 1;\n      var moduleName = hasSeparator && list.head(splits);\n      var methodName = hasSeparator ? list.last(splits) : list.head(splits);\n\n      var module = this.getModule(moduleName);\n      var method = module[methodName];\n\n      return method && method.apply(module, args);\n    };\n\n    /**\n     * returns module\n     *\n     * @param {String} moduleName - name of module\n     * @return {Module} - defaults is editor\n     */\n    this.getModule = function (moduleName) {\n      return this.modules[moduleName] || this.modules.editor;\n    };\n\n    /**\n     * @param {jQuery} $holder\n     * @param {Object} callbacks\n     * @param {String} eventNamespace\n     * @returns {Function}\n     */\n    var bindCustomEvent = this.bindCustomEvent = function ($holder, callbacks, eventNamespace) {\n      return function () {\n        var callback = callbacks[func.namespaceToCamel(eventNamespace, 'on')];\n        if (callback) {\n          callback.apply($holder[0], arguments);\n        }\n        return $holder.trigger('summernote.' + eventNamespace, arguments);\n      };\n    };\n\n    /**\n     * insert Images from file array.\n     *\n     * @private\n     * @param {Object} layoutInfo\n     * @param {File[]} files\n     */\n    this.insertImages = function (layoutInfo, files) {\n      var $editor = layoutInfo.editor(),\n          $editable = layoutInfo.editable(),\n          $holder = layoutInfo.holder();\n\n      var callbacks = $editable.data('callbacks');\n      var options = $editor.data('options');\n\n      // If onImageUpload options setted\n      if (callbacks.onImageUpload) {\n        bindCustomEvent($holder, callbacks, 'image.upload')(files);\n      // else insert Image as dataURL\n      } else {\n        $.each(files, function (idx, file) {\n          var filename = file.name;\n          if (options.maximumImageFileSize && options.maximumImageFileSize < file.size) {\n            bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);\n          } else {\n            async.readFileAsDataURL(file).then(function (sDataURL) {\n              modules.editor.insertImage($editable, sDataURL, filename);\n            }).fail(function () {\n              bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);\n            });\n          }\n        });\n      }\n    };\n\n    var commands = {\n      /**\n       * @param {Object} layoutInfo\n       */\n      showLinkDialog: function (layoutInfo) {\n        modules.linkDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      showImageDialog: function (layoutInfo) {\n        modules.imageDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      showHelpDialog: function (layoutInfo) {\n        modules.helpDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      fullscreen: function (layoutInfo) {\n        modules.fullscreen.toggle(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      codeview: function (layoutInfo) {\n        modules.codeview.toggle(layoutInfo);\n      }\n    };\n\n    var hMousedown = function (event) {\n      //preventDefault Selection for FF, IE8+\n      if (dom.isImg(event.target)) {\n        event.preventDefault();\n      }\n    };\n\n    var hKeyupAndMouseup = function (event) {\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      modules.editor.removeBogus(layoutInfo.editable());\n      hToolbarAndPopoverUpdate(event);\n    };\n\n    /**\n     * update sytle info\n     * @param {Object} styleInfo\n     * @param {Object} layoutInfo\n     */\n    this.updateStyleInfo = function (styleInfo, layoutInfo) {\n      if (!styleInfo) {\n        return;\n      }\n      var isAirMode = layoutInfo.editor().data('options').airMode;\n      if (!isAirMode) {\n        modules.toolbar.update(layoutInfo.toolbar(), styleInfo);\n      }\n\n      modules.popover.update(layoutInfo.popover(), styleInfo, isAirMode);\n      modules.handle.update(layoutInfo.handle(), styleInfo, isAirMode);\n    };\n\n    var hToolbarAndPopoverUpdate = function (event) {\n      var target = event.target;\n      // delay for range after mouseup\n      setTimeout(function () {\n        var layoutInfo = dom.makeLayoutInfo(target);\n        var styleInfo = modules.editor.currentStyle(target);\n        self.updateStyleInfo(styleInfo, layoutInfo);\n      }, 0);\n    };\n\n    var hScroll = function (event) {\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      //hide popover and handle when scrolled\n      modules.popover.hide(layoutInfo.popover());\n      modules.handle.hide(layoutInfo.handle());\n    };\n\n    var hToolbarAndPopoverMousedown = function (event) {\n      // prevent default event when insertTable (FF, Webkit)\n      var $btn = $(event.target).closest('[data-event]');\n      if ($btn.length) {\n        event.preventDefault();\n      }\n    };\n\n    var hToolbarAndPopoverClick = function (event) {\n      var $btn = $(event.target).closest('[data-event]');\n\n      if (!$btn.length) {\n        return;\n      }\n\n      var eventName = $btn.attr('data-event'),\n          value = $btn.attr('data-value'),\n          hide = $btn.attr('data-hide');\n\n      var layoutInfo = dom.makeLayoutInfo(event.target);\n\n      // before command: detect control selection element($target)\n      var $target;\n      if ($.inArray(eventName, ['resize', 'floatMe', 'removeMedia', 'imageShape']) !== -1) {\n        var $selection = layoutInfo.handle().find('.note-control-selection');\n        $target = $($selection.data('target'));\n      }\n\n      // If requested, hide the popover when the button is clicked.\n      // Useful for things like showHelpDialog.\n      if (hide) {\n        $btn.parents('.popover').hide();\n      }\n\n      if ($.isFunction($.summernote.pluginEvents[eventName])) {\n        $.summernote.pluginEvents[eventName](event, modules.editor, layoutInfo, value);\n      } else if (modules.editor[eventName]) { // on command\n        var $editable = layoutInfo.editable();\n        $editable.focus();\n        modules.editor[eventName]($editable, value, $target);\n        event.preventDefault();\n      } else if (commands[eventName]) {\n        commands[eventName].call(this, layoutInfo);\n        event.preventDefault();\n      }\n\n      // after command\n      if ($.inArray(eventName, ['backColor', 'foreColor']) !== -1) {\n        var options = layoutInfo.editor().data('options', options);\n        var module = options.airMode ? modules.popover : modules.toolbar;\n        module.updateRecentColor(list.head($btn), eventName, value);\n      }\n\n      hToolbarAndPopoverUpdate(event);\n    };\n\n    var PX_PER_EM = 18;\n    var hDimensionPickerMove = function (event, options) {\n      var $picker = $(event.target.parentNode); // target is mousecatcher\n      var $dimensionDisplay = $picker.next();\n      var $catcher = $picker.find('.note-dimension-picker-mousecatcher');\n      var $highlighted = $picker.find('.note-dimension-picker-highlighted');\n      var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');\n\n      var posOffset;\n      // HTML5 with jQuery - e.offsetX is undefined in Firefox\n      if (event.offsetX === undefined) {\n        var posCatcher = $(event.target).offset();\n        posOffset = {\n          x: event.pageX - posCatcher.left,\n          y: event.pageY - posCatcher.top\n        };\n      } else {\n        posOffset = {\n          x: event.offsetX,\n          y: event.offsetY\n        };\n      }\n\n      var dim = {\n        c: Math.ceil(posOffset.x / PX_PER_EM) || 1,\n        r: Math.ceil(posOffset.y / PX_PER_EM) || 1\n      };\n\n      $highlighted.css({ width: dim.c + 'em', height: dim.r + 'em' });\n      $catcher.attr('data-value', dim.c + 'x' + dim.r);\n\n      if (3 < dim.c && dim.c < options.insertTableMaxSize.col) {\n        $unhighlighted.css({ width: dim.c + 1 + 'em'});\n      }\n\n      if (3 < dim.r && dim.r < options.insertTableMaxSize.row) {\n        $unhighlighted.css({ height: dim.r + 1 + 'em'});\n      }\n\n      $dimensionDisplay.html(dim.c + ' x ' + dim.r);\n    };\n    \n    /**\n     * bind KeyMap on keydown\n     *\n     * @param {Object} layoutInfo\n     * @param {Object} keyMap\n     */\n    this.bindKeyMap = function (layoutInfo, keyMap) {\n      var $editor = layoutInfo.editor();\n      var $editable = layoutInfo.editable();\n\n      $editable.on('keydown', function (event) {\n        var keys = [];\n\n        // modifier\n        if (event.metaKey) { keys.push('CMD'); }\n        if (event.ctrlKey && !event.altKey) { keys.push('CTRL'); }\n        if (event.shiftKey) { keys.push('SHIFT'); }\n\n        // keycode\n        var keyName = key.nameFromCode[event.keyCode];\n        if (keyName) {\n          keys.push(keyName);\n        }\n\n        var pluginEvent;\n        var keyString = keys.join('+');\n        var eventName = keyMap[keyString];\n        if (eventName) {\n          // FIXME Summernote doesn't support event pipeline yet.\n          //  - Plugin -> Base Code\n          pluginEvent = $.summernote.pluginEvents[keyString];\n          if ($.isFunction(pluginEvent)) {\n            if (pluginEvent(event, modules.editor, layoutInfo)) {\n              return false;\n            }\n          }\n\n          pluginEvent = $.summernote.pluginEvents[eventName];\n\n          if ($.isFunction(pluginEvent)) {\n            pluginEvent(event, modules.editor, layoutInfo);\n          } else if (modules.editor[eventName]) {\n            modules.editor[eventName]($editable, $editor.data('options'));\n            event.preventDefault();\n          } else if (commands[eventName]) {\n            commands[eventName].call(this, layoutInfo);\n            event.preventDefault();\n          }\n        } else if (key.isEdit(event.keyCode)) {\n          modules.editor.afterCommand($editable);\n        }\n      });\n    };\n\n    /**\n     * attach eventhandler\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options - user options include custom event handlers\n     */\n    this.attach = function (layoutInfo, options) {\n      // handlers for editable\n      if (options.shortcuts) {\n        this.bindKeyMap(layoutInfo, options.keyMap[agent.isMac ? 'mac' : 'pc']);\n      }\n      layoutInfo.editable().on('mousedown', hMousedown);\n      layoutInfo.editable().on('keyup mouseup', hKeyupAndMouseup);\n      layoutInfo.editable().on('scroll', hScroll);\n\n      // handler for clipboard\n      modules.clipboard.attach(layoutInfo, options);\n\n      // handler for handle and popover\n      modules.handle.attach(layoutInfo, options);\n      layoutInfo.popover().on('click', hToolbarAndPopoverClick);\n      layoutInfo.popover().on('mousedown', hToolbarAndPopoverMousedown);\n\n      // handler for drag and drop\n      modules.dragAndDrop.attach(layoutInfo, options);\n\n      // handlers for frame mode (toolbar, statusbar)\n      if (!options.airMode) {\n        // handler for toolbar\n        layoutInfo.toolbar().on('click', hToolbarAndPopoverClick);\n        layoutInfo.toolbar().on('mousedown', hToolbarAndPopoverMousedown);\n\n        // handler for statusbar\n        modules.statusbar.attach(layoutInfo, options);\n      }\n\n      // handler for table dimension\n      var $catcherContainer = options.airMode ? layoutInfo.popover() :\n                                                layoutInfo.toolbar();\n      var $catcher = $catcherContainer.find('.note-dimension-picker-mousecatcher');\n      $catcher.css({\n        width: options.insertTableMaxSize.col + 'em',\n        height: options.insertTableMaxSize.row + 'em'\n      }).on('mousemove', function (event) {\n        hDimensionPickerMove(event, options);\n      });\n\n      // save options on editor\n      layoutInfo.editor().data('options', options);\n\n      // ret styleWithCSS for backColor / foreColor clearing with 'inherit'.\n      if (!agent.isMSIE) {\n        // [workaround] for Firefox\n        //  - protect FF Error: NS_ERROR_FAILURE: Failure\n        setTimeout(function () {\n          document.execCommand('styleWithCSS', 0, options.styleWithSpan);\n        }, 0);\n      }\n\n      // History\n      var history = new History(layoutInfo.editable());\n      layoutInfo.editable().data('NoteHistory', history);\n\n      // All editor status will be saved on editable with jquery's data\n      // for support multiple editor with singleton object.\n      layoutInfo.editable().data('callbacks', {\n        onInit: options.onInit,\n        onFocus: options.onFocus,\n        onBlur: options.onBlur,\n        onKeydown: options.onKeydown,\n        onKeyup: options.onKeyup,\n        onMousedown: options.onMousedown,\n        onEnter: options.onEnter,\n        onPaste: options.onPaste,\n        onBeforeCommand: options.onBeforeCommand,\n        onChange: options.onChange,\n        onImageUpload: options.onImageUpload,\n        onImageUploadError: options.onImageUploadError,\n        onMediaDelete: options.onMediaDelete,\n        onToolbarClick: options.onToolbarClick\n      });\n\n      var styleInfo = modules.editor.styleFromNode(layoutInfo.editable());\n      this.updateStyleInfo(styleInfo, layoutInfo);\n    };\n\n    /**\n     * attach jquery custom event\n     *\n     * @param {Object} layoutInfo - layout Informations\n     */\n    this.attachCustomEvent = function (layoutInfo, options) {\n      var $holder = layoutInfo.holder();\n      var $editable = layoutInfo.editable();\n      var callbacks = $editable.data('callbacks');\n\n      $editable.focus(bindCustomEvent($holder, callbacks, 'focus'));\n      $editable.blur(bindCustomEvent($holder, callbacks, 'blur'));\n\n      $editable.keydown(function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          bindCustomEvent($holder, callbacks, 'enter').call(this, event);\n        }\n        bindCustomEvent($holder, callbacks, 'keydown').call(this, event);\n      });\n      $editable.keyup(bindCustomEvent($holder, callbacks, 'keyup'));\n\n      $editable.on('mousedown', bindCustomEvent($holder, callbacks, 'mousedown'));\n      $editable.on('mouseup', bindCustomEvent($holder, callbacks, 'mouseup'));\n      $editable.on('scroll', bindCustomEvent($holder, callbacks, 'scroll'));\n\n      $editable.on('paste', bindCustomEvent($holder, callbacks, 'paste'));\n      \n      // [workaround] IE doesn't have input events for contentEditable\n      //  - see: https://goo.gl/4bfIvA\n      var changeEventName = agent.isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input';\n      $editable.on(changeEventName, function () {\n        bindCustomEvent($holder, callbacks, 'change')($editable.html(), $editable);\n      });\n\n      if (!options.airMode) {\n        layoutInfo.toolbar().click(bindCustomEvent($holder, callbacks, 'toolbar.click'));\n        layoutInfo.popover().click(bindCustomEvent($holder, callbacks, 'popover.click'));\n      }\n\n      // Textarea: auto filling the code before form submit.\n      if (dom.isTextarea(list.head($holder))) {\n        $holder.closest('form').submit(function (e) {\n          layoutInfo.holder().val(layoutInfo.holder().code());\n          bindCustomEvent($holder, callbacks, 'submit').call(this, e, $holder.code());\n        });\n      }\n\n      // textarea auto sync\n      if (dom.isTextarea(list.head($holder)) && options.textareaAutoSync) {\n        $holder.on('summernote.change', function () {\n          layoutInfo.holder().val(layoutInfo.holder().code());\n        });\n      }\n\n      // fire init event\n      bindCustomEvent($holder, callbacks, 'init')(layoutInfo);\n\n      // fire plugin init event\n      for (var i = 0, len = $.summernote.plugins.length; i < len; i++) {\n        if ($.isFunction($.summernote.plugins[i].init)) {\n          $.summernote.plugins[i].init(layoutInfo);\n        }\n      }\n    };\n      \n    this.detach = function (layoutInfo, options) {\n      layoutInfo.holder().off();\n      layoutInfo.editable().off();\n\n      layoutInfo.popover().off();\n      layoutInfo.handle().off();\n      layoutInfo.dialog().off();\n\n      if (!options.airMode) {\n        layoutInfo.dropzone().off();\n        layoutInfo.toolbar().off();\n        layoutInfo.statusbar().off();\n      }\n    };\n  };\n\n  /**\n   * @class Renderer\n   *\n   * renderer\n   *\n   * rendering toolbar and editable\n   */\n  var Renderer = function () {\n\n    /**\n     * bootstrap button template\n     * @private\n     * @param {String} label button name\n     * @param {Object} [options] button options\n     * @param {String} [options.event] data-event\n     * @param {String} [options.className] button's class name\n     * @param {String} [options.value] data-value\n     * @param {String} [options.title] button's title for popup\n     * @param {String} [options.dropdown] dropdown html\n     * @param {String} [options.hide] data-hide\n     */\n    var tplButton = function (label, options) {\n      var event = options.event;\n      var value = options.value;\n      var title = options.title;\n      var className = options.className;\n      var dropdown = options.dropdown;\n      var hide = options.hide;\n\n      return (dropdown ? '<div class=\"btn-group' +\n               (className ? ' ' + className : '') + '\">' : '') +\n               '<button type=\"button\"' +\n                 ' class=\"btn btn-default btn-sm' +\n                   ((!dropdown && className) ? ' ' + className : '') +\n                   (dropdown ? ' dropdown-toggle' : '') +\n                 '\"' +\n                 (dropdown ? ' data-toggle=\"dropdown\"' : '') +\n                 (title ? ' title=\"' + title + '\"' : '') +\n                 (event ? ' data-event=\"' + event + '\"' : '') +\n                 (value ? ' data-value=\\'' + value + '\\'' : '') +\n                 (hide ? ' data-hide=\\'' + hide + '\\'' : '') +\n                 ' tabindex=\"-1\">' +\n                 label +\n                 (dropdown ? ' <span class=\"caret\"></span>' : '') +\n               '</button>' +\n               (dropdown || '') +\n             (dropdown ? '</div>' : '');\n    };\n\n    /**\n     * bootstrap icon button template\n     * @private\n     * @param {String} iconClassName\n     * @param {Object} [options]\n     * @param {String} [options.event]\n     * @param {String} [options.value]\n     * @param {String} [options.title]\n     * @param {String} [options.dropdown]\n     */\n    var tplIconButton = function (iconClassName, options) {\n      var label = '<i class=\"' + iconClassName + '\"></i>';\n      return tplButton(label, options);\n    };\n\n    /**\n     * bootstrap popover template\n     * @private\n     * @param {String} className\n     * @param {String} content\n     */\n    var tplPopover = function (className, content) {\n      var $popover = $('<div class=\"' + className + ' popover bottom in\" style=\"display: none;\">' +\n               '<div class=\"arrow\"></div>' +\n               '<div class=\"popover-content\">' +\n               '</div>' +\n             '</div>');\n\n      $popover.find('.popover-content').append(content);\n      return $popover;\n    };\n\n    /**\n     * bootstrap dialog template\n     *\n     * @param {String} className\n     * @param {String} [title='']\n     * @param {String} body\n     * @param {String} [footer='']\n     */\n    var tplDialog = function (className, title, body, footer) {\n      return '<div class=\"' + className + ' modal\" aria-hidden=\"false\">' +\n               '<div class=\"modal-dialog\">' +\n                 '<div class=\"modal-content\">' +\n                   (title ?\n                   '<div class=\"modal-header\">' +\n                     '<button type=\"button\" class=\"close\" aria-hidden=\"true\" tabindex=\"-1\">&times;</button>' +\n                     '<h4 class=\"modal-title\">' + title + '</h4>' +\n                   '</div>' : ''\n                   ) +\n                   '<div class=\"modal-body\">' + body + '</div>' +\n                   (footer ?\n                   '<div class=\"modal-footer\">' + footer + '</div>' : ''\n                   ) +\n                 '</div>' +\n               '</div>' +\n             '</div>';\n    };\n\n    /**\n     * bootstrap dropdown template\n     *\n     * @param {String|String[]} contents\n     * @param {String} [className='']\n     * @param {String} [nodeName='']\n     */\n    var tplDropdown = function (contents, className, nodeName) {\n      var classes = 'dropdown-menu' + (className ? ' ' + className : '');\n      nodeName = nodeName || 'ul';\n      if (contents instanceof Array) {\n        contents = contents.join('');\n      }\n\n      return '<' + nodeName + ' class=\"' + classes + '\">' + contents + '</' + nodeName + '>';\n    };\n\n    var tplButtonInfo = {\n      picture: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.image.image, {\n          event: 'showImageDialog',\n          title: lang.image.image,\n          hide: true\n        });\n      },\n      link: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.link.link, {\n          event: 'showLinkDialog',\n          title: lang.link.link,\n          hide: true\n        });\n      },\n      table: function (lang, options) {\n        var dropdown = [\n          '<div class=\"note-dimension-picker\">',\n          '<div class=\"note-dimension-picker-mousecatcher\" data-event=\"insertTable\" data-value=\"1x1\"></div>',\n          '<div class=\"note-dimension-picker-highlighted\"></div>',\n          '<div class=\"note-dimension-picker-unhighlighted\"></div>',\n          '</div>',\n          '<div class=\"note-dimension-display\"> 1 x 1 </div>'\n        ];\n\n        return tplIconButton(options.iconPrefix + options.icons.table.table, {\n          title: lang.table.table,\n          dropdown: tplDropdown(dropdown, 'note-table')\n        });\n      },\n      style: function (lang, options) {\n        var items = options.styleTags.reduce(function (memo, v) {\n          var label = lang.style[v === 'p' ? 'normal' : v];\n          return memo + '<li><a data-event=\"formatBlock\" href=\"#\" data-value=\"' + v + '\">' +\n                   (\n                     (v === 'p' || v === 'pre') ? label :\n                     '<' + v + '>' + label + '</' + v + '>'\n                   ) +\n                 '</a></li>';\n        }, '');\n\n        return tplIconButton(options.iconPrefix + options.icons.style.style, {\n          title: lang.style.style,\n          dropdown: tplDropdown(items)\n        });\n      },\n      fontname: function (lang, options) {\n        var realFontList = [];\n        var items = options.fontNames.reduce(function (memo, v) {\n          if (!agent.isFontInstalled(v) && !list.contains(options.fontNamesIgnoreCheck, v)) {\n            return memo;\n          }\n          realFontList.push(v);\n          return memo + '<li><a data-event=\"fontName\" href=\"#\" data-value=\"' + v + '\" style=\"font-family:\\'' + v + '\\'\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        var hasDefaultFont = agent.isFontInstalled(options.defaultFontName);\n        var defaultFontName = (hasDefaultFont) ? options.defaultFontName : realFontList[0];\n\n        var label = '<span class=\"note-current-fontname\">' +\n                        defaultFontName +\n                     '</span>';\n        return tplButton(label, {\n          title: lang.font.name,\n          className: 'note-fontname',\n          dropdown: tplDropdown(items, 'note-check')\n        });\n      },\n      fontsize: function (lang, options) {\n        var items = options.fontSizes.reduce(function (memo, v) {\n          return memo + '<li><a data-event=\"fontSize\" href=\"#\" data-value=\"' + v + '\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        var label = '<span class=\"note-current-fontsize\">11</span>';\n        return tplButton(label, {\n          title: lang.font.size,\n          className: 'note-fontsize',\n          dropdown: tplDropdown(items, 'note-check')\n        });\n      },\n      color: function (lang, options) {\n        var colorButtonLabel = '<i class=\"' +\n                                  options.iconPrefix + options.icons.color.recent +\n                                '\" style=\"color:black;background-color:yellow;\"></i>';\n\n        var colorButton = tplButton(colorButtonLabel, {\n          className: 'note-recent-color',\n          title: lang.color.recent,\n          event: 'color',\n          value: '{\"backColor\":\"yellow\"}'\n        });\n\n        var items = [\n          '<li><div class=\"btn-group\">',\n          '<div class=\"note-palette-title\">' + lang.color.background + '</div>',\n          '<div class=\"note-color-reset\" data-event=\"backColor\"',\n          ' data-value=\"inherit\" title=\"' + lang.color.transparent + '\">' + lang.color.setTransparent + '</div>',\n          '<div class=\"note-color-palette\" data-target-event=\"backColor\"></div>',\n          '</div><div class=\"btn-group\">',\n          '<div class=\"note-palette-title\">' + lang.color.foreground + '</div>',\n          '<div class=\"note-color-reset\" data-event=\"foreColor\" data-value=\"inherit\" title=\"' + lang.color.reset + '\">',\n          lang.color.resetToDefault,\n          '</div>',\n          '<div class=\"note-color-palette\" data-target-event=\"foreColor\"></div>',\n          '</div></li>'\n        ];\n\n        var moreButton = tplButton('', {\n          title: lang.color.more,\n          dropdown: tplDropdown(items)\n        });\n\n        return colorButton + moreButton;\n      },\n      bold: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.bold, {\n          event: 'bold',\n          title: lang.font.bold\n        });\n      },\n      italic: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.italic, {\n          event: 'italic',\n          title: lang.font.italic\n        });\n      },\n      underline: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.underline, {\n          event: 'underline',\n          title: lang.font.underline\n        });\n      },\n      strikethrough: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.strikethrough, {\n          event: 'strikethrough',\n          title: lang.font.strikethrough\n        });\n      },\n      superscript: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.superscript, {\n          event: 'superscript',\n          title: lang.font.superscript\n        });\n      },\n      subscript: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.subscript, {\n          event: 'subscript',\n          title: lang.font.subscript\n        });\n      },\n      clear: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.clear, {\n          event: 'removeFormat',\n          title: lang.font.clear\n        });\n      },\n      ul: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.lists.unordered, {\n          event: 'insertUnorderedList',\n          title: lang.lists.unordered\n        });\n      },\n      ol: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.lists.ordered, {\n          event: 'insertOrderedList',\n          title: lang.lists.ordered\n        });\n      },\n      paragraph: function (lang, options) {\n        var leftButton = tplIconButton(options.iconPrefix + options.icons.paragraph.left, {\n          title: lang.paragraph.left,\n          event: 'justifyLeft'\n        });\n        var centerButton = tplIconButton(options.iconPrefix + options.icons.paragraph.center, {\n          title: lang.paragraph.center,\n          event: 'justifyCenter'\n        });\n        var rightButton = tplIconButton(options.iconPrefix + options.icons.paragraph.right, {\n          title: lang.paragraph.right,\n          event: 'justifyRight'\n        });\n        var justifyButton = tplIconButton(options.iconPrefix + options.icons.paragraph.justify, {\n          title: lang.paragraph.justify,\n          event: 'justifyFull'\n        });\n\n        var outdentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.outdent, {\n          title: lang.paragraph.outdent,\n          event: 'outdent'\n        });\n        var indentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.indent, {\n          title: lang.paragraph.indent,\n          event: 'indent'\n        });\n\n        var dropdown = [\n          '<div class=\"note-align btn-group\">',\n          leftButton + centerButton + rightButton + justifyButton,\n          '</div><div class=\"note-list btn-group\">',\n          indentButton + outdentButton,\n          '</div>'\n        ];\n\n        return tplIconButton(options.iconPrefix + options.icons.paragraph.paragraph, {\n          title: lang.paragraph.paragraph,\n          dropdown: tplDropdown(dropdown, '', 'div')\n        });\n      },\n      height: function (lang, options) {\n        var items = options.lineHeights.reduce(function (memo, v) {\n          return memo + '<li><a data-event=\"lineHeight\" href=\"#\" data-value=\"' + parseFloat(v) + '\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        return tplIconButton(options.iconPrefix + options.icons.font.height, {\n          title: lang.font.height,\n          dropdown: tplDropdown(items, 'note-check')\n        });\n\n      },\n      help: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.help, {\n          event: 'showHelpDialog',\n          title: lang.options.help,\n          hide: true\n        });\n      },\n      fullscreen: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.fullscreen, {\n          event: 'fullscreen',\n          title: lang.options.fullscreen\n        });\n      },\n      codeview: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.codeview, {\n          event: 'codeview',\n          title: lang.options.codeview\n        });\n      },\n      undo: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.history.undo, {\n          event: 'undo',\n          title: lang.history.undo\n        });\n      },\n      redo: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.history.redo, {\n          event: 'redo',\n          title: lang.history.redo\n        });\n      },\n      hr: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.hr.insert, {\n          event: 'insertHorizontalRule',\n          title: lang.hr.insert\n        });\n      }\n    };\n\n    var tplPopovers = function (lang, options) {\n      var tplLinkPopover = function () {\n        var linkButton = tplIconButton(options.iconPrefix + options.icons.link.edit, {\n          title: lang.link.edit,\n          event: 'showLinkDialog',\n          hide: true\n        });\n        var unlinkButton = tplIconButton(options.iconPrefix + options.icons.link.unlink, {\n          title: lang.link.unlink,\n          event: 'unlink'\n        });\n        var content = '<a href=\"http://www.google.com\" target=\"_blank\">www.google.com</a>&nbsp;&nbsp;' +\n                      '<div class=\"note-insert btn-group\">' +\n                        linkButton + unlinkButton +\n                      '</div>';\n        return tplPopover('note-link-popover', content);\n      };\n\n      var tplImagePopover = function () {\n        var fullButton = tplButton('<span class=\"note-fontsize-10\">100%</span>', {\n          title: lang.image.resizeFull,\n          event: 'resize',\n          value: '1'\n        });\n        var halfButton = tplButton('<span class=\"note-fontsize-10\">50%</span>', {\n          title: lang.image.resizeHalf,\n          event: 'resize',\n          value: '0.5'\n        });\n        var quarterButton = tplButton('<span class=\"note-fontsize-10\">25%</span>', {\n          title: lang.image.resizeQuarter,\n          event: 'resize',\n          value: '0.25'\n        });\n\n        var leftButton = tplIconButton(options.iconPrefix + options.icons.image.floatLeft, {\n          title: lang.image.floatLeft,\n          event: 'floatMe',\n          value: 'left'\n        });\n        var rightButton = tplIconButton(options.iconPrefix + options.icons.image.floatRight, {\n          title: lang.image.floatRight,\n          event: 'floatMe',\n          value: 'right'\n        });\n        var justifyButton = tplIconButton(options.iconPrefix + options.icons.image.floatNone, {\n          title: lang.image.floatNone,\n          event: 'floatMe',\n          value: 'none'\n        });\n\n        var roundedButton = tplIconButton(options.iconPrefix + options.icons.image.shapeRounded, {\n          title: lang.image.shapeRounded,\n          event: 'imageShape',\n          value: 'img-rounded'\n        });\n        var circleButton = tplIconButton(options.iconPrefix + options.icons.image.shapeCircle, {\n          title: lang.image.shapeCircle,\n          event: 'imageShape',\n          value: 'img-circle'\n        });\n        var thumbnailButton = tplIconButton(options.iconPrefix + options.icons.image.shapeThumbnail, {\n          title: lang.image.shapeThumbnail,\n          event: 'imageShape',\n          value: 'img-thumbnail'\n        });\n        var noneButton = tplIconButton(options.iconPrefix + options.icons.image.shapeNone, {\n          title: lang.image.shapeNone,\n          event: 'imageShape',\n          value: ''\n        });\n\n        var removeButton = tplIconButton(options.iconPrefix + options.icons.image.remove, {\n          title: lang.image.remove,\n          event: 'removeMedia',\n          value: 'none'\n        });\n\n        var content = (options.disableResizeImage ? '' : '<div class=\"btn-group\">' + fullButton + halfButton + quarterButton + '</div>') +\n                      '<div class=\"btn-group\">' + leftButton + rightButton + justifyButton + '</div><br>' +\n                      '<div class=\"btn-group\">' + roundedButton + circleButton + thumbnailButton + noneButton + '</div>' +\n                      '<div class=\"btn-group\">' + removeButton + '</div>';\n        return tplPopover('note-image-popover', content);\n      };\n\n      var tplAirPopover = function () {\n        var $content = $('<div />');\n        for (var idx = 0, len = options.airPopover.length; idx < len; idx ++) {\n          var group = options.airPopover[idx];\n\n          var $group = $('<div class=\"note-' + group[0] + ' btn-group\">');\n          for (var i = 0, lenGroup = group[1].length; i < lenGroup; i++) {\n            var $button = $(tplButtonInfo[group[1][i]](lang, options));\n\n            $button.attr('data-name', group[1][i]);\n\n            $group.append($button);\n          }\n          $content.append($group);\n        }\n\n        return tplPopover('note-air-popover', $content.children());\n      };\n\n      var $notePopover = $('<div class=\"note-popover\" />');\n\n      $notePopover.append(tplLinkPopover());\n      $notePopover.append(tplImagePopover());\n\n      if (options.airMode) {\n        $notePopover.append(tplAirPopover());\n      }\n\n      return $notePopover;\n    };\n\n    var tplHandles = function (options) {\n      return '<div class=\"note-handle\">' +\n               '<div class=\"note-control-selection\">' +\n                 '<div class=\"note-control-selection-bg\"></div>' +\n                 '<div class=\"note-control-holder note-control-nw\"></div>' +\n                 '<div class=\"note-control-holder note-control-ne\"></div>' +\n                 '<div class=\"note-control-holder note-control-sw\"></div>' +\n                 '<div class=\"' +\n                 (options.disableResizeImage ? 'note-control-holder' : 'note-control-sizing') +\n                 ' note-control-se\"></div>' +\n                 (options.disableResizeImage ? '' : '<div class=\"note-control-selection-info\"></div>') +\n               '</div>' +\n             '</div>';\n    };\n\n    /**\n     * shortcut table template\n     * @param {String} title\n     * @param {String} body\n     */\n    var tplShortcut = function (title, keys) {\n      var keyClass = 'note-shortcut-col col-xs-6 note-shortcut-';\n      var body = [];\n\n      for (var i in keys) {\n        if (keys.hasOwnProperty(i)) {\n          body.push(\n            '<div class=\"' + keyClass + 'key\">' + keys[i].kbd + '</div>' +\n            '<div class=\"' + keyClass + 'name\">' + keys[i].text + '</div>'\n            );\n        }\n      }\n\n      return '<div class=\"note-shortcut-row row\"><div class=\"' + keyClass + 'title col-xs-offset-6\">' + title + '</div></div>' +\n             '<div class=\"note-shortcut-row row\">' + body.join('</div><div class=\"note-shortcut-row row\">') + '</div>';\n    };\n\n    var tplShortcutText = function (lang) {\n      var keys = [\n        { kbd: '⌘ + B', text: lang.font.bold },\n        { kbd: '⌘ + I', text: lang.font.italic },\n        { kbd: '⌘ + U', text: lang.font.underline },\n        { kbd: '⌘ + \\\\', text: lang.font.clear }\n      ];\n\n      return tplShortcut(lang.shortcut.textFormatting, keys);\n    };\n\n    var tplShortcutAction = function (lang) {\n      var keys = [\n        { kbd: '⌘ + Z', text: lang.history.undo },\n        { kbd: '⌘ + ⇧ + Z', text: lang.history.redo },\n        { kbd: '⌘ + ]', text: lang.paragraph.indent },\n        { kbd: '⌘ + [', text: lang.paragraph.outdent },\n        { kbd: '⌘ + ENTER', text: lang.hr.insert }\n      ];\n\n      return tplShortcut(lang.shortcut.action, keys);\n    };\n\n    var tplShortcutPara = function (lang) {\n      var keys = [\n        { kbd: '⌘ + ⇧ + L', text: lang.paragraph.left },\n        { kbd: '⌘ + ⇧ + E', text: lang.paragraph.center },\n        { kbd: '⌘ + ⇧ + R', text: lang.paragraph.right },\n        { kbd: '⌘ + ⇧ + J', text: lang.paragraph.justify },\n        { kbd: '⌘ + ⇧ + NUM7', text: lang.lists.ordered },\n        { kbd: '⌘ + ⇧ + NUM8', text: lang.lists.unordered }\n      ];\n\n      return tplShortcut(lang.shortcut.paragraphFormatting, keys);\n    };\n\n    var tplShortcutStyle = function (lang) {\n      var keys = [\n        { kbd: '⌘ + NUM0', text: lang.style.normal },\n        { kbd: '⌘ + NUM1', text: lang.style.h1 },\n        { kbd: '⌘ + NUM2', text: lang.style.h2 },\n        { kbd: '⌘ + NUM3', text: lang.style.h3 },\n        { kbd: '⌘ + NUM4', text: lang.style.h4 },\n        { kbd: '⌘ + NUM5', text: lang.style.h5 },\n        { kbd: '⌘ + NUM6', text: lang.style.h6 }\n      ];\n\n      return tplShortcut(lang.shortcut.documentStyle, keys);\n    };\n\n    var tplExtraShortcuts = function (lang, options) {\n      var extraKeys = options.extraKeys;\n      var keys = [];\n\n      for (var key in extraKeys) {\n        if (extraKeys.hasOwnProperty(key)) {\n          keys.push({ kbd: key, text: extraKeys[key] });\n        }\n      }\n\n      return tplShortcut(lang.shortcut.extraKeys, keys);\n    };\n\n    var tplShortcutTable = function (lang, options) {\n      var colClass = 'class=\"note-shortcut note-shortcut-col col-sm-6 col-xs-12\"';\n      var template = [\n        '<div ' + colClass + '>' + tplShortcutAction(lang, options) + '</div>' +\n        '<div ' + colClass + '>' + tplShortcutText(lang, options) + '</div>',\n        '<div ' + colClass + '>' + tplShortcutStyle(lang, options) + '</div>' +\n        '<div ' + colClass + '>' + tplShortcutPara(lang, options) + '</div>'\n      ];\n\n      if (options.extraKeys) {\n        template.push('<div ' + colClass + '>' + tplExtraShortcuts(lang, options) + '</div>');\n      }\n\n      return '<div class=\"note-shortcut-row row\">' +\n               template.join('</div><div class=\"note-shortcut-row row\">') +\n             '</div>';\n    };\n\n    var replaceMacKeys = function (sHtml) {\n      return sHtml.replace(/⌘/g, 'Ctrl').replace(/⇧/g, 'Shift');\n    };\n\n    var tplDialogInfo = {\n      image: function (lang, options) {\n        var imageLimitation = '';\n        if (options.maximumImageFileSize) {\n          var unit = Math.floor(Math.log(options.maximumImageFileSize) / Math.log(1024));\n          var readableSize = (options.maximumImageFileSize / Math.pow(1024, unit)).toFixed(2) * 1 +\n                             ' ' + ' KMGTP'[unit] + 'B';\n          imageLimitation = '<small>' + lang.image.maximumFileSize + ' : ' + readableSize + '</small>';\n        }\n\n        var body = '<div class=\"form-group row note-group-select-from-files\">' +\n                     '<label>' + lang.image.selectFromFiles + '</label>' +\n                     '<input class=\"note-image-input form-control\" type=\"file\" name=\"files\" accept=\"image/*\" multiple=\"multiple\" />' +\n                     imageLimitation +\n                   '</div>' +\n                   '<div class=\"form-group row\">' +\n                     '<label>' + lang.image.url + '</label>' +\n                     '<input class=\"note-image-url form-control col-md-12\" type=\"text\" />' +\n                   '</div>';\n        var footer = '<button href=\"#\" class=\"btn btn-primary note-image-btn disabled\" disabled>' + lang.image.insert + '</button>';\n        return tplDialog('note-image-dialog', lang.image.insert, body, footer);\n      },\n\n      link: function (lang, options) {\n        var body = '<div class=\"form-group row\">' +\n                     '<label>' + lang.link.textToDisplay + '</label>' +\n                     '<input class=\"note-link-text form-control col-md-12\" type=\"text\" />' +\n                   '</div>' +\n                   '<div class=\"form-group row\">' +\n                     '<label>' + lang.link.url + '</label>' +\n                     '<input class=\"note-link-url form-control col-md-12\" type=\"text\" value=\"http://\" />' +\n                   '</div>' +\n                   (!options.disableLinkTarget ?\n                     '<div class=\"checkbox\">' +\n                       '<label>' + '<input type=\"checkbox\" checked> ' +\n                         lang.link.openInNewWindow +\n                       '</label>' +\n                     '</div>' : ''\n                   );\n        var footer = '<button href=\"#\" class=\"btn btn-primary note-link-btn disabled\" disabled>' + lang.link.insert + '</button>';\n        return tplDialog('note-link-dialog', lang.link.insert, body, footer);\n      },\n\n      help: function (lang, options) {\n        var body = '<a class=\"modal-close pull-right\" aria-hidden=\"true\" tabindex=\"-1\">' + lang.shortcut.close + '</a>' +\n                   '<div class=\"title\">' + lang.shortcut.shortcuts + '</div>' +\n                   (agent.isMac ? tplShortcutTable(lang, options) : replaceMacKeys(tplShortcutTable(lang, options))) +\n                   '<p class=\"text-center\">' +\n                     '<a href=\"//summernote.org/\" target=\"_blank\">Summernote 0.6.16</a> · ' +\n                     '<a href=\"//github.com/summernote/summernote\" target=\"_blank\">Project</a> · ' +\n                     '<a href=\"//github.com/summernote/summernote/issues\" target=\"_blank\">Issues</a>' +\n                   '</p>';\n        return tplDialog('note-help-dialog', '', body, '');\n      }\n    };\n\n    var tplDialogs = function (lang, options) {\n      var dialogs = '';\n\n      $.each(tplDialogInfo, function (idx, tplDialog) {\n        dialogs += tplDialog(lang, options);\n      });\n\n      return '<div class=\"note-dialog\">' + dialogs + '</div>';\n    };\n\n    var tplStatusbar = function () {\n      return '<div class=\"note-resizebar\">' +\n               '<div class=\"note-icon-bar\"></div>' +\n               '<div class=\"note-icon-bar\"></div>' +\n               '<div class=\"note-icon-bar\"></div>' +\n             '</div>';\n    };\n\n    var representShortcut = function (str) {\n      if (agent.isMac) {\n        str = str.replace('CMD', '⌘').replace('SHIFT', '⇧');\n      }\n\n      return str.replace('BACKSLASH', '\\\\')\n                .replace('SLASH', '/')\n                .replace('LEFTBRACKET', '[')\n                .replace('RIGHTBRACKET', ']');\n    };\n\n    /**\n     * createTooltip\n     *\n     * @param {jQuery} $container\n     * @param {Object} keyMap\n     * @param {String} [sPlacement]\n     */\n    var createTooltip = function ($container, keyMap, sPlacement) {\n      var invertedKeyMap = func.invertObject(keyMap);\n      var $buttons = $container.find('button');\n\n      $buttons.each(function (i, elBtn) {\n        var $btn = $(elBtn);\n        var sShortcut = invertedKeyMap[$btn.data('event')];\n        if (sShortcut) {\n          $btn.attr('title', function (i, v) {\n            return v + ' (' + representShortcut(sShortcut) + ')';\n          });\n        }\n      // bootstrap tooltip on btn-group bug\n      // https://github.com/twbs/bootstrap/issues/5687\n      }).tooltip({\n        container: 'body',\n        trigger: 'hover',\n        placement: sPlacement || 'top'\n      }).on('click', function () {\n        $(this).tooltip('hide');\n      });\n    };\n\n    // createPalette\n    var createPalette = function ($container, options) {\n      var colorInfo = options.colors;\n      $container.find('.note-color-palette').each(function () {\n        var $palette = $(this), eventName = $palette.attr('data-target-event');\n        var paletteContents = [];\n        for (var row = 0, lenRow = colorInfo.length; row < lenRow; row++) {\n          var colors = colorInfo[row];\n          var buttons = [];\n          for (var col = 0, lenCol = colors.length; col < lenCol; col++) {\n            var color = colors[col];\n            buttons.push(['<button type=\"button\" class=\"note-color-btn\" style=\"background-color:', color,\n                           ';\" data-event=\"', eventName,\n                           '\" data-value=\"', color,\n                           '\" title=\"', color,\n                           '\" data-toggle=\"button\" tabindex=\"-1\"></button>'].join(''));\n          }\n          paletteContents.push('<div class=\"note-color-row\">' + buttons.join('') + '</div>');\n        }\n        $palette.html(paletteContents.join(''));\n      });\n    };\n\n    /**\n     * create summernote layout (air mode)\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayoutByAirMode = function ($holder, options) {\n      var langInfo = options.langInfo;\n      var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];\n      var id = func.uniqueId();\n\n      $holder.addClass('note-air-editor note-editable panel-body');\n      $holder.attr({\n        'id': 'note-editor-' + id,\n        'contentEditable': true\n      });\n\n      var body = document.body;\n\n      // create Popover\n      var $popover = $(tplPopovers(langInfo, options));\n      $popover.addClass('note-air-layout');\n      $popover.attr('id', 'note-popover-' + id);\n      $popover.appendTo(body);\n      createTooltip($popover, keyMap);\n      createPalette($popover, options);\n\n      // create Handle\n      var $handle = $(tplHandles(options));\n      $handle.addClass('note-air-layout');\n      $handle.attr('id', 'note-handle-' + id);\n      $handle.appendTo(body);\n\n      // create Dialog\n      var $dialog = $(tplDialogs(langInfo, options));\n      $dialog.addClass('note-air-layout');\n      $dialog.attr('id', 'note-dialog-' + id);\n      $dialog.find('button.close, a.modal-close').click(function () {\n        $(this).closest('.modal').modal('hide');\n      });\n      $dialog.appendTo(body);\n    };\n\n    /**\n     * create summernote layout (normal mode)\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayoutByFrame = function ($holder, options) {\n      var langInfo = options.langInfo;\n\n      //01. create Editor\n      var $editor = $('<div class=\"note-editor panel panel-default\" />');\n      if (options.width) {\n        $editor.width(options.width);\n      }\n\n      //02. statusbar (resizebar)\n      if (options.height > 0) {\n        $('<div class=\"note-statusbar\">' + (options.disableResizeEditor ? '' : tplStatusbar()) + '</div>').prependTo($editor);\n      }\n\n      //03 editing area\n      var $editingArea = $('<div class=\"note-editing-area\" />');\n      //03. create editable\n      var isContentEditable = !$holder.is(':disabled');\n      var $editable = $('<div class=\"note-editable panel-body\" contentEditable=\"' + isContentEditable + '\"></div>').prependTo($editingArea);\n      \n      if (options.height) {\n        $editable.height(options.height);\n      }\n      if (options.direction) {\n        $editable.attr('dir', options.direction);\n      }\n      var placeholder = $holder.attr('placeholder') || options.placeholder;\n      if (placeholder) {\n        $editable.attr('data-placeholder', placeholder);\n      }\n\n      $editable.html(dom.html($holder) || dom.emptyPara);\n\n      //031. create codable\n      $('<textarea class=\"note-codable\"></textarea>').prependTo($editingArea);\n\n      //04. create Popover\n      var $popover = $(tplPopovers(langInfo, options)).prependTo($editingArea);\n      createPalette($popover, options);\n      createTooltip($popover, keyMap);\n\n      //05. handle(control selection, ...)\n      $(tplHandles(options)).prependTo($editingArea);\n\n      $editingArea.prependTo($editor);\n\n      //06. create Toolbar\n      var $toolbar = $('<div class=\"note-toolbar panel-heading\" />');\n      for (var idx = 0, len = options.toolbar.length; idx < len; idx ++) {\n        var groupName = options.toolbar[idx][0];\n        var groupButtons = options.toolbar[idx][1];\n\n        var $group = $('<div class=\"note-' + groupName + ' btn-group\" />');\n        for (var i = 0, btnLength = groupButtons.length; i < btnLength; i++) {\n          var buttonInfo = tplButtonInfo[groupButtons[i]];\n          // continue creating toolbar even if a button doesn't exist\n          if (!$.isFunction(buttonInfo)) { continue; }\n\n          var $button = $(buttonInfo(langInfo, options));\n          $button.attr('data-name', groupButtons[i]);  // set button's alias, becuase to get button element from $toolbar\n          $group.append($button);\n        }\n        $toolbar.append($group);\n      }\n\n      var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];\n      createPalette($toolbar, options);\n      createTooltip($toolbar, keyMap, 'bottom');\n      $toolbar.prependTo($editor);\n\n      //07. create Dropzone\n      $('<div class=\"note-dropzone\"><div class=\"note-dropzone-message\"></div></div>').prependTo($editor);\n\n      //08. create Dialog\n      var $dialogContainer = options.dialogsInBody ? $(document.body) : $editor;\n      var $dialog = $(tplDialogs(langInfo, options)).prependTo($dialogContainer);\n      $dialog.find('button.close, a.modal-close').click(function () {\n        $(this).closest('.modal').modal('hide');\n      });\n\n      //09. Editor/Holder switch\n      $editor.insertAfter($holder);\n      $holder.hide();\n    };\n\n    this.hasNoteEditor = function ($holder) {\n      return this.noteEditorFromHolder($holder).length > 0;\n    };\n\n    this.noteEditorFromHolder = function ($holder) {\n      if ($holder.hasClass('note-air-editor')) {\n        return $holder;\n      } else if ($holder.next().hasClass('note-editor')) {\n        return $holder.next();\n      } else {\n        return $();\n      }\n    };\n\n    /**\n     * create summernote layout\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayout = function ($holder, options) {\n      if (options.airMode) {\n        this.createLayoutByAirMode($holder, options);\n      } else {\n        this.createLayoutByFrame($holder, options);\n      }\n    };\n\n    /**\n     * returns layoutInfo from holder\n     *\n     * @param {jQuery} $holder - placeholder\n     * @return {Object}\n     */\n    this.layoutInfoFromHolder = function ($holder) {\n      var $editor = this.noteEditorFromHolder($holder);\n      if (!$editor.length) {\n        return;\n      }\n\n      // connect $holder to $editor\n      $editor.data('holder', $holder);\n\n      return dom.buildLayoutInfo($editor);\n    };\n\n    /**\n     * removeLayout\n     *\n     * @param {jQuery} $holder - placeholder\n     * @param {Object} layoutInfo\n     * @param {Object} options\n     *\n     */\n    this.removeLayout = function ($holder, layoutInfo, options) {\n      if (options.airMode) {\n        $holder.removeClass('note-air-editor note-editable')\n               .removeAttr('id contentEditable');\n\n        layoutInfo.popover().remove();\n        layoutInfo.handle().remove();\n        layoutInfo.dialog().remove();\n      } else {\n        $holder.html(layoutInfo.editable().html());\n\n        if (options.dialogsInBody) {\n          layoutInfo.dialog().remove();\n        }\n        layoutInfo.editor().remove();\n        $holder.show();\n      }\n    };\n\n    /**\n     *\n     * @return {Object}\n     * @return {function(label, options=):string} return.button {@link #tplButton function to make text button}\n     * @return {function(iconClass, options=):string} return.iconButton {@link #tplIconButton function to make icon button}\n     * @return {function(className, title=, body=, footer=):string} return.dialog {@link #tplDialog function to make dialog}\n     */\n    this.getTemplate = function () {\n      return {\n        button: tplButton,\n        iconButton: tplIconButton,\n        dialog: tplDialog\n      };\n    };\n\n    /**\n     * add button information\n     *\n     * @param {String} name button name\n     * @param {Function} buttonInfo function to make button, reference to {@link #tplButton},{@link #tplIconButton}\n     */\n    this.addButtonInfo = function (name, buttonInfo) {\n      tplButtonInfo[name] = buttonInfo;\n    };\n\n    /**\n     *\n     * @param {String} name\n     * @param {Function} dialogInfo function to make dialog, reference to {@link #tplDialog}\n     */\n    this.addDialogInfo = function (name, dialogInfo) {\n      tplDialogInfo[name] = dialogInfo;\n    };\n  };\n\n\n  // jQuery namespace for summernote\n  /**\n   * @class $.summernote \n   * \n   * summernote attribute  \n   * \n   * @mixin defaults\n   * @singleton  \n   * \n   */\n  $.summernote = $.summernote || {};\n\n  // extends default settings\n  //  - $.summernote.version\n  //  - $.summernote.options\n  //  - $.summernote.lang\n  $.extend($.summernote, defaults);\n\n  var renderer = new Renderer();\n  var eventHandler = new EventHandler();\n\n  $.extend($.summernote, {\n    /** @property {Renderer} */\n    renderer: renderer,\n    /** @property {EventHandler} */\n    eventHandler: eventHandler,\n    /** \n     * @property {Object} core \n     * @property {core.agent} core.agent \n     * @property {core.dom} core.dom\n     * @property {core.range} core.range \n     */\n    core: {\n      agent: agent,\n      list : list,\n      dom: dom,\n      range: range\n    },\n    /** \n     * @property {Object} \n     * pluginEvents event list for plugins\n     * event has name and callback function.\n     * \n     * ``` \n     * $.summernote.addPlugin({\n     *     events : {\n     *          'hello' : function(layoutInfo, value, $target) {\n     *              console.log('event name is hello, value is ' + value );\n     *          }\n     *     }     \n     * })\n     * ```\n     * \n     * * event name is data-event property.\n     * * layoutInfo is a summernote layout information.\n     * * value is data-value property.\n     */\n    pluginEvents: {},\n\n    plugins : []\n  });\n\n  /**\n   * @method addPlugin\n   *\n   * add Plugin in Summernote \n   * \n   * Summernote can make a own plugin.\n   *\n   * ### Define plugin\n   * ```\n   * // get template function  \n   * var tmpl = $.summernote.renderer.getTemplate();\n   * \n   * // add a button   \n   * $.summernote.addPlugin({\n   *     buttons : {\n   *        // \"hello\"  is button's namespace.      \n   *        \"hello\" : function(lang, options) {\n   *            // make icon button by template function          \n   *            return tmpl.iconButton(options.iconPrefix + 'header', {\n   *                // callback function name when button clicked \n   *                event : 'hello',\n   *                // set data-value property                 \n   *                value : 'hello',                \n   *                hide : true\n   *            });           \n   *        }\n   *     \n   *     }, \n   *     \n   *     events : {\n   *        \"hello\" : function(layoutInfo, value) {\n   *            // here is event code \n   *        }\n   *     }     \n   * });\n   * ``` \n   * ### Use a plugin in toolbar\n   * \n   * ``` \n   *    $(\"#editor\").summernote({\n   *    ...\n   *    toolbar : [\n   *        // display hello plugin in toolbar     \n   *        ['group', [ 'hello' ]]\n   *    ]\n   *    ...    \n   *    });\n   * ```\n   *  \n   *  \n   * @param {Object} plugin\n   * @param {Object} [plugin.buttons] define plugin button. for detail, see to Renderer.addButtonInfo\n   * @param {Object} [plugin.dialogs] define plugin dialog. for detail, see to Renderer.addDialogInfo\n   * @param {Object} [plugin.events] add event in $.summernote.pluginEvents \n   * @param {Object} [plugin.langs] update $.summernote.lang\n   * @param {Object} [plugin.options] update $.summernote.options\n   */\n  $.summernote.addPlugin = function (plugin) {\n\n    // save plugin list\n    $.summernote.plugins.push(plugin);\n\n    if (plugin.buttons) {\n      $.each(plugin.buttons, function (name, button) {\n        renderer.addButtonInfo(name, button);\n      });\n    }\n\n    if (plugin.dialogs) {\n      $.each(plugin.dialogs, function (name, dialog) {\n        renderer.addDialogInfo(name, dialog);\n      });\n    }\n\n    if (plugin.events) {\n      $.each(plugin.events, function (name, event) {\n        $.summernote.pluginEvents[name] = event;\n      });\n    }\n\n    if (plugin.langs) {\n      $.each(plugin.langs, function (locale, lang) {\n        if ($.summernote.lang[locale]) {\n          $.extend($.summernote.lang[locale], lang);\n        }\n      });\n    }\n\n    if (plugin.options) {\n      $.extend($.summernote.options, plugin.options);\n    }\n  };\n\n  /*\n   * extend $.fn\n   */\n  $.fn.extend({\n    /**\n     * @method\n     * Initialize summernote\n     *  - create editor layout and attach Mouse and keyboard events.\n     * \n     * ```\n     * $(\"#summernote\").summernote( { options ..} );\n     * ```\n     *   \n     * @member $.fn\n     * @param {Object|String} options reference to $.summernote.options\n     * @return {this}\n     */\n    summernote: function () {\n      // check first argument's type\n      //  - {String}: External API call {{module}}.{{method}}\n      //  - {Object}: init options\n      var type = $.type(list.head(arguments));\n      var isExternalAPICalled = type === 'string';\n      var hasInitOptions = type === 'object';\n\n      // extend default options with custom user options\n      var options = hasInitOptions ? list.head(arguments) : {};\n\n      options = $.extend({}, $.summernote.options, options);\n      options.icons = $.extend({}, $.summernote.options.icons, options.icons);\n\n      // Include langInfo in options for later use, e.g. for image drag-n-drop\n      // Setup language info with en-US as default\n      options.langInfo = $.extend(true, {}, $.summernote.lang['en-US'], $.summernote.lang[options.lang]);\n\n      // override plugin options\n      if (!isExternalAPICalled && hasInitOptions) {\n        for (var i = 0, len = $.summernote.plugins.length; i < len; i++) {\n          var plugin = $.summernote.plugins[i];\n\n          if (options.plugin[plugin.name]) {\n            $.summernote.plugins[i] = $.extend(true, plugin, options.plugin[plugin.name]);\n          }\n        }\n      }\n\n      this.each(function (idx, holder) {\n        var $holder = $(holder);\n\n        // if layout isn't created yet, createLayout and attach events\n        if (!renderer.hasNoteEditor($holder)) {\n          renderer.createLayout($holder, options);\n\n          var layoutInfo = renderer.layoutInfoFromHolder($holder);\n          $holder.data('layoutInfo', layoutInfo);\n\n          eventHandler.attach(layoutInfo, options);\n          eventHandler.attachCustomEvent(layoutInfo, options);\n        }\n      });\n\n      var $first = this.first();\n      if ($first.length) {\n        var layoutInfo = renderer.layoutInfoFromHolder($first);\n\n        // external API\n        if (isExternalAPICalled) {\n          var moduleAndMethod = list.head(list.from(arguments));\n          var args = list.tail(list.from(arguments));\n\n          // TODO now external API only works for editor\n          var params = [moduleAndMethod, layoutInfo.editable()].concat(args);\n          return eventHandler.invoke.apply(eventHandler, params);\n        } else if (options.focus) {\n          // focus on first editable element for initialize editor\n          layoutInfo.editable().focus();\n        }\n      }\n\n      return this;\n    },\n\n    /**\n     * @method \n     * \n     * get the HTML contents of note or set the HTML contents of note.\n     *\n     * * get contents \n     * ```\n     * var content = $(\"#summernote\").code();\n     * ```\n     * * set contents \n     *\n     * ```\n     * $(\"#summernote\").code(html);\n     * ```\n     *\n     * @member $.fn \n     * @param {String} [html] - HTML contents(optional, set)\n     * @return {this|String} - context(set) or HTML contents of note(get).\n     */\n    code: function (html) {\n      // get the HTML contents of note\n      if (html === undefined) {\n        var $holder = this.first();\n        if (!$holder.length) {\n          return;\n        }\n\n        var layoutInfo = renderer.layoutInfoFromHolder($holder);\n        var $editable = layoutInfo && layoutInfo.editable();\n\n        if ($editable && $editable.length) {\n          var isCodeview = eventHandler.invoke('codeview.isActivated', layoutInfo);\n          eventHandler.invoke('codeview.sync', layoutInfo);\n          return isCodeview ? layoutInfo.codable().val() :\n                              layoutInfo.editable().html();\n        }\n        return dom.value($holder);\n      }\n\n      // set the HTML contents of note\n      this.each(function (i, holder) {\n        var layoutInfo = renderer.layoutInfoFromHolder($(holder));\n        var $editable = layoutInfo && layoutInfo.editable();\n        if ($editable) {\n          $editable.html(html);\n        }\n      });\n\n      return this;\n    },\n\n    /**\n     * @method\n     * \n     * destroy Editor Layout and detach Key and Mouse Event\n     *\n     * @member $.fn\n     * @return {this}\n     */\n    destroy: function () {\n      this.each(function (idx, holder) {\n        var $holder = $(holder);\n\n        if (!renderer.hasNoteEditor($holder)) {\n          return;\n        }\n\n        var info = renderer.layoutInfoFromHolder($holder);\n        var options = info.editor().data('options');\n\n        eventHandler.detach(info, options);\n        renderer.removeLayout($holder, info, options);\n      });\n\n      return this;\n    }\n  });\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/farbtastic/farbtastic.css",
    "content": "/**\n * Farbtastic Color Picker 1.2\n * © 2008 Steven Wittens\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n */\n.farbtastic {\n  position: relative;\n}\n.farbtastic * {\n  position: absolute;\n  cursor: crosshair;\n}\n.farbtastic, .farbtastic .wheel {\n  width: 195px;\n  height: 195px;\n}\n.farbtastic .color, .farbtastic .overlay {\n  top: 47px;\n  left: 47px;\n  width: 101px;\n  height: 101px;\n}\n.farbtastic .wheel {\n  background: url(wheel.png) no-repeat;\n  width: 195px;\n  height: 195px;\n}\n.farbtastic .overlay {\n  background: url(mask.png) no-repeat;\n}\n.farbtastic .marker {\n  width: 17px;\n  height: 17px;\n  margin: -8px 0 0 -8px;\n  overflow: hidden; \n  background: url(marker.png) no-repeat;\n}\n\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/farbtastic/farbtastic.js",
    "content": "/**\n * Farbtastic Color Picker 1.2\n * © 2008 Steven Wittens\n *\n * This program is free software; you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation; either version 2 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\n */\n\njQuery.fn.farbtastic = function (callback) {\n  $.farbtastic(this, callback);\n  return this;\n};\n\njQuery.farbtastic = function (container, callback) {\n  var container = $(container).get(0);\n  return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback));\n}\n\njQuery._farbtastic = function (container, callback) {\n  // Store farbtastic object\n  var fb = this;\n\n  // Insert markup\n  $(container).html('<div class=\"farbtastic\"><div class=\"color\"></div><div class=\"wheel\"></div><div class=\"overlay\"></div><div class=\"h-marker marker\"></div><div class=\"sl-marker marker\"></div></div>');\n  var e = $('.farbtastic', container);\n  fb.wheel = $('.wheel', container).get(0);\n  // Dimensions\n  fb.radius = 84;\n  fb.square = 100;\n  fb.width = 194;\n\n  // Fix background PNGs in IE6\n  if (navigator.appVersion.match(/MSIE [0-6]\\./)) {\n    $('*', e).each(function () {\n      if (this.currentStyle.backgroundImage != 'none') {\n        var image = this.currentStyle.backgroundImage;\n        image = this.currentStyle.backgroundImage.substring(5, image.length - 2);\n        $(this).css({\n          'backgroundImage': 'none',\n          'filter': \"progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='\" + image + \"')\"\n        });\n      }\n    });\n  }\n\n  /**\n   * Link to the given element(s) or callback.\n   */\n  fb.linkTo = function (callback) {\n    // Unbind previous nodes\n    if (typeof fb.callback == 'object') {\n      $(fb.callback).unbind('keyup', fb.updateValue);\n    }\n\n    // Reset color\n    fb.color = null;\n\n    // Bind callback or elements\n    if (typeof callback == 'function') {\n      fb.callback = callback;\n    }\n    else if (typeof callback == 'object' || typeof callback == 'string') {\n      fb.callback = $(callback);\n      fb.callback.bind('keyup', fb.updateValue);\n      if (fb.callback.get(0).value) {\n        fb.setColor(fb.callback.get(0).value);\n      }\n    }\n    return this;\n  }\n  fb.updateValue = function (event) {\n    if (this.value && this.value != fb.color) {\n      fb.setColor(this.value);\n    }\n  }\n\n  /**\n   * Change color with HTML syntax #123456\n   */\n  fb.setColor = function (color) {\n    var unpack = fb.unpack(color);\n    if (fb.color != color && unpack) {\n      fb.color = color;\n      fb.rgb = unpack;\n      fb.hsl = fb.RGBToHSL(fb.rgb);\n      fb.updateDisplay();\n    }\n    return this;\n  }\n\n  /**\n   * Change color with HSL triplet [0..1, 0..1, 0..1]\n   */\n  fb.setHSL = function (hsl) {\n    fb.hsl = hsl;\n    fb.rgb = fb.HSLToRGB(hsl);\n    fb.color = fb.pack(fb.rgb);\n    fb.updateDisplay();\n    return this;\n  }\n\n  /////////////////////////////////////////////////////\n\n  /**\n   * Retrieve the coordinates of the given event relative to the center\n   * of the widget.\n   */\n  fb.widgetCoords = function (event) {\n    var x, y;\n    var el = event.target || event.srcElement;\n    var reference = fb.wheel;\n\n    if (typeof event.offsetX != 'undefined') {\n      // Use offset coordinates and find common offsetParent\n      var pos = { x: event.offsetX, y: event.offsetY };\n\n      // Send the coordinates upwards through the offsetParent chain.\n      var e = el;\n      while (e) {\n        e.mouseX = pos.x;\n        e.mouseY = pos.y;\n        pos.x += e.offsetLeft;\n        pos.y += e.offsetTop;\n        e = e.offsetParent;\n      }\n\n      // Look for the coordinates starting from the wheel widget.\n      var e = reference;\n      var offset = { x: 0, y: 0 }\n      while (e) {\n        if (typeof e.mouseX != 'undefined') {\n          x = e.mouseX - offset.x;\n          y = e.mouseY - offset.y;\n          break;\n        }\n        offset.x += e.offsetLeft;\n        offset.y += e.offsetTop;\n        e = e.offsetParent;\n      }\n\n      // Reset stored coordinates\n      e = el;\n      while (e) {\n        e.mouseX = undefined;\n        e.mouseY = undefined;\n        e = e.offsetParent;\n      }\n    }\n    else {\n      // Use absolute coordinates\n      var pos = fb.absolutePosition(reference);\n      x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x;\n      y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y;\n    }\n    // Subtract distance to middle\n    return { x: x - fb.width / 2, y: y - fb.width / 2 };\n  }\n\n  /**\n   * Mousedown handler\n   */\n  fb.mousedown = function (event) {\n    // Capture mouse\n    if (!document.dragging) {\n      $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup);\n      document.dragging = true;\n    }\n\n    // Check which area is being dragged\n    var pos = fb.widgetCoords(event);\n    fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square;\n\n    // Process\n    fb.mousemove(event);\n    return false;\n  }\n\n  /**\n   * Mousemove handler\n   */\n  fb.mousemove = function (event) {\n    // Get coordinates relative to color picker center\n    var pos = fb.widgetCoords(event);\n\n    // Set new HSL parameters\n    if (fb.circleDrag) {\n      var hue = Math.atan2(pos.x, -pos.y) / 6.28;\n      if (hue < 0) hue += 1;\n      fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]);\n    }\n    else {\n      var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5));\n      var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5));\n      fb.setHSL([fb.hsl[0], sat, lum]);\n    }\n    return false;\n  }\n\n  /**\n   * Mouseup handler\n   */\n  fb.mouseup = function () {\n    // Uncapture mouse\n    $(document).unbind('mousemove', fb.mousemove);\n    $(document).unbind('mouseup', fb.mouseup);\n    document.dragging = false;\n  }\n\n  /**\n   * Update the markers and styles\n   */\n  fb.updateDisplay = function () {\n    // Markers\n    var angle = fb.hsl[0] * 6.28;\n    $('.h-marker', e).css({\n      left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px',\n      top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px'\n    });\n\n    $('.sl-marker', e).css({\n      left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px',\n      top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px'\n    });\n\n    // Saturation/Luminance gradient\n    $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5])));\n\n    // Linked elements or callback\n    if (typeof fb.callback == 'object') {\n      // Set background/foreground color\n      $(fb.callback).css({\n        backgroundColor: fb.color,\n        color: fb.hsl[2] > 0.5 ? '#000' : '#fff'\n      });\n\n      // Change linked value\n      $(fb.callback).each(function() {\n        if (this.value && this.value != fb.color) {\n          this.value = fb.color;\n        }\n      });\n    }\n    else if (typeof fb.callback == 'function') {\n      fb.callback.call(fb, fb.color);\n    }\n  }\n\n  /**\n   * Get absolute position of element\n   */\n  fb.absolutePosition = function (el) {\n    var r = { x: el.offsetLeft, y: el.offsetTop };\n    // Resolve relative to offsetParent\n    if (el.offsetParent) {\n      var tmp = fb.absolutePosition(el.offsetParent);\n      r.x += tmp.x;\n      r.y += tmp.y;\n    }\n    return r;\n  };\n\n  /* Various color utility functions */\n  fb.pack = function (rgb) {\n    var r = Math.round(rgb[0] * 255);\n    var g = Math.round(rgb[1] * 255);\n    var b = Math.round(rgb[2] * 255);\n    return '#' + (r < 16 ? '0' : '') + r.toString(16) +\n           (g < 16 ? '0' : '') + g.toString(16) +\n           (b < 16 ? '0' : '') + b.toString(16);\n  }\n\n  fb.unpack = function (color) {\n    if (color.length == 7) {\n      return [parseInt('0x' + color.substring(1, 3)) / 255,\n        parseInt('0x' + color.substring(3, 5)) / 255,\n        parseInt('0x' + color.substring(5, 7)) / 255];\n    }\n    else if (color.length == 4) {\n      return [parseInt('0x' + color.substring(1, 2)) / 15,\n        parseInt('0x' + color.substring(2, 3)) / 15,\n        parseInt('0x' + color.substring(3, 4)) / 15];\n    }\n  }\n\n  fb.HSLToRGB = function (hsl) {\n    var m1, m2, r, g, b;\n    var h = hsl[0], s = hsl[1], l = hsl[2];\n    m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;\n    m1 = l * 2 - m2;\n    return [this.hueToRGB(m1, m2, h+0.33333),\n        this.hueToRGB(m1, m2, h),\n        this.hueToRGB(m1, m2, h-0.33333)];\n  }\n\n  fb.hueToRGB = function (m1, m2, h) {\n    h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);\n    if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;\n    if (h * 2 < 1) return m2;\n    if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;\n    return m1;\n  }\n\n  fb.RGBToHSL = function (rgb) {\n    var min, max, delta, h, s, l;\n    var r = rgb[0], g = rgb[1], b = rgb[2];\n    min = Math.min(r, Math.min(g, b));\n    max = Math.max(r, Math.max(g, b));\n    delta = max - min;\n    l = (min + max) / 2;\n    s = 0;\n    if (l > 0 && l < 1) {\n      s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));\n    }\n    h = 0;\n    if (delta > 0) {\n      if (max == r && max != g) h += (g - b) / delta;\n      if (max == g && max != b) h += (2 + (b - r) / delta);\n      if (max == b && max != r) h += (4 + (r - g) / delta);\n      h /= 6;\n    }\n    return [h, s, l];\n  }\n\n  // Install mousedown handler (the others are set on the document on-demand)\n  $('*', e).mousedown(fb.mousedown);\n\n    // Init color\n  fb.setColor('#000000');\n\n  // Set linked elements/callback\n  if (callback) {\n    fb.linkTo(callback);\n  }\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/fileinput/fileinput.js",
    "content": "/* ===========================================================\n * Bootstrap: fileinput.js v3.1.3\n * http://jasny.github.com/bootstrap/javascript/#fileinput\n * ===========================================================\n * Copyright 2012-2014 Arnold Daniels\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\")\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n * ========================================================== */\n\n+function ($) { \"use strict\";\n\n  var isIE = window.navigator.appName == 'Microsoft Internet Explorer'\n\n  // FILEUPLOAD PUBLIC CLASS DEFINITION\n  // =================================\n\n  var Fileinput = function (element, options) {\n    this.$element = $(element)\n    \n    this.$input = this.$element.find(':file')\n    if (this.$input.length === 0) return\n\n    this.name = this.$input.attr('name') || options.name\n\n    this.$hidden = this.$element.find('input[type=hidden][name=\"' + this.name + '\"]')\n    if (this.$hidden.length === 0) {\n      this.$hidden = $('<input type=\"hidden\">').insertBefore(this.$input)\n    }\n\n    this.$preview = this.$element.find('.fileinput-preview')\n    var height = this.$preview.css('height')\n    if (this.$preview.css('display') !== 'inline' && height !== '0px' && height !== 'none') {\n      this.$preview.css('line-height', height)\n    }\n        \n    this.original = {\n      exists: this.$element.hasClass('fileinput-exists'),\n      preview: this.$preview.html(),\n      hiddenVal: this.$hidden.val()\n    }\n    \n    this.listen()\n  }\n  \n  Fileinput.prototype.listen = function() {\n    this.$input.on('change.bs.fileinput', $.proxy(this.change, this))\n    $(this.$input[0].form).on('reset.bs.fileinput', $.proxy(this.reset, this))\n    \n    this.$element.find('[data-trigger=\"fileinput\"]').on('click.bs.fileinput', $.proxy(this.trigger, this))\n    this.$element.find('[data-dismiss=\"fileinput\"]').on('click.bs.fileinput', $.proxy(this.clear, this))\n  },\n\n  Fileinput.prototype.change = function(e) {\n    var files = e.target.files === undefined ? (e.target && e.target.value ? [{ name: e.target.value.replace(/^.+\\\\/, '')}] : []) : e.target.files\n    \n    e.stopPropagation()\n\n    if (files.length === 0) {\n      this.clear()\n      return\n    }\n\n    this.$hidden.val('')\n    this.$hidden.attr('name', '')\n    this.$input.attr('name', this.name)\n\n    var file = files[0]\n\n    if (this.$preview.length > 0 && (typeof file.type !== \"undefined\" ? file.type.match(/^image\\/(gif|png|jpeg)$/) : file.name.match(/\\.(gif|png|jpe?g)$/i)) && typeof FileReader !== \"undefined\") {\n      var reader = new FileReader()\n      var preview = this.$preview\n      var element = this.$element\n\n      reader.onload = function(re) {\n        var $img = $('<img>')\n        $img[0].src = re.target.result\n        files[0].result = re.target.result\n        \n        element.find('.fileinput-filename').text(file.name)\n        \n        // if parent has max-height, using `(max-)height: 100%` on child doesn't take padding and border into account\n        if (preview.css('max-height') != 'none') $img.css('max-height', parseInt(preview.css('max-height'), 10) - parseInt(preview.css('padding-top'), 10) - parseInt(preview.css('padding-bottom'), 10)  - parseInt(preview.css('border-top'), 10) - parseInt(preview.css('border-bottom'), 10))\n        \n        preview.html($img)\n        element.addClass('fileinput-exists').removeClass('fileinput-new')\n\n        element.trigger('change.bs.fileinput', files)\n      }\n\n      reader.readAsDataURL(file)\n    } else {\n      this.$element.find('.fileinput-filename').text(file.name)\n      this.$preview.text(file.name)\n      \n      this.$element.addClass('fileinput-exists').removeClass('fileinput-new')\n      \n      this.$element.trigger('change.bs.fileinput')\n    }\n  },\n\n  Fileinput.prototype.clear = function(e) {\n    if (e) e.preventDefault()\n    \n    this.$hidden.val('')\n    this.$hidden.attr('name', this.name)\n    this.$input.attr('name', '')\n\n    //ie8+ doesn't support changing the value of input with type=file so clone instead\n    if (isIE) { \n      var inputClone = this.$input.clone(true);\n      this.$input.after(inputClone);\n      this.$input.remove();\n      this.$input = inputClone;\n    } else {\n      this.$input.val('')\n    }\n\n    this.$preview.html('')\n    this.$element.find('.fileinput-filename').text('')\n    this.$element.addClass('fileinput-new').removeClass('fileinput-exists')\n    \n    if (e !== undefined) {\n      this.$input.trigger('change')\n      this.$element.trigger('clear.bs.fileinput')\n    }\n  },\n\n  Fileinput.prototype.reset = function() {\n    this.clear()\n\n    this.$hidden.val(this.original.hiddenVal)\n    this.$preview.html(this.original.preview)\n    this.$element.find('.fileinput-filename').text('')\n\n    if (this.original.exists) this.$element.addClass('fileinput-exists').removeClass('fileinput-new')\n     else this.$element.addClass('fileinput-new').removeClass('fileinput-exists')\n    \n    this.$element.trigger('reset.bs.fileinput')\n  },\n\n  Fileinput.prototype.trigger = function(e) {\n    this.$input.trigger('click')\n    e.preventDefault()\n  }\n\n  \n  // FILEUPLOAD PLUGIN DEFINITION\n  // ===========================\n\n  var old = $.fn.fileinput\n  \n  $.fn.fileinput = function (options) {\n    return this.each(function () {\n      var $this = $(this),\n          data = $this.data('bs.fileinput')\n      if (!data) $this.data('bs.fileinput', (data = new Fileinput(this, options)))\n      if (typeof options == 'string') data[options]()\n    })\n  }\n\n  $.fn.fileinput.Constructor = Fileinput\n\n\n  // FILEINPUT NO CONFLICT\n  // ====================\n\n  $.fn.fileinput.noConflict = function () {\n    $.fn.fileinput = old\n    return this\n  }\n\n\n  // FILEUPLOAD DATA-API\n  // ==================\n\n  $(document).on('click.fileinput.data-api', '[data-provides=\"fileinput\"]', function (e) {\n    var $this = $(this)\n    if ($this.data('bs.fileinput')) return\n    $this.fileinput($this.data())\n      \n    var $target = $(e.target).closest('[data-dismiss=\"fileinput\"],[data-trigger=\"fileinput\"]');\n    if ($target.length > 0) {\n      e.preventDefault()\n      $target.trigger('click.bs.fileinput')\n    }\n  })\n\n}(window.jQuery);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/fileinput/fileinput.less",
    "content": "// Fileinput.less\n// CSS for file upload button and fileinput widget\n// ------------------------------------------------\n\n.btn-file {\n  overflow: hidden;\n  position: relative;\n  vertical-align: middle;\n  > input {\n    position: absolute;\n    top: 0;\n    right: 0;\n    margin: 0;\n    opacity: 0;\n    filter: alpha(opacity=0);\n    font-size: 23px;\n    height: 100%;\n    width: 100%;\n    direction: ltr;\n    cursor: pointer;\n  }\n}\n\n.fileinput {\n  margin-bottom: 9px;\n  display: inline-block;\n  .form-control {\n    padding-top: 7px;\n    padding-bottom: 5px;\n    display: inline-block;\n    margin-bottom: 0px;\n    vertical-align: middle;\n    cursor: text;\n  }\n  .thumbnail {\n    overflow: hidden;\n    display: inline-block;\n    margin-bottom: 5px;\n    vertical-align: middle;\n    text-align: center;\n    > img {\n      max-height: 100%;\n    }\n  }\n  .btn {\n    vertical-align: middle;\n  }\n}\n.fileinput-exists .fileinput-new,\n.fileinput-new .fileinput-exists {\n  display: none;\n}\n.fileinput-inline .fileinput-controls {\n  display: inline;\n}\n\n.fileinput-filename {\n  vertical-align: middle;\n  display: inline-block;\n  overflow: hidden;\n}\n.form-control .fileinput-filename {\n  vertical-align: bottom;\n}\n\n.fileinput.input-group {\n    display: table;\n    \n    > * {\n        position: relative;\n        z-index: 2;\n    }\n    > .btn-file {\n        z-index: 1;\n    }\n}\n\n// Not 100% correct, but helps in typical use case\n.fileinput-new.input-group .btn-file,\n.fileinput-new .input-group .btn-file {\n  border-radius: 0 @border-radius-base @border-radius-base 0;\n\n  &.btn-xs,\n  &.btn-sm {\n    border-radius: 0 @border-radius-small @border-radius-small 0;\n  }\n  &.btn-lg {\n    border-radius: 0 @border-radius-large @border-radius-large 0;\n  }\n}\n\n.form-group.has-warning .fileinput {\n  .fileinput-preview {\n    color: @state-warning-text;\n  }\n  .thumbnail {\n    border-color: @state-warning-border;\n  }\n}\n.form-group.has-error .fileinput {\n  .fileinput-preview {\n    color: @state-danger-text;\n  }\n  .thumbnail {\n    border-color: @state-danger-border;\n  }\n}\n.form-group.has-success .fileinput {\n  .fileinput-preview {\n    color: @state-success-text;\n  }\n  .thumbnail {\n    border-color: @state-success-border;\n  }\n}\n\n\n// Input group fixes\n\n.input-group-addon:not(:first-child) {\n  border-left: 0;\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/input-mask/input-mask.js",
    "content": " /**\n * jquery.mask.js\n * @version: v1.5.3\n * @author: Igor Escobar\n *\n * Created by Igor Escobar on 2012-03-10. Please report any bug at http://blog.igorescobar.com\n *\n * Copyright (c) 2012 Igor Escobar http://blog.igorescobar.com\n *\n * The MIT License (http://www.opensource.org/licenses/mit-license.php)\n *\n * Permission is hereby granted, free of charge, to any person\n * obtaining a copy of this software and associated documentation\n * files (the \"Software\"), to deal in the Software without\n * restriction, including without limitation the rights to use,\n * copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following\n * conditions:\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n */\n\n(function ($) {\n    \"use strict\";\n    var Mask = function (el, mask, options) {\n        var jMask = this, old_value;\n        el = $(el);\n\n        mask = typeof mask === \"function\" ? mask(el.val(), undefined, el,  options) : mask;\n\n        jMask.init = function() {\n            options = options || {};\n\n            jMask.byPassKeys = [9, 16, 17, 18, 36, 37, 38, 39, 40, 91];\n            jMask.translation = {\n                '0': {pattern: /\\d/},\n                '9': {pattern: /\\d/, optional: true},\n                '#': {pattern: /\\d/, recursive: true},\n                'A': {pattern: /[a-zA-Z0-9]/},\n                'S': {pattern: /[a-zA-Z]/}\n            };\n\n            jMask.translation = $.extend({}, jMask.translation, options.translation);\n            jMask = $.extend(true, {}, jMask, options);\n\n            el.each(function() {\n                if (options.maxlength !== false) {\n                    el.attr('maxlength', mask.length);\n                }\n\n                el.attr('autocomplete', 'off');\n                p.destroyEvents();\n                p.events();\n                p.val(p.getMasked());\n            });\n        };\n\n        var p = {\n            getCaret: function () {\n                var sel,\n                    pos = 0,\n                    ctrl = el.get(0),\n                    dSel = document.selection,\n                    cSelStart = ctrl.selectionStart;\n\n                // IE Support\n                if (dSel && navigator.appVersion.indexOf(\"MSIE 10\") === -1) {\n                    ctrl.focus();\n                    sel = dSel.createRange ();\n                    sel.moveStart ('character', -ctrl.value.length);\n                    pos = sel.text.length;\n                } \n                // Firefox support\n                else if (cSelStart || cSelStart === '0') {\n                    pos = cSelStart;\n                }\n                \n                return pos;\n            },\n            setCaret: function(pos) {\n                var range, ctrl = el.get(0);\n\n                if (ctrl.setSelectionRange) {\n                    ctrl.focus();\n                    ctrl.setSelectionRange(pos,pos);\n                } else if (ctrl.createTextRange) {\n                    range = ctrl.createTextRange();\n                    range.collapse(true);\n                    range.moveEnd('character', pos);\n                    range.moveStart('character', pos);\n                    range.select();\n                }\n            },\n            events: function() {\n                el.on('keydown.mask', function() {\n                    old_value = p.val();\n                });\n                el.on('keyup.mask', p.behaviour);\n                el.on(\"paste.mask\", function() {\n                    setTimeout(function() {\n                        el.keydown().keyup();\n                    }, 100);\n                });\n            },\n            destroyEvents: function() {\n                el.off('keydown.mask keyup.mask paste.mask');\n            },\n            val: function(v) {\n                var isInput = el.get(0).tagName.toLowerCase() === \"input\";\n                return arguments.length > 0 \n                    ? (isInput ? el.val(v) : el.text(v)) \n                    : (isInput ? el.val() : el.text());\n            },\n            behaviour: function(e) {\n                e = e || window.event;\n                if ($.inArray(e.keyCode || e.which, jMask.byPassKeys) === -1) {\n                    \n                    var changeCaret, caretPos = p.getCaret();\n                    if (caretPos < p.val().length) {\n                        changeCaret = true;\n                    }\n                    \n                    p.val(p.getMasked());\n                    \n                    if (changeCaret) {\n                        p.setCaret(caretPos);     \n                    }\n\n                    return p.callbacks(e);\n                }\n            },\n            getMasked: function (skipMaskChars) {\n                var buf = [],\n                    value = p.val(),\n                    m = 0, maskLen = mask.length,\n                    v = 0, valLen = value.length,\n                    offset = 1, addMethod = \"push\",\n                    resetPos = -1,\n                    lastMaskChar,\n                    check;\n\n                if (options.reverse) {\n                    addMethod = \"unshift\";\n                    offset = -1;\n                    lastMaskChar = 0;\n                    m = maskLen - 1;\n                    v = valLen - 1;\n                    check = function () {\n                        return m > -1 && v > -1;\n                    };\n                } else {\n                    lastMaskChar = maskLen - 1;\n                    check = function () {\n                        return m < maskLen && v < valLen;\n                    };\n                }\n\n                while (check()) {\n                    var maskDigit = mask.charAt(m),\n                        valDigit = value.charAt(v),\n                        translation = jMask.translation[maskDigit];\n\n                    if (translation) {\n                        if (valDigit.match(translation.pattern)) {\n                            buf[addMethod](valDigit);\n                             if (translation.recursive) {\n                                if (resetPos === -1) {\n                                    resetPos = m;\n                                } else if (m === lastMaskChar) {\n                                    m = resetPos - offset;\n                                }\n\n                                if (lastMaskChar === resetPos) {\n                                    m -= offset;\n                                }\n                            }\n                            m += offset;\n                        } else if (translation.optional) {\n                            m += offset;\n                            v -= offset;\n                        }\n                        v += offset;\n                    } else {\n                        if (!skipMaskChars) {\n                            buf[addMethod](maskDigit);\n                        }\n                        \n                        if (valDigit === maskDigit) {\n                            v += offset;\n                        }\n\n                        m += offset;\n                    }\n                }\n                \n                var lastMaskCharDigit = mask.charAt(lastMaskChar);\n                if (maskLen === valLen + 1 && !jMask.translation[lastMaskCharDigit]) {\n                    buf.push(lastMaskCharDigit);\n                }\n                \n                return buf.join(\"\");\n            },\n            callbacks: function (e) {\n                var val = p.val(),\n                    changed = p.val() !== old_value;\n                if (changed === true) {\n                    if (typeof options.onChange === \"function\") {\n                        options.onChange(val, e, el, options);\n                    }\n                }\n\n                if (changed === true && typeof options.onKeyPress === \"function\") {\n                    options.onKeyPress(val, e, el, options);\n                }\n\n                if (typeof options.onComplete === \"function\" && val.length === mask.length) {\n                    options.onComplete(val, e, el, options);\n                }\n            }\n        };\n\n        // public methods\n        jMask.remove = function() {\n          p.destroyEvents();\n          p.val(jMask.getCleanVal()).removeAttr('maxlength');\n        };\n\n        // get value without mask\n        jMask.getCleanVal = function() {\n           return p.getMasked(true);\n        };\n\n        jMask.init();\n    };\n\n    $.fn.mask = function(mask, options) {\n        return this.each(function() {\n            $(this).data('mask', new Mask(this, mask, options));\n        });\n    };\n\n    $.fn.unmask = function() {\n        return this.each(function() {\n            try {\n                $(this).data('mask').remove();\n            } catch (e) {}\n        });\n    };\n\n    $.fn.cleanVal = function() {\n        return $(this).data('mask').getCleanVal();\n    };\n\n    // looking for inputs with data-mask attribute\n    $('*[data-mask]').each(function() {\n        var input = $(this),\n            options = {};\n\n        if (input.attr('data-mask-reverse') === 'true') {\n            options.reverse = true;\n        }\n\n        if (input.attr('data-mask-maxlength') === 'false') {\n            options.maxlength = false;\n        }\n\n        input.mask(input.attr('data-mask'), options);\n    });\n\n})(window.jQuery || window.Zepto);\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/sparklines/jquery.sparkline.js",
    "content": "/**\n*\n* jquery.sparkline.js\n*\n* v2.1.2\n* (c) Splunk, Inc\n* Contact: Gareth Watts (gareth@splunk.com)\n* http://omnipotent.net/jquery.sparkline/\n*\n* Generates inline sparkline charts from data supplied either to the method\n* or inline in HTML\n*\n* Compatible with Internet Explorer 6.0+ and modern browsers equipped with the canvas tag\n* (Firefox 2.0+, Safari, Opera, etc)\n*\n* License: New BSD License\n*\n* Copyright (c) 2012, Splunk Inc.\n* All rights reserved.\n*\n* Redistribution and use in source and binary forms, with or without modification,\n* are permitted provided that the following conditions are met:\n*\n*     * Redistributions of source code must retain the above copyright notice,\n*       this list of conditions and the following disclaimer.\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*     * Neither the name of Splunk Inc nor the names of its contributors may\n*       be used to endorse or promote products derived from this software without\n*       specific prior written permission.\n*\n* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY\n* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\n* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\n* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*\n*\n* Usage:\n*  $(selector).sparkline(values, options)\n*\n* If values is undefined or set to 'html' then the data values are read from the specified tag:\n*   <p>Sparkline: <span class=\"sparkline\">1,4,6,6,8,5,3,5</span></p>\n*   $('.sparkline').sparkline();\n* There must be no spaces in the enclosed data set\n*\n* Otherwise values must be an array of numbers or null values\n*    <p>Sparkline: <span id=\"sparkline1\">This text replaced if the browser is compatible</span></p>\n*    $('#sparkline1').sparkline([1,4,6,6,8,5,3,5])\n*    $('#sparkline2').sparkline([1,4,6,null,null,5,3,5])\n*\n* Values can also be specified in an HTML comment, or as a values attribute:\n*    <p>Sparkline: <span class=\"sparkline\"><!--1,4,6,6,8,5,3,5 --></span></p>\n*    <p>Sparkline: <span class=\"sparkline\" values=\"1,4,6,6,8,5,3,5\"></span></p>\n*    $('.sparkline').sparkline();\n*\n* For line charts, x values can also be specified:\n*   <p>Sparkline: <span class=\"sparkline\">1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5</span></p>\n*    $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ])\n*\n* By default, options should be passed in as teh second argument to the sparkline function:\n*   $('.sparkline').sparkline([1,2,3,4], {type: 'bar'})\n*\n* Options can also be set by passing them on the tag itself.  This feature is disabled by default though\n* as there's a slight performance overhead:\n*   $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true})\n*   <p>Sparkline: <span class=\"sparkline\" sparkType=\"bar\" sparkBarColor=\"red\">loading</span></p>\n* Prefix all options supplied as tag attribute with \"spark\" (configurable by setting tagOptionPrefix)\n*\n* Supported options:\n*   lineColor - Color of the line used for the chart\n*   fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart\n*   width - Width of the chart - Defaults to 3 times the number of values in pixels\n*   height - Height of the chart - Defaults to the height of the containing element\n*   chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied\n*   chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied\n*   chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax\n*   chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied\n*   chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied\n*   composite - If true then don't erase any existing chart attached to the tag, but draw\n*           another chart over the top - Note that width and height are ignored if an\n*           existing chart is detected.\n*   tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values'\n*   enableTagOptions - Whether to check tags for sparkline options\n*   tagOptionPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark'\n*   disableHiddenCheck - If set to true, then the plugin will assume that charts will never be drawn into a\n*           hidden dom element, avoding a browser reflow\n*   disableInteraction - If set to true then all mouseover/click interaction behaviour will be disabled,\n*       making the plugin perform much like it did in 1.x\n*   disableTooltips - If set to true then tooltips will be disabled - Defaults to false (tooltips enabled)\n*   disableHighlight - If set to true then highlighting of selected chart elements on mouseover will be disabled\n*       defaults to false (highlights enabled)\n*   highlightLighten - Factor to lighten/darken highlighted chart values by - Defaults to 1.4 for a 40% increase\n*   tooltipContainer - Specify which DOM element the tooltip should be rendered into - defaults to document.body\n*   tooltipClassname - Optional CSS classname to apply to tooltips - If not specified then a default style will be applied\n*   tooltipOffsetX - How many pixels away from the mouse pointer to render the tooltip on the X axis\n*   tooltipOffsetY - How many pixels away from the mouse pointer to render the tooltip on the r axis\n*   tooltipFormatter  - Optional callback that allows you to override the HTML displayed in the tooltip\n*       callback is given arguments of (sparkline, options, fields)\n*   tooltipChartTitle - If specified then the tooltip uses the string specified by this setting as a title\n*   tooltipFormat - A format string or SPFormat object  (or an array thereof for multiple entries)\n*       to control the format of the tooltip\n*   tooltipPrefix - A string to prepend to each field displayed in a tooltip\n*   tooltipSuffix - A string to append to each field displayed in a tooltip\n*   tooltipSkipNull - If true then null values will not have a tooltip displayed (defaults to true)\n*   tooltipValueLookups - An object or range map to map field values to tooltip strings\n*       (eg. to map -1 to \"Lost\", 0 to \"Draw\", and 1 to \"Win\")\n*   numberFormatter - Optional callback for formatting numbers in tooltips\n*   numberDigitGroupSep - Character to use for group separator in numbers \"1,234\" - Defaults to \",\"\n*   numberDecimalMark - Character to use for the decimal point when formatting numbers - Defaults to \".\"\n*   numberDigitGroupCount - Number of digits between group separator - Defaults to 3\n*\n* There are 7 types of sparkline, selected by supplying a \"type\" option of 'line' (default),\n* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box'\n*    line - Line chart.  Options:\n*       spotColor - Set to '' to not end each line in a circular spot\n*       minSpotColor - If set, color of spot at minimum value\n*       maxSpotColor - If set, color of spot at maximum value\n*       spotRadius - Radius in pixels\n*       lineWidth - Width of line in pixels\n*       normalRangeMin\n*       normalRangeMax - If set draws a filled horizontal bar between these two values marking the \"normal\"\n*                      or expected range of values\n*       normalRangeColor - Color to use for the above bar\n*       drawNormalOnTop - Draw the normal range above the chart fill color if true\n*       defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart\n*       highlightSpotColor - The color to use for drawing a highlight spot on mouseover - Set to null to disable\n*       highlightLineColor - The color to use for drawing a highlight line on mouseover - Set to null to disable\n*       valueSpots - Specify which points to draw spots on, and in which color.  Accepts a range map\n*\n*   bar - Bar chart.  Options:\n*       barColor - Color of bars for postive values\n*       negBarColor - Color of bars for negative values\n*       zeroColor - Color of bars with zero values\n*       nullColor - Color of bars with null values - Defaults to omitting the bar entirely\n*       barWidth - Width of bars in pixels\n*       colorMap - Optional mappnig of values to colors to override the *BarColor values above\n*                  can be an Array of values to control the color of individual bars or a range map\n*                  to specify colors for individual ranges of values\n*       barSpacing - Gap between bars in pixels\n*       zeroAxis - Centers the y-axis around zero if true\n*\n*   tristate - Charts values of win (>0), lose (<0) or draw (=0)\n*       posBarColor - Color of win values\n*       negBarColor - Color of lose values\n*       zeroBarColor - Color of draw values\n*       barWidth - Width of bars in pixels\n*       barSpacing - Gap between bars in pixels\n*       colorMap - Optional mappnig of values to colors to override the *BarColor values above\n*                  can be an Array of values to control the color of individual bars or a range map\n*                  to specify colors for individual ranges of values\n*\n*   discrete - Options:\n*       lineHeight - Height of each line in pixels - Defaults to 30% of the graph height\n*       thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor\n*       thresholdColor\n*\n*   bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ...\n*       options:\n*       targetColor - The color of the vertical target marker\n*       targetWidth - The width of the target marker in pixels\n*       performanceColor - The color of the performance measure horizontal bar\n*       rangeColors - Colors to use for each qualitative range background color\n*\n*   pie - Pie chart. Options:\n*       sliceColors - An array of colors to use for pie slices\n*       offset - Angle in degrees to offset the first slice - Try -90 or +90\n*       borderWidth - Width of border to draw around the pie chart, in pixels - Defaults to 0 (no border)\n*       borderColor - Color to use for the pie chart border - Defaults to #000\n*\n*   box - Box plot. Options:\n*       raw - Set to true to supply pre-computed plot points as values\n*             values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier\n*             When set to false you can supply any number of values and the box plot will\n*             be computed for you.  Default is false.\n*       showOutliers - Set to true (default) to display outliers as circles\n*       outlierIQR - Interquartile range used to determine outliers.  Default 1.5\n*       boxLineColor - Outline color of the box\n*       boxFillColor - Fill color for the box\n*       whiskerColor - Line color used for whiskers\n*       outlierLineColor - Outline color of outlier circles\n*       outlierFillColor - Fill color of the outlier circles\n*       spotRadius - Radius of outlier circles\n*       medianColor - Line color of the median line\n*       target - Draw a target cross hair at the supplied value (default undefined)\n*\n*\n*\n*   Examples:\n*   $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false });\n*   $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 });\n*   $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }):\n*   $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' });\n*   $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' });\n*   $('#pie').sparkline([1,1,2], { type:'pie' });\n*/\n\n/*jslint regexp: true, browser: true, jquery: true, white: true, nomen: false, plusplus: false, maxerr: 500, indent: 4 */\n\n(function(document, Math, undefined) { // performance/minified-size optimization\n(function(factory) {\n    if(typeof define === 'function' && define.amd) {\n        define(['jquery'], factory);\n    } else if (jQuery && !jQuery.fn.sparkline) {\n        factory(jQuery);\n    }\n}\n(function($) {\n    'use strict';\n\n    var UNSET_OPTION = {},\n        getDefaults, createClass, SPFormat, clipval, quartile, normalizeValue, normalizeValues,\n        remove, isNumber, all, sum, addCSS, ensureArray, formatNumber, RangeMap,\n        MouseHandler, Tooltip, barHighlightMixin,\n        line, bar, tristate, discrete, bullet, pie, box, defaultStyles, initStyles,\n        VShape, VCanvas_base, VCanvas_canvas, VCanvas_vml, pending, shapeCount = 0;\n\n    /**\n     * Default configuration settings\n     */\n    getDefaults = function () {\n        return {\n            // Settings common to most/all chart types\n            common: {\n                type: 'line',\n                lineColor: '#00f',\n                fillColor: '#cdf',\n                defaultPixelsPerValue: 3,\n                width: 'auto',\n                height: 'auto',\n                composite: false,\n                tagValuesAttribute: 'values',\n                tagOptionsPrefix: 'spark',\n                enableTagOptions: false,\n                enableHighlight: true,\n                highlightLighten: 1.4,\n                tooltipSkipNull: true,\n                tooltipPrefix: '',\n                tooltipSuffix: '',\n                disableHiddenCheck: false,\n                numberFormatter: false,\n                numberDigitGroupCount: 3,\n                numberDigitGroupSep: ',',\n                numberDecimalMark: '.',\n                disableTooltips: false,\n                disableInteraction: false\n            },\n            // Defaults for line charts\n            line: {\n                spotColor: '#f80',\n                highlightSpotColor: '#5f5',\n                highlightLineColor: '#f22',\n                spotRadius: 1.5,\n                minSpotColor: '#f80',\n                maxSpotColor: '#f80',\n                lineWidth: 1,\n                normalRangeMin: undefined,\n                normalRangeMax: undefined,\n                normalRangeColor: '#ccc',\n                drawNormalOnTop: false,\n                chartRangeMin: undefined,\n                chartRangeMax: undefined,\n                chartRangeMinX: undefined,\n                chartRangeMaxX: undefined,\n                tooltipFormat: new SPFormat('<span style=\"color: {{color}}\">&#9679;</span> {{prefix}}{{y}}{{suffix}}')\n            },\n            // Defaults for bar charts\n            bar: {\n                barColor: '#3366cc',\n                negBarColor: '#f44',\n                stackedBarColor: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',\n                    '#dd4477', '#0099c6', '#990099'],\n                zeroColor: undefined,\n                nullColor: undefined,\n                zeroAxis: true,\n                barWidth: 4,\n                barSpacing: 1,\n                chartRangeMax: undefined,\n                chartRangeMin: undefined,\n                chartRangeClip: false,\n                colorMap: undefined,\n                tooltipFormat: new SPFormat('<span style=\"color: {{color}}\">&#9679;</span> {{prefix}}{{value}}{{suffix}}')\n            },\n            // Defaults for tristate charts\n            tristate: {\n                barWidth: 4,\n                barSpacing: 1,\n                posBarColor: '#6f6',\n                negBarColor: '#f44',\n                zeroBarColor: '#999',\n                colorMap: {},\n                tooltipFormat: new SPFormat('<span style=\"color: {{color}}\">&#9679;</span> {{value:map}}'),\n                tooltipValueLookups: { map: { '-1': 'Loss', '0': 'Draw', '1': 'Win' } }\n            },\n            // Defaults for discrete charts\n            discrete: {\n                lineHeight: 'auto',\n                thresholdColor: undefined,\n                thresholdValue: 0,\n                chartRangeMax: undefined,\n                chartRangeMin: undefined,\n                chartRangeClip: false,\n                tooltipFormat: new SPFormat('{{prefix}}{{value}}{{suffix}}')\n            },\n            // Defaults for bullet charts\n            bullet: {\n                targetColor: '#f33',\n                targetWidth: 3, // width of the target bar in pixels\n                performanceColor: '#33f',\n                rangeColors: ['#d3dafe', '#a8b6ff', '#7f94ff'],\n                base: undefined, // set this to a number to change the base start number\n                tooltipFormat: new SPFormat('{{fieldkey:fields}} - {{value}}'),\n                tooltipValueLookups: { fields: {r: 'Range', p: 'Performance', t: 'Target'} }\n            },\n            // Defaults for pie charts\n            pie: {\n                offset: 0,\n                sliceColors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#66aa00',\n                    '#dd4477', '#0099c6', '#990099'],\n                borderWidth: 0,\n                borderColor: '#000',\n                tooltipFormat: new SPFormat('<span style=\"color: {{color}}\">&#9679;</span> {{value}} ({{percent.1}}%)')\n            },\n            // Defaults for box plots\n            box: {\n                raw: false,\n                boxLineColor: '#000',\n                boxFillColor: '#cdf',\n                whiskerColor: '#000',\n                outlierLineColor: '#333',\n                outlierFillColor: '#fff',\n                medianColor: '#f00',\n                showOutliers: true,\n                outlierIQR: 1.5,\n                spotRadius: 1.5,\n                target: undefined,\n                targetColor: '#4a2',\n                chartRangeMax: undefined,\n                chartRangeMin: undefined,\n                tooltipFormat: new SPFormat('{{field:fields}}: {{value}}'),\n                tooltipFormatFieldlistKey: 'field',\n                tooltipValueLookups: { fields: { lq: 'Lower Quartile', med: 'Median',\n                    uq: 'Upper Quartile', lo: 'Left Outlier', ro: 'Right Outlier',\n                    lw: 'Left Whisker', rw: 'Right Whisker'} }\n            }\n        };\n    };\n\n    // You can have tooltips use a css class other than jqstooltip by specifying tooltipClassname\n    defaultStyles = '.jqstooltip { ' +\n            'position: absolute;' +\n            'left: 0px;' +\n            'top: 0px;' +\n            'visibility: hidden;' +\n            'background: rgb(0, 0, 0) transparent;' +\n            'background-color: rgba(0,0,0,0.6);' +\n            'filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000);' +\n            '-ms-filter: \"progid:DXImageTransform.Microsoft.gradient(startColorstr=#99000000, endColorstr=#99000000)\";' +\n            'color: white;' +\n            'font: 10px arial, san serif;' +\n            'text-align: left;' +\n            'white-space: nowrap;' +\n            'padding: 5px;' +\n            'border: 1px solid white;' +\n            'z-index: 10000;' +\n            '}' +\n            '.jqsfield { ' +\n            'color: white;' +\n            'font: 10px arial, san serif;' +\n            'text-align: left;' +\n            '}';\n\n    /**\n     * Utilities\n     */\n\n    createClass = function (/* [baseclass, [mixin, ...]], definition */) {\n        var Class, args;\n        Class = function () {\n            this.init.apply(this, arguments);\n        };\n        if (arguments.length > 1) {\n            if (arguments[0]) {\n                Class.prototype = $.extend(new arguments[0](), arguments[arguments.length - 1]);\n                Class._super = arguments[0].prototype;\n            } else {\n                Class.prototype = arguments[arguments.length - 1];\n            }\n            if (arguments.length > 2) {\n                args = Array.prototype.slice.call(arguments, 1, -1);\n                args.unshift(Class.prototype);\n                $.extend.apply($, args);\n            }\n        } else {\n            Class.prototype = arguments[0];\n        }\n        Class.prototype.cls = Class;\n        return Class;\n    };\n\n    /**\n     * Wraps a format string for tooltips\n     * {{x}}\n     * {{x.2}\n     * {{x:months}}\n     */\n    $.SPFormatClass = SPFormat = createClass({\n        fre: /\\{\\{([\\w.]+?)(:(.+?))?\\}\\}/g,\n        precre: /(\\w+)\\.(\\d+)/,\n\n        init: function (format, fclass) {\n            this.format = format;\n            this.fclass = fclass;\n        },\n\n        render: function (fieldset, lookups, options) {\n            var self = this,\n                fields = fieldset,\n                match, token, lookupkey, fieldvalue, prec;\n            return this.format.replace(this.fre, function () {\n                var lookup;\n                token = arguments[1];\n                lookupkey = arguments[3];\n                match = self.precre.exec(token);\n                if (match) {\n                    prec = match[2];\n                    token = match[1];\n                } else {\n                    prec = false;\n                }\n                fieldvalue = fields[token];\n                if (fieldvalue === undefined) {\n                    return '';\n                }\n                if (lookupkey && lookups && lookups[lookupkey]) {\n                    lookup = lookups[lookupkey];\n                    if (lookup.get) { // RangeMap\n                        return lookups[lookupkey].get(fieldvalue) || fieldvalue;\n                    } else {\n                        return lookups[lookupkey][fieldvalue] || fieldvalue;\n                    }\n                }\n                if (isNumber(fieldvalue)) {\n                    if (options.get('numberFormatter')) {\n                        fieldvalue = options.get('numberFormatter')(fieldvalue);\n                    } else {\n                        fieldvalue = formatNumber(fieldvalue, prec,\n                            options.get('numberDigitGroupCount'),\n                            options.get('numberDigitGroupSep'),\n                            options.get('numberDecimalMark'));\n                    }\n                }\n                return fieldvalue;\n            });\n        }\n    });\n\n    // convience method to avoid needing the new operator\n    $.spformat = function(format, fclass) {\n        return new SPFormat(format, fclass);\n    };\n\n    clipval = function (val, min, max) {\n        if (val < min) {\n            return min;\n        }\n        if (val > max) {\n            return max;\n        }\n        return val;\n    };\n\n    quartile = function (values, q) {\n        var vl;\n        if (q === 2) {\n            vl = Math.floor(values.length / 2);\n            return values.length % 2 ? values[vl] : (values[vl-1] + values[vl]) / 2;\n        } else {\n            if (values.length % 2 ) { // odd\n                vl = (values.length * q + q) / 4;\n                return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 : values[vl-1];\n            } else { //even\n                vl = (values.length * q + 2) / 4;\n                return vl % 1 ? (values[Math.floor(vl)] + values[Math.floor(vl) - 1]) / 2 :  values[vl-1];\n\n            }\n        }\n    };\n\n    normalizeValue = function (val) {\n        var nf;\n        switch (val) {\n            case 'undefined':\n                val = undefined;\n                break;\n            case 'null':\n                val = null;\n                break;\n            case 'true':\n                val = true;\n                break;\n            case 'false':\n                val = false;\n                break;\n            default:\n                nf = parseFloat(val);\n                if (val == nf) {\n                    val = nf;\n                }\n        }\n        return val;\n    };\n\n    normalizeValues = function (vals) {\n        var i, result = [];\n        for (i = vals.length; i--;) {\n            result[i] = normalizeValue(vals[i]);\n        }\n        return result;\n    };\n\n    remove = function (vals, filter) {\n        var i, vl, result = [];\n        for (i = 0, vl = vals.length; i < vl; i++) {\n            if (vals[i] !== filter) {\n                result.push(vals[i]);\n            }\n        }\n        return result;\n    };\n\n    isNumber = function (num) {\n        return !isNaN(parseFloat(num)) && isFinite(num);\n    };\n\n    formatNumber = function (num, prec, groupsize, groupsep, decsep) {\n        var p, i;\n        num = (prec === false ? parseFloat(num).toString() : num.toFixed(prec)).split('');\n        p = (p = $.inArray('.', num)) < 0 ? num.length : p;\n        if (p < num.length) {\n            num[p] = decsep;\n        }\n        for (i = p - groupsize; i > 0; i -= groupsize) {\n            num.splice(i, 0, groupsep);\n        }\n        return num.join('');\n    };\n\n    // determine if all values of an array match a value\n    // returns true if the array is empty\n    all = function (val, arr, ignoreNull) {\n        var i;\n        for (i = arr.length; i--; ) {\n            if (ignoreNull && arr[i] === null) continue;\n            if (arr[i] !== val) {\n                return false;\n            }\n        }\n        return true;\n    };\n\n    // sums the numeric values in an array, ignoring other values\n    sum = function (vals) {\n        var total = 0, i;\n        for (i = vals.length; i--;) {\n            total += typeof vals[i] === 'number' ? vals[i] : 0;\n        }\n        return total;\n    };\n\n    ensureArray = function (val) {\n        return $.isArray(val) ? val : [val];\n    };\n\n    // http://paulirish.com/2008/bookmarklet-inject-new-css-rules/\n    addCSS = function(css) {\n        var tag;\n        //if ('\\v' == 'v') /* ie only */ {\n        if (document.createStyleSheet) {\n            document.createStyleSheet().cssText = css;\n        } else {\n            tag = document.createElement('style');\n            tag.type = 'text/css';\n            document.getElementsByTagName('head')[0].appendChild(tag);\n            tag[(typeof document.body.style.WebkitAppearance == 'string') /* webkit only */ ? 'innerText' : 'innerHTML'] = css;\n        }\n    };\n\n    // Provide a cross-browser interface to a few simple drawing primitives\n    $.fn.simpledraw = function (width, height, useExisting, interact) {\n        var target, mhandler;\n        if (useExisting && (target = this.data('_jqs_vcanvas'))) {\n            return target;\n        }\n\n        if ($.fn.sparkline.canvas === false) {\n            // We've already determined that neither Canvas nor VML are available\n            return false;\n\n        } else if ($.fn.sparkline.canvas === undefined) {\n            // No function defined yet -- need to see if we support Canvas or VML\n            var el = document.createElement('canvas');\n            if (!!(el.getContext && el.getContext('2d'))) {\n                // Canvas is available\n                $.fn.sparkline.canvas = function(width, height, target, interact) {\n                    return new VCanvas_canvas(width, height, target, interact);\n                };\n            } else if (document.namespaces && !document.namespaces.v) {\n                // VML is available\n                document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML');\n                $.fn.sparkline.canvas = function(width, height, target, interact) {\n                    return new VCanvas_vml(width, height, target);\n                };\n            } else {\n                // Neither Canvas nor VML are available\n                $.fn.sparkline.canvas = false;\n                return false;\n            }\n        }\n\n        if (width === undefined) {\n            width = $(this).innerWidth();\n        }\n        if (height === undefined) {\n            height = $(this).innerHeight();\n        }\n\n        target = $.fn.sparkline.canvas(width, height, this, interact);\n\n        mhandler = $(this).data('_jqs_mhandler');\n        if (mhandler) {\n            mhandler.registerCanvas(target);\n        }\n        return target;\n    };\n\n    $.fn.cleardraw = function () {\n        var target = this.data('_jqs_vcanvas');\n        if (target) {\n            target.reset();\n        }\n    };\n\n    $.RangeMapClass = RangeMap = createClass({\n        init: function (map) {\n            var key, range, rangelist = [];\n            for (key in map) {\n                if (map.hasOwnProperty(key) && typeof key === 'string' && key.indexOf(':') > -1) {\n                    range = key.split(':');\n                    range[0] = range[0].length === 0 ? -Infinity : parseFloat(range[0]);\n                    range[1] = range[1].length === 0 ? Infinity : parseFloat(range[1]);\n                    range[2] = map[key];\n                    rangelist.push(range);\n                }\n            }\n            this.map = map;\n            this.rangelist = rangelist || false;\n        },\n\n        get: function (value) {\n            var rangelist = this.rangelist,\n                i, range, result;\n            if ((result = this.map[value]) !== undefined) {\n                return result;\n            }\n            if (rangelist) {\n                for (i = rangelist.length; i--;) {\n                    range = rangelist[i];\n                    if (range[0] <= value && range[1] >= value) {\n                        return range[2];\n                    }\n                }\n            }\n            return undefined;\n        }\n    });\n\n    // Convenience function\n    $.range_map = function(map) {\n        return new RangeMap(map);\n    };\n\n    MouseHandler = createClass({\n        init: function (el, options) {\n            var $el = $(el);\n            this.$el = $el;\n            this.options = options;\n            this.currentPageX = 0;\n            this.currentPageY = 0;\n            this.el = el;\n            this.splist = [];\n            this.tooltip = null;\n            this.over = false;\n            this.displayTooltips = !options.get('disableTooltips');\n            this.highlightEnabled = !options.get('disableHighlight');\n        },\n\n        registerSparkline: function (sp) {\n            this.splist.push(sp);\n            if (this.over) {\n                this.updateDisplay();\n            }\n        },\n\n        registerCanvas: function (canvas) {\n            var $canvas = $(canvas.canvas);\n            this.canvas = canvas;\n            this.$canvas = $canvas;\n            $canvas.mouseenter($.proxy(this.mouseenter, this));\n            $canvas.mouseleave($.proxy(this.mouseleave, this));\n            $canvas.click($.proxy(this.mouseclick, this));\n        },\n\n        reset: function (removeTooltip) {\n            this.splist = [];\n            if (this.tooltip && removeTooltip) {\n                this.tooltip.remove();\n                this.tooltip = undefined;\n            }\n        },\n\n        mouseclick: function (e) {\n            var clickEvent = $.Event('sparklineClick');\n            clickEvent.originalEvent = e;\n            clickEvent.sparklines = this.splist;\n            this.$el.trigger(clickEvent);\n        },\n\n        mouseenter: function (e) {\n            $(document.body).unbind('mousemove.jqs');\n            $(document.body).bind('mousemove.jqs', $.proxy(this.mousemove, this));\n            this.over = true;\n            this.currentPageX = e.pageX;\n            this.currentPageY = e.pageY;\n            this.currentEl = e.target;\n            if (!this.tooltip && this.displayTooltips) {\n                this.tooltip = new Tooltip(this.options);\n                this.tooltip.updatePosition(e.pageX, e.pageY);\n            }\n            this.updateDisplay();\n        },\n\n        mouseleave: function () {\n            $(document.body).unbind('mousemove.jqs');\n            var splist = this.splist,\n                 spcount = splist.length,\n                 needsRefresh = false,\n                 sp, i;\n            this.over = false;\n            this.currentEl = null;\n\n            if (this.tooltip) {\n                this.tooltip.remove();\n                this.tooltip = null;\n            }\n\n            for (i = 0; i < spcount; i++) {\n                sp = splist[i];\n                if (sp.clearRegionHighlight()) {\n                    needsRefresh = true;\n                }\n            }\n\n            if (needsRefresh) {\n                this.canvas.render();\n            }\n        },\n\n        mousemove: function (e) {\n            this.currentPageX = e.pageX;\n            this.currentPageY = e.pageY;\n            this.currentEl = e.target;\n            if (this.tooltip) {\n                this.tooltip.updatePosition(e.pageX, e.pageY);\n            }\n            this.updateDisplay();\n        },\n\n        updateDisplay: function () {\n            var splist = this.splist,\n                 spcount = splist.length,\n                 needsRefresh = false,\n                 offset = this.$canvas.offset(),\n                 localX = this.currentPageX - offset.left,\n                 localY = this.currentPageY - offset.top,\n                 tooltiphtml, sp, i, result, changeEvent;\n            if (!this.over) {\n                return;\n            }\n            for (i = 0; i < spcount; i++) {\n                sp = splist[i];\n                result = sp.setRegionHighlight(this.currentEl, localX, localY);\n                if (result) {\n                    needsRefresh = true;\n                }\n            }\n            if (needsRefresh) {\n                changeEvent = $.Event('sparklineRegionChange');\n                changeEvent.sparklines = this.splist;\n                this.$el.trigger(changeEvent);\n                if (this.tooltip) {\n                    tooltiphtml = '';\n                    for (i = 0; i < spcount; i++) {\n                        sp = splist[i];\n                        tooltiphtml += sp.getCurrentRegionTooltip();\n                    }\n                    this.tooltip.setContent(tooltiphtml);\n                }\n                if (!this.disableHighlight) {\n                    this.canvas.render();\n                }\n            }\n            if (result === null) {\n                this.mouseleave();\n            }\n        }\n    });\n\n\n    Tooltip = createClass({\n        sizeStyle: 'position: static !important;' +\n            'display: block !important;' +\n            'visibility: hidden !important;' +\n            'float: left !important;',\n\n        init: function (options) {\n            var tooltipClassname = options.get('tooltipClassname', 'jqstooltip'),\n                sizetipStyle = this.sizeStyle,\n                offset;\n            this.container = options.get('tooltipContainer') || document.body;\n            this.tooltipOffsetX = options.get('tooltipOffsetX', 10);\n            this.tooltipOffsetY = options.get('tooltipOffsetY', 12);\n            // remove any previous lingering tooltip\n            $('#jqssizetip').remove();\n            $('#jqstooltip').remove();\n            this.sizetip = $('<div/>', {\n                id: 'jqssizetip',\n                style: sizetipStyle,\n                'class': tooltipClassname\n            });\n            this.tooltip = $('<div/>', {\n                id: 'jqstooltip',\n                'class': tooltipClassname\n            }).appendTo(this.container);\n            // account for the container's location\n            offset = this.tooltip.offset();\n            this.offsetLeft = offset.left;\n            this.offsetTop = offset.top;\n            this.hidden = true;\n            $(window).unbind('resize.jqs scroll.jqs');\n            $(window).bind('resize.jqs scroll.jqs', $.proxy(this.updateWindowDims, this));\n            this.updateWindowDims();\n        },\n\n        updateWindowDims: function () {\n            this.scrollTop = $(window).scrollTop();\n            this.scrollLeft = $(window).scrollLeft();\n            this.scrollRight = this.scrollLeft + $(window).width();\n            this.updatePosition();\n        },\n\n        getSize: function (content) {\n            this.sizetip.html(content).appendTo(this.container);\n            this.width = this.sizetip.width() + 1;\n            this.height = this.sizetip.height();\n            this.sizetip.remove();\n        },\n\n        setContent: function (content) {\n            if (!content) {\n                this.tooltip.css('visibility', 'hidden');\n                this.hidden = true;\n                return;\n            }\n            this.getSize(content);\n            this.tooltip.html(content)\n                .css({\n                    'width': this.width,\n                    'height': this.height,\n                    'visibility': 'visible'\n                });\n            if (this.hidden) {\n                this.hidden = false;\n                this.updatePosition();\n            }\n        },\n\n        updatePosition: function (x, y) {\n            if (x === undefined) {\n                if (this.mousex === undefined) {\n                    return;\n                }\n                x = this.mousex - this.offsetLeft;\n                y = this.mousey - this.offsetTop;\n\n            } else {\n                this.mousex = x = x - this.offsetLeft;\n                this.mousey = y = y - this.offsetTop;\n            }\n            if (!this.height || !this.width || this.hidden) {\n                return;\n            }\n\n            y -= this.height + this.tooltipOffsetY;\n            x += this.tooltipOffsetX;\n\n            if (y < this.scrollTop) {\n                y = this.scrollTop;\n            }\n            if (x < this.scrollLeft) {\n                x = this.scrollLeft;\n            } else if (x + this.width > this.scrollRight) {\n                x = this.scrollRight - this.width;\n            }\n\n            this.tooltip.css({\n                'left': x,\n                'top': y\n            });\n        },\n\n        remove: function () {\n            this.tooltip.remove();\n            this.sizetip.remove();\n            this.sizetip = this.tooltip = undefined;\n            $(window).unbind('resize.jqs scroll.jqs');\n        }\n    });\n\n    initStyles = function() {\n        addCSS(defaultStyles);\n    };\n\n    $(initStyles);\n\n    pending = [];\n    $.fn.sparkline = function (userValues, userOptions) {\n        return this.each(function () {\n            var options = new $.fn.sparkline.options(this, userOptions),\n                 $this = $(this),\n                 render, i;\n            render = function () {\n                var values, width, height, tmp, mhandler, sp, vals;\n                if (userValues === 'html' || userValues === undefined) {\n                    vals = this.getAttribute(options.get('tagValuesAttribute'));\n                    if (vals === undefined || vals === null) {\n                        vals = $this.html();\n                    }\n                    values = vals.replace(/(^\\s*<!--)|(-->\\s*$)|\\s+/g, '').split(',');\n                } else {\n                    values = userValues;\n                }\n\n                width = options.get('width') === 'auto' ? values.length * options.get('defaultPixelsPerValue') : options.get('width');\n                if (options.get('height') === 'auto') {\n                    if (!options.get('composite') || !$.data(this, '_jqs_vcanvas')) {\n                        // must be a better way to get the line height\n                        tmp = document.createElement('span');\n                        tmp.innerHTML = 'a';\n                        $this.html(tmp);\n                        height = $(tmp).innerHeight() || $(tmp).height();\n                        $(tmp).remove();\n                        tmp = null;\n                    }\n                } else {\n                    height = options.get('height');\n                }\n\n                if (!options.get('disableInteraction')) {\n                    mhandler = $.data(this, '_jqs_mhandler');\n                    if (!mhandler) {\n                        mhandler = new MouseHandler(this, options);\n                        $.data(this, '_jqs_mhandler', mhandler);\n                    } else if (!options.get('composite')) {\n                        mhandler.reset();\n                    }\n                } else {\n                    mhandler = false;\n                }\n\n                if (options.get('composite') && !$.data(this, '_jqs_vcanvas')) {\n                    if (!$.data(this, '_jqs_errnotify')) {\n                        alert('Attempted to attach a composite sparkline to an element with no existing sparkline');\n                        $.data(this, '_jqs_errnotify', true);\n                    }\n                    return;\n                }\n\n                sp = new $.fn.sparkline[options.get('type')](this, values, options, width, height);\n\n                sp.render();\n\n                if (mhandler) {\n                    mhandler.registerSparkline(sp);\n                }\n            };\n            if (($(this).html() && !options.get('disableHiddenCheck') && $(this).is(':hidden')) || !$(this).parents('body').length) {\n                if (!options.get('composite') && $.data(this, '_jqs_pending')) {\n                    // remove any existing references to the element\n                    for (i = pending.length; i; i--) {\n                        if (pending[i - 1][0] == this) {\n                            pending.splice(i - 1, 1);\n                        }\n                    }\n                }\n                pending.push([this, render]);\n                $.data(this, '_jqs_pending', true);\n            } else {\n                render.call(this);\n            }\n        });\n    };\n\n    $.fn.sparkline.defaults = getDefaults();\n\n\n    $.sparkline_display_visible = function () {\n        var el, i, pl;\n        var done = [];\n        for (i = 0, pl = pending.length; i < pl; i++) {\n            el = pending[i][0];\n            if ($(el).is(':visible') && !$(el).parents().is(':hidden')) {\n                pending[i][1].call(el);\n                $.data(pending[i][0], '_jqs_pending', false);\n                done.push(i);\n            } else if (!$(el).closest('html').length && !$.data(el, '_jqs_pending')) {\n                // element has been inserted and removed from the DOM\n                // If it was not yet inserted into the dom then the .data request\n                // will return true.\n                // removing from the dom causes the data to be removed.\n                $.data(pending[i][0], '_jqs_pending', false);\n                done.push(i);\n            }\n        }\n        for (i = done.length; i; i--) {\n            pending.splice(done[i - 1], 1);\n        }\n    };\n\n\n    /**\n     * User option handler\n     */\n    $.fn.sparkline.options = createClass({\n        init: function (tag, userOptions) {\n            var extendedOptions, defaults, base, tagOptionType;\n            this.userOptions = userOptions = userOptions || {};\n            this.tag = tag;\n            this.tagValCache = {};\n            defaults = $.fn.sparkline.defaults;\n            base = defaults.common;\n            this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix);\n\n            tagOptionType = this.getTagSetting('type');\n            if (tagOptionType === UNSET_OPTION) {\n                extendedOptions = defaults[userOptions.type || base.type];\n            } else {\n                extendedOptions = defaults[tagOptionType];\n            }\n            this.mergedOptions = $.extend({}, base, extendedOptions, userOptions);\n        },\n\n\n        getTagSetting: function (key) {\n            var prefix = this.tagOptionsPrefix,\n                val, i, pairs, keyval;\n            if (prefix === false || prefix === undefined) {\n                return UNSET_OPTION;\n            }\n            if (this.tagValCache.hasOwnProperty(key)) {\n                val = this.tagValCache.key;\n            } else {\n                val = this.tag.getAttribute(prefix + key);\n                if (val === undefined || val === null) {\n                    val = UNSET_OPTION;\n                } else if (val.substr(0, 1) === '[') {\n                    val = val.substr(1, val.length - 2).split(',');\n                    for (i = val.length; i--;) {\n                        val[i] = normalizeValue(val[i].replace(/(^\\s*)|(\\s*$)/g, ''));\n                    }\n                } else if (val.substr(0, 1) === '{') {\n                    pairs = val.substr(1, val.length - 2).split(',');\n                    val = {};\n                    for (i = pairs.length; i--;) {\n                        keyval = pairs[i].split(':', 2);\n                        val[keyval[0].replace(/(^\\s*)|(\\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\\s*)|(\\s*$)/g, ''));\n                    }\n                } else {\n                    val = normalizeValue(val);\n                }\n                this.tagValCache.key = val;\n            }\n            return val;\n        },\n\n        get: function (key, defaultval) {\n            var tagOption = this.getTagSetting(key),\n                result;\n            if (tagOption !== UNSET_OPTION) {\n                return tagOption;\n            }\n            return (result = this.mergedOptions[key]) === undefined ? defaultval : result;\n        }\n    });\n\n\n    $.fn.sparkline._base = createClass({\n        disabled: false,\n\n        init: function (el, values, options, width, height) {\n            this.el = el;\n            this.$el = $(el);\n            this.values = values;\n            this.options = options;\n            this.width = width;\n            this.height = height;\n            this.currentRegion = undefined;\n        },\n\n        /**\n         * Setup the canvas\n         */\n        initTarget: function () {\n            var interactive = !this.options.get('disableInteraction');\n            if (!(this.target = this.$el.simpledraw(this.width, this.height, this.options.get('composite'), interactive))) {\n                this.disabled = true;\n            } else {\n                this.canvasWidth = this.target.pixelWidth;\n                this.canvasHeight = this.target.pixelHeight;\n            }\n        },\n\n        /**\n         * Actually render the chart to the canvas\n         */\n        render: function () {\n            if (this.disabled) {\n                this.el.innerHTML = '';\n                return false;\n            }\n            return true;\n        },\n\n        /**\n         * Return a region id for a given x/y co-ordinate\n         */\n        getRegion: function (x, y) {\n        },\n\n        /**\n         * Highlight an item based on the moused-over x,y co-ordinate\n         */\n        setRegionHighlight: function (el, x, y) {\n            var currentRegion = this.currentRegion,\n                highlightEnabled = !this.options.get('disableHighlight'),\n                newRegion;\n            if (x > this.canvasWidth || y > this.canvasHeight || x < 0 || y < 0) {\n                return null;\n            }\n            newRegion = this.getRegion(el, x, y);\n            if (currentRegion !== newRegion) {\n                if (currentRegion !== undefined && highlightEnabled) {\n                    this.removeHighlight();\n                }\n                this.currentRegion = newRegion;\n                if (newRegion !== undefined && highlightEnabled) {\n                    this.renderHighlight();\n                }\n                return true;\n            }\n            return false;\n        },\n\n        /**\n         * Reset any currently highlighted item\n         */\n        clearRegionHighlight: function () {\n            if (this.currentRegion !== undefined) {\n                this.removeHighlight();\n                this.currentRegion = undefined;\n                return true;\n            }\n            return false;\n        },\n\n        renderHighlight: function () {\n            this.changeHighlight(true);\n        },\n\n        removeHighlight: function () {\n            this.changeHighlight(false);\n        },\n\n        changeHighlight: function (highlight)  {},\n\n        /**\n         * Fetch the HTML to display as a tooltip\n         */\n        getCurrentRegionTooltip: function () {\n            var options = this.options,\n                header = '',\n                entries = [],\n                fields, formats, formatlen, fclass, text, i,\n                showFields, showFieldsKey, newFields, fv,\n                formatter, format, fieldlen, j;\n            if (this.currentRegion === undefined) {\n                return '';\n            }\n            fields = this.getCurrentRegionFields();\n            formatter = options.get('tooltipFormatter');\n            if (formatter) {\n                return formatter(this, options, fields);\n            }\n            if (options.get('tooltipChartTitle')) {\n                header += '<div class=\"jqs jqstitle\">' + options.get('tooltipChartTitle') + '</div>\\n';\n            }\n            formats = this.options.get('tooltipFormat');\n            if (!formats) {\n                return '';\n            }\n            if (!$.isArray(formats)) {\n                formats = [formats];\n            }\n            if (!$.isArray(fields)) {\n                fields = [fields];\n            }\n            showFields = this.options.get('tooltipFormatFieldlist');\n            showFieldsKey = this.options.get('tooltipFormatFieldlistKey');\n            if (showFields && showFieldsKey) {\n                // user-selected ordering of fields\n                newFields = [];\n                for (i = fields.length; i--;) {\n                    fv = fields[i][showFieldsKey];\n                    if ((j = $.inArray(fv, showFields)) != -1) {\n                        newFields[j] = fields[i];\n                    }\n                }\n                fields = newFields;\n            }\n            formatlen = formats.length;\n            fieldlen = fields.length;\n            for (i = 0; i < formatlen; i++) {\n                format = formats[i];\n                if (typeof format === 'string') {\n                    format = new SPFormat(format);\n                }\n                fclass = format.fclass || 'jqsfield';\n                for (j = 0; j < fieldlen; j++) {\n                    if (!fields[j].isNull || !options.get('tooltipSkipNull')) {\n                        $.extend(fields[j], {\n                            prefix: options.get('tooltipPrefix'),\n                            suffix: options.get('tooltipSuffix')\n                        });\n                        text = format.render(fields[j], options.get('tooltipValueLookups'), options);\n                        entries.push('<div class=\"' + fclass + '\">' + text + '</div>');\n                    }\n                }\n            }\n            if (entries.length) {\n                return header + entries.join('\\n');\n            }\n            return '';\n        },\n\n        getCurrentRegionFields: function () {},\n\n        calcHighlightColor: function (color, options) {\n            var highlightColor = options.get('highlightColor'),\n                lighten = options.get('highlightLighten'),\n                parse, mult, rgbnew, i;\n            if (highlightColor) {\n                return highlightColor;\n            }\n            if (lighten) {\n                // extract RGB values\n                parse = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(color) || /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);\n                if (parse) {\n                    rgbnew = [];\n                    mult = color.length === 4 ? 16 : 1;\n                    for (i = 0; i < 3; i++) {\n                        rgbnew[i] = clipval(Math.round(parseInt(parse[i + 1], 16) * mult * lighten), 0, 255);\n                    }\n                    return 'rgb(' + rgbnew.join(',') + ')';\n                }\n\n            }\n            return color;\n        }\n\n    });\n\n    barHighlightMixin = {\n        changeHighlight: function (highlight) {\n            var currentRegion = this.currentRegion,\n                target = this.target,\n                shapeids = this.regionShapes[currentRegion],\n                newShapes;\n            // will be null if the region value was null\n            if (shapeids) {\n                newShapes = this.renderRegion(currentRegion, highlight);\n                if ($.isArray(newShapes) || $.isArray(shapeids)) {\n                    target.replaceWithShapes(shapeids, newShapes);\n                    this.regionShapes[currentRegion] = $.map(newShapes, function (newShape) {\n                        return newShape.id;\n                    });\n                } else {\n                    target.replaceWithShape(shapeids, newShapes);\n                    this.regionShapes[currentRegion] = newShapes.id;\n                }\n            }\n        },\n\n        render: function () {\n            var values = this.values,\n                target = this.target,\n                regionShapes = this.regionShapes,\n                shapes, ids, i, j;\n\n            if (!this.cls._super.render.call(this)) {\n                return;\n            }\n            for (i = values.length; i--;) {\n                shapes = this.renderRegion(i);\n                if (shapes) {\n                    if ($.isArray(shapes)) {\n                        ids = [];\n                        for (j = shapes.length; j--;) {\n                            shapes[j].append();\n                            ids.push(shapes[j].id);\n                        }\n                        regionShapes[i] = ids;\n                    } else {\n                        shapes.append();\n                        regionShapes[i] = shapes.id; // store just the shapeid\n                    }\n                } else {\n                    // null value\n                    regionShapes[i] = null;\n                }\n            }\n            target.render();\n        }\n    };\n\n    /**\n     * Line charts\n     */\n    $.fn.sparkline.line = line = createClass($.fn.sparkline._base, {\n        type: 'line',\n\n        init: function (el, values, options, width, height) {\n            line._super.init.call(this, el, values, options, width, height);\n            this.vertices = [];\n            this.regionMap = [];\n            this.xvalues = [];\n            this.yvalues = [];\n            this.yminmax = [];\n            this.hightlightSpotId = null;\n            this.lastShapeId = null;\n            this.initTarget();\n        },\n\n        getRegion: function (el, x, y) {\n            var i,\n                regionMap = this.regionMap; // maps regions to value positions\n            for (i = regionMap.length; i--;) {\n                if (regionMap[i] !== null && x >= regionMap[i][0] && x <= regionMap[i][1]) {\n                    return regionMap[i][2];\n                }\n            }\n            return undefined;\n        },\n\n        getCurrentRegionFields: function () {\n            var currentRegion = this.currentRegion;\n            return {\n                isNull: this.yvalues[currentRegion] === null,\n                x: this.xvalues[currentRegion],\n                y: this.yvalues[currentRegion],\n                color: this.options.get('lineColor'),\n                fillColor: this.options.get('fillColor'),\n                offset: currentRegion\n            };\n        },\n\n        renderHighlight: function () {\n            var currentRegion = this.currentRegion,\n                target = this.target,\n                vertex = this.vertices[currentRegion],\n                options = this.options,\n                spotRadius = options.get('spotRadius'),\n                highlightSpotColor = options.get('highlightSpotColor'),\n                highlightLineColor = options.get('highlightLineColor'),\n                highlightSpot, highlightLine;\n\n            if (!vertex) {\n                return;\n            }\n            if (spotRadius && highlightSpotColor) {\n                highlightSpot = target.drawCircle(vertex[0], vertex[1],\n                    spotRadius, undefined, highlightSpotColor);\n                this.highlightSpotId = highlightSpot.id;\n                target.insertAfterShape(this.lastShapeId, highlightSpot);\n            }\n            if (highlightLineColor) {\n                highlightLine = target.drawLine(vertex[0], this.canvasTop, vertex[0],\n                    this.canvasTop + this.canvasHeight, highlightLineColor);\n                this.highlightLineId = highlightLine.id;\n                target.insertAfterShape(this.lastShapeId, highlightLine);\n            }\n        },\n\n        removeHighlight: function () {\n            var target = this.target;\n            if (this.highlightSpotId) {\n                target.removeShapeId(this.highlightSpotId);\n                this.highlightSpotId = null;\n            }\n            if (this.highlightLineId) {\n                target.removeShapeId(this.highlightLineId);\n                this.highlightLineId = null;\n            }\n        },\n\n        scanValues: function () {\n            var values = this.values,\n                valcount = values.length,\n                xvalues = this.xvalues,\n                yvalues = this.yvalues,\n                yminmax = this.yminmax,\n                i, val, isStr, isArray, sp;\n            for (i = 0; i < valcount; i++) {\n                val = values[i];\n                isStr = typeof(values[i]) === 'string';\n                isArray = typeof(values[i]) === 'object' && values[i] instanceof Array;\n                sp = isStr && values[i].split(':');\n                if (isStr && sp.length === 2) { // x:y\n                    xvalues.push(Number(sp[0]));\n                    yvalues.push(Number(sp[1]));\n                    yminmax.push(Number(sp[1]));\n                } else if (isArray) {\n                    xvalues.push(val[0]);\n                    yvalues.push(val[1]);\n                    yminmax.push(val[1]);\n                } else {\n                    xvalues.push(i);\n                    if (values[i] === null || values[i] === 'null') {\n                        yvalues.push(null);\n                    } else {\n                        yvalues.push(Number(val));\n                        yminmax.push(Number(val));\n                    }\n                }\n            }\n            if (this.options.get('xvalues')) {\n                xvalues = this.options.get('xvalues');\n            }\n\n            this.maxy = this.maxyorg = Math.max.apply(Math, yminmax);\n            this.miny = this.minyorg = Math.min.apply(Math, yminmax);\n\n            this.maxx = Math.max.apply(Math, xvalues);\n            this.minx = Math.min.apply(Math, xvalues);\n\n            this.xvalues = xvalues;\n            this.yvalues = yvalues;\n            this.yminmax = yminmax;\n\n        },\n\n        processRangeOptions: function () {\n            var options = this.options,\n                normalRangeMin = options.get('normalRangeMin'),\n                normalRangeMax = options.get('normalRangeMax');\n\n            if (normalRangeMin !== undefined) {\n                if (normalRangeMin < this.miny) {\n                    this.miny = normalRangeMin;\n                }\n                if (normalRangeMax > this.maxy) {\n                    this.maxy = normalRangeMax;\n                }\n            }\n            if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.miny)) {\n                this.miny = options.get('chartRangeMin');\n            }\n            if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.maxy)) {\n                this.maxy = options.get('chartRangeMax');\n            }\n            if (options.get('chartRangeMinX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX') < this.minx)) {\n                this.minx = options.get('chartRangeMinX');\n            }\n            if (options.get('chartRangeMaxX') !== undefined && (options.get('chartRangeClipX') || options.get('chartRangeMaxX') > this.maxx)) {\n                this.maxx = options.get('chartRangeMaxX');\n            }\n\n        },\n\n        drawNormalRange: function (canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey) {\n            var normalRangeMin = this.options.get('normalRangeMin'),\n                normalRangeMax = this.options.get('normalRangeMax'),\n                ytop = canvasTop + Math.round(canvasHeight - (canvasHeight * ((normalRangeMax - this.miny) / rangey))),\n                height = Math.round((canvasHeight * (normalRangeMax - normalRangeMin)) / rangey);\n            this.target.drawRect(canvasLeft, ytop, canvasWidth, height, undefined, this.options.get('normalRangeColor')).append();\n        },\n\n        render: function () {\n            var options = this.options,\n                target = this.target,\n                canvasWidth = this.canvasWidth,\n                canvasHeight = this.canvasHeight,\n                vertices = this.vertices,\n                spotRadius = options.get('spotRadius'),\n                regionMap = this.regionMap,\n                rangex, rangey, yvallast,\n                canvasTop, canvasLeft,\n                vertex, path, paths, x, y, xnext, xpos, xposnext,\n                last, next, yvalcount, lineShapes, fillShapes, plen,\n                valueSpots, hlSpotsEnabled, color, xvalues, yvalues, i;\n\n            if (!line._super.render.call(this)) {\n                return;\n            }\n\n            this.scanValues();\n            this.processRangeOptions();\n\n            xvalues = this.xvalues;\n            yvalues = this.yvalues;\n\n            if (!this.yminmax.length || this.yvalues.length < 2) {\n                // empty or all null valuess\n                return;\n            }\n\n            canvasTop = canvasLeft = 0;\n\n            rangex = this.maxx - this.minx === 0 ? 1 : this.maxx - this.minx;\n            rangey = this.maxy - this.miny === 0 ? 1 : this.maxy - this.miny;\n            yvallast = this.yvalues.length - 1;\n\n            if (spotRadius && (canvasWidth < (spotRadius * 4) || canvasHeight < (spotRadius * 4))) {\n                spotRadius = 0;\n            }\n            if (spotRadius) {\n                // adjust the canvas size as required so that spots will fit\n                hlSpotsEnabled = options.get('highlightSpotColor') &&  !options.get('disableInteraction');\n                if (hlSpotsEnabled || options.get('minSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.miny)) {\n                    canvasHeight -= Math.ceil(spotRadius);\n                }\n                if (hlSpotsEnabled || options.get('maxSpotColor') || (options.get('spotColor') && yvalues[yvallast] === this.maxy)) {\n                    canvasHeight -= Math.ceil(spotRadius);\n                    canvasTop += Math.ceil(spotRadius);\n                }\n                if (hlSpotsEnabled ||\n                     ((options.get('minSpotColor') || options.get('maxSpotColor')) && (yvalues[0] === this.miny || yvalues[0] === this.maxy))) {\n                    canvasLeft += Math.ceil(spotRadius);\n                    canvasWidth -= Math.ceil(spotRadius);\n                }\n                if (hlSpotsEnabled || options.get('spotColor') ||\n                    (options.get('minSpotColor') || options.get('maxSpotColor') &&\n                        (yvalues[yvallast] === this.miny || yvalues[yvallast] === this.maxy))) {\n                    canvasWidth -= Math.ceil(spotRadius);\n                }\n            }\n\n\n            canvasHeight--;\n\n            if (options.get('normalRangeMin') !== undefined && !options.get('drawNormalOnTop')) {\n                this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);\n            }\n\n            path = [];\n            paths = [path];\n            last = next = null;\n            yvalcount = yvalues.length;\n            for (i = 0; i < yvalcount; i++) {\n                x = xvalues[i];\n                xnext = xvalues[i + 1];\n                y = yvalues[i];\n                xpos = canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex));\n                xposnext = i < yvalcount - 1 ? canvasLeft + Math.round((xnext - this.minx) * (canvasWidth / rangex)) : canvasWidth;\n                next = xpos + ((xposnext - xpos) / 2);\n                regionMap[i] = [last || 0, next, i];\n                last = next;\n                if (y === null) {\n                    if (i) {\n                        if (yvalues[i - 1] !== null) {\n                            path = [];\n                            paths.push(path);\n                        }\n                        vertices.push(null);\n                    }\n                } else {\n                    if (y < this.miny) {\n                        y = this.miny;\n                    }\n                    if (y > this.maxy) {\n                        y = this.maxy;\n                    }\n                    if (!path.length) {\n                        // previous value was null\n                        path.push([xpos, canvasTop + canvasHeight]);\n                    }\n                    vertex = [xpos, canvasTop + Math.round(canvasHeight - (canvasHeight * ((y - this.miny) / rangey)))];\n                    path.push(vertex);\n                    vertices.push(vertex);\n                }\n            }\n\n            lineShapes = [];\n            fillShapes = [];\n            plen = paths.length;\n            for (i = 0; i < plen; i++) {\n                path = paths[i];\n                if (path.length) {\n                    if (options.get('fillColor')) {\n                        path.push([path[path.length - 1][0], (canvasTop + canvasHeight)]);\n                        fillShapes.push(path.slice(0));\n                        path.pop();\n                    }\n                    // if there's only a single point in this path, then we want to display it\n                    // as a vertical line which means we keep path[0]  as is\n                    if (path.length > 2) {\n                        // else we want the first value\n                        path[0] = [path[0][0], path[1][1]];\n                    }\n                    lineShapes.push(path);\n                }\n            }\n\n            // draw the fill first, then optionally the normal range, then the line on top of that\n            plen = fillShapes.length;\n            for (i = 0; i < plen; i++) {\n                target.drawShape(fillShapes[i],\n                    options.get('fillColor'), options.get('fillColor')).append();\n            }\n\n            if (options.get('normalRangeMin') !== undefined && options.get('drawNormalOnTop')) {\n                this.drawNormalRange(canvasLeft, canvasTop, canvasHeight, canvasWidth, rangey);\n            }\n\n            plen = lineShapes.length;\n            for (i = 0; i < plen; i++) {\n                target.drawShape(lineShapes[i], options.get('lineColor'), undefined,\n                    options.get('lineWidth')).append();\n            }\n\n            if (spotRadius && options.get('valueSpots')) {\n                valueSpots = options.get('valueSpots');\n                if (valueSpots.get === undefined) {\n                    valueSpots = new RangeMap(valueSpots);\n                }\n                for (i = 0; i < yvalcount; i++) {\n                    color = valueSpots.get(yvalues[i]);\n                    if (color) {\n                        target.drawCircle(canvasLeft + Math.round((xvalues[i] - this.minx) * (canvasWidth / rangex)),\n                            canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[i] - this.miny) / rangey))),\n                            spotRadius, undefined,\n                            color).append();\n                    }\n                }\n\n            }\n            if (spotRadius && options.get('spotColor') && yvalues[yvallast] !== null) {\n                target.drawCircle(canvasLeft + Math.round((xvalues[xvalues.length - 1] - this.minx) * (canvasWidth / rangex)),\n                    canvasTop + Math.round(canvasHeight - (canvasHeight * ((yvalues[yvallast] - this.miny) / rangey))),\n                    spotRadius, undefined,\n                    options.get('spotColor')).append();\n            }\n            if (this.maxy !== this.minyorg) {\n                if (spotRadius && options.get('minSpotColor')) {\n                    x = xvalues[$.inArray(this.minyorg, yvalues)];\n                    target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),\n                        canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.minyorg - this.miny) / rangey))),\n                        spotRadius, undefined,\n                        options.get('minSpotColor')).append();\n                }\n                if (spotRadius && options.get('maxSpotColor')) {\n                    x = xvalues[$.inArray(this.maxyorg, yvalues)];\n                    target.drawCircle(canvasLeft + Math.round((x - this.minx) * (canvasWidth / rangex)),\n                        canvasTop + Math.round(canvasHeight - (canvasHeight * ((this.maxyorg - this.miny) / rangey))),\n                        spotRadius, undefined,\n                        options.get('maxSpotColor')).append();\n                }\n            }\n\n            this.lastShapeId = target.getLastShapeId();\n            this.canvasTop = canvasTop;\n            target.render();\n        }\n    });\n\n    /**\n     * Bar charts\n     */\n    $.fn.sparkline.bar = bar = createClass($.fn.sparkline._base, barHighlightMixin, {\n        type: 'bar',\n\n        init: function (el, values, options, width, height) {\n            var barWidth = parseInt(options.get('barWidth'), 10),\n                barSpacing = parseInt(options.get('barSpacing'), 10),\n                chartRangeMin = options.get('chartRangeMin'),\n                chartRangeMax = options.get('chartRangeMax'),\n                chartRangeClip = options.get('chartRangeClip'),\n                stackMin = Infinity,\n                stackMax = -Infinity,\n                isStackString, groupMin, groupMax, stackRanges,\n                numValues, i, vlen, range, zeroAxis, xaxisOffset, min, max, clipMin, clipMax,\n                stacked, vlist, j, slen, svals, val, yoffset, yMaxCalc, canvasHeightEf;\n            bar._super.init.call(this, el, values, options, width, height);\n\n            // scan values to determine whether to stack bars\n            for (i = 0, vlen = values.length; i < vlen; i++) {\n                val = values[i];\n                isStackString = typeof(val) === 'string' && val.indexOf(':') > -1;\n                if (isStackString || $.isArray(val)) {\n                    stacked = true;\n                    if (isStackString) {\n                        val = values[i] = normalizeValues(val.split(':'));\n                    }\n                    val = remove(val, null); // min/max will treat null as zero\n                    groupMin = Math.min.apply(Math, val);\n                    groupMax = Math.max.apply(Math, val);\n                    if (groupMin < stackMin) {\n                        stackMin = groupMin;\n                    }\n                    if (groupMax > stackMax) {\n                        stackMax = groupMax;\n                    }\n                }\n            }\n\n            this.stacked = stacked;\n            this.regionShapes = {};\n            this.barWidth = barWidth;\n            this.barSpacing = barSpacing;\n            this.totalBarWidth = barWidth + barSpacing;\n            this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);\n\n            this.initTarget();\n\n            if (chartRangeClip) {\n                clipMin = chartRangeMin === undefined ? -Infinity : chartRangeMin;\n                clipMax = chartRangeMax === undefined ? Infinity : chartRangeMax;\n            }\n\n            numValues = [];\n            stackRanges = stacked ? [] : numValues;\n            var stackTotals = [];\n            var stackRangesNeg = [];\n            for (i = 0, vlen = values.length; i < vlen; i++) {\n                if (stacked) {\n                    vlist = values[i];\n                    values[i] = svals = [];\n                    stackTotals[i] = 0;\n                    stackRanges[i] = stackRangesNeg[i] = 0;\n                    for (j = 0, slen = vlist.length; j < slen; j++) {\n                        val = svals[j] = chartRangeClip ? clipval(vlist[j], clipMin, clipMax) : vlist[j];\n                        if (val !== null) {\n                            if (val > 0) {\n                                stackTotals[i] += val;\n                            }\n                            if (stackMin < 0 && stackMax > 0) {\n                                if (val < 0) {\n                                    stackRangesNeg[i] += Math.abs(val);\n                                } else {\n                                    stackRanges[i] += val;\n                                }\n                            } else {\n                                stackRanges[i] += Math.abs(val - (val < 0 ? stackMax : stackMin));\n                            }\n                            numValues.push(val);\n                        }\n                    }\n                } else {\n                    val = chartRangeClip ? clipval(values[i], clipMin, clipMax) : values[i];\n                    val = values[i] = normalizeValue(val);\n                    if (val !== null) {\n                        numValues.push(val);\n                    }\n                }\n            }\n            this.max = max = Math.max.apply(Math, numValues);\n            this.min = min = Math.min.apply(Math, numValues);\n            this.stackMax = stackMax = stacked ? Math.max.apply(Math, stackTotals) : max;\n            this.stackMin = stackMin = stacked ? Math.min.apply(Math, numValues) : min;\n\n            if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < min)) {\n                min = options.get('chartRangeMin');\n            }\n            if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > max)) {\n                max = options.get('chartRangeMax');\n            }\n\n            this.zeroAxis = zeroAxis = options.get('zeroAxis', true);\n            if (min <= 0 && max >= 0 && zeroAxis) {\n                xaxisOffset = 0;\n            } else if (zeroAxis == false) {\n                xaxisOffset = min;\n            } else if (min > 0) {\n                xaxisOffset = min;\n            } else {\n                xaxisOffset = max;\n            }\n            this.xaxisOffset = xaxisOffset;\n\n            range = stacked ? (Math.max.apply(Math, stackRanges) + Math.max.apply(Math, stackRangesNeg)) : max - min;\n\n            // as we plot zero/min values a single pixel line, we add a pixel to all other\n            // values - Reduce the effective canvas size to suit\n            this.canvasHeightEf = (zeroAxis && min < 0) ? this.canvasHeight - 2 : this.canvasHeight - 1;\n\n            if (min < xaxisOffset) {\n                yMaxCalc = (stacked && max >= 0) ? stackMax : max;\n                yoffset = (yMaxCalc - xaxisOffset) / range * this.canvasHeight;\n                if (yoffset !== Math.ceil(yoffset)) {\n                    this.canvasHeightEf -= 2;\n                    yoffset = Math.ceil(yoffset);\n                }\n            } else {\n                yoffset = this.canvasHeight;\n            }\n            this.yoffset = yoffset;\n\n            if ($.isArray(options.get('colorMap'))) {\n                this.colorMapByIndex = options.get('colorMap');\n                this.colorMapByValue = null;\n            } else {\n                this.colorMapByIndex = null;\n                this.colorMapByValue = options.get('colorMap');\n                if (this.colorMapByValue && this.colorMapByValue.get === undefined) {\n                    this.colorMapByValue = new RangeMap(this.colorMapByValue);\n                }\n            }\n\n            this.range = range;\n        },\n\n        getRegion: function (el, x, y) {\n            var result = Math.floor(x / this.totalBarWidth);\n            return (result < 0 || result >= this.values.length) ? undefined : result;\n        },\n\n        getCurrentRegionFields: function () {\n            var currentRegion = this.currentRegion,\n                values = ensureArray(this.values[currentRegion]),\n                result = [],\n                value, i;\n            for (i = values.length; i--;) {\n                value = values[i];\n                result.push({\n                    isNull: value === null,\n                    value: value,\n                    color: this.calcColor(i, value, currentRegion),\n                    offset: currentRegion\n                });\n            }\n            return result;\n        },\n\n        calcColor: function (stacknum, value, valuenum) {\n            var colorMapByIndex = this.colorMapByIndex,\n                colorMapByValue = this.colorMapByValue,\n                options = this.options,\n                color, newColor;\n            if (this.stacked) {\n                color = options.get('stackedBarColor');\n            } else {\n                color = (value < 0) ? options.get('negBarColor') : options.get('barColor');\n            }\n            if (value === 0 && options.get('zeroColor') !== undefined) {\n                color = options.get('zeroColor');\n            }\n            if (colorMapByValue && (newColor = colorMapByValue.get(value))) {\n                color = newColor;\n            } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {\n                color = colorMapByIndex[valuenum];\n            }\n            return $.isArray(color) ? color[stacknum % color.length] : color;\n        },\n\n        /**\n         * Render bar(s) for a region\n         */\n        renderRegion: function (valuenum, highlight) {\n            var vals = this.values[valuenum],\n                options = this.options,\n                xaxisOffset = this.xaxisOffset,\n                result = [],\n                range = this.range,\n                stacked = this.stacked,\n                target = this.target,\n                x = valuenum * this.totalBarWidth,\n                canvasHeightEf = this.canvasHeightEf,\n                yoffset = this.yoffset,\n                y, height, color, isNull, yoffsetNeg, i, valcount, val, minPlotted, allMin;\n\n            vals = $.isArray(vals) ? vals : [vals];\n            valcount = vals.length;\n            val = vals[0];\n            isNull = all(null, vals);\n            allMin = all(xaxisOffset, vals, true);\n\n            if (isNull) {\n                if (options.get('nullColor')) {\n                    color = highlight ? options.get('nullColor') : this.calcHighlightColor(options.get('nullColor'), options);\n                    y = (yoffset > 0) ? yoffset - 1 : yoffset;\n                    return target.drawRect(x, y, this.barWidth - 1, 0, color, color);\n                } else {\n                    return undefined;\n                }\n            }\n            yoffsetNeg = yoffset;\n            for (i = 0; i < valcount; i++) {\n                val = vals[i];\n\n                if (stacked && val === xaxisOffset) {\n                    if (!allMin || minPlotted) {\n                        continue;\n                    }\n                    minPlotted = true;\n                }\n\n                if (range > 0) {\n                    height = Math.floor(canvasHeightEf * ((Math.abs(val - xaxisOffset) / range))) + 1;\n                } else {\n                    height = 1;\n                }\n                if (val < xaxisOffset || (val === xaxisOffset && yoffset === 0)) {\n                    y = yoffsetNeg;\n                    yoffsetNeg += height;\n                } else {\n                    y = yoffset - height;\n                    yoffset -= height;\n                }\n                color = this.calcColor(i, val, valuenum);\n                if (highlight) {\n                    color = this.calcHighlightColor(color, options);\n                }\n                result.push(target.drawRect(x, y, this.barWidth - 1, height - 1, color, color));\n            }\n            if (result.length === 1) {\n                return result[0];\n            }\n            return result;\n        }\n    });\n\n    /**\n     * Tristate charts\n     */\n    $.fn.sparkline.tristate = tristate = createClass($.fn.sparkline._base, barHighlightMixin, {\n        type: 'tristate',\n\n        init: function (el, values, options, width, height) {\n            var barWidth = parseInt(options.get('barWidth'), 10),\n                barSpacing = parseInt(options.get('barSpacing'), 10);\n            tristate._super.init.call(this, el, values, options, width, height);\n\n            this.regionShapes = {};\n            this.barWidth = barWidth;\n            this.barSpacing = barSpacing;\n            this.totalBarWidth = barWidth + barSpacing;\n            this.values = $.map(values, Number);\n            this.width = width = (values.length * barWidth) + ((values.length - 1) * barSpacing);\n\n            if ($.isArray(options.get('colorMap'))) {\n                this.colorMapByIndex = options.get('colorMap');\n                this.colorMapByValue = null;\n            } else {\n                this.colorMapByIndex = null;\n                this.colorMapByValue = options.get('colorMap');\n                if (this.colorMapByValue && this.colorMapByValue.get === undefined) {\n                    this.colorMapByValue = new RangeMap(this.colorMapByValue);\n                }\n            }\n            this.initTarget();\n        },\n\n        getRegion: function (el, x, y) {\n            return Math.floor(x / this.totalBarWidth);\n        },\n\n        getCurrentRegionFields: function () {\n            var currentRegion = this.currentRegion;\n            return {\n                isNull: this.values[currentRegion] === undefined,\n                value: this.values[currentRegion],\n                color: this.calcColor(this.values[currentRegion], currentRegion),\n                offset: currentRegion\n            };\n        },\n\n        calcColor: function (value, valuenum) {\n            var values = this.values,\n                options = this.options,\n                colorMapByIndex = this.colorMapByIndex,\n                colorMapByValue = this.colorMapByValue,\n                color, newColor;\n\n            if (colorMapByValue && (newColor = colorMapByValue.get(value))) {\n                color = newColor;\n            } else if (colorMapByIndex && colorMapByIndex.length > valuenum) {\n                color = colorMapByIndex[valuenum];\n            } else if (values[valuenum] < 0) {\n                color = options.get('negBarColor');\n            } else if (values[valuenum] > 0) {\n                color = options.get('posBarColor');\n            } else {\n                color = options.get('zeroBarColor');\n            }\n            return color;\n        },\n\n        renderRegion: function (valuenum, highlight) {\n            var values = this.values,\n                options = this.options,\n                target = this.target,\n                canvasHeight, height, halfHeight,\n                x, y, color;\n\n            canvasHeight = target.pixelHeight;\n            halfHeight = Math.round(canvasHeight / 2);\n\n            x = valuenum * this.totalBarWidth;\n            if (values[valuenum] < 0) {\n                y = halfHeight;\n                height = halfHeight - 1;\n            } else if (values[valuenum] > 0) {\n                y = 0;\n                height = halfHeight - 1;\n            } else {\n                y = halfHeight - 1;\n                height = 2;\n            }\n            color = this.calcColor(values[valuenum], valuenum);\n            if (color === null) {\n                return;\n            }\n            if (highlight) {\n                color = this.calcHighlightColor(color, options);\n            }\n            return target.drawRect(x, y, this.barWidth - 1, height - 1, color, color);\n        }\n    });\n\n    /**\n     * Discrete charts\n     */\n    $.fn.sparkline.discrete = discrete = createClass($.fn.sparkline._base, barHighlightMixin, {\n        type: 'discrete',\n\n        init: function (el, values, options, width, height) {\n            discrete._super.init.call(this, el, values, options, width, height);\n\n            this.regionShapes = {};\n            this.values = values = $.map(values, Number);\n            this.min = Math.min.apply(Math, values);\n            this.max = Math.max.apply(Math, values);\n            this.range = this.max - this.min;\n            this.width = width = options.get('width') === 'auto' ? values.length * 2 : this.width;\n            this.interval = Math.floor(width / values.length);\n            this.itemWidth = width / values.length;\n            if (options.get('chartRangeMin') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMin') < this.min)) {\n                this.min = options.get('chartRangeMin');\n            }\n            if (options.get('chartRangeMax') !== undefined && (options.get('chartRangeClip') || options.get('chartRangeMax') > this.max)) {\n                this.max = options.get('chartRangeMax');\n            }\n            this.initTarget();\n            if (this.target) {\n                this.lineHeight = options.get('lineHeight') === 'auto' ? Math.round(this.canvasHeight * 0.3) : options.get('lineHeight');\n            }\n        },\n\n        getRegion: function (el, x, y) {\n            return Math.floor(x / this.itemWidth);\n        },\n\n        getCurrentRegionFields: function () {\n            var currentRegion = this.currentRegion;\n            return {\n                isNull: this.values[currentRegion] === undefined,\n                value: this.values[currentRegion],\n                offset: currentRegion\n            };\n        },\n\n        renderRegion: function (valuenum, highlight) {\n            var values = this.values,\n                options = this.options,\n                min = this.min,\n                max = this.max,\n                range = this.range,\n                interval = this.interval,\n                target = this.target,\n                canvasHeight = this.canvasHeight,\n                lineHeight = this.lineHeight,\n                pheight = canvasHeight - lineHeight,\n                ytop, val, color, x;\n\n            val = clipval(values[valuenum], min, max);\n            x = valuenum * interval;\n            ytop = Math.round(pheight - pheight * ((val - min) / range));\n            color = (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor');\n            if (highlight) {\n                color = this.calcHighlightColor(color, options);\n            }\n            return target.drawLine(x, ytop, x, ytop + lineHeight, color);\n        }\n    });\n\n    /**\n     * Bullet charts\n     */\n    $.fn.sparkline.bullet = bullet = createClass($.fn.sparkline._base, {\n        type: 'bullet',\n\n        init: function (el, values, options, width, height) {\n            var min, max, vals;\n            bullet._super.init.call(this, el, values, options, width, height);\n\n            // values: target, performance, range1, range2, range3\n            this.values = values = normalizeValues(values);\n            // target or performance could be null\n            vals = values.slice();\n            vals[0] = vals[0] === null ? vals[2] : vals[0];\n            vals[1] = values[1] === null ? vals[2] : vals[1];\n            min = Math.min.apply(Math, values);\n            max = Math.max.apply(Math, values);\n            if (options.get('base') === undefined) {\n                min = min < 0 ? min : 0;\n            } else {\n                min = options.get('base');\n            }\n            this.min = min;\n            this.max = max;\n            this.range = max - min;\n            this.shapes = {};\n            this.valueShapes = {};\n            this.regiondata = {};\n            this.width = width = options.get('width') === 'auto' ? '4.0em' : width;\n            this.target = this.$el.simpledraw(width, height, options.get('composite'));\n            if (!values.length) {\n                this.disabled = true;\n            }\n            this.initTarget();\n        },\n\n        getRegion: function (el, x, y) {\n            var shapeid = this.target.getShapeAt(el, x, y);\n            return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;\n        },\n\n        getCurrentRegionFields: function () {\n            var currentRegion = this.currentRegion;\n            return {\n                fieldkey: currentRegion.substr(0, 1),\n                value: this.values[currentRegion.substr(1)],\n                region: currentRegion\n            };\n        },\n\n        changeHighlight: function (highlight) {\n            var currentRegion = this.currentRegion,\n                shapeid = this.valueShapes[currentRegion],\n                shape;\n            delete this.shapes[shapeid];\n            switch (currentRegion.substr(0, 1)) {\n                case 'r':\n                    shape = this.renderRange(currentRegion.substr(1), highlight);\n                    break;\n                case 'p':\n                    shape = this.renderPerformance(highlight);\n                    break;\n                case 't':\n                    shape = this.renderTarget(highlight);\n                    break;\n            }\n            this.valueShapes[currentRegion] = shape.id;\n            this.shapes[shape.id] = currentRegion;\n            this.target.replaceWithShape(shapeid, shape);\n        },\n\n        renderRange: function (rn, highlight) {\n            var rangeval = this.values[rn],\n                rangewidth = Math.round(this.canvasWidth * ((rangeval - this.min) / this.range)),\n                color = this.options.get('rangeColors')[rn - 2];\n            if (highlight) {\n                color = this.calcHighlightColor(color, this.options);\n            }\n            return this.target.drawRect(0, 0, rangewidth - 1, this.canvasHeight - 1, color, color);\n        },\n\n        renderPerformance: function (highlight) {\n            var perfval = this.values[1],\n                perfwidth = Math.round(this.canvasWidth * ((perfval - this.min) / this.range)),\n                color = this.options.get('performanceColor');\n            if (highlight) {\n                color = this.calcHighlightColor(color, this.options);\n            }\n            return this.target.drawRect(0, Math.round(this.canvasHeight * 0.3), perfwidth - 1,\n                Math.round(this.canvasHeight * 0.4) - 1, color, color);\n        },\n\n        renderTarget: function (highlight) {\n            var targetval = this.values[0],\n                x = Math.round(this.canvasWidth * ((targetval - this.min) / this.range) - (this.options.get('targetWidth') / 2)),\n                targettop = Math.round(this.canvasHeight * 0.10),\n                targetheight = this.canvasHeight - (targettop * 2),\n                color = this.options.get('targetColor');\n            if (highlight) {\n                color = this.calcHighlightColor(color, this.options);\n            }\n            return this.target.drawRect(x, targettop, this.options.get('targetWidth') - 1, targetheight - 1, color, color);\n        },\n\n        render: function () {\n            var vlen = this.values.length,\n                target = this.target,\n                i, shape;\n            if (!bullet._super.render.call(this)) {\n                return;\n            }\n            for (i = 2; i < vlen; i++) {\n                shape = this.renderRange(i).append();\n                this.shapes[shape.id] = 'r' + i;\n                this.valueShapes['r' + i] = shape.id;\n            }\n            if (this.values[1] !== null) {\n                shape = this.renderPerformance().append();\n                this.shapes[shape.id] = 'p1';\n                this.valueShapes.p1 = shape.id;\n            }\n            if (this.values[0] !== null) {\n                shape = this.renderTarget().append();\n                this.shapes[shape.id] = 't0';\n                this.valueShapes.t0 = shape.id;\n            }\n            target.render();\n        }\n    });\n\n    /**\n     * Pie charts\n     */\n    $.fn.sparkline.pie = pie = createClass($.fn.sparkline._base, {\n        type: 'pie',\n\n        init: function (el, values, options, width, height) {\n            var total = 0, i;\n\n            pie._super.init.call(this, el, values, options, width, height);\n\n            this.shapes = {}; // map shape ids to value offsets\n            this.valueShapes = {}; // maps value offsets to shape ids\n            this.values = values = $.map(values, Number);\n\n            if (options.get('width') === 'auto') {\n                this.width = this.height;\n            }\n\n            if (values.length > 0) {\n                for (i = values.length; i--;) {\n                    total += values[i];\n                }\n            }\n            this.total = total;\n            this.initTarget();\n            this.radius = Math.floor(Math.min(this.canvasWidth, this.canvasHeight) / 2);\n        },\n\n        getRegion: function (el, x, y) {\n            var shapeid = this.target.getShapeAt(el, x, y);\n            return (shapeid !== undefined && this.shapes[shapeid] !== undefined) ? this.shapes[shapeid] : undefined;\n        },\n\n        getCurrentRegionFields: function () {\n            var currentRegion = this.currentRegion;\n            return {\n                isNull: this.values[currentRegion] === undefined,\n                value: this.values[currentRegion],\n                percent: this.values[currentRegion] / this.total * 100,\n                color: this.options.get('sliceColors')[currentRegion % this.options.get('sliceColors').length],\n                offset: currentRegion\n            };\n        },\n\n        changeHighlight: function (highlight) {\n            var currentRegion = this.currentRegion,\n                 newslice = this.renderSlice(currentRegion, highlight),\n                 shapeid = this.valueShapes[currentRegion];\n            delete this.shapes[shapeid];\n            this.target.replaceWithShape(shapeid, newslice);\n            this.valueShapes[currentRegion] = newslice.id;\n            this.shapes[newslice.id] = currentRegion;\n        },\n\n        renderSlice: function (valuenum, highlight) {\n            var target = this.target,\n                options = this.options,\n                radius = this.radius,\n                borderWidth = options.get('borderWidth'),\n                offset = options.get('offset'),\n                circle = 2 * Math.PI,\n                values = this.values,\n                total = this.total,\n                next = offset ? (2*Math.PI)*(offset/360) : 0,\n                start, end, i, vlen, color;\n\n            vlen = values.length;\n            for (i = 0; i < vlen; i++) {\n                start = next;\n                end = next;\n                if (total > 0) {  // avoid divide by zero\n                    end = next + (circle * (values[i] / total));\n                }\n                if (valuenum === i) {\n                    color = options.get('sliceColors')[i % options.get('sliceColors').length];\n                    if (highlight) {\n                        color = this.calcHighlightColor(color, options);\n                    }\n\n                    return target.drawPieSlice(radius, radius, radius - borderWidth, start, end, undefined, color);\n                }\n                next = end;\n            }\n        },\n\n        render: function () {\n            var target = this.target,\n                values = this.values,\n                options = this.options,\n                radius = this.radius,\n                borderWidth = options.get('borderWidth'),\n                shape, i;\n\n            if (!pie._super.render.call(this)) {\n                return;\n            }\n            if (borderWidth) {\n                target.drawCircle(radius, radius, Math.floor(radius - (borderWidth / 2)),\n                    options.get('borderColor'), undefined, borderWidth).append();\n            }\n            for (i = values.length; i--;) {\n                if (values[i]) { // don't render zero values\n                    shape = this.renderSlice(i).append();\n                    this.valueShapes[i] = shape.id; // store just the shapeid\n                    this.shapes[shape.id] = i;\n                }\n            }\n            target.render();\n        }\n    });\n\n    /**\n     * Box plots\n     */\n    $.fn.sparkline.box = box = createClass($.fn.sparkline._base, {\n        type: 'box',\n\n        init: function (el, values, options, width, height) {\n            box._super.init.call(this, el, values, options, width, height);\n            this.values = $.map(values, Number);\n            this.width = options.get('width') === 'auto' ? '4.0em' : width;\n            this.initTarget();\n            if (!this.values.length) {\n                this.disabled = 1;\n            }\n        },\n\n        /**\n         * Simulate a single region\n         */\n        getRegion: function () {\n            return 1;\n        },\n\n        getCurrentRegionFields: function () {\n            var result = [\n                { field: 'lq', value: this.quartiles[0] },\n                { field: 'med', value: this.quartiles[1] },\n                { field: 'uq', value: this.quartiles[2] }\n            ];\n            if (this.loutlier !== undefined) {\n                result.push({ field: 'lo', value: this.loutlier});\n            }\n            if (this.routlier !== undefined) {\n                result.push({ field: 'ro', value: this.routlier});\n            }\n            if (this.lwhisker !== undefined) {\n                result.push({ field: 'lw', value: this.lwhisker});\n            }\n            if (this.rwhisker !== undefined) {\n                result.push({ field: 'rw', value: this.rwhisker});\n            }\n            return result;\n        },\n\n        render: function () {\n            var target = this.target,\n                values = this.values,\n                vlen = values.length,\n                options = this.options,\n                canvasWidth = this.canvasWidth,\n                canvasHeight = this.canvasHeight,\n                minValue = options.get('chartRangeMin') === undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'),\n                maxValue = options.get('chartRangeMax') === undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'),\n                canvasLeft = 0,\n                lwhisker, loutlier, iqr, q1, q2, q3, rwhisker, routlier, i,\n                size, unitSize;\n\n            if (!box._super.render.call(this)) {\n                return;\n            }\n\n            if (options.get('raw')) {\n                if (options.get('showOutliers') && values.length > 5) {\n                    loutlier = values[0];\n                    lwhisker = values[1];\n                    q1 = values[2];\n                    q2 = values[3];\n                    q3 = values[4];\n                    rwhisker = values[5];\n                    routlier = values[6];\n                } else {\n                    lwhisker = values[0];\n                    q1 = values[1];\n                    q2 = values[2];\n                    q3 = values[3];\n                    rwhisker = values[4];\n                }\n            } else {\n                values.sort(function (a, b) { return a - b; });\n                q1 = quartile(values, 1);\n                q2 = quartile(values, 2);\n                q3 = quartile(values, 3);\n                iqr = q3 - q1;\n                if (options.get('showOutliers')) {\n                    lwhisker = rwhisker = undefined;\n                    for (i = 0; i < vlen; i++) {\n                        if (lwhisker === undefined && values[i] > q1 - (iqr * options.get('outlierIQR'))) {\n                            lwhisker = values[i];\n                        }\n                        if (values[i] < q3 + (iqr * options.get('outlierIQR'))) {\n                            rwhisker = values[i];\n                        }\n                    }\n                    loutlier = values[0];\n                    routlier = values[vlen - 1];\n                } else {\n                    lwhisker = values[0];\n                    rwhisker = values[vlen - 1];\n                }\n            }\n            this.quartiles = [q1, q2, q3];\n            this.lwhisker = lwhisker;\n            this.rwhisker = rwhisker;\n            this.loutlier = loutlier;\n            this.routlier = routlier;\n\n            unitSize = canvasWidth / (maxValue - minValue + 1);\n            if (options.get('showOutliers')) {\n                canvasLeft = Math.ceil(options.get('spotRadius'));\n                canvasWidth -= 2 * Math.ceil(options.get('spotRadius'));\n                unitSize = canvasWidth / (maxValue - minValue + 1);\n                if (loutlier < lwhisker) {\n                    target.drawCircle((loutlier - minValue) * unitSize + canvasLeft,\n                        canvasHeight / 2,\n                        options.get('spotRadius'),\n                        options.get('outlierLineColor'),\n                        options.get('outlierFillColor')).append();\n                }\n                if (routlier > rwhisker) {\n                    target.drawCircle((routlier - minValue) * unitSize + canvasLeft,\n                        canvasHeight / 2,\n                        options.get('spotRadius'),\n                        options.get('outlierLineColor'),\n                        options.get('outlierFillColor')).append();\n                }\n            }\n\n            // box\n            target.drawRect(\n                Math.round((q1 - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight * 0.1),\n                Math.round((q3 - q1) * unitSize),\n                Math.round(canvasHeight * 0.8),\n                options.get('boxLineColor'),\n                options.get('boxFillColor')).append();\n            // left whisker\n            target.drawLine(\n                Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight / 2),\n                Math.round((q1 - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight / 2),\n                options.get('lineColor')).append();\n            target.drawLine(\n                Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight / 4),\n                Math.round((lwhisker - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight - canvasHeight / 4),\n                options.get('whiskerColor')).append();\n            // right whisker\n            target.drawLine(Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight / 2),\n                Math.round((q3 - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight / 2),\n                options.get('lineColor')).append();\n            target.drawLine(\n                Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight / 4),\n                Math.round((rwhisker - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight - canvasHeight / 4),\n                options.get('whiskerColor')).append();\n            // median line\n            target.drawLine(\n                Math.round((q2 - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight * 0.1),\n                Math.round((q2 - minValue) * unitSize + canvasLeft),\n                Math.round(canvasHeight * 0.9),\n                options.get('medianColor')).append();\n            if (options.get('target')) {\n                size = Math.ceil(options.get('spotRadius'));\n                target.drawLine(\n                    Math.round((options.get('target') - minValue) * unitSize + canvasLeft),\n                    Math.round((canvasHeight / 2) - size),\n                    Math.round((options.get('target') - minValue) * unitSize + canvasLeft),\n                    Math.round((canvasHeight / 2) + size),\n                    options.get('targetColor')).append();\n                target.drawLine(\n                    Math.round((options.get('target') - minValue) * unitSize + canvasLeft - size),\n                    Math.round(canvasHeight / 2),\n                    Math.round((options.get('target') - minValue) * unitSize + canvasLeft + size),\n                    Math.round(canvasHeight / 2),\n                    options.get('targetColor')).append();\n            }\n            target.render();\n        }\n    });\n\n    // Setup a very simple \"virtual canvas\" to make drawing the few shapes we need easier\n    // This is accessible as $(foo).simpledraw()\n\n    VShape = createClass({\n        init: function (target, id, type, args) {\n            this.target = target;\n            this.id = id;\n            this.type = type;\n            this.args = args;\n        },\n        append: function () {\n            this.target.appendShape(this);\n            return this;\n        }\n    });\n\n    VCanvas_base = createClass({\n        _pxregex: /(\\d+)(px)?\\s*$/i,\n\n        init: function (width, height, target) {\n            if (!width) {\n                return;\n            }\n            this.width = width;\n            this.height = height;\n            this.target = target;\n            this.lastShapeId = null;\n            if (target[0]) {\n                target = target[0];\n            }\n            $.data(target, '_jqs_vcanvas', this);\n        },\n\n        drawLine: function (x1, y1, x2, y2, lineColor, lineWidth) {\n            return this.drawShape([[x1, y1], [x2, y2]], lineColor, lineWidth);\n        },\n\n        drawShape: function (path, lineColor, fillColor, lineWidth) {\n            return this._genShape('Shape', [path, lineColor, fillColor, lineWidth]);\n        },\n\n        drawCircle: function (x, y, radius, lineColor, fillColor, lineWidth) {\n            return this._genShape('Circle', [x, y, radius, lineColor, fillColor, lineWidth]);\n        },\n\n        drawPieSlice: function (x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n            return this._genShape('PieSlice', [x, y, radius, startAngle, endAngle, lineColor, fillColor]);\n        },\n\n        drawRect: function (x, y, width, height, lineColor, fillColor) {\n            return this._genShape('Rect', [x, y, width, height, lineColor, fillColor]);\n        },\n\n        getElement: function () {\n            return this.canvas;\n        },\n\n        /**\n         * Return the most recently inserted shape id\n         */\n        getLastShapeId: function () {\n            return this.lastShapeId;\n        },\n\n        /**\n         * Clear and reset the canvas\n         */\n        reset: function () {\n            alert('reset not implemented');\n        },\n\n        _insert: function (el, target) {\n            $(target).html(el);\n        },\n\n        /**\n         * Calculate the pixel dimensions of the canvas\n         */\n        _calculatePixelDims: function (width, height, canvas) {\n            // XXX This should probably be a configurable option\n            var match;\n            match = this._pxregex.exec(height);\n            if (match) {\n                this.pixelHeight = match[1];\n            } else {\n                this.pixelHeight = $(canvas).height();\n            }\n            match = this._pxregex.exec(width);\n            if (match) {\n                this.pixelWidth = match[1];\n            } else {\n                this.pixelWidth = $(canvas).width();\n            }\n        },\n\n        /**\n         * Generate a shape object and id for later rendering\n         */\n        _genShape: function (shapetype, shapeargs) {\n            var id = shapeCount++;\n            shapeargs.unshift(id);\n            return new VShape(this, id, shapetype, shapeargs);\n        },\n\n        /**\n         * Add a shape to the end of the render queue\n         */\n        appendShape: function (shape) {\n            alert('appendShape not implemented');\n        },\n\n        /**\n         * Replace one shape with another\n         */\n        replaceWithShape: function (shapeid, shape) {\n            alert('replaceWithShape not implemented');\n        },\n\n        /**\n         * Insert one shape after another in the render queue\n         */\n        insertAfterShape: function (shapeid, shape) {\n            alert('insertAfterShape not implemented');\n        },\n\n        /**\n         * Remove a shape from the queue\n         */\n        removeShapeId: function (shapeid) {\n            alert('removeShapeId not implemented');\n        },\n\n        /**\n         * Find a shape at the specified x/y co-ordinates\n         */\n        getShapeAt: function (el, x, y) {\n            alert('getShapeAt not implemented');\n        },\n\n        /**\n         * Render all queued shapes onto the canvas\n         */\n        render: function () {\n            alert('render not implemented');\n        }\n    });\n\n    VCanvas_canvas = createClass(VCanvas_base, {\n        init: function (width, height, target, interact) {\n            VCanvas_canvas._super.init.call(this, width, height, target);\n            this.canvas = document.createElement('canvas');\n            if (target[0]) {\n                target = target[0];\n            }\n            $.data(target, '_jqs_vcanvas', this);\n            $(this.canvas).css({ display: 'inline-block', width: width, height: height, verticalAlign: 'top' });\n            this._insert(this.canvas, target);\n            this._calculatePixelDims(width, height, this.canvas);\n            this.canvas.width = this.pixelWidth;\n            this.canvas.height = this.pixelHeight;\n            this.interact = interact;\n            this.shapes = {};\n            this.shapeseq = [];\n            this.currentTargetShapeId = undefined;\n            $(this.canvas).css({width: this.pixelWidth, height: this.pixelHeight});\n        },\n\n        _getContext: function (lineColor, fillColor, lineWidth) {\n            var context = this.canvas.getContext('2d');\n            if (lineColor !== undefined) {\n                context.strokeStyle = lineColor;\n            }\n            context.lineWidth = lineWidth === undefined ? 1 : lineWidth;\n            if (fillColor !== undefined) {\n                context.fillStyle = fillColor;\n            }\n            return context;\n        },\n\n        reset: function () {\n            var context = this._getContext();\n            context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);\n            this.shapes = {};\n            this.shapeseq = [];\n            this.currentTargetShapeId = undefined;\n        },\n\n        _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {\n            var context = this._getContext(lineColor, fillColor, lineWidth),\n                i, plen;\n            context.beginPath();\n            context.moveTo(path[0][0] + 0.5, path[0][1] + 0.5);\n            for (i = 1, plen = path.length; i < plen; i++) {\n                context.lineTo(path[i][0] + 0.5, path[i][1] + 0.5); // the 0.5 offset gives us crisp pixel-width lines\n            }\n            if (lineColor !== undefined) {\n                context.stroke();\n            }\n            if (fillColor !== undefined) {\n                context.fill();\n            }\n            if (this.targetX !== undefined && this.targetY !== undefined &&\n                context.isPointInPath(this.targetX, this.targetY)) {\n                this.currentTargetShapeId = shapeid;\n            }\n        },\n\n        _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {\n            var context = this._getContext(lineColor, fillColor, lineWidth);\n            context.beginPath();\n            context.arc(x, y, radius, 0, 2 * Math.PI, false);\n            if (this.targetX !== undefined && this.targetY !== undefined &&\n                context.isPointInPath(this.targetX, this.targetY)) {\n                this.currentTargetShapeId = shapeid;\n            }\n            if (lineColor !== undefined) {\n                context.stroke();\n            }\n            if (fillColor !== undefined) {\n                context.fill();\n            }\n        },\n\n        _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n            var context = this._getContext(lineColor, fillColor);\n            context.beginPath();\n            context.moveTo(x, y);\n            context.arc(x, y, radius, startAngle, endAngle, false);\n            context.lineTo(x, y);\n            context.closePath();\n            if (lineColor !== undefined) {\n                context.stroke();\n            }\n            if (fillColor) {\n                context.fill();\n            }\n            if (this.targetX !== undefined && this.targetY !== undefined &&\n                context.isPointInPath(this.targetX, this.targetY)) {\n                this.currentTargetShapeId = shapeid;\n            }\n        },\n\n        _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {\n            return this._drawShape(shapeid, [[x, y], [x + width, y], [x + width, y + height], [x, y + height], [x, y]], lineColor, fillColor);\n        },\n\n        appendShape: function (shape) {\n            this.shapes[shape.id] = shape;\n            this.shapeseq.push(shape.id);\n            this.lastShapeId = shape.id;\n            return shape.id;\n        },\n\n        replaceWithShape: function (shapeid, shape) {\n            var shapeseq = this.shapeseq,\n                i;\n            this.shapes[shape.id] = shape;\n            for (i = shapeseq.length; i--;) {\n                if (shapeseq[i] == shapeid) {\n                    shapeseq[i] = shape.id;\n                }\n            }\n            delete this.shapes[shapeid];\n        },\n\n        replaceWithShapes: function (shapeids, shapes) {\n            var shapeseq = this.shapeseq,\n                shapemap = {},\n                sid, i, first;\n\n            for (i = shapeids.length; i--;) {\n                shapemap[shapeids[i]] = true;\n            }\n            for (i = shapeseq.length; i--;) {\n                sid = shapeseq[i];\n                if (shapemap[sid]) {\n                    shapeseq.splice(i, 1);\n                    delete this.shapes[sid];\n                    first = i;\n                }\n            }\n            for (i = shapes.length; i--;) {\n                shapeseq.splice(first, 0, shapes[i].id);\n                this.shapes[shapes[i].id] = shapes[i];\n            }\n\n        },\n\n        insertAfterShape: function (shapeid, shape) {\n            var shapeseq = this.shapeseq,\n                i;\n            for (i = shapeseq.length; i--;) {\n                if (shapeseq[i] === shapeid) {\n                    shapeseq.splice(i + 1, 0, shape.id);\n                    this.shapes[shape.id] = shape;\n                    return;\n                }\n            }\n        },\n\n        removeShapeId: function (shapeid) {\n            var shapeseq = this.shapeseq,\n                i;\n            for (i = shapeseq.length; i--;) {\n                if (shapeseq[i] === shapeid) {\n                    shapeseq.splice(i, 1);\n                    break;\n                }\n            }\n            delete this.shapes[shapeid];\n        },\n\n        getShapeAt: function (el, x, y) {\n            this.targetX = x;\n            this.targetY = y;\n            this.render();\n            return this.currentTargetShapeId;\n        },\n\n        render: function () {\n            var shapeseq = this.shapeseq,\n                shapes = this.shapes,\n                shapeCount = shapeseq.length,\n                context = this._getContext(),\n                shapeid, shape, i;\n            context.clearRect(0, 0, this.pixelWidth, this.pixelHeight);\n            for (i = 0; i < shapeCount; i++) {\n                shapeid = shapeseq[i];\n                shape = shapes[shapeid];\n                this['_draw' + shape.type].apply(this, shape.args);\n            }\n            if (!this.interact) {\n                // not interactive so no need to keep the shapes array\n                this.shapes = {};\n                this.shapeseq = [];\n            }\n        }\n\n    });\n\n    VCanvas_vml = createClass(VCanvas_base, {\n        init: function (width, height, target) {\n            var groupel;\n            VCanvas_vml._super.init.call(this, width, height, target);\n            if (target[0]) {\n                target = target[0];\n            }\n            $.data(target, '_jqs_vcanvas', this);\n            this.canvas = document.createElement('span');\n            $(this.canvas).css({ display: 'inline-block', position: 'relative', overflow: 'hidden', width: width, height: height, margin: '0px', padding: '0px', verticalAlign: 'top'});\n            this._insert(this.canvas, target);\n            this._calculatePixelDims(width, height, this.canvas);\n            this.canvas.width = this.pixelWidth;\n            this.canvas.height = this.pixelHeight;\n            groupel = '<v:group coordorigin=\"0 0\" coordsize=\"' + this.pixelWidth + ' ' + this.pixelHeight + '\"' +\n                    ' style=\"position:absolute;top:0;left:0;width:' + this.pixelWidth + 'px;height=' + this.pixelHeight + 'px;\"></v:group>';\n            this.canvas.insertAdjacentHTML('beforeEnd', groupel);\n            this.group = $(this.canvas).children()[0];\n            this.rendered = false;\n            this.prerender = '';\n        },\n\n        _drawShape: function (shapeid, path, lineColor, fillColor, lineWidth) {\n            var vpath = [],\n                initial, stroke, fill, closed, vel, plen, i;\n            for (i = 0, plen = path.length; i < plen; i++) {\n                vpath[i] = '' + (path[i][0]) + ',' + (path[i][1]);\n            }\n            initial = vpath.splice(0, 1);\n            lineWidth = lineWidth === undefined ? 1 : lineWidth;\n            stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"' + lineWidth + 'px\" strokeColor=\"' + lineColor + '\" ';\n            fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n            closed = vpath[0] === vpath[vpath.length - 1] ? 'x ' : '';\n            vel = '<v:shape coordorigin=\"0 0\" coordsize=\"' + this.pixelWidth + ' ' + this.pixelHeight + '\" ' +\n                 ' id=\"jqsshape' + shapeid + '\" ' +\n                 stroke +\n                 fill +\n                ' style=\"position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;\" ' +\n                ' path=\"m ' + initial + ' l ' + vpath.join(', ') + ' ' + closed + 'e\">' +\n                ' </v:shape>';\n            return vel;\n        },\n\n        _drawCircle: function (shapeid, x, y, radius, lineColor, fillColor, lineWidth) {\n            var stroke, fill, vel;\n            x -= radius;\n            y -= radius;\n            stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"' + lineWidth + 'px\" strokeColor=\"' + lineColor + '\" ';\n            fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n            vel = '<v:oval ' +\n                 ' id=\"jqsshape' + shapeid + '\" ' +\n                stroke +\n                fill +\n                ' style=\"position:absolute;top:' + y + 'px; left:' + x + 'px; width:' + (radius * 2) + 'px; height:' + (radius * 2) + 'px\"></v:oval>';\n            return vel;\n\n        },\n\n        _drawPieSlice: function (shapeid, x, y, radius, startAngle, endAngle, lineColor, fillColor) {\n            var vpath, startx, starty, endx, endy, stroke, fill, vel;\n            if (startAngle === endAngle) {\n                return '';  // VML seems to have problem when start angle equals end angle.\n            }\n            if ((endAngle - startAngle) === (2 * Math.PI)) {\n                startAngle = 0.0;  // VML seems to have a problem when drawing a full circle that doesn't start 0\n                endAngle = (2 * Math.PI);\n            }\n\n            startx = x + Math.round(Math.cos(startAngle) * radius);\n            starty = y + Math.round(Math.sin(startAngle) * radius);\n            endx = x + Math.round(Math.cos(endAngle) * radius);\n            endy = y + Math.round(Math.sin(endAngle) * radius);\n\n            if (startx === endx && starty === endy) {\n                if ((endAngle - startAngle) < Math.PI) {\n                    // Prevent very small slices from being mistaken as a whole pie\n                    return '';\n                }\n                // essentially going to be the entire circle, so ignore startAngle\n                startx = endx = x + radius;\n                starty = endy = y;\n            }\n\n            if (startx === endx && starty === endy && (endAngle - startAngle) < Math.PI) {\n                return '';\n            }\n\n            vpath = [x - radius, y - radius, x + radius, y + radius, startx, starty, endx, endy];\n            stroke = lineColor === undefined ? ' stroked=\"false\" ' : ' strokeWeight=\"1px\" strokeColor=\"' + lineColor + '\" ';\n            fill = fillColor === undefined ? ' filled=\"false\"' : ' fillColor=\"' + fillColor + '\" filled=\"true\" ';\n            vel = '<v:shape coordorigin=\"0 0\" coordsize=\"' + this.pixelWidth + ' ' + this.pixelHeight + '\" ' +\n                 ' id=\"jqsshape' + shapeid + '\" ' +\n                 stroke +\n                 fill +\n                ' style=\"position:absolute;left:0px;top:0px;height:' + this.pixelHeight + 'px;width:' + this.pixelWidth + 'px;padding:0px;margin:0px;\" ' +\n                ' path=\"m ' + x + ',' + y + ' wa ' + vpath.join(', ') + ' x e\">' +\n                ' </v:shape>';\n            return vel;\n        },\n\n        _drawRect: function (shapeid, x, y, width, height, lineColor, fillColor) {\n            return this._drawShape(shapeid, [[x, y], [x, y + height], [x + width, y + height], [x + width, y], [x, y]], lineColor, fillColor);\n        },\n\n        reset: function () {\n            this.group.innerHTML = '';\n        },\n\n        appendShape: function (shape) {\n            var vel = this['_draw' + shape.type].apply(this, shape.args);\n            if (this.rendered) {\n                this.group.insertAdjacentHTML('beforeEnd', vel);\n            } else {\n                this.prerender += vel;\n            }\n            this.lastShapeId = shape.id;\n            return shape.id;\n        },\n\n        replaceWithShape: function (shapeid, shape) {\n            var existing = $('#jqsshape' + shapeid),\n                vel = this['_draw' + shape.type].apply(this, shape.args);\n            existing[0].outerHTML = vel;\n        },\n\n        replaceWithShapes: function (shapeids, shapes) {\n            // replace the first shapeid with all the new shapes then toast the remaining old shapes\n            var existing = $('#jqsshape' + shapeids[0]),\n                replace = '',\n                slen = shapes.length,\n                i;\n            for (i = 0; i < slen; i++) {\n                replace += this['_draw' + shapes[i].type].apply(this, shapes[i].args);\n            }\n            existing[0].outerHTML = replace;\n            for (i = 1; i < shapeids.length; i++) {\n                $('#jqsshape' + shapeids[i]).remove();\n            }\n        },\n\n        insertAfterShape: function (shapeid, shape) {\n            var existing = $('#jqsshape' + shapeid),\n                 vel = this['_draw' + shape.type].apply(this, shape.args);\n            existing[0].insertAdjacentHTML('afterEnd', vel);\n        },\n\n        removeShapeId: function (shapeid) {\n            var existing = $('#jqsshape' + shapeid);\n            this.group.removeChild(existing[0]);\n        },\n\n        getShapeAt: function (el, x, y) {\n            var shapeid = el.id.substr(8);\n            return shapeid;\n        },\n\n        render: function () {\n            if (!this.rendered) {\n                // batch the intial render into a single repaint\n                this.group.innerHTML = this.prerender;\n                this.rendered = true;\n            }\n        }\n    });\n\n}))}(document, Math));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/summernote/.bower.json",
    "content": "{\n  \"name\": \"summernote\",\n  \"homepage\": \"http://summernote.org\",\n  \"license\": \"MIT\",\n  \"main\": [\n    \"./dist/summernote.js\",\n    \"./dist/summernote.css\"\n  ],\n  \"ignore\": [\n    \"**/.*\",\n    \"node_modules\",\n    \"bower_components\",\n    \"test\",\n    \"tests\"\n  ],\n  \"dependencies\": {\n    \"jquery\": \">= 1.9.0\",\n    \"bootstrap\": \">= 3.0.1\",\n    \"font-awesome\": \">=4.2.0\"\n  },\n  \"version\": \"0.6.16\",\n  \"_release\": \"0.6.16\",\n  \"_resolution\": {\n    \"type\": \"version\",\n    \"tag\": \"v0.6.16\",\n    \"commit\": \"4a988eebc69b783f649e16e44511bea5afa73df8\"\n  },\n  \"_source\": \"git://github.com/summernote/summernote.git\",\n  \"_target\": \"~0.6.16\",\n  \"_originalSource\": \"summernote\",\n  \"_direct\": true\n}"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/summernote/dist/summernote-bs3.css",
    "content": ".note-editor {\n  /*! normalize.css v2.1.3 | MIT License | git.io/normalize */\n\n}\n.note-editor article,\n.note-editor aside,\n.note-editor details,\n.note-editor figcaption,\n.note-editor figure,\n.note-editor footer,\n.note-editor header,\n.note-editor hgroup,\n.note-editor main,\n.note-editor nav,\n.note-editor section,\n.note-editor summary {\n  display: block;\n}\n.note-editor audio,\n.note-editor canvas,\n.note-editor video {\n  display: inline-block;\n}\n.note-editor audio:not([controls]) {\n  display: none;\n  height: 0;\n}\n.note-editor [hidden],\n.note-editor template {\n  display: none;\n}\n.note-editor html {\n  font-family: sans-serif;\n  -ms-text-size-adjust: 100%;\n  -webkit-text-size-adjust: 100%;\n}\n.note-editor body {\n  margin: 0;\n}\n.note-editor a {\n  background: transparent;\n}\n.note-editor a:focus {\n  outline: thin dotted;\n}\n.note-editor a:active,\n.note-editor a:hover {\n  outline: 0;\n}\n.note-editor h1 {\n  font-size: 2em;\n  margin: 0.67em 0;\n}\n.note-editor abbr[title] {\n  border-bottom: 1px dotted;\n}\n.note-editor b,\n.note-editor strong {\n  font-weight: bold;\n}\n.note-editor dfn {\n  font-style: italic;\n}\n.note-editor hr {\n  -moz-box-sizing: content-box;\n  box-sizing: content-box;\n  height: 0;\n}\n.note-editor mark {\n  background: #ff0;\n  color: #000;\n}\n.note-editor code,\n.note-editor kbd,\n.note-editor pre,\n.note-editor samp {\n  font-family: monospace, serif;\n  font-size: 1em;\n}\n.note-editor pre {\n  white-space: pre-wrap;\n}\n.note-editor q {\n  quotes: \"\\201C\" \"\\201D\" \"\\2018\" \"\\2019\";\n}\n.note-editor small {\n  font-size: 80%;\n}\n.note-editor sub,\n.note-editor sup {\n  font-size: 75%;\n  line-height: 0;\n  position: relative;\n  vertical-align: baseline;\n}\n.note-editor sup {\n  top: -0.5em;\n}\n.note-editor sub {\n  bottom: -0.25em;\n}\n.note-editor img {\n  border: 0;\n}\n.note-editor svg:not(:root) {\n  overflow: hidden;\n}\n.note-editor figure {\n  margin: 0;\n}\n.note-editor fieldset {\n  border: 1px solid #c0c0c0;\n  margin: 0 2px;\n  padding: 0.35em 0.625em 0.75em;\n}\n.note-editor legend {\n  border: 0;\n  padding: 0;\n}\n.note-editor button,\n.note-editor input,\n.note-editor select,\n.note-editor textarea {\n  font-family: inherit;\n  font-size: 100%;\n  margin: 0;\n}\n.note-editor button,\n.note-editor input {\n  line-height: normal;\n}\n.note-editor button,\n.note-editor select {\n  text-transform: none;\n}\n.note-editor button,\n.note-editor html input[type=\"button\"],\n.note-editor input[type=\"reset\"],\n.note-editor input[type=\"submit\"] {\n  -webkit-appearance: button;\n  cursor: pointer;\n}\n.note-editor button[disabled],\n.note-editor html input[disabled] {\n  cursor: default;\n}\n.note-editor input[type=\"checkbox\"],\n.note-editor input[type=\"radio\"] {\n  box-sizing: border-box;\n  padding: 0;\n}\n.note-editor input[type=\"search\"] {\n  -webkit-appearance: textfield;\n  -moz-box-sizing: content-box;\n  -webkit-box-sizing: content-box;\n  box-sizing: content-box;\n}\n.note-editor input[type=\"search\"]::-webkit-search-cancel-button,\n.note-editor input[type=\"search\"]::-webkit-search-decoration {\n  -webkit-appearance: none;\n}\n.note-editor button::-moz-focus-inner,\n.note-editor input::-moz-focus-inner {\n  border: 0;\n  padding: 0;\n}\n.note-editor textarea {\n  overflow: auto;\n  vertical-align: top;\n}\n.note-editor table {\n  border-collapse: collapse;\n  border-spacing: 0;\n}\n@media print {\n  .note-editor * {\n    text-shadow: none !important;\n    color: #000 !important;\n    background: transparent !important;\n    box-shadow: none !important;\n  }\n  .note-editor a,\n  .note-editor a:visited {\n    text-decoration: underline;\n  }\n  .note-editor a[href]:after {\n    content: \" (\" attr(href) \")\";\n  }\n  .note-editor abbr[title]:after {\n    content: \" (\" attr(title) \")\";\n  }\n  .note-editor .ir a:after,\n  .note-editor a[href^=\"javascript:\"]:after,\n  .note-editor a[href^=\"#\"]:after {\n    content: \"\";\n  }\n  .note-editor pre,\n  .note-editor blockquote {\n    border: 1px solid #999;\n    page-break-inside: avoid;\n  }\n  .note-editor thead {\n    display: table-header-group;\n  }\n  .note-editor tr,\n  .note-editor img {\n    page-break-inside: avoid;\n  }\n  .note-editor img {\n    max-width: 100% !important;\n  }\n  @page  {\n    margin: 2cm .5cm;\n  }\n  .note-editor p,\n  .note-editor h2,\n  .note-editor h3 {\n    orphans: 3;\n    widows: 3;\n  }\n  .note-editor h2,\n  .note-editor h3 {\n    page-break-after: avoid;\n  }\n  .note-editor .navbar {\n    display: none;\n  }\n  .note-editor .table td,\n  .note-editor .table th {\n    background-color: #fff !important;\n  }\n  .note-editor .btn > .caret,\n  .note-editor .dropup > .btn > .caret {\n    border-top-color: #000 !important;\n  }\n  .note-editor .label {\n    border: 1px solid #000;\n  }\n  .note-editor .table {\n    border-collapse: collapse !important;\n  }\n  .note-editor .table-bordered th,\n  .note-editor .table-bordered td {\n    border: 1px solid #ddd !important;\n  }\n}\n.note-editor *,\n.note-editor *:before,\n.note-editor *:after {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n.note-editor html {\n  font-size: 62.5%;\n  -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n.note-editor body {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #333333;\n  background-color: #ffffff;\n}\n.note-editor input,\n.note-editor button,\n.note-editor select,\n.note-editor textarea {\n  font-family: inherit;\n  font-size: inherit;\n  line-height: inherit;\n}\n.note-editor a {\n  color: #428bca;\n  text-decoration: none;\n}\n.note-editor a:hover,\n.note-editor a:focus {\n  color: #2a6496;\n  text-decoration: underline;\n}\n.note-editor a:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.note-editor img {\n  vertical-align: middle;\n}\n.note-editor .img-responsive {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.note-editor .img-rounded {\n  border-radius: 6px;\n}\n.note-editor .img-thumbnail {\n  padding: 4px;\n  line-height: 1.428571429;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n}\n.note-editor .img-circle {\n  border-radius: 50%;\n}\n.note-editor hr {\n  margin-top: 20px;\n  margin-bottom: 20px;\n  border: 0;\n  border-top: 1px solid #eeeeee;\n}\n.note-editor .sr-only {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  margin: -1px;\n  padding: 0;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  border: 0;\n}\n.note-editor p {\n  margin: 0 0 10px;\n}\n.note-editor .lead {\n  margin-bottom: 20px;\n  font-size: 16px;\n  font-weight: 200;\n  line-height: 1.4;\n}\n@media (min-width: 768px) {\n  .note-editor .lead {\n    font-size: 21px;\n  }\n}\n.note-editor small,\n.note-editor .small {\n  font-size: 85%;\n}\n.note-editor cite {\n  font-style: normal;\n}\n.note-editor .text-muted {\n  color: #999999;\n}\n.note-editor .text-primary {\n  color: #428bca;\n}\n.note-editor .text-primary:hover {\n  color: #3071a9;\n}\n.note-editor .text-warning {\n  color: #c09853;\n}\n.note-editor .text-warning:hover {\n  color: #a47e3c;\n}\n.note-editor .text-danger {\n  color: #b94a48;\n}\n.note-editor .text-danger:hover {\n  color: #953b39;\n}\n.note-editor .text-success {\n  color: #468847;\n}\n.note-editor .text-success:hover {\n  color: #356635;\n}\n.note-editor .text-info {\n  color: #3a87ad;\n}\n.note-editor .text-info:hover {\n  color: #2d6987;\n}\n.note-editor .text-left {\n  text-align: left;\n}\n.note-editor .text-right {\n  text-align: right;\n}\n.note-editor .text-center {\n  text-align: center;\n}\n.note-editor h1,\n.note-editor h2,\n.note-editor h3,\n.note-editor h4,\n.note-editor h5,\n.note-editor h6,\n.note-editor .h1,\n.note-editor .h2,\n.note-editor .h3,\n.note-editor .h4,\n.note-editor .h5,\n.note-editor .h6 {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n  font-weight: 500;\n  line-height: 1.1;\n  color: inherit;\n}\n.note-editor h1 small,\n.note-editor h2 small,\n.note-editor h3 small,\n.note-editor h4 small,\n.note-editor h5 small,\n.note-editor h6 small,\n.note-editor .h1 small,\n.note-editor .h2 small,\n.note-editor .h3 small,\n.note-editor .h4 small,\n.note-editor .h5 small,\n.note-editor .h6 small,\n.note-editor h1 .small,\n.note-editor h2 .small,\n.note-editor h3 .small,\n.note-editor h4 .small,\n.note-editor h5 .small,\n.note-editor h6 .small,\n.note-editor .h1 .small,\n.note-editor .h2 .small,\n.note-editor .h3 .small,\n.note-editor .h4 .small,\n.note-editor .h5 .small,\n.note-editor .h6 .small {\n  font-weight: normal;\n  line-height: 1;\n  color: #999999;\n}\n.note-editor h1,\n.note-editor h2,\n.note-editor h3 {\n  margin-top: 20px;\n  margin-bottom: 10px;\n}\n.note-editor h1 small,\n.note-editor h2 small,\n.note-editor h3 small,\n.note-editor h1 .small,\n.note-editor h2 .small,\n.note-editor h3 .small {\n  font-size: 65%;\n}\n.note-editor h4,\n.note-editor h5,\n.note-editor h6 {\n  margin-top: 10px;\n  margin-bottom: 10px;\n}\n.note-editor h4 small,\n.note-editor h5 small,\n.note-editor h6 small,\n.note-editor h4 .small,\n.note-editor h5 .small,\n.note-editor h6 .small {\n  font-size: 75%;\n}\n.note-editor h1,\n.note-editor .h1 {\n  font-size: 36px;\n}\n.note-editor h2,\n.note-editor .h2 {\n  font-size: 30px;\n}\n.note-editor h3,\n.note-editor .h3 {\n  font-size: 24px;\n}\n.note-editor h4,\n.note-editor .h4 {\n  font-size: 18px;\n}\n.note-editor h5,\n.note-editor .h5 {\n  font-size: 14px;\n}\n.note-editor h6,\n.note-editor .h6 {\n  font-size: 12px;\n}\n.note-editor .page-header {\n  padding-bottom: 9px;\n  margin: 40px 0 20px;\n  border-bottom: 1px solid #eeeeee;\n}\n.note-editor ul,\n.note-editor ol {\n  margin-top: 0;\n  margin-bottom: 10px;\n}\n.note-editor ul ul,\n.note-editor ol ul,\n.note-editor ul ol,\n.note-editor ol ol {\n  margin-bottom: 0;\n}\n.note-editor .list-unstyled {\n  padding-left: 0;\n  list-style: none;\n}\n.note-editor .list-inline {\n  padding-left: 0;\n  list-style: none;\n}\n.note-editor .list-inline > li {\n  display: inline-block;\n  padding-left: 5px;\n  padding-right: 5px;\n}\n.note-editor dl {\n  margin-bottom: 20px;\n}\n.note-editor dt,\n.note-editor dd {\n  line-height: 1.428571429;\n}\n.note-editor dt {\n  font-weight: bold;\n}\n.note-editor dd {\n  margin-left: 0;\n}\n@media (min-width: 768px) {\n  .note-editor .dl-horizontal dt {\n    float: left;\n    width: 160px;\n    clear: left;\n    text-align: right;\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n  .note-editor .dl-horizontal dd {\n    margin-left: 180px;\n  }\n  .note-editor .dl-horizontal dd:before,\n  .note-editor .dl-horizontal dd:after {\n    content: \" \";\n    /* 1 */\n  \n    display: table;\n    /* 2 */\n  \n  }\n  .note-editor .dl-horizontal dd:after {\n    clear: both;\n  }\n  .note-editor .dl-horizontal dd:before,\n  .note-editor .dl-horizontal dd:after {\n    content: \" \";\n    /* 1 */\n  \n    display: table;\n    /* 2 */\n  \n  }\n  .note-editor .dl-horizontal dd:after {\n    clear: both;\n  }\n}\n.note-editor abbr[title],\n.note-editor abbr[data-original-title] {\n  cursor: help;\n  border-bottom: 1px dotted #999999;\n}\n.note-editor abbr.initialism {\n  font-size: 90%;\n  text-transform: uppercase;\n}\n.note-editor blockquote {\n  padding: 10px 20px;\n  margin: 0 0 20px;\n  border-left: 5px solid #eeeeee;\n}\n.note-editor blockquote p {\n  font-size: 17.5px;\n  font-weight: 300;\n  line-height: 1.25;\n}\n.note-editor blockquote p:last-child {\n  margin-bottom: 0;\n}\n.note-editor blockquote small {\n  display: block;\n  line-height: 1.428571429;\n  color: #999999;\n}\n.note-editor blockquote small:before {\n  content: '\\2014 \\00A0';\n}\n.note-editor blockquote.pull-right {\n  padding-right: 15px;\n  padding-left: 0;\n  border-right: 5px solid #eeeeee;\n  border-left: 0;\n}\n.note-editor blockquote.pull-right p,\n.note-editor blockquote.pull-right small,\n.note-editor blockquote.pull-right .small {\n  text-align: right;\n}\n.note-editor blockquote.pull-right small:before,\n.note-editor blockquote.pull-right .small:before {\n  content: '';\n}\n.note-editor blockquote.pull-right small:after,\n.note-editor blockquote.pull-right .small:after {\n  content: '\\00A0 \\2014';\n}\n.note-editor blockquote:before,\n.note-editor blockquote:after {\n  content: \"\";\n}\n.note-editor address {\n  margin-bottom: 20px;\n  font-style: normal;\n  line-height: 1.428571429;\n}\n.note-editor code,\n.note-editor kdb,\n.note-editor pre,\n.note-editor samp {\n  font-family: Monaco, Menlo, Consolas, \"Courier New\", monospace;\n}\n.note-editor code {\n  padding: 2px 4px;\n  font-size: 90%;\n  color: #c7254e;\n  background-color: #f9f2f4;\n  white-space: nowrap;\n  border-radius: 4px;\n}\n.note-editor pre {\n  display: block;\n  padding: 9.5px;\n  margin: 0 0 10px;\n  font-size: 13px;\n  line-height: 1.428571429;\n  word-break: break-all;\n  word-wrap: break-word;\n  color: #333333;\n  background-color: #f5f5f5;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\n.note-editor pre 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.note-editor .pre-scrollable {\n  max-height: 340px;\n  overflow-y: scroll;\n}\n.note-editor .container {\n  margin-right: auto;\n  margin-left: auto;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.note-editor .container:before,\n.note-editor .container:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .container:after {\n  clear: both;\n}\n.note-editor .container:before,\n.note-editor .container:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .container:after {\n  clear: both;\n}\n.note-editor .row {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.note-editor .row:before,\n.note-editor .row:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .row:after {\n  clear: both;\n}\n.note-editor .row:before,\n.note-editor .row:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .row:after {\n  clear: both;\n}\n.note-editor .col-xs-1, \n.note-editor .col-sm-1, \n.note-editor .col-md-1, \n.note-editor .col-lg-1, \n.note-editor .col-xs-2, \n.note-editor .col-sm-2, \n.note-editor .col-md-2, \n.note-editor .col-lg-2, \n.note-editor .col-xs-3, \n.note-editor .col-sm-3, \n.note-editor .col-md-3, \n.note-editor .col-lg-3, \n.note-editor .col-xs-4, \n.note-editor .col-sm-4, \n.note-editor .col-md-4, \n.note-editor .col-lg-4, \n.note-editor .col-xs-5, \n.note-editor .col-sm-5, \n.note-editor .col-md-5, \n.note-editor .col-lg-5, \n.note-editor .col-xs-6, \n.note-editor .col-sm-6, \n.note-editor .col-md-6, \n.note-editor .col-lg-6, \n.note-editor .col-xs-7, \n.note-editor .col-sm-7, \n.note-editor .col-md-7, \n.note-editor .col-lg-7, \n.note-editor .col-xs-8, \n.note-editor .col-sm-8, \n.note-editor .col-md-8, \n.note-editor .col-lg-8, \n.note-editor .col-xs-9, \n.note-editor .col-sm-9, \n.note-editor .col-md-9, \n.note-editor .col-lg-9, \n.note-editor .col-xs-10, \n.note-editor .col-sm-10, \n.note-editor .col-md-10, \n.note-editor .col-lg-10, \n.note-editor .col-xs-11, \n.note-editor .col-sm-11, \n.note-editor .col-md-11, \n.note-editor .col-lg-11, \n.note-editor .col-xs-12, \n.note-editor .col-sm-12, \n.note-editor .col-md-12, \n.note-editor .col-lg-12 {\n  position: relative;\n  min-height: 1px;\n  padding-left: 15px;\n  padding-right: 15px;\n}\n.note-editor .col-xs-1, \n.note-editor .col-xs-2, \n.note-editor .col-xs-3, \n.note-editor .col-xs-4, \n.note-editor .col-xs-5, \n.note-editor .col-xs-6, \n.note-editor .col-xs-7, \n.note-editor .col-xs-8, \n.note-editor .col-xs-9, \n.note-editor .col-xs-10, \n.note-editor .col-xs-11 {\n  float: left;\n}\n.note-editor .col-xs-12 {\n  width: 100%;\n}\n.note-editor .col-xs-11 {\n  width: 91.66666666666666%;\n}\n.note-editor .col-xs-10 {\n  width: 83.33333333333334%;\n}\n.note-editor .col-xs-9 {\n  width: 75%;\n}\n.note-editor .col-xs-8 {\n  width: 66.66666666666666%;\n}\n.note-editor .col-xs-7 {\n  width: 58.333333333333336%;\n}\n.note-editor .col-xs-6 {\n  width: 50%;\n}\n.note-editor .col-xs-5 {\n  width: 41.66666666666667%;\n}\n.note-editor .col-xs-4 {\n  width: 33.33333333333333%;\n}\n.note-editor .col-xs-3 {\n  width: 25%;\n}\n.note-editor .col-xs-2 {\n  width: 16.666666666666664%;\n}\n.note-editor .col-xs-1 {\n  width: 8.333333333333332%;\n}\n.note-editor .col-xs-pull-12 {\n  right: 100%;\n}\n.note-editor .col-xs-pull-11 {\n  right: 91.66666666666666%;\n}\n.note-editor .col-xs-pull-10 {\n  right: 83.33333333333334%;\n}\n.note-editor .col-xs-pull-9 {\n  right: 75%;\n}\n.note-editor .col-xs-pull-8 {\n  right: 66.66666666666666%;\n}\n.note-editor .col-xs-pull-7 {\n  right: 58.333333333333336%;\n}\n.note-editor .col-xs-pull-6 {\n  right: 50%;\n}\n.note-editor .col-xs-pull-5 {\n  right: 41.66666666666667%;\n}\n.note-editor .col-xs-pull-4 {\n  right: 33.33333333333333%;\n}\n.note-editor .col-xs-pull-3 {\n  right: 25%;\n}\n.note-editor .col-xs-pull-2 {\n  right: 16.666666666666664%;\n}\n.note-editor .col-xs-pull-1 {\n  right: 8.333333333333332%;\n}\n.note-editor .col-xs-push-12 {\n  left: 100%;\n}\n.note-editor .col-xs-push-11 {\n  left: 91.66666666666666%;\n}\n.note-editor .col-xs-push-10 {\n  left: 83.33333333333334%;\n}\n.note-editor .col-xs-push-9 {\n  left: 75%;\n}\n.note-editor .col-xs-push-8 {\n  left: 66.66666666666666%;\n}\n.note-editor .col-xs-push-7 {\n  left: 58.333333333333336%;\n}\n.note-editor .col-xs-push-6 {\n  left: 50%;\n}\n.note-editor .col-xs-push-5 {\n  left: 41.66666666666667%;\n}\n.note-editor .col-xs-push-4 {\n  left: 33.33333333333333%;\n}\n.note-editor .col-xs-push-3 {\n  left: 25%;\n}\n.note-editor .col-xs-push-2 {\n  left: 16.666666666666664%;\n}\n.note-editor .col-xs-push-1 {\n  left: 8.333333333333332%;\n}\n.note-editor .col-xs-offset-12 {\n  margin-left: 100%;\n}\n.note-editor .col-xs-offset-11 {\n  margin-left: 91.66666666666666%;\n}\n.note-editor .col-xs-offset-10 {\n  margin-left: 83.33333333333334%;\n}\n.note-editor .col-xs-offset-9 {\n  margin-left: 75%;\n}\n.note-editor .col-xs-offset-8 {\n  margin-left: 66.66666666666666%;\n}\n.note-editor .col-xs-offset-7 {\n  margin-left: 58.333333333333336%;\n}\n.note-editor .col-xs-offset-6 {\n  margin-left: 50%;\n}\n.note-editor .col-xs-offset-5 {\n  margin-left: 41.66666666666667%;\n}\n.note-editor .col-xs-offset-4 {\n  margin-left: 33.33333333333333%;\n}\n.note-editor .col-xs-offset-3 {\n  margin-left: 25%;\n}\n.note-editor .col-xs-offset-2 {\n  margin-left: 16.666666666666664%;\n}\n.note-editor .col-xs-offset-1 {\n  margin-left: 8.333333333333332%;\n}\n@media (min-width: 768px) {\n  .note-editor .container {\n    width: 750px;\n  }\n  .note-editor .col-sm-1, \n  .note-editor .col-sm-2, \n  .note-editor .col-sm-3, \n  .note-editor .col-sm-4, \n  .note-editor .col-sm-5, \n  .note-editor .col-sm-6, \n  .note-editor .col-sm-7, \n  .note-editor .col-sm-8, \n  .note-editor .col-sm-9, \n  .note-editor .col-sm-10, \n  .note-editor .col-sm-11 {\n    float: left;\n  }\n  .note-editor .col-sm-12 {\n    width: 100%;\n  }\n  .note-editor .col-sm-11 {\n    width: 91.66666666666666%;\n  }\n  .note-editor .col-sm-10 {\n    width: 83.33333333333334%;\n  }\n  .note-editor .col-sm-9 {\n    width: 75%;\n  }\n  .note-editor .col-sm-8 {\n    width: 66.66666666666666%;\n  }\n  .note-editor .col-sm-7 {\n    width: 58.333333333333336%;\n  }\n  .note-editor .col-sm-6 {\n    width: 50%;\n  }\n  .note-editor .col-sm-5 {\n    width: 41.66666666666667%;\n  }\n  .note-editor .col-sm-4 {\n    width: 33.33333333333333%;\n  }\n  .note-editor .col-sm-3 {\n    width: 25%;\n  }\n  .note-editor .col-sm-2 {\n    width: 16.666666666666664%;\n  }\n  .note-editor .col-sm-1 {\n    width: 8.333333333333332%;\n  }\n  .note-editor .col-sm-pull-12 {\n    right: 100%;\n  }\n  .note-editor .col-sm-pull-11 {\n    right: 91.66666666666666%;\n  }\n  .note-editor .col-sm-pull-10 {\n    right: 83.33333333333334%;\n  }\n  .note-editor .col-sm-pull-9 {\n    right: 75%;\n  }\n  .note-editor .col-sm-pull-8 {\n    right: 66.66666666666666%;\n  }\n  .note-editor .col-sm-pull-7 {\n    right: 58.333333333333336%;\n  }\n  .note-editor .col-sm-pull-6 {\n    right: 50%;\n  }\n  .note-editor .col-sm-pull-5 {\n    right: 41.66666666666667%;\n  }\n  .note-editor .col-sm-pull-4 {\n    right: 33.33333333333333%;\n  }\n  .note-editor .col-sm-pull-3 {\n    right: 25%;\n  }\n  .note-editor .col-sm-pull-2 {\n    right: 16.666666666666664%;\n  }\n  .note-editor .col-sm-pull-1 {\n    right: 8.333333333333332%;\n  }\n  .note-editor .col-sm-push-12 {\n    left: 100%;\n  }\n  .note-editor .col-sm-push-11 {\n    left: 91.66666666666666%;\n  }\n  .note-editor .col-sm-push-10 {\n    left: 83.33333333333334%;\n  }\n  .note-editor .col-sm-push-9 {\n    left: 75%;\n  }\n  .note-editor .col-sm-push-8 {\n    left: 66.66666666666666%;\n  }\n  .note-editor .col-sm-push-7 {\n    left: 58.333333333333336%;\n  }\n  .note-editor .col-sm-push-6 {\n    left: 50%;\n  }\n  .note-editor .col-sm-push-5 {\n    left: 41.66666666666667%;\n  }\n  .note-editor .col-sm-push-4 {\n    left: 33.33333333333333%;\n  }\n  .note-editor .col-sm-push-3 {\n    left: 25%;\n  }\n  .note-editor .col-sm-push-2 {\n    left: 16.666666666666664%;\n  }\n  .note-editor .col-sm-push-1 {\n    left: 8.333333333333332%;\n  }\n  .note-editor .col-sm-offset-12 {\n    margin-left: 100%;\n  }\n  .note-editor .col-sm-offset-11 {\n    margin-left: 91.66666666666666%;\n  }\n  .note-editor .col-sm-offset-10 {\n    margin-left: 83.33333333333334%;\n  }\n  .note-editor .col-sm-offset-9 {\n    margin-left: 75%;\n  }\n  .note-editor .col-sm-offset-8 {\n    margin-left: 66.66666666666666%;\n  }\n  .note-editor .col-sm-offset-7 {\n    margin-left: 58.333333333333336%;\n  }\n  .note-editor .col-sm-offset-6 {\n    margin-left: 50%;\n  }\n  .note-editor .col-sm-offset-5 {\n    margin-left: 41.66666666666667%;\n  }\n  .note-editor .col-sm-offset-4 {\n    margin-left: 33.33333333333333%;\n  }\n  .note-editor .col-sm-offset-3 {\n    margin-left: 25%;\n  }\n  .note-editor .col-sm-offset-2 {\n    margin-left: 16.666666666666664%;\n  }\n  .note-editor .col-sm-offset-1 {\n    margin-left: 8.333333333333332%;\n  }\n}\n@media (min-width: 992px) {\n  .note-editor .container {\n    width: 970px;\n  }\n  .note-editor .col-md-1, \n  .note-editor .col-md-2, \n  .note-editor .col-md-3, \n  .note-editor .col-md-4, \n  .note-editor .col-md-5, \n  .note-editor .col-md-6, \n  .note-editor .col-md-7, \n  .note-editor .col-md-8, \n  .note-editor .col-md-9, \n  .note-editor .col-md-10, \n  .note-editor .col-md-11 {\n    float: left;\n  }\n  .note-editor .col-md-12 {\n    width: 100%;\n  }\n  .note-editor .col-md-11 {\n    width: 91.66666666666666%;\n  }\n  .note-editor .col-md-10 {\n    width: 83.33333333333334%;\n  }\n  .note-editor .col-md-9 {\n    width: 75%;\n  }\n  .note-editor .col-md-8 {\n    width: 66.66666666666666%;\n  }\n  .note-editor .col-md-7 {\n    width: 58.333333333333336%;\n  }\n  .note-editor .col-md-6 {\n    width: 50%;\n  }\n  .note-editor .col-md-5 {\n    width: 41.66666666666667%;\n  }\n  .note-editor .col-md-4 {\n    width: 33.33333333333333%;\n  }\n  .note-editor .col-md-3 {\n    width: 25%;\n  }\n  .note-editor .col-md-2 {\n    width: 16.666666666666664%;\n  }\n  .note-editor .col-md-1 {\n    width: 8.333333333333332%;\n  }\n  .note-editor .col-md-pull-12 {\n    right: 100%;\n  }\n  .note-editor .col-md-pull-11 {\n    right: 91.66666666666666%;\n  }\n  .note-editor .col-md-pull-10 {\n    right: 83.33333333333334%;\n  }\n  .note-editor .col-md-pull-9 {\n    right: 75%;\n  }\n  .note-editor .col-md-pull-8 {\n    right: 66.66666666666666%;\n  }\n  .note-editor .col-md-pull-7 {\n    right: 58.333333333333336%;\n  }\n  .note-editor .col-md-pull-6 {\n    right: 50%;\n  }\n  .note-editor .col-md-pull-5 {\n    right: 41.66666666666667%;\n  }\n  .note-editor .col-md-pull-4 {\n    right: 33.33333333333333%;\n  }\n  .note-editor .col-md-pull-3 {\n    right: 25%;\n  }\n  .note-editor .col-md-pull-2 {\n    right: 16.666666666666664%;\n  }\n  .note-editor .col-md-pull-1 {\n    right: 8.333333333333332%;\n  }\n  .note-editor .col-md-push-12 {\n    left: 100%;\n  }\n  .note-editor .col-md-push-11 {\n    left: 91.66666666666666%;\n  }\n  .note-editor .col-md-push-10 {\n    left: 83.33333333333334%;\n  }\n  .note-editor .col-md-push-9 {\n    left: 75%;\n  }\n  .note-editor .col-md-push-8 {\n    left: 66.66666666666666%;\n  }\n  .note-editor .col-md-push-7 {\n    left: 58.333333333333336%;\n  }\n  .note-editor .col-md-push-6 {\n    left: 50%;\n  }\n  .note-editor .col-md-push-5 {\n    left: 41.66666666666667%;\n  }\n  .note-editor .col-md-push-4 {\n    left: 33.33333333333333%;\n  }\n  .note-editor .col-md-push-3 {\n    left: 25%;\n  }\n  .note-editor .col-md-push-2 {\n    left: 16.666666666666664%;\n  }\n  .note-editor .col-md-push-1 {\n    left: 8.333333333333332%;\n  }\n  .note-editor .col-md-offset-12 {\n    margin-left: 100%;\n  }\n  .note-editor .col-md-offset-11 {\n    margin-left: 91.66666666666666%;\n  }\n  .note-editor .col-md-offset-10 {\n    margin-left: 83.33333333333334%;\n  }\n  .note-editor .col-md-offset-9 {\n    margin-left: 75%;\n  }\n  .note-editor .col-md-offset-8 {\n    margin-left: 66.66666666666666%;\n  }\n  .note-editor .col-md-offset-7 {\n    margin-left: 58.333333333333336%;\n  }\n  .note-editor .col-md-offset-6 {\n    margin-left: 50%;\n  }\n  .note-editor .col-md-offset-5 {\n    margin-left: 41.66666666666667%;\n  }\n  .note-editor .col-md-offset-4 {\n    margin-left: 33.33333333333333%;\n  }\n  .note-editor .col-md-offset-3 {\n    margin-left: 25%;\n  }\n  .note-editor .col-md-offset-2 {\n    margin-left: 16.666666666666664%;\n  }\n  .note-editor .col-md-offset-1 {\n    margin-left: 8.333333333333332%;\n  }\n}\n@media (min-width: 1200px) {\n  .note-editor .container {\n    width: 1170px;\n  }\n  .note-editor .col-lg-1, \n  .note-editor .col-lg-2, \n  .note-editor .col-lg-3, \n  .note-editor .col-lg-4, \n  .note-editor .col-lg-5, \n  .note-editor .col-lg-6, \n  .note-editor .col-lg-7, \n  .note-editor .col-lg-8, \n  .note-editor .col-lg-9, \n  .note-editor .col-lg-10, \n  .note-editor .col-lg-11 {\n    float: left;\n  }\n  .note-editor .col-lg-12 {\n    width: 100%;\n  }\n  .note-editor .col-lg-11 {\n    width: 91.66666666666666%;\n  }\n  .note-editor .col-lg-10 {\n    width: 83.33333333333334%;\n  }\n  .note-editor .col-lg-9 {\n    width: 75%;\n  }\n  .note-editor .col-lg-8 {\n    width: 66.66666666666666%;\n  }\n  .note-editor .col-lg-7 {\n    width: 58.333333333333336%;\n  }\n  .note-editor .col-lg-6 {\n    width: 50%;\n  }\n  .note-editor .col-lg-5 {\n    width: 41.66666666666667%;\n  }\n  .note-editor .col-lg-4 {\n    width: 33.33333333333333%;\n  }\n  .note-editor .col-lg-3 {\n    width: 25%;\n  }\n  .note-editor .col-lg-2 {\n    width: 16.666666666666664%;\n  }\n  .note-editor .col-lg-1 {\n    width: 8.333333333333332%;\n  }\n  .note-editor .col-lg-pull-12 {\n    right: 100%;\n  }\n  .note-editor .col-lg-pull-11 {\n    right: 91.66666666666666%;\n  }\n  .note-editor .col-lg-pull-10 {\n    right: 83.33333333333334%;\n  }\n  .note-editor .col-lg-pull-9 {\n    right: 75%;\n  }\n  .note-editor .col-lg-pull-8 {\n    right: 66.66666666666666%;\n  }\n  .note-editor .col-lg-pull-7 {\n    right: 58.333333333333336%;\n  }\n  .note-editor .col-lg-pull-6 {\n    right: 50%;\n  }\n  .note-editor .col-lg-pull-5 {\n    right: 41.66666666666667%;\n  }\n  .note-editor .col-lg-pull-4 {\n    right: 33.33333333333333%;\n  }\n  .note-editor .col-lg-pull-3 {\n    right: 25%;\n  }\n  .note-editor .col-lg-pull-2 {\n    right: 16.666666666666664%;\n  }\n  .note-editor .col-lg-pull-1 {\n    right: 8.333333333333332%;\n  }\n  .note-editor .col-lg-push-12 {\n    left: 100%;\n  }\n  .note-editor .col-lg-push-11 {\n    left: 91.66666666666666%;\n  }\n  .note-editor .col-lg-push-10 {\n    left: 83.33333333333334%;\n  }\n  .note-editor .col-lg-push-9 {\n    left: 75%;\n  }\n  .note-editor .col-lg-push-8 {\n    left: 66.66666666666666%;\n  }\n  .note-editor .col-lg-push-7 {\n    left: 58.333333333333336%;\n  }\n  .note-editor .col-lg-push-6 {\n    left: 50%;\n  }\n  .note-editor .col-lg-push-5 {\n    left: 41.66666666666667%;\n  }\n  .note-editor .col-lg-push-4 {\n    left: 33.33333333333333%;\n  }\n  .note-editor .col-lg-push-3 {\n    left: 25%;\n  }\n  .note-editor .col-lg-push-2 {\n    left: 16.666666666666664%;\n  }\n  .note-editor .col-lg-push-1 {\n    left: 8.333333333333332%;\n  }\n  .note-editor .col-lg-offset-12 {\n    margin-left: 100%;\n  }\n  .note-editor .col-lg-offset-11 {\n    margin-left: 91.66666666666666%;\n  }\n  .note-editor .col-lg-offset-10 {\n    margin-left: 83.33333333333334%;\n  }\n  .note-editor .col-lg-offset-9 {\n    margin-left: 75%;\n  }\n  .note-editor .col-lg-offset-8 {\n    margin-left: 66.66666666666666%;\n  }\n  .note-editor .col-lg-offset-7 {\n    margin-left: 58.333333333333336%;\n  }\n  .note-editor .col-lg-offset-6 {\n    margin-left: 50%;\n  }\n  .note-editor .col-lg-offset-5 {\n    margin-left: 41.66666666666667%;\n  }\n  .note-editor .col-lg-offset-4 {\n    margin-left: 33.33333333333333%;\n  }\n  .note-editor .col-lg-offset-3 {\n    margin-left: 25%;\n  }\n  .note-editor .col-lg-offset-2 {\n    margin-left: 16.666666666666664%;\n  }\n  .note-editor .col-lg-offset-1 {\n    margin-left: 8.333333333333332%;\n  }\n}\n.note-editor table {\n  max-width: 100%;\n  background-color: transparent;\n}\n.note-editor th {\n  text-align: left;\n}\n.note-editor .table {\n  width: 100%;\n  margin-bottom: 20px;\n}\n.note-editor .table > thead > tr > th,\n.note-editor .table > tbody > tr > th,\n.note-editor .table > tfoot > tr > th,\n.note-editor .table > thead > tr > td,\n.note-editor .table > tbody > tr > td,\n.note-editor .table > tfoot > tr > td {\n  padding: 8px;\n  line-height: 1.428571429;\n  vertical-align: top;\n  border-top: 1px solid #dddddd;\n}\n.note-editor .table > thead > tr > th {\n  vertical-align: bottom;\n  border-bottom: 2px solid #dddddd;\n}\n.note-editor .table > caption + thead > tr:first-child > th,\n.note-editor .table > colgroup + thead > tr:first-child > th,\n.note-editor .table > thead:first-child > tr:first-child > th,\n.note-editor .table > caption + thead > tr:first-child > td,\n.note-editor .table > colgroup + thead > tr:first-child > td,\n.note-editor .table > thead:first-child > tr:first-child > td {\n  border-top: 0;\n}\n.note-editor .table > tbody + tbody {\n  border-top: 2px solid #dddddd;\n}\n.note-editor .table .table {\n  background-color: #ffffff;\n}\n.note-editor .table-condensed > thead > tr > th,\n.note-editor .table-condensed > tbody > tr > th,\n.note-editor .table-condensed > tfoot > tr > th,\n.note-editor .table-condensed > thead > tr > td,\n.note-editor .table-condensed > tbody > tr > td,\n.note-editor .table-condensed > tfoot > tr > td {\n  padding: 5px;\n}\n.note-editor .table-bordered {\n  border: 1px solid #dddddd;\n}\n.note-editor .table-bordered > thead > tr > th,\n.note-editor .table-bordered > tbody > tr > th,\n.note-editor .table-bordered > tfoot > tr > th,\n.note-editor .table-bordered > thead > tr > td,\n.note-editor .table-bordered > tbody > tr > td,\n.note-editor .table-bordered > tfoot > tr > td {\n  border: 1px solid #dddddd;\n}\n.note-editor .table-bordered > thead > tr > th,\n.note-editor .table-bordered > thead > tr > td {\n  border-bottom-width: 2px;\n}\n.note-editor .table-striped > tbody > tr:nth-child(odd) > td,\n.note-editor .table-striped > tbody > tr:nth-child(odd) > th {\n  background-color: #f9f9f9;\n}\n.note-editor .table-hover > tbody > tr:hover > td,\n.note-editor .table-hover > tbody > tr:hover > th {\n  background-color: #f5f5f5;\n}\n.note-editor table col[class*=\"col-\"] {\n  float: none;\n  display: table-column;\n}\n.note-editor table td[class*=\"col-\"],\n.note-editor table th[class*=\"col-\"] {\n  float: none;\n  display: table-cell;\n}\n.note-editor .table > thead > tr > td.active,\n.note-editor .table > tbody > tr > td.active,\n.note-editor .table > tfoot > tr > td.active,\n.note-editor .table > thead > tr > th.active,\n.note-editor .table > tbody > tr > th.active,\n.note-editor .table > tfoot > tr > th.active,\n.note-editor .table > thead > tr.active > td,\n.note-editor .table > tbody > tr.active > td,\n.note-editor .table > tfoot > tr.active > td,\n.note-editor .table > thead > tr.active > th,\n.note-editor .table > tbody > tr.active > th,\n.note-editor .table > tfoot > tr.active > th {\n  background-color: #f5f5f5;\n}\n.note-editor .table > thead > tr > td.success,\n.note-editor .table > tbody > tr > td.success,\n.note-editor .table > tfoot > tr > td.success,\n.note-editor .table > thead > tr > th.success,\n.note-editor .table > tbody > tr > th.success,\n.note-editor .table > tfoot > tr > th.success,\n.note-editor .table > thead > tr.success > td,\n.note-editor .table > tbody > tr.success > td,\n.note-editor .table > tfoot > tr.success > td,\n.note-editor .table > thead > tr.success > th,\n.note-editor .table > tbody > tr.success > th,\n.note-editor .table > tfoot > tr.success > th {\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.note-editor .table-hover > tbody > tr > td.success:hover,\n.note-editor .table-hover > tbody > tr > th.success:hover,\n.note-editor .table-hover > tbody > tr.success:hover > td,\n.note-editor .table-hover > tbody > tr.success:hover > th {\n  background-color: #d0e9c6;\n  border-color: #c9e2b3;\n}\n.note-editor .table > thead > tr > td.danger,\n.note-editor .table > tbody > tr > td.danger,\n.note-editor .table > tfoot > tr > td.danger,\n.note-editor .table > thead > tr > th.danger,\n.note-editor .table > tbody > tr > th.danger,\n.note-editor .table > tfoot > tr > th.danger,\n.note-editor .table > thead > tr.danger > td,\n.note-editor .table > tbody > tr.danger > td,\n.note-editor .table > tfoot > tr.danger > td,\n.note-editor .table > thead > tr.danger > th,\n.note-editor .table > tbody > tr.danger > th,\n.note-editor .table > tfoot > tr.danger > th {\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.note-editor .table-hover > tbody > tr > td.danger:hover,\n.note-editor .table-hover > tbody > tr > th.danger:hover,\n.note-editor .table-hover > tbody > tr.danger:hover > td,\n.note-editor .table-hover > tbody > tr.danger:hover > th {\n  background-color: #ebcccc;\n  border-color: #e4b9c0;\n}\n.note-editor .table > thead > tr > td.warning,\n.note-editor .table > tbody > tr > td.warning,\n.note-editor .table > tfoot > tr > td.warning,\n.note-editor .table > thead > tr > th.warning,\n.note-editor .table > tbody > tr > th.warning,\n.note-editor .table > tfoot > tr > th.warning,\n.note-editor .table > thead > tr.warning > td,\n.note-editor .table > tbody > tr.warning > td,\n.note-editor .table > tfoot > tr.warning > td,\n.note-editor .table > thead > tr.warning > th,\n.note-editor .table > tbody > tr.warning > th,\n.note-editor .table > tfoot > tr.warning > th {\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.note-editor .table-hover > tbody > tr > td.warning:hover,\n.note-editor .table-hover > tbody > tr > th.warning:hover,\n.note-editor .table-hover > tbody > tr.warning:hover > td,\n.note-editor .table-hover > tbody > tr.warning:hover > th {\n  background-color: #faf2cc;\n  border-color: #f7e1b5;\n}\n@media (max-width: 767px) {\n  .note-editor .table-responsive {\n    width: 100%;\n    margin-bottom: 15px;\n    overflow-y: hidden;\n    overflow-x: scroll;\n    -ms-overflow-style: -ms-autohiding-scrollbar;\n    border: 1px solid #dddddd;\n    -webkit-overflow-scrolling: touch;\n  }\n  .note-editor .table-responsive > .table {\n    margin-bottom: 0;\n  }\n  .note-editor .table-responsive > .table > thead > tr > th,\n  .note-editor .table-responsive > .table > tbody > tr > th,\n  .note-editor .table-responsive > .table > tfoot > tr > th,\n  .note-editor .table-responsive > .table > thead > tr > td,\n  .note-editor .table-responsive > .table > tbody > tr > td,\n  .note-editor .table-responsive > .table > tfoot > tr > td {\n    white-space: nowrap;\n  }\n  .note-editor .table-responsive > .table-bordered {\n    border: 0;\n  }\n  .note-editor .table-responsive > .table-bordered > thead > tr > th:first-child,\n  .note-editor .table-responsive > .table-bordered > tbody > tr > th:first-child,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n  .note-editor .table-responsive > .table-bordered > thead > tr > td:first-child,\n  .note-editor .table-responsive > .table-bordered > tbody > tr > td:first-child,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n    border-left: 0;\n  }\n  .note-editor .table-responsive > .table-bordered > thead > tr > th:last-child,\n  .note-editor .table-responsive > .table-bordered > tbody > tr > th:last-child,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n  .note-editor .table-responsive > .table-bordered > thead > tr > td:last-child,\n  .note-editor .table-responsive > .table-bordered > tbody > tr > td:last-child,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n    border-right: 0;\n  }\n  .note-editor .table-responsive > .table-bordered > tbody > tr:last-child > th,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n  .note-editor .table-responsive > .table-bordered > tbody > tr:last-child > td,\n  .note-editor .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n    border-bottom: 0;\n  }\n}\n.note-editor fieldset {\n  padding: 0;\n  margin: 0;\n  border: 0;\n}\n.note-editor legend {\n  display: block;\n  width: 100%;\n  padding: 0;\n  margin-bottom: 20px;\n  font-size: 21px;\n  line-height: inherit;\n  color: #333333;\n  border: 0;\n  border-bottom: 1px solid #e5e5e5;\n}\n.note-editor label {\n  display: inline-block;\n  margin-bottom: 5px;\n  font-weight: bold;\n}\n.note-editor input[type=\"search\"] {\n  -webkit-box-sizing: border-box;\n  -moz-box-sizing: border-box;\n  box-sizing: border-box;\n}\n.note-editor input[type=\"radio\"],\n.note-editor input[type=\"checkbox\"] {\n  margin: 4px 0 0;\n  margin-top: 1px \\9;\n  /* IE8-9 */\n\n  line-height: normal;\n}\n.note-editor input[type=\"file\"] {\n  display: block;\n}\n.note-editor select[multiple],\n.note-editor select[size] {\n  height: auto;\n}\n.note-editor select optgroup {\n  font-size: inherit;\n  font-style: inherit;\n  font-family: inherit;\n}\n.note-editor input[type=\"file\"]:focus,\n.note-editor input[type=\"radio\"]:focus,\n.note-editor input[type=\"checkbox\"]:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.note-editor input[type=\"number\"]::-webkit-outer-spin-button,\n.note-editor input[type=\"number\"]::-webkit-inner-spin-button {\n  height: auto;\n}\n.note-editor output {\n  display: block;\n  padding-top: 7px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #555555;\n  vertical-align: middle;\n}\n.note-editor .form-control:-moz-placeholder {\n  color: #999999;\n}\n.note-editor .form-control::-moz-placeholder {\n  color: #999999;\n}\n.note-editor .form-control:-ms-input-placeholder {\n  color: #999999;\n}\n.note-editor .form-control::-webkit-input-placeholder {\n  color: #999999;\n}\n.note-editor .form-control {\n  display: block;\n  width: 100%;\n  height: 34px;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  color: #555555;\n  vertical-align: middle;\n  background-color: #ffffff;\n  background-image: none;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  -webkit-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.note-editor .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, 0.6);\n  box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.note-editor .form-control[disabled],\n.note-editor .form-control[readonly],\nfieldset[disabled] .note-editor .form-control {\n  cursor: not-allowed;\n  background-color: #eeeeee;\n}\ntextarea.note-editor .form-control {\n  height: auto;\n}\n.note-editor .form-group {\n  margin-bottom: 15px;\n}\n.note-editor .radio,\n.note-editor .checkbox {\n  display: block;\n  min-height: 20px;\n  margin-top: 10px;\n  margin-bottom: 10px;\n  padding-left: 20px;\n  vertical-align: middle;\n}\n.note-editor .radio label,\n.note-editor .checkbox label {\n  display: inline;\n  margin-bottom: 0;\n  font-weight: normal;\n  cursor: pointer;\n}\n.note-editor .radio input[type=\"radio\"],\n.note-editor .radio-inline input[type=\"radio\"],\n.note-editor .checkbox input[type=\"checkbox\"],\n.note-editor .checkbox-inline input[type=\"checkbox\"] {\n  float: left;\n  margin-left: -20px;\n}\n.note-editor .radio + .radio,\n.note-editor .checkbox + .checkbox {\n  margin-top: -5px;\n}\n.note-editor .radio-inline,\n.note-editor .checkbox-inline {\n  display: inline-block;\n  padding-left: 20px;\n  margin-bottom: 0;\n  vertical-align: middle;\n  font-weight: normal;\n  cursor: pointer;\n}\n.note-editor .radio-inline + .radio-inline,\n.note-editor .checkbox-inline + .checkbox-inline {\n  margin-top: 0;\n  margin-left: 10px;\n}\n.note-editor input[type=\"radio\"][disabled],\n.note-editor input[type=\"checkbox\"][disabled],\n.note-editor .radio[disabled],\n.note-editor .radio-inline[disabled],\n.note-editor .checkbox[disabled],\n.note-editor .checkbox-inline[disabled],\nfieldset[disabled] .note-editor input[type=\"radio\"],\nfieldset[disabled] .note-editor input[type=\"checkbox\"],\nfieldset[disabled] .note-editor .radio,\nfieldset[disabled] .note-editor .radio-inline,\nfieldset[disabled] .note-editor .checkbox,\nfieldset[disabled] .note-editor .checkbox-inline {\n  cursor: not-allowed;\n}\n.note-editor .input-sm {\n  height: 30px;\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\nselect.note-editor .input-sm {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.note-editor .input-sm {\n  height: auto;\n}\n.note-editor .input-lg {\n  height: 45px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\nselect.note-editor .input-lg {\n  height: 45px;\n  line-height: 45px;\n}\ntextarea.note-editor .input-lg {\n  height: auto;\n}\n.note-editor .has-warning .help-block,\n.note-editor .has-warning .control-label {\n  color: #c09853;\n}\n.note-editor .has-warning .form-control {\n  border-color: #c09853;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.note-editor .has-warning .form-control:focus {\n  border-color: #a47e3c;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e;\n}\n.note-editor .has-warning .input-group-addon {\n  color: #c09853;\n  border-color: #c09853;\n  background-color: #fcf8e3;\n}\n.note-editor .has-error .help-block,\n.note-editor .has-error .control-label {\n  color: #b94a48;\n}\n.note-editor .has-error .form-control {\n  border-color: #b94a48;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.note-editor .has-error .form-control:focus {\n  border-color: #953b39;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392;\n}\n.note-editor .has-error .input-group-addon {\n  color: #b94a48;\n  border-color: #b94a48;\n  background-color: #f2dede;\n}\n.note-editor .has-success .help-block,\n.note-editor .has-success .control-label {\n  color: #468847;\n}\n.note-editor .has-success .form-control {\n  border-color: #468847;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.note-editor .has-success .form-control:focus {\n  border-color: #356635;\n  -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b;\n}\n.note-editor .has-success .input-group-addon {\n  color: #468847;\n  border-color: #468847;\n  background-color: #dff0d8;\n}\n.note-editor .form-control-static {\n  margin-bottom: 0;\n}\n.note-editor .help-block {\n  display: block;\n  margin-top: 5px;\n  margin-bottom: 10px;\n  color: #737373;\n}\n@media (min-width: 768px) {\n  .note-editor .form-inline .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .note-editor .form-inline .form-control {\n    display: inline-block;\n  }\n  .note-editor .form-inline .radio,\n  .note-editor .form-inline .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-left: 0;\n  }\n  .note-editor .form-inline .radio input[type=\"radio\"],\n  .note-editor .form-inline .checkbox input[type=\"checkbox\"] {\n    float: none;\n    margin-left: 0;\n  }\n}\n.note-editor .form-horizontal .control-label,\n.note-editor .form-horizontal .radio,\n.note-editor .form-horizontal .checkbox,\n.note-editor .form-horizontal .radio-inline,\n.note-editor .form-horizontal .checkbox-inline {\n  margin-top: 0;\n  margin-bottom: 0;\n  padding-top: 7px;\n}\n.note-editor .form-horizontal .form-group {\n  margin-left: -15px;\n  margin-right: -15px;\n}\n.note-editor .form-horizontal .form-group:before,\n.note-editor .form-horizontal .form-group:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .form-horizontal .form-group:after {\n  clear: both;\n}\n.note-editor .form-horizontal .form-group:before,\n.note-editor .form-horizontal .form-group:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .form-horizontal .form-group:after {\n  clear: both;\n}\n.note-editor .form-horizontal .form-control-static {\n  padding-top: 7px;\n}\n@media (min-width: 768px) {\n  .note-editor .form-horizontal .control-label {\n    text-align: right;\n  }\n}\n.note-editor .btn {\n  display: inline-block;\n  margin-bottom: 0;\n  font-weight: normal;\n  text-align: center;\n  vertical-align: middle;\n  cursor: pointer;\n  background-image: none;\n  border: 1px solid transparent;\n  white-space: nowrap;\n  padding: 6px 12px;\n  font-size: 14px;\n  line-height: 1.428571429;\n  border-radius: 4px;\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  -ms-user-select: none;\n  -o-user-select: none;\n  user-select: none;\n}\n.note-editor .btn:focus {\n  outline: thin dotted #333;\n  outline: 5px auto -webkit-focus-ring-color;\n  outline-offset: -2px;\n}\n.note-editor .btn:hover,\n.note-editor .btn:focus {\n  color: #333333;\n  text-decoration: none;\n}\n.note-editor .btn:active,\n.note-editor .btn.active {\n  outline: 0;\n  background-image: none;\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.note-editor .btn.disabled,\n.note-editor .btn[disabled],\nfieldset[disabled] .note-editor .btn {\n  cursor: not-allowed;\n  pointer-events: none;\n  opacity: 0.65;\n  filter: alpha(opacity=65);\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.note-editor .btn-default {\n  color: #333333;\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.note-editor .btn-default:hover,\n.note-editor .btn-default:focus,\n.note-editor .btn-default:active,\n.note-editor .btn-default.active,\n.open .dropdown-toggle.note-editor .btn-default {\n  color: #333333;\n  background-color: #ebebeb;\n  border-color: #adadad;\n}\n.note-editor .btn-default:active,\n.note-editor .btn-default.active,\n.open .dropdown-toggle.note-editor .btn-default {\n  background-image: none;\n}\n.note-editor .btn-default.disabled,\n.note-editor .btn-default[disabled],\nfieldset[disabled] .note-editor .btn-default,\n.note-editor .btn-default.disabled:hover,\n.note-editor .btn-default[disabled]:hover,\nfieldset[disabled] .note-editor .btn-default:hover,\n.note-editor .btn-default.disabled:focus,\n.note-editor .btn-default[disabled]:focus,\nfieldset[disabled] .note-editor .btn-default:focus,\n.note-editor .btn-default.disabled:active,\n.note-editor .btn-default[disabled]:active,\nfieldset[disabled] .note-editor .btn-default:active,\n.note-editor .btn-default.disabled.active,\n.note-editor .btn-default[disabled].active,\nfieldset[disabled] .note-editor .btn-default.active {\n  background-color: #ffffff;\n  border-color: #cccccc;\n}\n.note-editor .btn-primary {\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.note-editor .btn-primary:hover,\n.note-editor .btn-primary:focus,\n.note-editor .btn-primary:active,\n.note-editor .btn-primary.active,\n.open .dropdown-toggle.note-editor .btn-primary {\n  color: #ffffff;\n  background-color: #3276b1;\n  border-color: #285e8e;\n}\n.note-editor .btn-primary:active,\n.note-editor .btn-primary.active,\n.open .dropdown-toggle.note-editor .btn-primary {\n  background-image: none;\n}\n.note-editor .btn-primary.disabled,\n.note-editor .btn-primary[disabled],\nfieldset[disabled] .note-editor .btn-primary,\n.note-editor .btn-primary.disabled:hover,\n.note-editor .btn-primary[disabled]:hover,\nfieldset[disabled] .note-editor .btn-primary:hover,\n.note-editor .btn-primary.disabled:focus,\n.note-editor .btn-primary[disabled]:focus,\nfieldset[disabled] .note-editor .btn-primary:focus,\n.note-editor .btn-primary.disabled:active,\n.note-editor .btn-primary[disabled]:active,\nfieldset[disabled] .note-editor .btn-primary:active,\n.note-editor .btn-primary.disabled.active,\n.note-editor .btn-primary[disabled].active,\nfieldset[disabled] .note-editor .btn-primary.active {\n  background-color: #428bca;\n  border-color: #357ebd;\n}\n.note-editor .btn-warning {\n  color: #ffffff;\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.note-editor .btn-warning:hover,\n.note-editor .btn-warning:focus,\n.note-editor .btn-warning:active,\n.note-editor .btn-warning.active,\n.open .dropdown-toggle.note-editor .btn-warning {\n  color: #ffffff;\n  background-color: #ed9c28;\n  border-color: #d58512;\n}\n.note-editor .btn-warning:active,\n.note-editor .btn-warning.active,\n.open .dropdown-toggle.note-editor .btn-warning {\n  background-image: none;\n}\n.note-editor .btn-warning.disabled,\n.note-editor .btn-warning[disabled],\nfieldset[disabled] .note-editor .btn-warning,\n.note-editor .btn-warning.disabled:hover,\n.note-editor .btn-warning[disabled]:hover,\nfieldset[disabled] .note-editor .btn-warning:hover,\n.note-editor .btn-warning.disabled:focus,\n.note-editor .btn-warning[disabled]:focus,\nfieldset[disabled] .note-editor .btn-warning:focus,\n.note-editor .btn-warning.disabled:active,\n.note-editor .btn-warning[disabled]:active,\nfieldset[disabled] .note-editor .btn-warning:active,\n.note-editor .btn-warning.disabled.active,\n.note-editor .btn-warning[disabled].active,\nfieldset[disabled] .note-editor .btn-warning.active {\n  background-color: #f0ad4e;\n  border-color: #eea236;\n}\n.note-editor .btn-danger {\n  color: #ffffff;\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.note-editor .btn-danger:hover,\n.note-editor .btn-danger:focus,\n.note-editor .btn-danger:active,\n.note-editor .btn-danger.active,\n.open .dropdown-toggle.note-editor .btn-danger {\n  color: #ffffff;\n  background-color: #d2322d;\n  border-color: #ac2925;\n}\n.note-editor .btn-danger:active,\n.note-editor .btn-danger.active,\n.open .dropdown-toggle.note-editor .btn-danger {\n  background-image: none;\n}\n.note-editor .btn-danger.disabled,\n.note-editor .btn-danger[disabled],\nfieldset[disabled] .note-editor .btn-danger,\n.note-editor .btn-danger.disabled:hover,\n.note-editor .btn-danger[disabled]:hover,\nfieldset[disabled] .note-editor .btn-danger:hover,\n.note-editor .btn-danger.disabled:focus,\n.note-editor .btn-danger[disabled]:focus,\nfieldset[disabled] .note-editor .btn-danger:focus,\n.note-editor .btn-danger.disabled:active,\n.note-editor .btn-danger[disabled]:active,\nfieldset[disabled] .note-editor .btn-danger:active,\n.note-editor .btn-danger.disabled.active,\n.note-editor .btn-danger[disabled].active,\nfieldset[disabled] .note-editor .btn-danger.active {\n  background-color: #d9534f;\n  border-color: #d43f3a;\n}\n.note-editor .btn-success {\n  color: #ffffff;\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.note-editor .btn-success:hover,\n.note-editor .btn-success:focus,\n.note-editor .btn-success:active,\n.note-editor .btn-success.active,\n.open .dropdown-toggle.note-editor .btn-success {\n  color: #ffffff;\n  background-color: #47a447;\n  border-color: #398439;\n}\n.note-editor .btn-success:active,\n.note-editor .btn-success.active,\n.open .dropdown-toggle.note-editor .btn-success {\n  background-image: none;\n}\n.note-editor .btn-success.disabled,\n.note-editor .btn-success[disabled],\nfieldset[disabled] .note-editor .btn-success,\n.note-editor .btn-success.disabled:hover,\n.note-editor .btn-success[disabled]:hover,\nfieldset[disabled] .note-editor .btn-success:hover,\n.note-editor .btn-success.disabled:focus,\n.note-editor .btn-success[disabled]:focus,\nfieldset[disabled] .note-editor .btn-success:focus,\n.note-editor .btn-success.disabled:active,\n.note-editor .btn-success[disabled]:active,\nfieldset[disabled] .note-editor .btn-success:active,\n.note-editor .btn-success.disabled.active,\n.note-editor .btn-success[disabled].active,\nfieldset[disabled] .note-editor .btn-success.active {\n  background-color: #5cb85c;\n  border-color: #4cae4c;\n}\n.note-editor .btn-info {\n  color: #ffffff;\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.note-editor .btn-info:hover,\n.note-editor .btn-info:focus,\n.note-editor .btn-info:active,\n.note-editor .btn-info.active,\n.open .dropdown-toggle.note-editor .btn-info {\n  color: #ffffff;\n  background-color: #39b3d7;\n  border-color: #269abc;\n}\n.note-editor .btn-info:active,\n.note-editor .btn-info.active,\n.open .dropdown-toggle.note-editor .btn-info {\n  background-image: none;\n}\n.note-editor .btn-info.disabled,\n.note-editor .btn-info[disabled],\nfieldset[disabled] .note-editor .btn-info,\n.note-editor .btn-info.disabled:hover,\n.note-editor .btn-info[disabled]:hover,\nfieldset[disabled] .note-editor .btn-info:hover,\n.note-editor .btn-info.disabled:focus,\n.note-editor .btn-info[disabled]:focus,\nfieldset[disabled] .note-editor .btn-info:focus,\n.note-editor .btn-info.disabled:active,\n.note-editor .btn-info[disabled]:active,\nfieldset[disabled] .note-editor .btn-info:active,\n.note-editor .btn-info.disabled.active,\n.note-editor .btn-info[disabled].active,\nfieldset[disabled] .note-editor .btn-info.active {\n  background-color: #5bc0de;\n  border-color: #46b8da;\n}\n.note-editor .btn-link {\n  color: #428bca;\n  font-weight: normal;\n  cursor: pointer;\n  border-radius: 0;\n}\n.note-editor .btn-link,\n.note-editor .btn-link:active,\n.note-editor .btn-link[disabled],\nfieldset[disabled] .note-editor .btn-link {\n  background-color: transparent;\n  -webkit-box-shadow: none;\n  box-shadow: none;\n}\n.note-editor .btn-link,\n.note-editor .btn-link:hover,\n.note-editor .btn-link:focus,\n.note-editor .btn-link:active {\n  border-color: transparent;\n}\n.note-editor .btn-link:hover,\n.note-editor .btn-link:focus {\n  color: #2a6496;\n  text-decoration: underline;\n  background-color: transparent;\n}\n.note-editor .btn-link[disabled]:hover,\nfieldset[disabled] .note-editor .btn-link:hover,\n.note-editor .btn-link[disabled]:focus,\nfieldset[disabled] .note-editor .btn-link:focus {\n  color: #999999;\n  text-decoration: none;\n}\n.note-editor .btn-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\n.note-editor .btn-sm,\n.note-editor .btn-xs {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.note-editor .btn-xs {\n  padding: 1px 5px;\n}\n.note-editor .btn-block {\n  display: block;\n  width: 100%;\n  padding-left: 0;\n  padding-right: 0;\n}\n.note-editor .btn-block + .btn-block {\n  margin-top: 5px;\n}\n.note-editor input[type=\"submit\"].btn-block,\n.note-editor input[type=\"reset\"].btn-block,\n.note-editor input[type=\"button\"].btn-block {\n  width: 100%;\n}\n.note-editor .fade {\n  opacity: 0;\n  -webkit-transition: opacity 0.15s linear;\n  transition: opacity 0.15s linear;\n}\n.note-editor .fade.in {\n  opacity: 1;\n}\n.note-editor .collapse {\n  display: none;\n}\n.note-editor .collapse.in {\n  display: block;\n}\n.note-editor .collapsing {\n  position: relative;\n  height: 0;\n  overflow: hidden;\n  -webkit-transition: height 0.35s ease;\n  transition: height 0.35s ease;\n}\n.note-editor .caret {\n  display: inline-block;\n  width: 0;\n  height: 0;\n  margin-left: 2px;\n  vertical-align: middle;\n  border-top: 4px solid #000000;\n  border-right: 4px solid transparent;\n  border-left: 4px solid transparent;\n  border-bottom: 0 dotted;\n}\n.note-editor .dropdown {\n  position: relative;\n}\n.note-editor .dropdown-toggle:focus {\n  outline: 0;\n}\n.note-editor .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  list-style: none;\n  font-size: 14px;\n  background-color: #ffffff;\n  border: 1px solid #cccccc;\n  border: 1px solid rgba(0, 0, 0, 0.15);\n  border-radius: 4px;\n  -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n  background-clip: padding-box;\n}\n.note-editor .dropdown-menu.pull-right {\n  right: 0;\n  left: auto;\n}\n.note-editor .dropdown-menu .divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.note-editor .dropdown-menu > li > a {\n  display: block;\n  padding: 3px 20px;\n  clear: both;\n  font-weight: normal;\n  line-height: 1.428571429;\n  color: #333333;\n  white-space: nowrap;\n}\n.note-editor .dropdown-menu > li > a:hover,\n.note-editor .dropdown-menu > li > a:focus {\n  text-decoration: none;\n  color: #262626;\n  background-color: #f5f5f5;\n}\n.note-editor .dropdown-menu > .active > a,\n.note-editor .dropdown-menu > .active > a:hover,\n.note-editor .dropdown-menu > .active > a:focus {\n  color: #ffffff;\n  text-decoration: none;\n  outline: 0;\n  background-color: #428bca;\n}\n.note-editor .dropdown-menu > .disabled > a,\n.note-editor .dropdown-menu > .disabled > a:hover,\n.note-editor .dropdown-menu > .disabled > a:focus {\n  color: #999999;\n}\n.note-editor .dropdown-menu > .disabled > a:hover,\n.note-editor .dropdown-menu > .disabled > a:focus {\n  text-decoration: none;\n  background-color: transparent;\n  background-image: none;\n  filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n  cursor: not-allowed;\n}\n.note-editor .open > .dropdown-menu {\n  display: block;\n}\n.note-editor .open > a {\n  outline: 0;\n}\n.note-editor .dropdown-header {\n  display: block;\n  padding: 3px 20px;\n  font-size: 12px;\n  line-height: 1.428571429;\n  color: #999999;\n}\n.note-editor .dropdown-backdrop {\n  position: fixed;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  top: 0;\n  z-index: 990;\n}\n.note-editor .pull-right > .dropdown-menu {\n  right: 0;\n  left: auto;\n}\n.note-editor .dropup .caret,\n.note-editor .navbar-fixed-bottom .dropdown .caret {\n  border-top: 0 dotted;\n  border-bottom: 4px solid #000000;\n  content: \"\";\n}\n.note-editor .dropup .dropdown-menu,\n.note-editor .navbar-fixed-bottom .dropdown .dropdown-menu {\n  top: auto;\n  bottom: 100%;\n  margin-bottom: 1px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-right .dropdown-menu {\n    right: 0;\n    left: auto;\n  }\n}\n.btn-default .note-editor .caret {\n  border-top-color: #333333;\n}\n.btn-primary .note-editor .caret,\n.btn-success .note-editor .caret,\n.btn-warning .note-editor .caret,\n.btn-danger .note-editor .caret,\n.btn-info .note-editor .caret {\n  border-top-color: #fff;\n}\n.note-editor .dropup .btn-default .caret {\n  border-bottom-color: #333333;\n}\n.note-editor .dropup .btn-primary .caret,\n.note-editor .dropup .btn-success .caret,\n.note-editor .dropup .btn-warning .caret,\n.note-editor .dropup .btn-danger .caret,\n.note-editor .dropup .btn-info .caret {\n  border-bottom-color: #fff;\n}\n.note-editor .btn-group,\n.note-editor .btn-group-vertical {\n  position: relative;\n  display: inline-block;\n  vertical-align: middle;\n}\n.note-editor .btn-group > .btn,\n.note-editor .btn-group-vertical > .btn {\n  position: relative;\n  float: left;\n}\n.note-editor .btn-group > .btn:hover,\n.note-editor .btn-group-vertical > .btn:hover,\n.note-editor .btn-group > .btn:focus,\n.note-editor .btn-group-vertical > .btn:focus,\n.note-editor .btn-group > .btn:active,\n.note-editor .btn-group-vertical > .btn:active,\n.note-editor .btn-group > .btn.active,\n.note-editor .btn-group-vertical > .btn.active {\n  z-index: 2;\n}\n.note-editor .btn-group > .btn:focus,\n.note-editor .btn-group-vertical > .btn:focus {\n  outline: none;\n}\n.note-editor .btn-group .btn + .btn,\n.note-editor .btn-group .btn + .btn-group,\n.note-editor .btn-group .btn-group + .btn,\n.note-editor .btn-group .btn-group + .btn-group {\n  margin-left: -1px;\n}\n.note-editor .btn-toolbar:before,\n.note-editor .btn-toolbar:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .btn-toolbar:after {\n  clear: both;\n}\n.note-editor .btn-toolbar:before,\n.note-editor .btn-toolbar:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .btn-toolbar:after {\n  clear: both;\n}\n.note-editor .btn-toolbar .btn-group {\n  float: left;\n}\n.note-editor .btn-toolbar > .btn + .btn,\n.note-editor .btn-toolbar > .btn-group + .btn,\n.note-editor .btn-toolbar > .btn + .btn-group,\n.note-editor .btn-toolbar > .btn-group + .btn-group {\n  margin-left: 5px;\n}\n.note-editor .btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n  border-radius: 0;\n}\n.note-editor .btn-group > .btn:first-child {\n  margin-left: 0;\n}\n.note-editor .btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.note-editor .btn-group > .btn:last-child:not(:first-child),\n.note-editor .btn-group > .dropdown-toggle:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .btn-group > .btn-group {\n  float: left;\n}\n.note-editor .btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.note-editor .btn-group > .btn-group:first-child > .btn:last-child,\n.note-editor .btn-group > .btn-group:first-child > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.note-editor .btn-group > .btn-group:last-child > .btn:first-child {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .btn-group .dropdown-toggle:active,\n.note-editor .btn-group.open .dropdown-toggle {\n  outline: 0;\n}\n.note-editor .btn-group-xs > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n  padding: 1px 5px;\n}\n.note-editor .btn-group-sm > .btn {\n  padding: 5px 10px;\n  font-size: 12px;\n  line-height: 1.5;\n  border-radius: 3px;\n}\n.note-editor .btn-group-lg > .btn {\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\n.note-editor .btn-group > .btn + .dropdown-toggle {\n  padding-left: 5px;\n  padding-right: 5px;\n}\n.note-editor .btn-group > .btn-lg + .dropdown-toggle {\n  padding-left: 12px;\n  padding-right: 12px;\n}\n.note-editor .btn-group.open .dropdown-toggle {\n  -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n  box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.note-editor .btn .caret {\n  margin-left: 0;\n}\n.note-editor .btn-lg .caret {\n  border-width: 5px 5px 0;\n  border-bottom-width: 0;\n}\n.note-editor .dropup .btn-lg .caret {\n  border-width: 0 5px 5px;\n}\n.note-editor .btn-group-vertical > .btn,\n.note-editor .btn-group-vertical > .btn-group {\n  display: block;\n  float: none;\n  width: 100%;\n  max-width: 100%;\n}\n.note-editor .btn-group-vertical > .btn-group:before,\n.note-editor .btn-group-vertical > .btn-group:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .btn-group-vertical > .btn-group:after {\n  clear: both;\n}\n.note-editor .btn-group-vertical > .btn-group:before,\n.note-editor .btn-group-vertical > .btn-group:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .btn-group-vertical > .btn-group:after {\n  clear: both;\n}\n.note-editor .btn-group-vertical > .btn-group > .btn {\n  float: none;\n}\n.note-editor .btn-group-vertical > .btn + .btn,\n.note-editor .btn-group-vertical > .btn + .btn-group,\n.note-editor .btn-group-vertical > .btn-group + .btn,\n.note-editor .btn-group-vertical > .btn-group + .btn-group {\n  margin-top: -1px;\n  margin-left: 0;\n}\n.note-editor .btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn:first-child:not(:last-child) {\n  border-top-right-radius: 4px;\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn:last-child:not(:first-child) {\n  border-bottom-left-radius: 4px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n  border-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn-group:first-child > .btn:last-child,\n.note-editor .btn-group-vertical > .btn-group:first-child > .dropdown-toggle {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.note-editor .btn-group-vertical > .btn-group:last-child > .btn:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .btn-group-justified {\n  display: table;\n  width: 100%;\n  table-layout: fixed;\n  border-collapse: separate;\n}\n.note-editor .btn-group-justified .btn {\n  float: none;\n  display: table-cell;\n  width: 1%;\n}\n.note-editor [data-toggle=\"buttons\"] > .btn > input[type=\"radio\"],\n.note-editor [data-toggle=\"buttons\"] > .btn > input[type=\"checkbox\"] {\n  display: none;\n}\n.note-editor .input-group {\n  position: relative;\n  display: table;\n  border-collapse: separate;\n}\n.note-editor .input-group.col {\n  float: none;\n  padding-left: 0;\n  padding-right: 0;\n}\n.note-editor .input-group .form-control {\n  width: 100%;\n  margin-bottom: 0;\n}\n.note-editor .input-group-lg > .form-control,\n.note-editor .input-group-lg > .input-group-addon,\n.note-editor .input-group-lg > .input-group-btn > .btn {\n  height: 45px;\n  padding: 10px 16px;\n  font-size: 18px;\n  line-height: 1.33;\n  border-radius: 6px;\n}\nselect.note-editor .input-group-lg > .form-control,\nselect.note-editor .input-group-lg > .input-group-addon,\nselect.note-editor .input-group-lg > .input-group-btn > .btn {\n  height: 45px;\n  line-height: 45px;\n}\ntextarea.note-editor .input-group-lg > .form-control,\ntextarea.note-editor .input-group-lg > .input-group-addon,\ntextarea.note-editor .input-group-lg > .input-group-btn > .btn {\n  height: auto;\n}\n.note-editor .input-group-sm > .form-control,\n.note-editor .input-group-sm > .input-group-addon,\n.note-editor .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.note-editor .input-group-sm > .form-control,\nselect.note-editor .input-group-sm > .input-group-addon,\nselect.note-editor .input-group-sm > .input-group-btn > .btn {\n  height: 30px;\n  line-height: 30px;\n}\ntextarea.note-editor .input-group-sm > .form-control,\ntextarea.note-editor .input-group-sm > .input-group-addon,\ntextarea.note-editor .input-group-sm > .input-group-btn > .btn {\n  height: auto;\n}\n.note-editor .input-group-addon,\n.note-editor .input-group-btn,\n.note-editor .input-group .form-control {\n  display: table-cell;\n}\n.note-editor .input-group-addon:not(:first-child):not(:last-child),\n.note-editor .input-group-btn:not(:first-child):not(:last-child),\n.note-editor .input-group .form-control:not(:first-child):not(:last-child) {\n  border-radius: 0;\n}\n.note-editor .input-group-addon,\n.note-editor .input-group-btn {\n  width: 1%;\n  white-space: nowrap;\n  vertical-align: middle;\n}\n.note-editor .input-group-addon {\n  padding: 6px 12px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 1;\n  color: #555555;\n  text-align: center;\n  background-color: #eeeeee;\n  border: 1px solid #cccccc;\n  border-radius: 4px;\n}\n.note-editor .input-group-addon.input-sm {\n  padding: 5px 10px;\n  font-size: 12px;\n  border-radius: 3px;\n}\n.note-editor .input-group-addon.input-lg {\n  padding: 10px 16px;\n  font-size: 18px;\n  border-radius: 6px;\n}\n.note-editor .input-group-addon input[type=\"radio\"],\n.note-editor .input-group-addon input[type=\"checkbox\"] {\n  margin-top: 0;\n}\n.note-editor .input-group .form-control:first-child,\n.note-editor .input-group-addon:first-child,\n.note-editor .input-group-btn:first-child > .btn,\n.note-editor .input-group-btn:first-child > .dropdown-toggle,\n.note-editor .input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle) {\n  border-bottom-right-radius: 0;\n  border-top-right-radius: 0;\n}\n.note-editor .input-group-addon:first-child {\n  border-right: 0;\n}\n.note-editor .input-group .form-control:last-child,\n.note-editor .input-group-addon:last-child,\n.note-editor .input-group-btn:last-child > .btn,\n.note-editor .input-group-btn:last-child > .dropdown-toggle,\n.note-editor .input-group-btn:first-child > .btn:not(:first-child) {\n  border-bottom-left-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .input-group-addon:last-child {\n  border-left: 0;\n}\n.note-editor .input-group-btn {\n  position: relative;\n  white-space: nowrap;\n}\n.note-editor .input-group-btn:first-child > .btn {\n  margin-right: -1px;\n}\n.note-editor .input-group-btn:last-child > .btn {\n  margin-left: -1px;\n}\n.note-editor .input-group-btn > .btn {\n  position: relative;\n}\n.note-editor .input-group-btn > .btn + .btn {\n  margin-left: -4px;\n}\n.note-editor .input-group-btn > .btn:hover,\n.note-editor .input-group-btn > .btn:active {\n  z-index: 2;\n}\n.note-editor .nav {\n  margin-bottom: 0;\n  padding-left: 0;\n  list-style: none;\n}\n.note-editor .nav:before,\n.note-editor .nav:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .nav:after {\n  clear: both;\n}\n.note-editor .nav:before,\n.note-editor .nav:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .nav:after {\n  clear: both;\n}\n.note-editor .nav > li {\n  position: relative;\n  display: block;\n}\n.note-editor .nav > li > a {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n}\n.note-editor .nav > li > a:hover,\n.note-editor .nav > li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.note-editor .nav > li.disabled > a {\n  color: #999999;\n}\n.note-editor .nav > li.disabled > a:hover,\n.note-editor .nav > li.disabled > a:focus {\n  color: #999999;\n  text-decoration: none;\n  background-color: transparent;\n  cursor: not-allowed;\n}\n.note-editor .nav .open > a,\n.note-editor .nav .open > a:hover,\n.note-editor .nav .open > a:focus {\n  background-color: #eeeeee;\n  border-color: #428bca;\n}\n.note-editor .nav .open > a .caret,\n.note-editor .nav .open > a:hover .caret,\n.note-editor .nav .open > a:focus .caret {\n  border-top-color: #2a6496;\n  border-bottom-color: #2a6496;\n}\n.note-editor .nav .nav-divider {\n  height: 1px;\n  margin: 9px 0;\n  overflow: hidden;\n  background-color: #e5e5e5;\n}\n.note-editor .nav > li > a > img {\n  max-width: none;\n}\n.note-editor .nav-tabs {\n  border-bottom: 1px solid #dddddd;\n}\n.note-editor .nav-tabs > li {\n  float: left;\n  margin-bottom: -1px;\n}\n.note-editor .nav-tabs > li > a {\n  margin-right: 2px;\n  line-height: 1.428571429;\n  border: 1px solid transparent;\n  border-radius: 4px 4px 0 0;\n}\n.note-editor .nav-tabs > li > a:hover {\n  border-color: #eeeeee #eeeeee #dddddd;\n}\n.note-editor .nav-tabs > li.active > a,\n.note-editor .nav-tabs > li.active > a:hover,\n.note-editor .nav-tabs > li.active > a:focus {\n  color: #555555;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-bottom-color: transparent;\n  cursor: default;\n}\n.note-editor .nav-tabs.nav-justified {\n  width: 100%;\n  border-bottom: 0;\n}\n.note-editor .nav-tabs.nav-justified > li {\n  float: none;\n}\n.note-editor .nav-tabs.nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n@media (min-width: 768px) {\n  .note-editor .nav-tabs.nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .note-editor .nav-tabs.nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.note-editor .nav-tabs.nav-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.note-editor .nav-tabs.nav-justified > .active > a,\n.note-editor .nav-tabs.nav-justified > .active > a:hover,\n.note-editor .nav-tabs.nav-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .note-editor .nav-tabs.nav-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .note-editor .nav-tabs.nav-justified > .active > a,\n  .note-editor .nav-tabs.nav-justified > .active > a:hover,\n  .note-editor .nav-tabs.nav-justified > .active > a:focus {\n    border-bottom-color: #ffffff;\n  }\n}\n.note-editor .nav-pills > li {\n  float: left;\n}\n.note-editor .nav-pills > li > a {\n  border-radius: 4px;\n}\n.note-editor .nav-pills > li + li {\n  margin-left: 2px;\n}\n.note-editor .nav-pills > li.active > a,\n.note-editor .nav-pills > li.active > a:hover,\n.note-editor .nav-pills > li.active > a:focus {\n  color: #ffffff;\n  background-color: #428bca;\n}\n.note-editor .nav-pills > li.active > a .caret,\n.note-editor .nav-pills > li.active > a:hover .caret,\n.note-editor .nav-pills > li.active > a:focus .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n.note-editor .nav-stacked > li {\n  float: none;\n}\n.note-editor .nav-stacked > li + li {\n  margin-top: 2px;\n  margin-left: 0;\n}\n.note-editor .nav-justified {\n  width: 100%;\n}\n.note-editor .nav-justified > li {\n  float: none;\n}\n.note-editor .nav-justified > li > a {\n  text-align: center;\n  margin-bottom: 5px;\n}\n@media (min-width: 768px) {\n  .note-editor .nav-justified > li {\n    display: table-cell;\n    width: 1%;\n  }\n  .note-editor .nav-justified > li > a {\n    margin-bottom: 0;\n  }\n}\n.note-editor .nav-tabs-justified {\n  border-bottom: 0;\n}\n.note-editor .nav-tabs-justified > li > a {\n  margin-right: 0;\n  border-radius: 4px;\n}\n.note-editor .nav-tabs-justified > .active > a,\n.note-editor .nav-tabs-justified > .active > a:hover,\n.note-editor .nav-tabs-justified > .active > a:focus {\n  border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n  .note-editor .nav-tabs-justified > li > a {\n    border-bottom: 1px solid #dddddd;\n    border-radius: 4px 4px 0 0;\n  }\n  .note-editor .nav-tabs-justified > .active > a,\n  .note-editor .nav-tabs-justified > .active > a:hover,\n  .note-editor .nav-tabs-justified > .active > a:focus {\n    border-bottom-color: #ffffff;\n  }\n}\n.note-editor .tab-content > .tab-pane {\n  display: none;\n}\n.note-editor .tab-content > .active {\n  display: block;\n}\n.note-editor .nav .caret {\n  border-top-color: #428bca;\n  border-bottom-color: #428bca;\n}\n.note-editor .nav a:hover .caret {\n  border-top-color: #2a6496;\n  border-bottom-color: #2a6496;\n}\n.note-editor .nav-tabs .dropdown-menu {\n  margin-top: -1px;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .navbar {\n  position: relative;\n  z-index: 1000;\n  min-height: 50px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n}\n.note-editor .navbar:before,\n.note-editor .navbar:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar:after {\n  clear: both;\n}\n.note-editor .navbar:before,\n.note-editor .navbar:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar {\n    border-radius: 4px;\n  }\n}\n.note-editor .navbar-header:before,\n.note-editor .navbar-header:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar-header:after {\n  clear: both;\n}\n.note-editor .navbar-header:before,\n.note-editor .navbar-header:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar-header:after {\n  clear: both;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-header {\n    float: left;\n  }\n}\n.note-editor .navbar-collapse {\n  max-height: 340px;\n  overflow-x: visible;\n  padding-right: 15px;\n  padding-left: 15px;\n  border-top: 1px solid transparent;\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n  -webkit-overflow-scrolling: touch;\n}\n.note-editor .navbar-collapse:before,\n.note-editor .navbar-collapse:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar-collapse:after {\n  clear: both;\n}\n.note-editor .navbar-collapse:before,\n.note-editor .navbar-collapse:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .navbar-collapse:after {\n  clear: both;\n}\n.note-editor .navbar-collapse.in {\n  overflow-y: auto;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-collapse {\n    width: auto;\n    border-top: 0;\n    box-shadow: none;\n  }\n  .note-editor .navbar-collapse.collapse {\n    display: block !important;\n    height: auto !important;\n    padding-bottom: 0;\n    overflow: visible !important;\n  }\n  .note-editor .navbar-collapse.in {\n    overflow-y: visible;\n  }\n  .note-editor .navbar-collapse .navbar-nav.navbar-left:first-child {\n    margin-left: -15px;\n  }\n  .note-editor .navbar-collapse .navbar-nav.navbar-right:last-child {\n    margin-right: -15px;\n  }\n  .note-editor .navbar-collapse .navbar-text:last-child {\n    margin-right: 0;\n  }\n}\n.note-editor .container > .navbar-header,\n.note-editor .container > .navbar-collapse {\n  margin-right: -15px;\n  margin-left: -15px;\n}\n@media (min-width: 768px) {\n  .note-editor .container > .navbar-header,\n  .note-editor .container > .navbar-collapse {\n    margin-right: 0;\n    margin-left: 0;\n  }\n}\n.note-editor .navbar-static-top {\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-static-top {\n    border-radius: 0;\n  }\n}\n.note-editor .navbar-fixed-top,\n.note-editor .navbar-fixed-bottom {\n  position: fixed;\n  right: 0;\n  left: 0;\n  border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-fixed-top,\n  .note-editor .navbar-fixed-bottom {\n    border-radius: 0;\n  }\n}\n.note-editor .navbar-fixed-top {\n  z-index: 1030;\n  top: 0;\n}\n.note-editor .navbar-fixed-bottom {\n  bottom: 0;\n  margin-bottom: 0;\n}\n.note-editor .navbar-brand {\n  float: left;\n  padding: 15px 15px;\n  font-size: 18px;\n  line-height: 20px;\n}\n.note-editor .navbar-brand:hover,\n.note-editor .navbar-brand:focus {\n  text-decoration: none;\n}\n@media (min-width: 768px) {\n  .navbar > .container .note-editor .navbar-brand {\n    margin-left: -15px;\n  }\n}\n.note-editor .navbar-toggle {\n  position: relative;\n  float: right;\n  margin-right: 15px;\n  padding: 9px 10px;\n  margin-top: 8px;\n  margin-bottom: 8px;\n  background-color: transparent;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.note-editor .navbar-toggle .icon-bar {\n  display: block;\n  width: 22px;\n  height: 2px;\n  border-radius: 1px;\n}\n.note-editor .navbar-toggle .icon-bar + .icon-bar {\n  margin-top: 4px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-toggle {\n    display: none;\n  }\n}\n.note-editor .navbar-nav {\n  margin: 7.5px -15px;\n}\n.note-editor .navbar-nav > li > a {\n  padding-top: 10px;\n  padding-bottom: 10px;\n  line-height: 20px;\n}\n@media (max-width: 767px) {\n  .note-editor .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    box-shadow: none;\n  }\n  .note-editor .navbar-nav .open .dropdown-menu > li > a,\n  .note-editor .navbar-nav .open .dropdown-menu .dropdown-header {\n    padding: 5px 15px 5px 25px;\n  }\n  .note-editor .navbar-nav .open .dropdown-menu > li > a {\n    line-height: 20px;\n  }\n  .note-editor .navbar-nav .open .dropdown-menu > li > a:hover,\n  .note-editor .navbar-nav .open .dropdown-menu > li > a:focus {\n    background-image: none;\n  }\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-nav {\n    float: left;\n    margin: 0;\n  }\n  .note-editor .navbar-nav > li {\n    float: left;\n  }\n  .note-editor .navbar-nav > li > a {\n    padding-top: 15px;\n    padding-bottom: 15px;\n  }\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-left {\n    float: left !important;\n  }\n  .note-editor .navbar-right {\n    float: right !important;\n  }\n}\n.note-editor .navbar-form {\n  margin-left: -15px;\n  margin-right: -15px;\n  padding: 10px 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, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-form .form-group {\n    display: inline-block;\n    margin-bottom: 0;\n    vertical-align: middle;\n  }\n  .note-editor .navbar-form .form-control {\n    display: inline-block;\n  }\n  .note-editor .navbar-form .radio,\n  .note-editor .navbar-form .checkbox {\n    display: inline-block;\n    margin-top: 0;\n    margin-bottom: 0;\n    padding-left: 0;\n  }\n  .note-editor .navbar-form .radio input[type=\"radio\"],\n  .note-editor .navbar-form .checkbox input[type=\"checkbox\"] {\n    float: none;\n    margin-left: 0;\n  }\n}\n@media (max-width: 767px) {\n  .note-editor .navbar-form .form-group {\n    margin-bottom: 5px;\n  }\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-form {\n    width: auto;\n    border: 0;\n    margin-left: 0;\n    margin-right: 0;\n    padding-top: 0;\n    padding-bottom: 0;\n    -webkit-box-shadow: none;\n    box-shadow: none;\n  }\n}\n.note-editor .navbar-nav > li > .dropdown-menu {\n  margin-top: 0;\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\n.note-editor .navbar-nav.pull-right > li > .dropdown-menu,\n.note-editor .navbar-nav > li > .dropdown-menu.pull-right {\n  left: auto;\n  right: 0;\n}\n.note-editor .navbar-btn {\n  margin-top: 8px;\n  margin-bottom: 8px;\n}\n.note-editor .navbar-text {\n  float: left;\n  margin-top: 15px;\n  margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n  .note-editor .navbar-text {\n    margin-left: 15px;\n    margin-right: 15px;\n  }\n}\n.note-editor .navbar-default {\n  background-color: #f8f8f8;\n  border-color: #e7e7e7;\n}\n.note-editor .navbar-default .navbar-brand {\n  color: #777777;\n}\n.note-editor .navbar-default .navbar-brand:hover,\n.note-editor .navbar-default .navbar-brand:focus {\n  color: #5e5e5e;\n  background-color: transparent;\n}\n.note-editor .navbar-default .navbar-text {\n  color: #777777;\n}\n.note-editor .navbar-default .navbar-nav > li > a {\n  color: #777777;\n}\n.note-editor .navbar-default .navbar-nav > li > a:hover,\n.note-editor .navbar-default .navbar-nav > li > a:focus {\n  color: #333333;\n  background-color: transparent;\n}\n.note-editor .navbar-default .navbar-nav > .active > a,\n.note-editor .navbar-default .navbar-nav > .active > a:hover,\n.note-editor .navbar-default .navbar-nav > .active > a:focus {\n  color: #555555;\n  background-color: #e7e7e7;\n}\n.note-editor .navbar-default .navbar-nav > .disabled > a,\n.note-editor .navbar-default .navbar-nav > .disabled > a:hover,\n.note-editor .navbar-default .navbar-nav > .disabled > a:focus {\n  color: #cccccc;\n  background-color: transparent;\n}\n.note-editor .navbar-default .navbar-toggle {\n  border-color: #dddddd;\n}\n.note-editor .navbar-default .navbar-toggle:hover,\n.note-editor .navbar-default .navbar-toggle:focus {\n  background-color: #dddddd;\n}\n.note-editor .navbar-default .navbar-toggle .icon-bar {\n  background-color: #cccccc;\n}\n.note-editor .navbar-default .navbar-collapse,\n.note-editor .navbar-default .navbar-form {\n  border-color: #e7e7e7;\n}\n.note-editor .navbar-default .navbar-nav > .dropdown > a:hover .caret,\n.note-editor .navbar-default .navbar-nav > .dropdown > a:focus .caret {\n  border-top-color: #333333;\n  border-bottom-color: #333333;\n}\n.note-editor .navbar-default .navbar-nav > .open > a,\n.note-editor .navbar-default .navbar-nav > .open > a:hover,\n.note-editor .navbar-default .navbar-nav > .open > a:focus {\n  background-color: #e7e7e7;\n  color: #555555;\n}\n.note-editor .navbar-default .navbar-nav > .open > a .caret,\n.note-editor .navbar-default .navbar-nav > .open > a:hover .caret,\n.note-editor .navbar-default .navbar-nav > .open > a:focus .caret {\n  border-top-color: #555555;\n  border-bottom-color: #555555;\n}\n.note-editor .navbar-default .navbar-nav > .dropdown > a .caret {\n  border-top-color: #777777;\n  border-bottom-color: #777777;\n}\n@media (max-width: 767px) {\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n    color: #777777;\n  }\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #333333;\n    background-color: transparent;\n  }\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #555555;\n    background-color: #e7e7e7;\n  }\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .note-editor .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #cccccc;\n    background-color: transparent;\n  }\n}\n.note-editor .navbar-default .navbar-link {\n  color: #777777;\n}\n.note-editor .navbar-default .navbar-link:hover {\n  color: #333333;\n}\n.note-editor .navbar-inverse {\n  background-color: #222222;\n  border-color: #080808;\n}\n.note-editor .navbar-inverse .navbar-brand {\n  color: #999999;\n}\n.note-editor .navbar-inverse .navbar-brand:hover,\n.note-editor .navbar-inverse .navbar-brand:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.note-editor .navbar-inverse .navbar-text {\n  color: #999999;\n}\n.note-editor .navbar-inverse .navbar-nav > li > a {\n  color: #999999;\n}\n.note-editor .navbar-inverse .navbar-nav > li > a:hover,\n.note-editor .navbar-inverse .navbar-nav > li > a:focus {\n  color: #ffffff;\n  background-color: transparent;\n}\n.note-editor .navbar-inverse .navbar-nav > .active > a,\n.note-editor .navbar-inverse .navbar-nav > .active > a:hover,\n.note-editor .navbar-inverse .navbar-nav > .active > a:focus {\n  color: #ffffff;\n  background-color: #080808;\n}\n.note-editor .navbar-inverse .navbar-nav > .disabled > a,\n.note-editor .navbar-inverse .navbar-nav > .disabled > a:hover,\n.note-editor .navbar-inverse .navbar-nav > .disabled > a:focus {\n  color: #444444;\n  background-color: transparent;\n}\n.note-editor .navbar-inverse .navbar-toggle {\n  border-color: #333333;\n}\n.note-editor .navbar-inverse .navbar-toggle:hover,\n.note-editor .navbar-inverse .navbar-toggle:focus {\n  background-color: #333333;\n}\n.note-editor .navbar-inverse .navbar-toggle .icon-bar {\n  background-color: #ffffff;\n}\n.note-editor .navbar-inverse .navbar-collapse,\n.note-editor .navbar-inverse .navbar-form {\n  border-color: #101010;\n}\n.note-editor .navbar-inverse .navbar-nav > .open > a,\n.note-editor .navbar-inverse .navbar-nav > .open > a:hover,\n.note-editor .navbar-inverse .navbar-nav > .open > a:focus {\n  background-color: #080808;\n  color: #ffffff;\n}\n.note-editor .navbar-inverse .navbar-nav > .dropdown > a:hover .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n.note-editor .navbar-inverse .navbar-nav > .dropdown > a .caret {\n  border-top-color: #999999;\n  border-bottom-color: #999999;\n}\n.note-editor .navbar-inverse .navbar-nav > .open > a .caret,\n.note-editor .navbar-inverse .navbar-nav > .open > a:hover .caret,\n.note-editor .navbar-inverse .navbar-nav > .open > a:focus .caret {\n  border-top-color: #ffffff;\n  border-bottom-color: #ffffff;\n}\n@media (max-width: 767px) {\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n    border-color: #080808;\n  }\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n    color: #999999;\n  }\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n    color: #ffffff;\n    background-color: transparent;\n  }\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n    color: #ffffff;\n    background-color: #080808;\n  }\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n  .note-editor .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n    color: #444444;\n    background-color: transparent;\n  }\n}\n.note-editor .navbar-inverse .navbar-link {\n  color: #999999;\n}\n.note-editor .navbar-inverse .navbar-link:hover {\n  color: #ffffff;\n}\n.note-editor .breadcrumb {\n  padding: 8px 15px;\n  margin-bottom: 20px;\n  list-style: none;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n}\n.note-editor .breadcrumb > li {\n  display: inline-block;\n}\n.note-editor .breadcrumb > li + li:before {\n  content: \"/\\00a0\";\n  padding: 0 5px;\n  color: #cccccc;\n}\n.note-editor .breadcrumb > .active {\n  color: #999999;\n}\n.note-editor .pagination {\n  display: inline-block;\n  padding-left: 0;\n  margin: 20px 0;\n  border-radius: 4px;\n}\n.note-editor .pagination > li {\n  display: inline;\n}\n.note-editor .pagination > li > a,\n.note-editor .pagination > li > span {\n  position: relative;\n  float: left;\n  padding: 6px 12px;\n  line-height: 1.428571429;\n  text-decoration: none;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  margin-left: -1px;\n}\n.note-editor .pagination > li:first-child > a,\n.note-editor .pagination > li:first-child > span {\n  margin-left: 0;\n  border-bottom-left-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.note-editor .pagination > li:last-child > a,\n.note-editor .pagination > li:last-child > span {\n  border-bottom-right-radius: 4px;\n  border-top-right-radius: 4px;\n}\n.note-editor .pagination > li > a:hover,\n.note-editor .pagination > li > span:hover,\n.note-editor .pagination > li > a:focus,\n.note-editor .pagination > li > span:focus {\n  background-color: #eeeeee;\n}\n.note-editor .pagination > .active > a,\n.note-editor .pagination > .active > span,\n.note-editor .pagination > .active > a:hover,\n.note-editor .pagination > .active > span:hover,\n.note-editor .pagination > .active > a:focus,\n.note-editor .pagination > .active > span:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n  cursor: default;\n}\n.note-editor .pagination > .disabled > span,\n.note-editor .pagination > .disabled > span:hover,\n.note-editor .pagination > .disabled > span:focus,\n.note-editor .pagination > .disabled > a,\n.note-editor .pagination > .disabled > a:hover,\n.note-editor .pagination > .disabled > a:focus {\n  color: #999999;\n  background-color: #ffffff;\n  border-color: #dddddd;\n  cursor: not-allowed;\n}\n.note-editor .pagination-lg > li > a,\n.note-editor .pagination-lg > li > span {\n  padding: 10px 16px;\n  font-size: 18px;\n}\n.note-editor .pagination-lg > li:first-child > a,\n.note-editor .pagination-lg > li:first-child > span {\n  border-bottom-left-radius: 6px;\n  border-top-left-radius: 6px;\n}\n.note-editor .pagination-lg > li:last-child > a,\n.note-editor .pagination-lg > li:last-child > span {\n  border-bottom-right-radius: 6px;\n  border-top-right-radius: 6px;\n}\n.note-editor .pagination-sm > li > a,\n.note-editor .pagination-sm > li > span {\n  padding: 5px 10px;\n  font-size: 12px;\n}\n.note-editor .pagination-sm > li:first-child > a,\n.note-editor .pagination-sm > li:first-child > span {\n  border-bottom-left-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.note-editor .pagination-sm > li:last-child > a,\n.note-editor .pagination-sm > li:last-child > span {\n  border-bottom-right-radius: 3px;\n  border-top-right-radius: 3px;\n}\n.note-editor .pager {\n  padding-left: 0;\n  margin: 20px 0;\n  list-style: none;\n  text-align: center;\n}\n.note-editor .pager:before,\n.note-editor .pager:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .pager:after {\n  clear: both;\n}\n.note-editor .pager:before,\n.note-editor .pager:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .pager:after {\n  clear: both;\n}\n.note-editor .pager li {\n  display: inline;\n}\n.note-editor .pager li > a,\n.note-editor .pager li > span {\n  display: inline-block;\n  padding: 5px 14px;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 15px;\n}\n.note-editor .pager li > a:hover,\n.note-editor .pager li > a:focus {\n  text-decoration: none;\n  background-color: #eeeeee;\n}\n.note-editor .pager .next > a,\n.note-editor .pager .next > span {\n  float: right;\n}\n.note-editor .pager .previous > a,\n.note-editor .pager .previous > span {\n  float: left;\n}\n.note-editor .pager .disabled > a,\n.note-editor .pager .disabled > a:hover,\n.note-editor .pager .disabled > a:focus,\n.note-editor .pager .disabled > span {\n  color: #999999;\n  background-color: #ffffff;\n  cursor: not-allowed;\n}\n.note-editor .label {\n  display: inline;\n  padding: .2em .6em .3em;\n  font-size: 75%;\n  font-weight: bold;\n  line-height: 1;\n  color: #ffffff;\n  text-align: center;\n  white-space: nowrap;\n  vertical-align: baseline;\n  border-radius: .25em;\n}\n.note-editor .label[href]:hover,\n.note-editor .label[href]:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.note-editor .label:empty {\n  display: none;\n}\n.note-editor .label-default {\n  background-color: #999999;\n}\n.note-editor .label-default[href]:hover,\n.note-editor .label-default[href]:focus {\n  background-color: #808080;\n}\n.note-editor .label-primary {\n  background-color: #428bca;\n}\n.note-editor .label-primary[href]:hover,\n.note-editor .label-primary[href]:focus {\n  background-color: #3071a9;\n}\n.note-editor .label-success {\n  background-color: #5cb85c;\n}\n.note-editor .label-success[href]:hover,\n.note-editor .label-success[href]:focus {\n  background-color: #449d44;\n}\n.note-editor .label-info {\n  background-color: #5bc0de;\n}\n.note-editor .label-info[href]:hover,\n.note-editor .label-info[href]:focus {\n  background-color: #31b0d5;\n}\n.note-editor .label-warning {\n  background-color: #f0ad4e;\n}\n.note-editor .label-warning[href]:hover,\n.note-editor .label-warning[href]:focus {\n  background-color: #ec971f;\n}\n.note-editor .label-danger {\n  background-color: #d9534f;\n}\n.note-editor .label-danger[href]:hover,\n.note-editor .label-danger[href]:focus {\n  background-color: #c9302c;\n}\n.note-editor .badge {\n  display: inline-block;\n  min-width: 10px;\n  padding: 3px 7px;\n  font-size: 12px;\n  font-weight: bold;\n  color: #ffffff;\n  line-height: 1;\n  vertical-align: baseline;\n  white-space: nowrap;\n  text-align: center;\n  background-color: #999999;\n  border-radius: 10px;\n}\n.note-editor .badge:empty {\n  display: none;\n}\n.note-editor a.badge:hover,\n.note-editor a.badge:focus {\n  color: #ffffff;\n  text-decoration: none;\n  cursor: pointer;\n}\n.note-editor .btn .badge {\n  position: relative;\n  top: -1px;\n}\n.note-editor a.list-group-item.active > .badge,\n.note-editor .nav-pills > .active > a > .badge {\n  color: #428bca;\n  background-color: #ffffff;\n}\n.note-editor .nav-pills > li > a > .badge {\n  margin-left: 3px;\n}\n.note-editor .jumbotron {\n  padding: 30px;\n  margin-bottom: 30px;\n  font-size: 21px;\n  font-weight: 200;\n  line-height: 2.1428571435;\n  color: inherit;\n  background-color: #eeeeee;\n}\n.note-editor .jumbotron h1 {\n  line-height: 1;\n  color: inherit;\n}\n.note-editor .jumbotron p {\n  line-height: 1.4;\n}\n.container .note-editor .jumbotron {\n  border-radius: 6px;\n}\n@media screen and (min-width: 768px) {\n  .note-editor .jumbotron {\n    padding-top: 48px;\n    padding-bottom: 48px;\n  }\n  .container .note-editor .jumbotron {\n    padding-left: 60px;\n    padding-right: 60px;\n  }\n  .note-editor .jumbotron h1 {\n    font-size: 63px;\n  }\n}\n.note-editor .thumbnail {\n  padding: 4px;\n  line-height: 1.428571429;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n  border-radius: 4px;\n  -webkit-transition: all 0.2s ease-in-out;\n  transition: all 0.2s ease-in-out;\n  display: inline-block;\n  max-width: 100%;\n  height: auto;\n  display: block;\n  margin-bottom: 20px;\n}\n.note-editor .thumbnail > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n}\n.note-editor a.thumbnail:hover,\n.note-editor a.thumbnail:focus,\n.note-editor a.thumbnail.active {\n  border-color: #428bca;\n}\n.note-editor .thumbnail > img {\n  margin-left: auto;\n  margin-right: auto;\n}\n.note-editor .thumbnail .caption {\n  padding: 9px;\n  color: #333333;\n}\n.note-editor .alert {\n  padding: 15px;\n  margin-bottom: 20px;\n  border: 1px solid transparent;\n  border-radius: 4px;\n}\n.note-editor .alert h4 {\n  margin-top: 0;\n  color: inherit;\n}\n.note-editor .alert .alert-link {\n  font-weight: bold;\n}\n.note-editor .alert > p,\n.note-editor .alert > ul {\n  margin-bottom: 0;\n}\n.note-editor .alert > p + p {\n  margin-top: 5px;\n}\n.note-editor .alert-dismissable {\n  padding-right: 35px;\n}\n.note-editor .alert-dismissable .close {\n  position: relative;\n  top: -2px;\n  right: -21px;\n  color: inherit;\n}\n.note-editor .alert-success {\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n  color: #468847;\n}\n.note-editor .alert-success hr {\n  border-top-color: #c9e2b3;\n}\n.note-editor .alert-success .alert-link {\n  color: #356635;\n}\n.note-editor .alert-info {\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n  color: #3a87ad;\n}\n.note-editor .alert-info hr {\n  border-top-color: #a6e1ec;\n}\n.note-editor .alert-info .alert-link {\n  color: #2d6987;\n}\n.note-editor .alert-warning {\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n  color: #c09853;\n}\n.note-editor .alert-warning hr {\n  border-top-color: #f7e1b5;\n}\n.note-editor .alert-warning .alert-link {\n  color: #a47e3c;\n}\n.note-editor .alert-danger {\n  background-color: #f2dede;\n  border-color: #ebccd1;\n  color: #b94a48;\n}\n.note-editor .alert-danger hr {\n  border-top-color: #e4b9c0;\n}\n.note-editor .alert-danger .alert-link {\n  color: #953b39;\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@-moz-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: 0 0;\n  }\n  to {\n    background-position: 40px 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.note-editor .progress {\n  overflow: hidden;\n  height: 20px;\n  margin-bottom: 20px;\n  background-color: #f5f5f5;\n  border-radius: 4px;\n  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.note-editor .progress-bar {\n  float: left;\n  width: 0%;\n  height: 100%;\n  font-size: 12px;\n  line-height: 20px;\n  color: #ffffff;\n  text-align: center;\n  background-color: #428bca;\n  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n  -webkit-transition: width 0.6s ease;\n  transition: width 0.6s ease;\n}\n.note-editor .progress-striped .progress-bar {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-size: 40px 40px;\n}\n.note-editor .progress.active .progress-bar {\n  -webkit-animation: progress-bar-stripes 2s linear infinite;\n  -moz-animation: progress-bar-stripes 2s linear infinite;\n  -ms-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.note-editor .progress-bar-success {\n  background-color: #5cb85c;\n}\n.progress-striped .note-editor .progress-bar-success {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.note-editor .progress-bar-info {\n  background-color: #5bc0de;\n}\n.progress-striped .note-editor .progress-bar-info {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.note-editor .progress-bar-warning {\n  background-color: #f0ad4e;\n}\n.progress-striped .note-editor .progress-bar-warning {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.note-editor .progress-bar-danger {\n  background-color: #d9534f;\n}\n.progress-striped .note-editor .progress-bar-danger {\n  background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));\n  background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n  background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.note-editor .media,\n.note-editor .media-body {\n  overflow: hidden;\n  zoom: 1;\n}\n.note-editor .media,\n.note-editor .media .media {\n  margin-top: 15px;\n}\n.note-editor .media:first-child {\n  margin-top: 0;\n}\n.note-editor .media-object {\n  display: block;\n}\n.note-editor .media-heading {\n  margin: 0 0 5px;\n}\n.note-editor .media > .pull-left {\n  margin-right: 10px;\n}\n.note-editor .media > .pull-right {\n  margin-left: 10px;\n}\n.note-editor .media-list {\n  padding-left: 0;\n  list-style: none;\n}\n.note-editor .list-group {\n  margin-bottom: 20px;\n  padding-left: 0;\n}\n.note-editor .list-group-item {\n  position: relative;\n  display: block;\n  padding: 10px 15px;\n  margin-bottom: -1px;\n  background-color: #ffffff;\n  border: 1px solid #dddddd;\n}\n.note-editor .list-group-item:first-child {\n  border-top-right-radius: 4px;\n  border-top-left-radius: 4px;\n}\n.note-editor .list-group-item:last-child {\n  margin-bottom: 0;\n  border-bottom-right-radius: 4px;\n  border-bottom-left-radius: 4px;\n}\n.note-editor .list-group-item > .badge {\n  float: right;\n}\n.note-editor .list-group-item > .badge + .badge {\n  margin-right: 5px;\n}\n.note-editor a.list-group-item {\n  color: #555555;\n}\n.note-editor a.list-group-item .list-group-item-heading {\n  color: #333333;\n}\n.note-editor a.list-group-item:hover,\n.note-editor a.list-group-item:focus {\n  text-decoration: none;\n  background-color: #f5f5f5;\n}\n.note-editor a.list-group-item.active,\n.note-editor a.list-group-item.active:hover,\n.note-editor a.list-group-item.active:focus {\n  z-index: 2;\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.note-editor a.list-group-item.active .list-group-item-heading,\n.note-editor a.list-group-item.active:hover .list-group-item-heading,\n.note-editor a.list-group-item.active:focus .list-group-item-heading {\n  color: inherit;\n}\n.note-editor a.list-group-item.active .list-group-item-text,\n.note-editor a.list-group-item.active:hover .list-group-item-text,\n.note-editor a.list-group-item.active:focus .list-group-item-text {\n  color: #e1edf7;\n}\n.note-editor .list-group-item-heading {\n  margin-top: 0;\n  margin-bottom: 5px;\n}\n.note-editor .list-group-item-text {\n  margin-bottom: 0;\n  line-height: 1.3;\n}\n.note-editor .panel {\n  margin-bottom: 20px;\n  background-color: #ffffff;\n  border: 1px solid transparent;\n  border-radius: 4px;\n  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.note-editor .panel-body {\n  padding: 15px;\n}\n.note-editor .panel-body:before,\n.note-editor .panel-body:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .panel-body:after {\n  clear: both;\n}\n.note-editor .panel-body:before,\n.note-editor .panel-body:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.note-editor .panel-body:after {\n  clear: both;\n}\n.note-editor .panel > .list-group {\n  margin-bottom: 0;\n}\n.note-editor .panel > .list-group .list-group-item {\n  border-width: 1px 0;\n}\n.note-editor .panel > .list-group .list-group-item:first-child {\n  border-top-right-radius: 0;\n  border-top-left-radius: 0;\n}\n.note-editor .panel > .list-group .list-group-item:last-child {\n  border-bottom: 0;\n}\n.note-editor .panel-heading + .list-group .list-group-item:first-child {\n  border-top-width: 0;\n}\n.note-editor .panel > .table,\n.note-editor .panel > .table-responsive {\n  margin-bottom: 0;\n}\n.note-editor .panel > .panel-body + .table,\n.note-editor .panel > .panel-body + .table-responsive {\n  border-top: 1px solid #dddddd;\n}\n.note-editor .panel > .table-bordered,\n.note-editor .panel > .table-responsive > .table-bordered {\n  border: 0;\n}\n.note-editor .panel > .table-bordered > thead > tr > th:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.note-editor .panel > .table-bordered > tbody > tr > th:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.note-editor .panel > .table-bordered > tfoot > tr > th:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.note-editor .panel > .table-bordered > thead > tr > td:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.note-editor .panel > .table-bordered > tbody > tr > td:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.note-editor .panel > .table-bordered > tfoot > tr > td:first-child,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n  border-left: 0;\n}\n.note-editor .panel > .table-bordered > thead > tr > th:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.note-editor .panel > .table-bordered > tbody > tr > th:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.note-editor .panel > .table-bordered > tfoot > tr > th:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.note-editor .panel > .table-bordered > thead > tr > td:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.note-editor .panel > .table-bordered > tbody > tr > td:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.note-editor .panel > .table-bordered > tfoot > tr > td:last-child,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n  border-right: 0;\n}\n.note-editor .panel > .table-bordered > thead > tr:last-child > th,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr:last-child > th,\n.note-editor .panel > .table-bordered > tbody > tr:last-child > th,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.note-editor .panel > .table-bordered > tfoot > tr:last-child > th,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n.note-editor .panel > .table-bordered > thead > tr:last-child > td,\n.note-editor .panel > .table-responsive > .table-bordered > thead > tr:last-child > td,\n.note-editor .panel > .table-bordered > tbody > tr:last-child > td,\n.note-editor .panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.note-editor .panel > .table-bordered > tfoot > tr:last-child > td,\n.note-editor .panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n  border-bottom: 0;\n}\n.note-editor .panel-heading {\n  padding: 10px 15px;\n  border-bottom: 1px solid transparent;\n  border-top-right-radius: 3px;\n  border-top-left-radius: 3px;\n}\n.note-editor .panel-title {\n  margin-top: 0;\n  margin-bottom: 0;\n  font-size: 16px;\n}\n.note-editor .panel-title > a {\n  color: inherit;\n}\n.note-editor .panel-footer {\n  padding: 10px 15px;\n  background-color: #f5f5f5;\n  border-top: 1px solid #dddddd;\n  border-bottom-right-radius: 3px;\n  border-bottom-left-radius: 3px;\n}\n.note-editor .panel-group .panel {\n  margin-bottom: 0;\n  border-radius: 4px;\n  overflow: hidden;\n}\n.note-editor .panel-group .panel + .panel {\n  margin-top: 5px;\n}\n.note-editor .panel-group .panel-heading {\n  border-bottom: 0;\n}\n.note-editor .panel-group .panel-heading + .panel-collapse .panel-body {\n  border-top: 1px solid #dddddd;\n}\n.note-editor .panel-group .panel-footer {\n  border-top: 0;\n}\n.note-editor .panel-group .panel-footer + .panel-collapse .panel-body {\n  border-bottom: 1px solid #dddddd;\n}\n.note-editor .panel-default {\n  border-color: #dddddd;\n}\n.note-editor .panel-default > .panel-heading {\n  color: #333333;\n  background-color: #f5f5f5;\n  border-color: #dddddd;\n}\n.note-editor .panel-default > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #dddddd;\n}\n.note-editor .panel-default > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #dddddd;\n}\n.note-editor .panel-primary {\n  border-color: #428bca;\n}\n.note-editor .panel-primary > .panel-heading {\n  color: #ffffff;\n  background-color: #428bca;\n  border-color: #428bca;\n}\n.note-editor .panel-primary > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #428bca;\n}\n.note-editor .panel-primary > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #428bca;\n}\n.note-editor .panel-success {\n  border-color: #d6e9c6;\n}\n.note-editor .panel-success > .panel-heading {\n  color: #468847;\n  background-color: #dff0d8;\n  border-color: #d6e9c6;\n}\n.note-editor .panel-success > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #d6e9c6;\n}\n.note-editor .panel-success > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #d6e9c6;\n}\n.note-editor .panel-warning {\n  border-color: #faebcc;\n}\n.note-editor .panel-warning > .panel-heading {\n  color: #c09853;\n  background-color: #fcf8e3;\n  border-color: #faebcc;\n}\n.note-editor .panel-warning > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #faebcc;\n}\n.note-editor .panel-warning > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #faebcc;\n}\n.note-editor .panel-danger {\n  border-color: #ebccd1;\n}\n.note-editor .panel-danger > .panel-heading {\n  color: #b94a48;\n  background-color: #f2dede;\n  border-color: #ebccd1;\n}\n.note-editor .panel-danger > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #ebccd1;\n}\n.note-editor .panel-danger > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #ebccd1;\n}\n.note-editor .panel-info {\n  border-color: #bce8f1;\n}\n.note-editor .panel-info > .panel-heading {\n  color: #3a87ad;\n  background-color: #d9edf7;\n  border-color: #bce8f1;\n}\n.note-editor .panel-info > .panel-heading + .panel-collapse .panel-body {\n  border-top-color: #bce8f1;\n}\n.note-editor .panel-info > .panel-footer + .panel-collapse .panel-body {\n  border-bottom-color: #bce8f1;\n}\n.note-editor .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, 0.05);\n  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.note-editor .well blockquote {\n  border-color: #ddd;\n  border-color: rgba(0, 0, 0, 0.15);\n}\n.note-editor .well-lg {\n  padding: 24px;\n  border-radius: 6px;\n}\n.note-editor .well-sm {\n  padding: 9px;\n  border-radius: 3px;\n}\n.note-editor .close {\n  float: right;\n  font-size: 21px;\n  font-weight: bold;\n  line-height: 1;\n  color: #000000;\n  text-shadow: 0 1px 0 #ffffff;\n  opacity: 0.2;\n  filter: alpha(opacity=20);\n}\n.note-editor .close:hover,\n.note-editor .close:focus {\n  color: #000000;\n  text-decoration: none;\n  cursor: pointer;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\nbutton.note-editor .close {\n  padding: 0;\n  cursor: pointer;\n  background: transparent;\n  border: 0;\n  -webkit-appearance: none;\n}\n.modal-open {\n  overflow: hidden;\n}\n.modal {\n  display: none;\n  overflow: auto;\n  overflow-y: scroll;\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1040;\n}\n.modal.fade .modal-dialog {\n  -webkit-transform: translate(0, -25%);\n  -ms-transform: translate(0, -25%);\n  transform: translate(0, -25%);\n  -webkit-transition: -webkit-transform 0.3s ease-out;\n  -moz-transition: -moz-transform 0.3s ease-out;\n  -o-transition: -o-transform 0.3s ease-out;\n  transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n  -webkit-transform: translate(0, 0);\n  -ms-transform: translate(0, 0);\n  transform: translate(0, 0);\n}\n.modal-dialog {\n  margin-left: auto;\n  margin-right: auto;\n  width: auto;\n  padding: 10px;\n  z-index: 1050;\n}\n.modal-content {\n  position: relative;\n  background-color: #ffffff;\n  border: 1px solid #999999;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n  background-clip: padding-box;\n  outline: none;\n}\n.modal-backdrop {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 1030;\n  background-color: #000000;\n}\n.modal-backdrop.fade {\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n}\n.modal-header {\n  padding: 15px;\n  border-bottom: 1px solid #e5e5e5;\n  min-height: 16.428571429px;\n}\n.modal-header .close {\n  margin-top: -2px;\n}\n.modal-title {\n  margin: 0;\n  line-height: 1.428571429;\n}\n.modal-body {\n  position: relative;\n  padding: 20px;\n}\n.modal-footer {\n  margin-top: 15px;\n  padding: 19px 20px 20px;\n  text-align: right;\n  border-top: 1px solid #e5e5e5;\n}\n.modal-footer:before,\n.modal-footer:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.modal-footer:after {\n  clear: both;\n}\n.modal-footer:before,\n.modal-footer:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.modal-footer:after {\n  clear: both;\n}\n.modal-footer .btn + .btn {\n  margin-left: 5px;\n  margin-bottom: 0;\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@media screen and (min-width: 768px) {\n  .modal-dialog {\n    width: 600px;\n    padding-top: 30px;\n    padding-bottom: 30px;\n  }\n  .modal-content {\n    -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n    box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n  }\n}\n.tooltip {\n  position: absolute;\n  z-index: 1030;\n  display: block;\n  visibility: visible;\n  font-size: 12px;\n  line-height: 1.4;\n  opacity: 0;\n  filter: alpha(opacity=0);\n}\n.tooltip.in {\n  opacity: 0.9;\n  filter: alpha(opacity=90);\n}\n.tooltip.top {\n  margin-top: -3px;\n  padding: 5px 0;\n}\n.tooltip.right {\n  margin-left: 3px;\n  padding: 0 5px;\n}\n.tooltip.bottom {\n  margin-top: 3px;\n  padding: 5px 0;\n}\n.tooltip.left {\n  margin-left: -3px;\n  padding: 0 5px;\n}\n.tooltip-inner {\n  max-width: 200px;\n  padding: 3px 8px;\n  color: #ffffff;\n  text-align: center;\n  text-decoration: none;\n  background-color: #000000;\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: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n  bottom: 0;\n  left: 5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n  bottom: 0;\n  right: 5px;\n  border-width: 5px 5px 0;\n  border-top-color: #000000;\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: #000000;\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: #000000;\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: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n  top: 0;\n  left: 5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n  top: 0;\n  right: 5px;\n  border-width: 0 5px 5px;\n  border-bottom-color: #000000;\n}\n.popover {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 1010;\n  display: none;\n  max-width: 276px;\n  padding: 1px;\n  text-align: left;\n  background-color: #ffffff;\n  background-clip: padding-box;\n  border: 1px solid #cccccc;\n  border: 1px solid rgba(0, 0, 0, 0.2);\n  border-radius: 6px;\n  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n  white-space: normal;\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  margin: 0;\n  padding: 8px 14px;\n  font-size: 14px;\n  font-weight: normal;\n  line-height: 18px;\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  border-width: 10px;\n  content: \"\";\n}\n.popover.top .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-bottom-width: 0;\n  border-top-color: #999999;\n  border-top-color: rgba(0, 0, 0, 0.25);\n  bottom: -11px;\n}\n.popover.top .arrow:after {\n  content: \" \";\n  bottom: 1px;\n  margin-left: -10px;\n  border-bottom-width: 0;\n  border-top-color: #ffffff;\n}\n.popover.right .arrow {\n  top: 50%;\n  left: -11px;\n  margin-top: -11px;\n  border-left-width: 0;\n  border-right-color: #999999;\n  border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right .arrow:after {\n  content: \" \";\n  left: 1px;\n  bottom: -10px;\n  border-left-width: 0;\n  border-right-color: #ffffff;\n}\n.popover.bottom .arrow {\n  left: 50%;\n  margin-left: -11px;\n  border-top-width: 0;\n  border-bottom-color: #999999;\n  border-bottom-color: rgba(0, 0, 0, 0.25);\n  top: -11px;\n}\n.popover.bottom .arrow:after {\n  content: \" \";\n  top: 1px;\n  margin-left: -10px;\n  border-top-width: 0;\n  border-bottom-color: #ffffff;\n}\n.popover.left .arrow {\n  top: 50%;\n  right: -11px;\n  margin-top: -11px;\n  border-right-width: 0;\n  border-left-color: #999999;\n  border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left .arrow:after {\n  content: \" \";\n  right: 1px;\n  border-right-width: 0;\n  border-left-color: #ffffff;\n  bottom: -10px;\n}\n.carousel {\n  position: relative;\n}\n.carousel-inner {\n  position: relative;\n  overflow: hidden;\n  width: 100%;\n}\n.carousel-inner > .item {\n  display: none;\n  position: relative;\n  -webkit-transition: 0.6s ease-in-out left;\n  transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n  display: block;\n  max-width: 100%;\n  height: auto;\n  line-height: 1;\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  left: 0;\n  bottom: 0;\n  width: 15%;\n  opacity: 0.5;\n  filter: alpha(opacity=50);\n  font-size: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n  background-image: -webkit-gradient(linear, 0% top, 100% top, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0.0001)));\n  background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.5) 0%), color-stop(rgba(0, 0, 0, 0.0001) 100%));\n  background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n  left: auto;\n  right: 0;\n  background-image: -webkit-gradient(linear, 0% top, 100% top, from(rgba(0, 0, 0, 0.0001)), to(rgba(0, 0, 0, 0.5)));\n  background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, 0.0001) 0%), color-stop(rgba(0, 0, 0, 0.5) 100%));\n  background-image: -moz-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n  background-repeat: repeat-x;\n  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n  color: #ffffff;\n  text-decoration: none;\n  opacity: 0.9;\n  filter: alpha(opacity=90);\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}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n  left: 50%;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n  right: 50%;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n  width: 20px;\n  height: 20px;\n  margin-top: -10px;\n  margin-left: -10px;\n  font-family: serif;\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  margin-left: -30%;\n  padding-left: 0;\n  list-style: none;\n  text-align: center;\n}\n.carousel-indicators li {\n  display: inline-block;\n  width: 10px;\n  height: 10px;\n  margin: 1px;\n  text-indent: -999px;\n  border: 1px solid #ffffff;\n  border-radius: 10px;\n  cursor: pointer;\n}\n.carousel-indicators .active {\n  margin: 0;\n  width: 12px;\n  height: 12px;\n  background-color: #ffffff;\n}\n.carousel-caption {\n  position: absolute;\n  left: 15%;\n  right: 15%;\n  bottom: 20px;\n  z-index: 10;\n  padding-top: 20px;\n  padding-bottom: 20px;\n  color: #ffffff;\n  text-align: center;\n  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n  text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n  .carousel-control .glyphicons-chevron-left,\n  .carousel-control .glyphicons-chevron-right,\n  .carousel-control .icon-prev,\n  .carousel-control .icon-next {\n    width: 30px;\n    height: 30px;\n    margin-top: -15px;\n    margin-left: -15px;\n    font-size: 30px;\n  }\n  .carousel-caption {\n    left: 20%;\n    right: 20%;\n    padding-bottom: 30px;\n  }\n  .carousel-indicators {\n    bottom: 20px;\n  }\n}\n.clearfix:before,\n.clearfix:after {\n  content: \" \";\n  /* 1 */\n\n  display: table;\n  /* 2 */\n\n}\n.clearfix:after {\n  clear: both;\n}\n.center-block {\n  display: block;\n  margin-left: auto;\n  margin-right: 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  visibility: hidden !important;\n}\n.affix {\n  position: fixed;\n}\n@-ms-viewport {\n  width: device-width;\n}\n.visible-xs,\ntr.visible-xs,\nth.visible-xs,\ntd.visible-xs {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-xs {\n    display: block !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 (min-width: 768px) and (max-width: 991px) {\n  .visible-xs.visible-sm {\n    display: block !important;\n  }\n  tr.visible-xs.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-xs.visible-sm,\n  td.visible-xs.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-xs.visible-md {\n    display: block !important;\n  }\n  tr.visible-xs.visible-md {\n    display: table-row !important;\n  }\n  th.visible-xs.visible-md,\n  td.visible-xs.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-xs.visible-lg {\n    display: block !important;\n  }\n  tr.visible-xs.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-xs.visible-lg,\n  td.visible-xs.visible-lg {\n    display: table-cell !important;\n  }\n}\n.visible-sm,\ntr.visible-sm,\nth.visible-sm,\ntd.visible-sm {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-sm.visible-xs {\n    display: block !important;\n  }\n  tr.visible-sm.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-sm.visible-xs,\n  td.visible-sm.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-sm {\n    display: block !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: 992px) and (max-width: 1199px) {\n  .visible-sm.visible-md {\n    display: block !important;\n  }\n  tr.visible-sm.visible-md {\n    display: table-row !important;\n  }\n  th.visible-sm.visible-md,\n  td.visible-sm.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-sm.visible-lg {\n    display: block !important;\n  }\n  tr.visible-sm.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-sm.visible-lg,\n  td.visible-sm.visible-lg {\n    display: table-cell !important;\n  }\n}\n.visible-md,\ntr.visible-md,\nth.visible-md,\ntd.visible-md {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-md.visible-xs {\n    display: block !important;\n  }\n  tr.visible-md.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-md.visible-xs,\n  td.visible-md.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-md.visible-sm {\n    display: block !important;\n  }\n  tr.visible-md.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-md.visible-sm,\n  td.visible-md.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-md {\n    display: block !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: 1200px) {\n  .visible-md.visible-lg {\n    display: block !important;\n  }\n  tr.visible-md.visible-lg {\n    display: table-row !important;\n  }\n  th.visible-md.visible-lg,\n  td.visible-md.visible-lg {\n    display: table-cell !important;\n  }\n}\n.visible-lg,\ntr.visible-lg,\nth.visible-lg,\ntd.visible-lg {\n  display: none !important;\n}\n@media (max-width: 767px) {\n  .visible-lg.visible-xs {\n    display: block !important;\n  }\n  tr.visible-lg.visible-xs {\n    display: table-row !important;\n  }\n  th.visible-lg.visible-xs,\n  td.visible-lg.visible-xs {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .visible-lg.visible-sm {\n    display: block !important;\n  }\n  tr.visible-lg.visible-sm {\n    display: table-row !important;\n  }\n  th.visible-lg.visible-sm,\n  td.visible-lg.visible-sm {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .visible-lg.visible-md {\n    display: block !important;\n  }\n  tr.visible-lg.visible-md {\n    display: table-row !important;\n  }\n  th.visible-lg.visible-md,\n  td.visible-lg.visible-md {\n    display: table-cell !important;\n  }\n}\n@media (min-width: 1200px) {\n  .visible-lg {\n    display: block !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.hidden-xs {\n  display: block !important;\n}\ntr.hidden-xs {\n  display: table-row !important;\n}\nth.hidden-xs,\ntd.hidden-xs {\n  display: table-cell !important;\n}\n@media (max-width: 767px) {\n  .hidden-xs,\n  tr.hidden-xs,\n  th.hidden-xs,\n  td.hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-xs.hidden-sm,\n  tr.hidden-xs.hidden-sm,\n  th.hidden-xs.hidden-sm,\n  td.hidden-xs.hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-xs.hidden-md,\n  tr.hidden-xs.hidden-md,\n  th.hidden-xs.hidden-md,\n  td.hidden-xs.hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-xs.hidden-lg,\n  tr.hidden-xs.hidden-lg,\n  th.hidden-xs.hidden-lg,\n  td.hidden-xs.hidden-lg {\n    display: none !important;\n  }\n}\n.hidden-sm {\n  display: block !important;\n}\ntr.hidden-sm {\n  display: table-row !important;\n}\nth.hidden-sm,\ntd.hidden-sm {\n  display: table-cell !important;\n}\n@media (max-width: 767px) {\n  .hidden-sm.hidden-xs,\n  tr.hidden-sm.hidden-xs,\n  th.hidden-sm.hidden-xs,\n  td.hidden-sm.hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-sm,\n  tr.hidden-sm,\n  th.hidden-sm,\n  td.hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-sm.hidden-md,\n  tr.hidden-sm.hidden-md,\n  th.hidden-sm.hidden-md,\n  td.hidden-sm.hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-sm.hidden-lg,\n  tr.hidden-sm.hidden-lg,\n  th.hidden-sm.hidden-lg,\n  td.hidden-sm.hidden-lg {\n    display: none !important;\n  }\n}\n.hidden-md {\n  display: block !important;\n}\ntr.hidden-md {\n  display: table-row !important;\n}\nth.hidden-md,\ntd.hidden-md {\n  display: table-cell !important;\n}\n@media (max-width: 767px) {\n  .hidden-md.hidden-xs,\n  tr.hidden-md.hidden-xs,\n  th.hidden-md.hidden-xs,\n  td.hidden-md.hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-md.hidden-sm,\n  tr.hidden-md.hidden-sm,\n  th.hidden-md.hidden-sm,\n  td.hidden-md.hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-md,\n  tr.hidden-md,\n  th.hidden-md,\n  td.hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-md.hidden-lg,\n  tr.hidden-md.hidden-lg,\n  th.hidden-md.hidden-lg,\n  td.hidden-md.hidden-lg {\n    display: none !important;\n  }\n}\n.hidden-lg {\n  display: block !important;\n}\ntr.hidden-lg {\n  display: table-row !important;\n}\nth.hidden-lg,\ntd.hidden-lg {\n  display: table-cell !important;\n}\n@media (max-width: 767px) {\n  .hidden-lg.hidden-xs,\n  tr.hidden-lg.hidden-xs,\n  th.hidden-lg.hidden-xs,\n  td.hidden-lg.hidden-xs {\n    display: none !important;\n  }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n  .hidden-lg.hidden-sm,\n  tr.hidden-lg.hidden-sm,\n  th.hidden-lg.hidden-sm,\n  td.hidden-lg.hidden-sm {\n    display: none !important;\n  }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n  .hidden-lg.hidden-md,\n  tr.hidden-lg.hidden-md,\n  th.hidden-lg.hidden-md,\n  td.hidden-lg.hidden-md {\n    display: none !important;\n  }\n}\n@media (min-width: 1200px) {\n  .hidden-lg,\n  tr.hidden-lg,\n  th.hidden-lg,\n  td.hidden-lg {\n    display: none !important;\n  }\n}\n.visible-print,\ntr.visible-print,\nth.visible-print,\ntd.visible-print {\n  display: none !important;\n}\n@media print {\n  .visible-print {\n    display: block !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  .hidden-print,\n  tr.hidden-print,\n  th.hidden-print,\n  td.hidden-print {\n    display: none !important;\n  }\n}\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/summernote/dist/summernote-updated.js",
    "content": "/**\n * Super simple wysiwyg editor on Bootstrap v0.6.16\n * http://summernote.org/\n *\n * summernote.js\n * Copyright 2013-2015 Alan Hong. and other contributors\n * summernote may be freely distributed under the MIT license./\n *\n * Date: 2015-08-03T16:41Z\n */\n(function (factory) {\n  /* global define */\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module.\n    define(['jquery'], factory);\n  } else {\n    // Browser globals: jQuery\n    factory(window.jQuery);\n  }\n}(function ($) {\n  \n\n\n  if (!Array.prototype.reduce) {\n    /**\n     * Array.prototype.reduce polyfill\n     *\n     * @param {Function} callback\n     * @param {Value} [initialValue]\n     * @return {Value}\n     *\n     * @see http://goo.gl/WNriQD\n     */\n    Array.prototype.reduce = function (callback) {\n      var t = Object(this), len = t.length >>> 0, k = 0, value;\n      if (arguments.length === 2) {\n        value = arguments[1];\n      } else {\n        while (k < len && !(k in t)) {\n          k++;\n        }\n        if (k >= len) {\n          throw new TypeError('Reduce of empty array with no initial value');\n        }\n        value = t[k++];\n      }\n      for (; k < len; k++) {\n        if (k in t) {\n          value = callback(value, t[k], k, t);\n        }\n      }\n      return value;\n    };\n  }\n\n  if ('function' !== typeof Array.prototype.filter) {\n    /**\n     * Array.prototype.filter polyfill\n     *\n     * @param {Function} func\n     * @return {Array}\n     *\n     * @see http://goo.gl/T1KFnq\n     */\n    Array.prototype.filter = function (func) {\n      var t = Object(this), len = t.length >>> 0;\n\n      var res = [];\n      var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n      for (var i = 0; i < len; i++) {\n        if (i in t) {\n          var val = t[i];\n          if (func.call(thisArg, val, i, t)) {\n            res.push(val);\n          }\n        }\n      }\n  \n      return res;\n    };\n  }\n\n  if (!Array.prototype.map) {\n    /**\n     * Array.prototype.map polyfill\n     *\n     * @param {Function} callback\n     * @return {Array}\n     *\n     * @see https://goo.gl/SMWaMK\n     */\n    Array.prototype.map = function (callback, thisArg) {\n      var T, A, k;\n      if (this === null) {\n        throw new TypeError(' this is null or not defined');\n      }\n\n      var O = Object(this);\n      var len = O.length >>> 0;\n      if (typeof callback !== 'function') {\n        throw new TypeError(callback + ' is not a function');\n      }\n  \n      if (arguments.length > 1) {\n        T = thisArg;\n      }\n  \n      A = new Array(len);\n      k = 0;\n  \n      while (k < len) {\n        var kValue, mappedValue;\n        if (k in O) {\n          kValue = O[k];\n          mappedValue = callback.call(T, kValue, k, O);\n          A[k] = mappedValue;\n        }\n        k++;\n      }\n      return A;\n    };\n  }\n\n  var isSupportAmd = typeof define === 'function' && define.amd;\n\n  /**\n   * returns whether font is installed or not.\n   *\n   * @param {String} fontName\n   * @return {Boolean}\n   */\n  var isFontInstalled = function (fontName) {\n    var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';\n    var $tester = $('<div>').css({\n      position: 'absolute',\n      left: '-9999px',\n      top: '-9999px',\n      fontSize: '200px'\n    }).text('mmmmmmmmmwwwwwww').appendTo(document.body);\n\n    var originalWidth = $tester.css('fontFamily', testFontName).width();\n    var width = $tester.css('fontFamily', fontName + ',' + testFontName).width();\n\n    $tester.remove();\n\n    return originalWidth !== width;\n  };\n\n  var userAgent = navigator.userAgent;\n  var isMSIE = /MSIE|Trident/i.test(userAgent);\n  var browserVersion;\n  if (isMSIE) {\n    var matches = /MSIE (\\d+[.]\\d+)/.exec(userAgent);\n    if (matches) {\n      browserVersion = parseFloat(matches[1]);\n    }\n    matches = /Trident\\/.*rv:([0-9]{1,}[\\.0-9]{0,})/.exec(userAgent);\n    if (matches) {\n      browserVersion = parseFloat(matches[1]);\n    }\n  }\n\n  /**\n   * @class core.agent\n   *\n   * Object which check platform and agent\n   *\n   * @singleton\n   * @alternateClassName agent\n   */\n  var agent = {\n    /** @property {Boolean} [isMac=false] true if this agent is Mac  */\n    isMac: navigator.appVersion.indexOf('Mac') > -1,\n    /** @property {Boolean} [isMSIE=false] true if this agent is a Internet Explorer  */\n    isMSIE: isMSIE,\n    /** @property {Boolean} [isFF=false] true if this agent is a Firefox  */\n    isFF: /firefox/i.test(userAgent),\n    isWebkit: /webkit/i.test(userAgent),\n    /** @property {Boolean} [isSafari=false] true if this agent is a Safari  */\n    isSafari: /safari/i.test(userAgent),\n    /** @property {Float} browserVersion current browser version  */\n    browserVersion: browserVersion,\n    /** @property {String} jqueryVersion current jQuery version string  */\n    jqueryVersion: parseFloat($.fn.jquery),\n    isSupportAmd: isSupportAmd,\n    hasCodeMirror: isSupportAmd ? require.specified('CodeMirror') : !!window.CodeMirror,\n    isFontInstalled: isFontInstalled,\n    isW3CRangeSupport: !!document.createRange\n  };\n\n  /**\n   * @class core.func\n   *\n   * func utils (for high-order func's arg)\n   *\n   * @singleton\n   * @alternateClassName func\n   */\n  var func = (function () {\n    var eq = function (itemA) {\n      return function (itemB) {\n        return itemA === itemB;\n      };\n    };\n\n    var eq2 = function (itemA, itemB) {\n      return itemA === itemB;\n    };\n\n    var peq2 = function (propName) {\n      return function (itemA, itemB) {\n        return itemA[propName] === itemB[propName];\n      };\n    };\n\n    var ok = function () {\n      return true;\n    };\n\n    var fail = function () {\n      return false;\n    };\n\n    var not = function (f) {\n      return function () {\n        return !f.apply(f, arguments);\n      };\n    };\n\n    var and = function (fA, fB) {\n      return function (item) {\n        return fA(item) && fB(item);\n      };\n    };\n\n    var self = function (a) {\n      return a;\n    };\n\n    var idCounter = 0;\n\n    /**\n     * generate a globally-unique id\n     *\n     * @param {String} [prefix]\n     */\n    var uniqueId = function (prefix) {\n      var id = ++idCounter + '';\n      return prefix ? prefix + id : id;\n    };\n\n    /**\n     * returns bnd (bounds) from rect\n     *\n     * - IE Compatability Issue: http://goo.gl/sRLOAo\n     * - Scroll Issue: http://goo.gl/sNjUc\n     *\n     * @param {Rect} rect\n     * @return {Object} bounds\n     * @return {Number} bounds.top\n     * @return {Number} bounds.left\n     * @return {Number} bounds.width\n     * @return {Number} bounds.height\n     */\n    var rect2bnd = function (rect) {\n      var $document = $(document);\n      return {\n        top: rect.top + $document.scrollTop(),\n        left: rect.left + $document.scrollLeft(),\n        width: rect.right - rect.left,\n        height: rect.bottom - rect.top\n      };\n    };\n\n    /**\n     * returns a copy of the object where the keys have become the values and the values the keys.\n     * @param {Object} obj\n     * @return {Object}\n     */\n    var invertObject = function (obj) {\n      var inverted = {};\n      for (var key in obj) {\n        if (obj.hasOwnProperty(key)) {\n          inverted[obj[key]] = key;\n        }\n      }\n      return inverted;\n    };\n\n    /**\n     * @param {String} namespace\n     * @param {String} [prefix]\n     * @return {String}\n     */\n    var namespaceToCamel = function (namespace, prefix) {\n      prefix = prefix || '';\n      return prefix + namespace.split('.').map(function (name) {\n        return name.substring(0, 1).toUpperCase() + name.substring(1);\n      }).join('');\n    };\n\n    return {\n      eq: eq,\n      eq2: eq2,\n      peq2: peq2,\n      ok: ok,\n      fail: fail,\n      self: self,\n      not: not,\n      and: and,\n      uniqueId: uniqueId,\n      rect2bnd: rect2bnd,\n      invertObject: invertObject,\n      namespaceToCamel: namespaceToCamel\n    };\n  })();\n\n  /**\n   * @class core.list\n   *\n   * list utils\n   *\n   * @singleton\n   * @alternateClassName list\n   */\n  var list = (function () {\n    /**\n     * returns the first item of an array.\n     *\n     * @param {Array} array\n     */\n    var head = function (array) {\n      return array[0];\n    };\n\n    /**\n     * returns the last item of an array.\n     *\n     * @param {Array} array\n     */\n    var last = function (array) {\n      return array[array.length - 1];\n    };\n\n    /**\n     * returns everything but the last entry of the array.\n     *\n     * @param {Array} array\n     */\n    var initial = function (array) {\n      return array.slice(0, array.length - 1);\n    };\n\n    /**\n     * returns the rest of the items in an array.\n     *\n     * @param {Array} array\n     */\n    var tail = function (array) {\n      return array.slice(1);\n    };\n\n    /**\n     * returns item of array\n     */\n    var find = function (array, pred) {\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        var item = array[idx];\n        if (pred(item)) {\n          return item;\n        }\n      }\n    };\n\n    /**\n     * returns true if all of the values in the array pass the predicate truth test.\n     */\n    var all = function (array, pred) {\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (!pred(array[idx])) {\n          return false;\n        }\n      }\n      return true;\n    };\n\n    /**\n     * returns index of item\n     */\n    var indexOf = function (array, item) {\n      return $.inArray(item, array);\n    };\n\n    /**\n     * returns true if the value is present in the list.\n     */\n    var contains = function (array, item) {\n      return indexOf(array, item) !== -1;\n    };\n\n    /**\n     * get sum from a list\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - iterator\n     */\n    var sum = function (array, fn) {\n      fn = fn || func.self;\n      return array.reduce(function (memo, v) {\n        return memo + fn(v);\n      }, 0);\n    };\n  \n    /**\n     * returns a copy of the collection with array type.\n     * @param {Collection} collection - collection eg) node.childNodes, ...\n     */\n    var from = function (collection) {\n      var result = [], idx = -1, length = collection.length;\n      while (++idx < length) {\n        result[idx] = collection[idx];\n      }\n      return result;\n    };\n  \n    /**\n     * cluster elements by predicate function.\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - predicate function for cluster rule\n     * @param {Array[]}\n     */\n    var clusterBy = function (array, fn) {\n      if (!array.length) { return []; }\n      var aTail = tail(array);\n      return aTail.reduce(function (memo, v) {\n        var aLast = last(memo);\n        if (fn(last(aLast), v)) {\n          aLast[aLast.length] = v;\n        } else {\n          memo[memo.length] = [v];\n        }\n        return memo;\n      }, [[head(array)]]);\n    };\n  \n    /**\n     * returns a copy of the array with all falsy values removed\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - predicate function for cluster rule\n     */\n    var compact = function (array) {\n      var aResult = [];\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (array[idx]) { aResult.push(array[idx]); }\n      }\n      return aResult;\n    };\n\n    /**\n     * produces a duplicate-free version of the array\n     *\n     * @param {Array} array\n     */\n    var unique = function (array) {\n      var results = [];\n\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (!contains(results, array[idx])) {\n          results.push(array[idx]);\n        }\n      }\n\n      return results;\n    };\n\n    /**\n     * returns next item.\n     * @param {Array} array\n     */\n    var next = function (array, item) {\n      var idx = indexOf(array, item);\n      if (idx === -1) { return null; }\n\n      return array[idx + 1];\n    };\n\n    /**\n     * returns prev item.\n     * @param {Array} array\n     */\n    var prev = function (array, item) {\n      var idx = indexOf(array, item);\n      if (idx === -1) { return null; }\n\n      return array[idx - 1];\n    };\n  \n    return { head: head, last: last, initial: initial, tail: tail,\n             prev: prev, next: next, find: find, contains: contains,\n             all: all, sum: sum, from: from,\n             clusterBy: clusterBy, compact: compact, unique: unique };\n  })();\n\n\n  var NBSP_CHAR = String.fromCharCode(160);\n  var ZERO_WIDTH_NBSP_CHAR = '\\ufeff';\n\n  /**\n   * @class core.dom\n   *\n   * Dom functions\n   *\n   * @singleton\n   * @alternateClassName dom\n   */\n  var dom = (function () {\n    /**\n     * @method isEditable\n     *\n     * returns whether node is `note-editable` or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isEditable = function (node) {\n      return node && $(node).hasClass('note-editable');\n    };\n\n    /**\n     * @method isControlSizing\n     *\n     * returns whether node is `note-control-sizing` or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isControlSizing = function (node) {\n      return node && $(node).hasClass('note-control-sizing');\n    };\n\n    /**\n     * @method  buildLayoutInfo\n     *\n     * build layoutInfo from $editor(.note-editor)\n     *\n     * @param {jQuery} $editor\n     * @return {Object}\n     * @return {Function} return.editor\n     * @return {Node} return.dropzone\n     * @return {Node} return.toolbar\n     * @return {Node} return.editable\n     * @return {Node} return.codable\n     * @return {Node} return.popover\n     * @return {Node} return.handle\n     * @return {Node} return.dialog\n     */\n    var buildLayoutInfo = function ($editor) {\n      var makeFinder;\n\n      // air mode\n      if ($editor.hasClass('note-air-editor')) {\n        var id = list.last($editor.attr('id').split('-'));\n        makeFinder = function (sIdPrefix) {\n          return function () { return $(sIdPrefix + id); };\n        };\n\n        return {\n          editor: function () { return $editor; },\n          holder : function () { return $editor.data('holder'); },\n          editable: function () { return $editor; },\n          popover: makeFinder('#note-popover-'),\n          handle: makeFinder('#note-handle-'),\n          dialog: makeFinder('#note-dialog-')\n        };\n\n        // frame mode\n      } else {\n        makeFinder = function (className, $base) {\n          $base = $base || $editor;\n          return function () { return $base.find(className); };\n        };\n\n        var options = $editor.data('options');\n        var $dialogHolder = (options && options.dialogsInBody) ? $(document.body) : null;\n\n        return {\n          editor: function () { return $editor; },\n          holder : function () { return $editor.data('holder'); },\n          dropzone: makeFinder('.note-dropzone'),\n          toolbar: makeFinder('.note-toolbar'),\n          editable: makeFinder('.note-editable'),\n          codable: makeFinder('.note-codable'),\n          statusbar: makeFinder('.note-statusbar'),\n          popover: makeFinder('.note-popover'),\n          handle: makeFinder('.note-handle'),\n          dialog: makeFinder('.note-dialog', $dialogHolder)\n        };\n      }\n    };\n\n    /**\n     * returns makeLayoutInfo from editor's descendant node.\n     *\n     * @private\n     * @param {Node} descendant\n     * @return {Object}\n     */\n    var makeLayoutInfo = function (descendant) {\n      var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout');\n\n      if (!$target.length) {\n        return null;\n      }\n\n      var $editor;\n      if ($target.is('.note-editor, .note-air-editor')) {\n        $editor = $target;\n      } else {\n        $editor = $('#note-editor-' + list.last($target.attr('id').split('-')));\n      }\n\n      return buildLayoutInfo($editor);\n    };\n\n    /**\n     * @method makePredByNodeName\n     *\n     * returns predicate which judge whether nodeName is same\n     *\n     * @param {String} nodeName\n     * @return {Function}\n     */\n    var makePredByNodeName = function (nodeName) {\n      nodeName = nodeName.toUpperCase();\n      return function (node) {\n        return node && node.nodeName.toUpperCase() === nodeName;\n      };\n    };\n\n    /**\n     * @method isText\n     *\n     *\n     *\n     * @param {Node} node\n     * @return {Boolean} true if node's type is text(3)\n     */\n    var isText = function (node) {\n      return node && node.nodeType === 3;\n    };\n\n    /**\n     * ex) br, col, embed, hr, img, input, ...\n     * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements\n     */\n    var isVoid = function (node) {\n      return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON/.test(node.nodeName.toUpperCase());\n    };\n\n    var isPara = function (node) {\n      if (isEditable(node)) {\n        return false;\n      }\n\n      // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph\n      return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());\n    };\n\n    var isLi = makePredByNodeName('LI');\n\n    var isPurePara = function (node) {\n      return isPara(node) && !isLi(node);\n    };\n\n    var isTable = makePredByNodeName('TABLE');\n\n    var isInline = function (node) {\n      return !isBodyContainer(node) &&\n             !isList(node) &&\n             !isHr(node) &&\n             !isPara(node) &&\n             !isTable(node) &&\n             !isBlockquote(node);\n    };\n\n    var isList = function (node) {\n      return node && /^UL|^OL/.test(node.nodeName.toUpperCase());\n    };\n\n    var isHr = makePredByNodeName('HR');\n\n    var isCell = function (node) {\n      return node && /^TD|^TH/.test(node.nodeName.toUpperCase());\n    };\n\n    var isBlockquote = makePredByNodeName('BLOCKQUOTE');\n\n    var isBodyContainer = function (node) {\n      return isCell(node) || isBlockquote(node) || isEditable(node);\n    };\n\n    var isAnchor = makePredByNodeName('A');\n\n    var isParaInline = function (node) {\n      return isInline(node) && !!ancestor(node, isPara);\n    };\n\n    var isBodyInline = function (node) {\n      return isInline(node) && !ancestor(node, isPara);\n    };\n\n    var isBody = makePredByNodeName('BODY');\n\n    /**\n     * returns whether nodeB is closest sibling of nodeA\n     *\n     * @param {Node} nodeA\n     * @param {Node} nodeB\n     * @return {Boolean}\n     */\n    var isClosestSibling = function (nodeA, nodeB) {\n      return nodeA.nextSibling === nodeB ||\n             nodeA.previousSibling === nodeB;\n    };\n\n    /**\n     * returns array of closest siblings with node\n     *\n     * @param {Node} node\n     * @param {function} [pred] - predicate function\n     * @return {Node[]}\n     */\n    var withClosestSiblings = function (node, pred) {\n      pred = pred || func.ok;\n\n      var siblings = [];\n      if (node.previousSibling && pred(node.previousSibling)) {\n        siblings.push(node.previousSibling);\n      }\n      siblings.push(node);\n      if (node.nextSibling && pred(node.nextSibling)) {\n        siblings.push(node.nextSibling);\n      }\n      return siblings;\n    };\n\n    /**\n     * blank HTML for cursor position\n     * - [workaround] old IE only works with &nbsp;\n     * - [workaround] IE11 and other browser works with bogus br\n     */\n    var blankHTML = agent.isMSIE && agent.browserVersion < 11 ? '&nbsp;' : '<br>';\n\n    /**\n     * @method nodeLength\n     *\n     * returns #text's text size or element's childNodes size\n     *\n     * @param {Node} node\n     */\n    var nodeLength = function (node) {\n      if (isText(node)) {\n        return node.nodeValue.length;\n      }\n\n      return node.childNodes.length;\n    };\n\n    /**\n     * returns whether node is empty or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isEmpty = function (node) {\n      var len = nodeLength(node);\n\n      if (len === 0) {\n        return true;\n      } else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) {\n        // ex) <p><br></p>, <span><br></span>\n        return true;\n      } else if (list.all(node.childNodes, isText) && node.innerHTML === '') {\n        // ex) <p></p>, <span></span>\n        return true;\n      }\n\n      return false;\n    };\n\n    /**\n     * padding blankHTML if node is empty (for cursor position)\n     */\n    var paddingBlankHTML = function (node) {\n      if (!isVoid(node) && !nodeLength(node)) {\n        node.innerHTML = blankHTML;\n      }\n    };\n\n    /**\n     * find nearest ancestor predicate hit\n     *\n     * @param {Node} node\n     * @param {Function} pred - predicate function\n     */\n    var ancestor = function (node, pred) {\n      while (node) {\n        if (pred(node)) { return node; }\n        if (isEditable(node)) { break; }\n\n        node = node.parentNode;\n      }\n      return null;\n    };\n\n    /**\n     * find nearest ancestor only single child blood line and predicate hit\n     *\n     * @param {Node} node\n     * @param {Function} pred - predicate function\n     */\n    var singleChildAncestor = function (node, pred) {\n      node = node.parentNode;\n\n      while (node) {\n        if (nodeLength(node) !== 1) { break; }\n        if (pred(node)) { return node; }\n        if (isEditable(node)) { break; }\n\n        node = node.parentNode;\n      }\n      return null;\n    };\n\n    /**\n     * returns new array of ancestor nodes (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [optional] pred - predicate function\n     */\n    var listAncestor = function (node, pred) {\n      pred = pred || func.fail;\n\n      var ancestors = [];\n      ancestor(node, function (el) {\n        if (!isEditable(el)) {\n          ancestors.push(el);\n        }\n\n        return pred(el);\n      });\n      return ancestors;\n    };\n\n    /**\n     * find farthest ancestor predicate hit\n     */\n    var lastAncestor = function (node, pred) {\n      var ancestors = listAncestor(node);\n      return list.last(ancestors.filter(pred));\n    };\n\n    /**\n     * returns common ancestor node between two nodes.\n     *\n     * @param {Node} nodeA\n     * @param {Node} nodeB\n     */\n    var commonAncestor = function (nodeA, nodeB) {\n      var ancestors = listAncestor(nodeA);\n      for (var n = nodeB; n; n = n.parentNode) {\n        if ($.inArray(n, ancestors) > -1) { return n; }\n      }\n      return null; // difference document area\n    };\n\n    /**\n     * listing all previous siblings (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [optional] pred - predicate function\n     */\n    var listPrev = function (node, pred) {\n      pred = pred || func.fail;\n\n      var nodes = [];\n      while (node) {\n        if (pred(node)) { break; }\n        nodes.push(node);\n        node = node.previousSibling;\n      }\n      return nodes;\n    };\n\n    /**\n     * listing next siblings (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [pred] - predicate function\n     */\n    var listNext = function (node, pred) {\n      pred = pred || func.fail;\n\n      var nodes = [];\n      while (node) {\n        if (pred(node)) { break; }\n        nodes.push(node);\n        node = node.nextSibling;\n      }\n      return nodes;\n    };\n\n    /**\n     * listing descendant nodes\n     *\n     * @param {Node} node\n     * @param {Function} [pred] - predicate function\n     */\n    var listDescendant = function (node, pred) {\n      var descendents = [];\n      pred = pred || func.ok;\n\n      // start DFS(depth first search) with node\n      (function fnWalk(current) {\n        if (node !== current && pred(current)) {\n          descendents.push(current);\n        }\n        for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {\n          fnWalk(current.childNodes[idx]);\n        }\n      })(node);\n\n      return descendents;\n    };\n\n    /**\n     * wrap node with new tag.\n     *\n     * @param {Node} node\n     * @param {Node} tagName of wrapper\n     * @return {Node} - wrapper\n     */\n    var wrap = function (node, wrapperName) {\n      var parent = node.parentNode;\n      var wrapper = $('<' + wrapperName + '>')[0];\n\n      parent.insertBefore(wrapper, node);\n      wrapper.appendChild(node);\n\n      return wrapper;\n    };\n\n    /**\n     * insert node after preceding\n     *\n     * @param {Node} node\n     * @param {Node} preceding - predicate function\n     */\n    var insertAfter = function (node, preceding) {\n      var next = preceding.nextSibling, parent = preceding.parentNode;\n      if (next) {\n        parent.insertBefore(node, next);\n      } else {\n        parent.appendChild(node);\n      }\n      return node;\n    };\n\n    /**\n     * append elements.\n     *\n     * @param {Node} node\n     * @param {Collection} aChild\n     */\n    var appendChildNodes = function (node, aChild) {\n      $.each(aChild, function (idx, child) {\n        node.appendChild(child);\n      });\n      return node;\n    };\n\n    /**\n     * returns whether boundaryPoint is left edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isLeftEdgePoint = function (point) {\n      return point.offset === 0;\n    };\n\n    /**\n     * returns whether boundaryPoint is right edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isRightEdgePoint = function (point) {\n      return point.offset === nodeLength(point.node);\n    };\n\n    /**\n     * returns whether boundaryPoint is edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isEdgePoint = function (point) {\n      return isLeftEdgePoint(point) || isRightEdgePoint(point);\n    };\n\n    /**\n     * returns wheter node is left edge of ancestor or not.\n     *\n     * @param {Node} node\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isLeftEdgeOf = function (node, ancestor) {\n      while (node && node !== ancestor) {\n        if (position(node) !== 0) {\n          return false;\n        }\n        node = node.parentNode;\n      }\n\n      return true;\n    };\n\n    /**\n     * returns whether node is right edge of ancestor or not.\n     *\n     * @param {Node} node\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isRightEdgeOf = function (node, ancestor) {\n      while (node && node !== ancestor) {\n        if (position(node) !== nodeLength(node.parentNode) - 1) {\n          return false;\n        }\n        node = node.parentNode;\n      }\n\n      return true;\n    };\n\n    /**\n     * returns whether point is left edge of ancestor or not.\n     * @param {BoundaryPoint} point\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isLeftEdgePointOf = function (point, ancestor) {\n      return isLeftEdgePoint(point) && isLeftEdgeOf(point.node, ancestor);\n    };\n\n    /**\n     * returns whether point is right edge of ancestor or not.\n     * @param {BoundaryPoint} point\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isRightEdgePointOf = function (point, ancestor) {\n      return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor);\n    };\n\n    /**\n     * returns offset from parent.\n     *\n     * @param {Node} node\n     */\n    var position = function (node) {\n      var offset = 0;\n      while ((node = node.previousSibling)) {\n        offset += 1;\n      }\n      return offset;\n    };\n\n    var hasChildren = function (node) {\n      return !!(node && node.childNodes && node.childNodes.length);\n    };\n\n    /**\n     * returns previous boundaryPoint\n     *\n     * @param {BoundaryPoint} point\n     * @param {Boolean} isSkipInnerOffset\n     * @return {BoundaryPoint}\n     */\n    var prevPoint = function (point, isSkipInnerOffset) {\n      var node, offset;\n\n      if (point.offset === 0) {\n        if (isEditable(point.node)) {\n          return null;\n        }\n\n        node = point.node.parentNode;\n        offset = position(point.node);\n      } else if (hasChildren(point.node)) {\n        node = point.node.childNodes[point.offset - 1];\n        offset = nodeLength(node);\n      } else {\n        node = point.node;\n        offset = isSkipInnerOffset ? 0 : point.offset - 1;\n      }\n\n      return {\n        node: node,\n        offset: offset\n      };\n    };\n\n    /**\n     * returns next boundaryPoint\n     *\n     * @param {BoundaryPoint} point\n     * @param {Boolean} isSkipInnerOffset\n     * @return {BoundaryPoint}\n     */\n    var nextPoint = function (point, isSkipInnerOffset) {\n      var node, offset;\n\n      if (nodeLength(point.node) === point.offset) {\n        if (isEditable(point.node)) {\n          return null;\n        }\n\n        node = point.node.parentNode;\n        offset = position(point.node) + 1;\n      } else if (hasChildren(point.node)) {\n        node = point.node.childNodes[point.offset];\n        offset = 0;\n      } else {\n        node = point.node;\n        offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;\n      }\n\n      return {\n        node: node,\n        offset: offset\n      };\n    };\n\n    /**\n     * returns whether pointA and pointB is same or not.\n     *\n     * @param {BoundaryPoint} pointA\n     * @param {BoundaryPoint} pointB\n     * @return {Boolean}\n     */\n    var isSamePoint = function (pointA, pointB) {\n      return pointA.node === pointB.node && pointA.offset === pointB.offset;\n    };\n\n    /**\n     * returns whether point is visible (can set cursor) or not.\n     * \n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isVisiblePoint = function (point) {\n      if (isText(point.node) || !hasChildren(point.node) || isEmpty(point.node)) {\n        return true;\n      }\n\n      var leftNode = point.node.childNodes[point.offset - 1];\n      var rightNode = point.node.childNodes[point.offset];\n      if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) {\n        return true;\n      }\n\n      return false;\n    };\n\n    /**\n     * @method prevPointUtil\n     *\n     * @param {BoundaryPoint} point\n     * @param {Function} pred\n     * @return {BoundaryPoint}\n     */\n    var prevPointUntil = function (point, pred) {\n      while (point) {\n        if (pred(point)) {\n          return point;\n        }\n\n        point = prevPoint(point);\n      }\n\n      return null;\n    };\n\n    /**\n     * @method nextPointUntil\n     *\n     * @param {BoundaryPoint} point\n     * @param {Function} pred\n     * @return {BoundaryPoint}\n     */\n    var nextPointUntil = function (point, pred) {\n      while (point) {\n        if (pred(point)) {\n          return point;\n        }\n\n        point = nextPoint(point);\n      }\n\n      return null;\n    };\n\n    /**\n     * returns whether point has character or not.\n     *\n     * @param {Point} point\n     * @return {Boolean}\n     */\n    var isCharPoint = function (point) {\n      if (!isText(point.node)) {\n        return false;\n      }\n\n      var ch = point.node.nodeValue.charAt(point.offset - 1);\n      return ch && (ch !== ' ' && ch !== NBSP_CHAR);\n    };\n\n    /**\n     * @method walkPoint\n     *\n     * @param {BoundaryPoint} startPoint\n     * @param {BoundaryPoint} endPoint\n     * @param {Function} handler\n     * @param {Boolean} isSkipInnerOffset\n     */\n    var walkPoint = function (startPoint, endPoint, handler, isSkipInnerOffset) {\n      var point = startPoint;\n\n      while (point) {\n        handler(point);\n\n        if (isSamePoint(point, endPoint)) {\n          break;\n        }\n\n        var isSkipOffset = isSkipInnerOffset &&\n                           startPoint.node !== point.node &&\n                           endPoint.node !== point.node;\n        point = nextPoint(point, isSkipOffset);\n      }\n    };\n\n    /**\n     * @method makeOffsetPath\n     *\n     * return offsetPath(array of offset) from ancestor\n     *\n     * @param {Node} ancestor - ancestor node\n     * @param {Node} node\n     */\n    var makeOffsetPath = function (ancestor, node) {\n      var ancestors = listAncestor(node, func.eq(ancestor));\n      return ancestors.map(position).reverse();\n    };\n\n    /**\n     * @method fromOffsetPath\n     *\n     * return element from offsetPath(array of offset)\n     *\n     * @param {Node} ancestor - ancestor node\n     * @param {array} offsets - offsetPath\n     */\n    var fromOffsetPath = function (ancestor, offsets) {\n      var current = ancestor;\n      for (var i = 0, len = offsets.length; i < len; i++) {\n        if (current.childNodes.length <= offsets[i]) {\n          current = current.childNodes[current.childNodes.length - 1];\n        } else {\n          current = current.childNodes[offsets[i]];\n        }\n      }\n      return current;\n    };\n\n    /**\n     * @method splitNode\n     *\n     * split element or #text\n     *\n     * @param {BoundaryPoint} point\n     * @param {Object} [options]\n     * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false\n     * @param {Boolean} [options.isNotSplitEdgePoint] - default: false\n     * @return {Node} right node of boundaryPoint\n     */\n    var splitNode = function (point, options) {\n      var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;\n      var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;\n\n      // edge case\n      if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {\n        if (isLeftEdgePoint(point)) {\n          return point.node;\n        } else if (isRightEdgePoint(point)) {\n          return point.node.nextSibling;\n        }\n      }\n\n      // split #text\n      if (isText(point.node)) {\n        return point.node.splitText(point.offset);\n      } else {\n        var childNode = point.node.childNodes[point.offset];\n        var clone = insertAfter(point.node.cloneNode(false), point.node);\n        appendChildNodes(clone, listNext(childNode));\n\n        if (!isSkipPaddingBlankHTML) {\n          paddingBlankHTML(point.node);\n          paddingBlankHTML(clone);\n        }\n\n        return clone;\n      }\n    };\n\n    /**\n     * @method splitTree\n     *\n     * split tree by point\n     *\n     * @param {Node} root - split root\n     * @param {BoundaryPoint} point\n     * @param {Object} [options]\n     * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false\n     * @param {Boolean} [options.isNotSplitEdgePoint] - default: false\n     * @return {Node} right node of boundaryPoint\n     */\n    var splitTree = function (root, point, options) {\n      // ex) [#text, <span>, <p>]\n      var ancestors = listAncestor(point.node, func.eq(root));\n\n      if (!ancestors.length) {\n        return null;\n      } else if (ancestors.length === 1) {\n        return splitNode(point, options);\n      }\n\n      return ancestors.reduce(function (node, parent) {\n        if (node === point.node) {\n          node = splitNode(point, options);\n        }\n\n        return splitNode({\n          node: parent,\n          offset: node ? dom.position(node) : nodeLength(parent)\n        }, options);\n      });\n    };\n\n    /**\n     * split point\n     *\n     * @param {Point} point\n     * @param {Boolean} isInline\n     * @return {Object}\n     */\n    var splitPoint = function (point, isInline) {\n      // find splitRoot, container\n      //  - inline: splitRoot is a child of paragraph\n      //  - block: splitRoot is a child of bodyContainer\n      var pred = isInline ? isPara : isBodyContainer;\n      var ancestors = listAncestor(point.node, pred);\n      var topAncestor = list.last(ancestors) || point.node;\n\n      var splitRoot, container;\n      if (pred(topAncestor)) {\n        splitRoot = ancestors[ancestors.length - 2];\n        container = topAncestor;\n      } else {\n        splitRoot = topAncestor;\n        container = splitRoot.parentNode;\n      }\n\n      // if splitRoot is exists, split with splitTree\n      var pivot = splitRoot && splitTree(splitRoot, point, {\n        isSkipPaddingBlankHTML: isInline,\n        isNotSplitEdgePoint: isInline\n      });\n\n      // if container is point.node, find pivot with point.offset\n      if (!pivot && container === point.node) {\n        pivot = point.node.childNodes[point.offset];\n      }\n\n      return {\n        rightNode: pivot,\n        container: container\n      };\n    };\n\n    var create = function (nodeName) {\n      return document.createElement(nodeName);\n    };\n\n    var createText = function (text) {\n      return document.createTextNode(text);\n    };\n\n    /**\n     * @method remove\n     *\n     * remove node, (isRemoveChild: remove child or not)\n     *\n     * @param {Node} node\n     * @param {Boolean} isRemoveChild\n     */\n    var remove = function (node, isRemoveChild) {\n      if (!node || !node.parentNode) { return; }\n      if (node.removeNode) { return node.removeNode(isRemoveChild); }\n\n      var parent = node.parentNode;\n      if (!isRemoveChild) {\n        var nodes = [];\n        var i, len;\n        for (i = 0, len = node.childNodes.length; i < len; i++) {\n          nodes.push(node.childNodes[i]);\n        }\n\n        for (i = 0, len = nodes.length; i < len; i++) {\n          parent.insertBefore(nodes[i], node);\n        }\n      }\n\n      parent.removeChild(node);\n    };\n\n    /**\n     * @method removeWhile\n     *\n     * @param {Node} node\n     * @param {Function} pred\n     */\n    var removeWhile = function (node, pred) {\n      while (node) {\n        if (isEditable(node) || !pred(node)) {\n          break;\n        }\n\n        var parent = node.parentNode;\n        remove(node);\n        node = parent;\n      }\n    };\n\n    /**\n     * @method replace\n     *\n     * replace node with provided nodeName\n     *\n     * @param {Node} node\n     * @param {String} nodeName\n     * @return {Node} - new node\n     */\n    var replace = function (node, nodeName) {\n      if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {\n        return node;\n      }\n\n      var newNode = create(nodeName);\n\n      if (node.style.cssText) {\n        newNode.style.cssText = node.style.cssText;\n      }\n\n      appendChildNodes(newNode, list.from(node.childNodes));\n      insertAfter(newNode, node);\n      remove(node);\n\n      return newNode;\n    };\n\n    var isTextarea = makePredByNodeName('TEXTAREA');\n\n    /**\n     * @param {jQuery} $node\n     * @param {Boolean} [stripLinebreaks] - default: false\n     */\n    var value = function ($node, stripLinebreaks) {\n      var val = isTextarea($node[0]) ? $node.val() : $node.html();\n      if (stripLinebreaks) {\n        return val.replace(/[\\n\\r]/g, '');\n      }\n      return val;\n    };\n\n    /**\n     * @method html\n     *\n     * get the HTML contents of node\n     *\n     * @param {jQuery} $node\n     * @param {Boolean} [isNewlineOnBlock]\n     */\n    var html = function ($node, isNewlineOnBlock) {\n      var markup = value($node);\n\n      if (isNewlineOnBlock) {\n        var regexTag = /<(\\/?)(\\b(?!!)[^>\\s]*)(.*?)(\\s*\\/?>)/g;\n        markup = markup.replace(regexTag, function (match, endSlash, name) {\n          name = name.toUpperCase();\n          var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) &&\n                                       !!endSlash;\n          var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);\n\n          return match + ((isEndOfInlineContainer || isBlockNode) ? '\\n' : '');\n        });\n        markup = $.trim(markup);\n      }\n\n      return markup;\n    };\n\n    return {\n      /** @property {String} NBSP_CHAR */\n      NBSP_CHAR: NBSP_CHAR,\n      /** @property {String} ZERO_WIDTH_NBSP_CHAR */\n      ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,\n      /** @property {String} blank */\n      blank: blankHTML,\n      /** @property {String} emptyPara */\n      emptyPara: '<p>' + blankHTML + '</p>',\n      makePredByNodeName: makePredByNodeName,\n      isEditable: isEditable,\n      isControlSizing: isControlSizing,\n      buildLayoutInfo: buildLayoutInfo,\n      makeLayoutInfo: makeLayoutInfo,\n      isText: isText,\n      isVoid: isVoid,\n      isPara: isPara,\n      isPurePara: isPurePara,\n      isInline: isInline,\n      isBlock: func.not(isInline),\n      isBodyInline: isBodyInline,\n      isBody: isBody,\n      isParaInline: isParaInline,\n      isList: isList,\n      isTable: isTable,\n      isCell: isCell,\n      isBlockquote: isBlockquote,\n      isBodyContainer: isBodyContainer,\n      isAnchor: isAnchor,\n      isDiv: makePredByNodeName('DIV'),\n      isLi: isLi,\n      isBR: makePredByNodeName('BR'),\n      isSpan: makePredByNodeName('SPAN'),\n      isB: makePredByNodeName('B'),\n      isU: makePredByNodeName('U'),\n      isS: makePredByNodeName('S'),\n      isI: makePredByNodeName('I'),\n      isImg: makePredByNodeName('IMG'),\n      isTextarea: isTextarea,\n      isEmpty: isEmpty,\n      isEmptyAnchor: func.and(isAnchor, isEmpty),\n      isClosestSibling: isClosestSibling,\n      withClosestSiblings: withClosestSiblings,\n      nodeLength: nodeLength,\n      isLeftEdgePoint: isLeftEdgePoint,\n      isRightEdgePoint: isRightEdgePoint,\n      isEdgePoint: isEdgePoint,\n      isLeftEdgeOf: isLeftEdgeOf,\n      isRightEdgeOf: isRightEdgeOf,\n      isLeftEdgePointOf: isLeftEdgePointOf,\n      isRightEdgePointOf: isRightEdgePointOf,\n      prevPoint: prevPoint,\n      nextPoint: nextPoint,\n      isSamePoint: isSamePoint,\n      isVisiblePoint: isVisiblePoint,\n      prevPointUntil: prevPointUntil,\n      nextPointUntil: nextPointUntil,\n      isCharPoint: isCharPoint,\n      walkPoint: walkPoint,\n      ancestor: ancestor,\n      singleChildAncestor: singleChildAncestor,\n      listAncestor: listAncestor,\n      lastAncestor: lastAncestor,\n      listNext: listNext,\n      listPrev: listPrev,\n      listDescendant: listDescendant,\n      commonAncestor: commonAncestor,\n      wrap: wrap,\n      insertAfter: insertAfter,\n      appendChildNodes: appendChildNodes,\n      position: position,\n      hasChildren: hasChildren,\n      makeOffsetPath: makeOffsetPath,\n      fromOffsetPath: fromOffsetPath,\n      splitTree: splitTree,\n      splitPoint: splitPoint,\n      create: create,\n      createText: createText,\n      remove: remove,\n      removeWhile: removeWhile,\n      replace: replace,\n      html: html,\n      value: value\n    };\n  })();\n\n\n  var range = (function () {\n\n    /**\n     * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js\n     *\n     * @param {TextRange} textRange\n     * @param {Boolean} isStart\n     * @return {BoundaryPoint}\n     *\n     * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx\n     */\n    var textRangeToPoint = function (textRange, isStart) {\n      var container = textRange.parentElement(), offset;\n  \n      var tester = document.body.createTextRange(), prevContainer;\n      var childNodes = list.from(container.childNodes);\n      for (offset = 0; offset < childNodes.length; offset++) {\n        if (dom.isText(childNodes[offset])) {\n          continue;\n        }\n        tester.moveToElementText(childNodes[offset]);\n        if (tester.compareEndPoints('StartToStart', textRange) >= 0) {\n          break;\n        }\n        prevContainer = childNodes[offset];\n      }\n  \n      if (offset !== 0 && dom.isText(childNodes[offset - 1])) {\n        var textRangeStart = document.body.createTextRange(), curTextNode = null;\n        textRangeStart.moveToElementText(prevContainer || container);\n        textRangeStart.collapse(!prevContainer);\n        curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;\n  \n        var pointTester = textRange.duplicate();\n        pointTester.setEndPoint('StartToStart', textRangeStart);\n        var textCount = pointTester.text.replace(/[\\r\\n]/g, '').length;\n  \n        while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {\n          textCount -= curTextNode.nodeValue.length;\n          curTextNode = curTextNode.nextSibling;\n        }\n  \n        /* jshint ignore:start */\n        var dummy = curTextNode.nodeValue; // enforce IE to re-reference curTextNode, hack\n        /* jshint ignore:end */\n  \n        if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) &&\n            textCount === curTextNode.nodeValue.length) {\n          textCount -= curTextNode.nodeValue.length;\n          curTextNode = curTextNode.nextSibling;\n        }\n  \n        container = curTextNode;\n        offset = textCount;\n      }\n  \n      return {\n        cont: container,\n        offset: offset\n      };\n    };\n    \n    /**\n     * return TextRange from boundary point (inspired by google closure-library)\n     * @param {BoundaryPoint} point\n     * @return {TextRange}\n     */\n    var pointToTextRange = function (point) {\n      var textRangeInfo = function (container, offset) {\n        var node, isCollapseToStart;\n  \n        if (dom.isText(container)) {\n          var prevTextNodes = dom.listPrev(container, func.not(dom.isText));\n          var prevContainer = list.last(prevTextNodes).previousSibling;\n          node =  prevContainer || container.parentNode;\n          offset += list.sum(list.tail(prevTextNodes), dom.nodeLength);\n          isCollapseToStart = !prevContainer;\n        } else {\n          node = container.childNodes[offset] || container;\n          if (dom.isText(node)) {\n            return textRangeInfo(node, 0);\n          }\n  \n          offset = 0;\n          isCollapseToStart = false;\n        }\n  \n        return {\n          node: node,\n          collapseToStart: isCollapseToStart,\n          offset: offset\n        };\n      };\n  \n      var textRange = document.body.createTextRange();\n      var info = textRangeInfo(point.node, point.offset);\n  \n      textRange.moveToElementText(info.node);\n      textRange.collapse(info.collapseToStart);\n      textRange.moveStart('character', info.offset);\n      return textRange;\n    };\n    \n    /**\n     * Wrapped Range\n     *\n     * @constructor\n     * @param {Node} sc - start container\n     * @param {Number} so - start offset\n     * @param {Node} ec - end container\n     * @param {Number} eo - end offset\n     */\n    var WrappedRange = function (sc, so, ec, eo) {\n      this.sc = sc;\n      this.so = so;\n      this.ec = ec;\n      this.eo = eo;\n  \n      // nativeRange: get nativeRange from sc, so, ec, eo\n      var nativeRange = function () {\n        if (agent.isW3CRangeSupport) {\n          var w3cRange = document.createRange();\n          w3cRange.setStart(sc, so);\n          w3cRange.setEnd(ec, eo);\n\n          return w3cRange;\n        } else {\n          var textRange = pointToTextRange({\n            node: sc,\n            offset: so\n          });\n\n          textRange.setEndPoint('EndToEnd', pointToTextRange({\n            node: ec,\n            offset: eo\n          }));\n\n          return textRange;\n        }\n      };\n\n      this.getPoints = function () {\n        return {\n          sc: sc,\n          so: so,\n          ec: ec,\n          eo: eo\n        };\n      };\n\n      this.getStartPoint = function () {\n        return {\n          node: sc,\n          offset: so\n        };\n      };\n\n      this.getEndPoint = function () {\n        return {\n          node: ec,\n          offset: eo\n        };\n      };\n\n      /**\n       * select update visible range\n       */\n      this.select = function () {\n        var nativeRng = nativeRange();\n        if (agent.isW3CRangeSupport) {\n          var selection = document.getSelection();\n          if (selection.rangeCount > 0) {\n            selection.removeAllRanges();\n          }\n          selection.addRange(nativeRng);\n        } else {\n          nativeRng.select();\n        }\n        \n        return this;\n      };\n\n      /**\n       * @return {WrappedRange}\n       */\n      this.normalize = function () {\n\n        /**\n         * @param {BoundaryPoint} point\n         * @param {Boolean} isLeftToRight\n         * @return {BoundaryPoint}\n         */\n        var getVisiblePoint = function (point, isLeftToRight) {\n          if ((dom.isVisiblePoint(point) && !dom.isEdgePoint(point)) ||\n              (dom.isVisiblePoint(point) && dom.isRightEdgePoint(point) && !isLeftToRight) ||\n              (dom.isVisiblePoint(point) && dom.isLeftEdgePoint(point) && isLeftToRight) ||\n              (dom.isVisiblePoint(point) && dom.isBlock(point.node) && dom.isEmpty(point.node))) {\n            return point;\n          }\n\n          // point on block's edge\n          var block = dom.ancestor(point.node, dom.isBlock);\n          if (((dom.isLeftEdgePointOf(point, block) || dom.isVoid(dom.prevPoint(point).node)) && !isLeftToRight) ||\n              ((dom.isRightEdgePointOf(point, block) || dom.isVoid(dom.nextPoint(point).node)) && isLeftToRight)) {\n\n            // returns point already on visible point\n            if (dom.isVisiblePoint(point)) {\n              return point;\n            }\n            // reverse direction \n            isLeftToRight = !isLeftToRight;\n          }\n\n          var nextPoint = isLeftToRight ? dom.nextPointUntil(dom.nextPoint(point), dom.isVisiblePoint) :\n                                          dom.prevPointUntil(dom.prevPoint(point), dom.isVisiblePoint);\n          return nextPoint || point;\n        };\n\n        var endPoint = getVisiblePoint(this.getEndPoint(), false);\n        var startPoint = this.isCollapsed() ? endPoint : getVisiblePoint(this.getStartPoint(), true);\n\n        return new WrappedRange(\n          startPoint.node,\n          startPoint.offset,\n          endPoint.node,\n          endPoint.offset\n        );\n      };\n\n      /**\n       * returns matched nodes on range\n       *\n       * @param {Function} [pred] - predicate function\n       * @param {Object} [options]\n       * @param {Boolean} [options.includeAncestor]\n       * @param {Boolean} [options.fullyContains]\n       * @return {Node[]}\n       */\n      this.nodes = function (pred, options) {\n        pred = pred || func.ok;\n\n        var includeAncestor = options && options.includeAncestor;\n        var fullyContains = options && options.fullyContains;\n\n        // TODO compare points and sort\n        var startPoint = this.getStartPoint();\n        var endPoint = this.getEndPoint();\n\n        var nodes = [];\n        var leftEdgeNodes = [];\n\n        dom.walkPoint(startPoint, endPoint, function (point) {\n          if (dom.isEditable(point.node)) {\n            return;\n          }\n\n          var node;\n          if (fullyContains) {\n            if (dom.isLeftEdgePoint(point)) {\n              leftEdgeNodes.push(point.node);\n            }\n            if (dom.isRightEdgePoint(point) && list.contains(leftEdgeNodes, point.node)) {\n              node = point.node;\n            }\n          } else if (includeAncestor) {\n            node = dom.ancestor(point.node, pred);\n          } else {\n            node = point.node;\n          }\n\n          if (node && pred(node)) {\n            nodes.push(node);\n          }\n        }, true);\n\n        return list.unique(nodes);\n      };\n\n      /**\n       * returns commonAncestor of range\n       * @return {Element} - commonAncestor\n       */\n      this.commonAncestor = function () {\n        return dom.commonAncestor(sc, ec);\n      };\n\n      /**\n       * returns expanded range by pred\n       *\n       * @param {Function} pred - predicate function\n       * @return {WrappedRange}\n       */\n      this.expand = function (pred) {\n        var startAncestor = dom.ancestor(sc, pred);\n        var endAncestor = dom.ancestor(ec, pred);\n\n        if (!startAncestor && !endAncestor) {\n          return new WrappedRange(sc, so, ec, eo);\n        }\n\n        var boundaryPoints = this.getPoints();\n\n        if (startAncestor) {\n          boundaryPoints.sc = startAncestor;\n          boundaryPoints.so = 0;\n        }\n\n        if (endAncestor) {\n          boundaryPoints.ec = endAncestor;\n          boundaryPoints.eo = dom.nodeLength(endAncestor);\n        }\n\n        return new WrappedRange(\n          boundaryPoints.sc,\n          boundaryPoints.so,\n          boundaryPoints.ec,\n          boundaryPoints.eo\n        );\n      };\n\n      /**\n       * @param {Boolean} isCollapseToStart\n       * @return {WrappedRange}\n       */\n      this.collapse = function (isCollapseToStart) {\n        if (isCollapseToStart) {\n          return new WrappedRange(sc, so, sc, so);\n        } else {\n          return new WrappedRange(ec, eo, ec, eo);\n        }\n      };\n\n      /**\n       * splitText on range\n       */\n      this.splitText = function () {\n        var isSameContainer = sc === ec;\n        var boundaryPoints = this.getPoints();\n\n        if (dom.isText(ec) && !dom.isEdgePoint(this.getEndPoint())) {\n          ec.splitText(eo);\n        }\n\n        if (dom.isText(sc) && !dom.isEdgePoint(this.getStartPoint())) {\n          boundaryPoints.sc = sc.splitText(so);\n          boundaryPoints.so = 0;\n\n          if (isSameContainer) {\n            boundaryPoints.ec = boundaryPoints.sc;\n            boundaryPoints.eo = eo - so;\n          }\n        }\n\n        return new WrappedRange(\n          boundaryPoints.sc,\n          boundaryPoints.so,\n          boundaryPoints.ec,\n          boundaryPoints.eo\n        );\n      };\n\n      /**\n       * delete contents on range\n       * @return {WrappedRange}\n       */\n      this.deleteContents = function () {\n        if (this.isCollapsed()) {\n          return this;\n        }\n\n        var rng = this.splitText();\n        var nodes = rng.nodes(null, {\n          fullyContains: true\n        });\n\n        // find new cursor point\n        var point = dom.prevPointUntil(rng.getStartPoint(), function (point) {\n          return !list.contains(nodes, point.node);\n        });\n\n        var emptyParents = [];\n        $.each(nodes, function (idx, node) {\n          // find empty parents\n          var parent = node.parentNode;\n          if (point.node !== parent && dom.nodeLength(parent) === 1) {\n            emptyParents.push(parent);\n          }\n          dom.remove(node, false);\n        });\n\n        // remove empty parents\n        $.each(emptyParents, function (idx, node) {\n          dom.remove(node, false);\n        });\n\n        return new WrappedRange(\n          point.node,\n          point.offset,\n          point.node,\n          point.offset\n        ).normalize();\n      };\n      \n      /**\n       * makeIsOn: return isOn(pred) function\n       */\n      var makeIsOn = function (pred) {\n        return function () {\n          var ancestor = dom.ancestor(sc, pred);\n          return !!ancestor && (ancestor === dom.ancestor(ec, pred));\n        };\n      };\n  \n      // isOnEditable: judge whether range is on editable or not\n      this.isOnEditable = makeIsOn(dom.isEditable);\n      // isOnList: judge whether range is on list node or not\n      this.isOnList = makeIsOn(dom.isList);\n      // isOnAnchor: judge whether range is on anchor node or not\n      this.isOnAnchor = makeIsOn(dom.isAnchor);\n      // isOnAnchor: judge whether range is on cell node or not\n      this.isOnCell = makeIsOn(dom.isCell);\n\n      /**\n       * @param {Function} pred\n       * @return {Boolean}\n       */\n      this.isLeftEdgeOf = function (pred) {\n        if (!dom.isLeftEdgePoint(this.getStartPoint())) {\n          return false;\n        }\n\n        var node = dom.ancestor(this.sc, pred);\n        return node && dom.isLeftEdgeOf(this.sc, node);\n      };\n\n      /**\n       * returns whether range was collapsed or not\n       */\n      this.isCollapsed = function () {\n        return sc === ec && so === eo;\n      };\n\n      /**\n       * wrap inline nodes which children of body with paragraph\n       *\n       * @return {WrappedRange}\n       */\n      this.wrapBodyInlineWithPara = function () {\n        if (dom.isBodyContainer(sc) && dom.isEmpty(sc)) {\n          sc.innerHTML = dom.emptyPara;\n          return new WrappedRange(sc.firstChild, 0, sc.firstChild, 0);\n        }\n\n        /**\n         * [workaround] firefox often create range on not visible point. so normalize here.\n         *  - firefox: |<p>text</p>|\n         *  - chrome: <p>|text|</p>\n         */\n        var rng = this.normalize();\n        if (dom.isParaInline(sc) || dom.isPara(sc)) {\n          return rng;\n        }\n\n        // find inline top ancestor\n        var topAncestor;\n        if (dom.isInline(rng.sc)) {\n          var ancestors = dom.listAncestor(rng.sc, func.not(dom.isInline));\n          topAncestor = list.last(ancestors);\n          if (!dom.isInline(topAncestor)) {\n            topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];\n          }\n        } else {\n          topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];\n        }\n\n        // siblings not in paragraph\n        var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();\n        inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline));\n\n        // wrap with paragraph\n        if (inlineSiblings.length) {\n          var para = dom.wrap(list.head(inlineSiblings), 'p');\n          dom.appendChildNodes(para, list.tail(inlineSiblings));\n        }\n\n        return this.normalize();\n      };\n\n      /**\n       * insert node at current cursor\n       *\n       * @param {Node} node\n       * @return {Node}\n       */\n      this.insertNode = function (node) {\n        var rng = this.wrapBodyInlineWithPara().deleteContents();\n        var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));\n\n        if (info.rightNode) {\n          info.rightNode.parentNode.insertBefore(node, info.rightNode);\n        } else {\n          info.container.appendChild(node);\n        }\n\n        return node;\n      };\n\n      /**\n       * insert html at current cursor\n       */\n      this.pasteHTML = function (markup) {\n        var contentsContainer = $('<div></div>').html(markup)[0];\n        var childNodes = list.from(contentsContainer.childNodes);\n\n        var rng = this.wrapBodyInlineWithPara().deleteContents();\n\n        return childNodes.reverse().map(function (childNode) {\n          return rng.insertNode(childNode);\n        }).reverse();\n      };\n  \n      /**\n       * returns text in range\n       *\n       * @return {String}\n       */\n      this.toString = function () {\n        var nativeRng = nativeRange();\n        return agent.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;\n      };\n\n      /**\n       * returns range for word before cursor\n       *\n       * @param {Boolean} [findAfter] - find after cursor, default: false\n       * @return {WrappedRange}\n       */\n      this.getWordRange = function (findAfter) {\n        var endPoint = this.getEndPoint();\n\n        if (!dom.isCharPoint(endPoint)) {\n          return this;\n        }\n\n        var startPoint = dom.prevPointUntil(endPoint, function (point) {\n          return !dom.isCharPoint(point);\n        });\n\n        if (findAfter) {\n          endPoint = dom.nextPointUntil(endPoint, function (point) {\n            return !dom.isCharPoint(point);\n          });\n        }\n\n        return new WrappedRange(\n          startPoint.node,\n          startPoint.offset,\n          endPoint.node,\n          endPoint.offset\n        );\n      };\n  \n      /**\n       * create offsetPath bookmark\n       *\n       * @param {Node} editable\n       */\n      this.bookmark = function (editable) {\n        return {\n          s: {\n            path: dom.makeOffsetPath(editable, sc),\n            offset: so\n          },\n          e: {\n            path: dom.makeOffsetPath(editable, ec),\n            offset: eo\n          }\n        };\n      };\n\n      /**\n       * create offsetPath bookmark base on paragraph\n       *\n       * @param {Node[]} paras\n       */\n      this.paraBookmark = function (paras) {\n        return {\n          s: {\n            path: list.tail(dom.makeOffsetPath(list.head(paras), sc)),\n            offset: so\n          },\n          e: {\n            path: list.tail(dom.makeOffsetPath(list.last(paras), ec)),\n            offset: eo\n          }\n        };\n      };\n\n      /**\n       * getClientRects\n       * @return {Rect[]}\n       */\n      this.getClientRects = function () {\n        var nativeRng = nativeRange();\n        return nativeRng.getClientRects();\n      };\n    };\n\n  /**\n   * @class core.range\n   *\n   * Data structure\n   *  * BoundaryPoint: a point of dom tree\n   *  * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range\n   *\n   * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position\n   *\n   * @singleton\n   * @alternateClassName range\n   */\n    return {\n      /**\n       * @method\n       * \n       * create Range Object From arguments or Browser Selection\n       *\n       * @param {Node} sc - start container\n       * @param {Number} so - start offset\n       * @param {Node} ec - end container\n       * @param {Number} eo - end offset\n       * @return {WrappedRange}\n       */\n      create : function (sc, so, ec, eo) {\n        if (!arguments.length) { // from Browser Selection\n          if (agent.isW3CRangeSupport) {\n            var selection = document.getSelection();\n            if (!selection || selection.rangeCount === 0) {\n              return null;\n            } else if (dom.isBody(selection.anchorNode)) {\n              // Firefox: returns entire body as range on initialization. We won't never need it.\n              return null;\n            }\n  \n            var nativeRng = selection.getRangeAt(0);\n            sc = nativeRng.startContainer;\n            so = nativeRng.startOffset;\n            ec = nativeRng.endContainer;\n            eo = nativeRng.endOffset;\n          } else { // IE8: TextRange\n            var textRange = document.selection.createRange();\n            var textRangeEnd = textRange.duplicate();\n            textRangeEnd.collapse(false);\n            var textRangeStart = textRange;\n            textRangeStart.collapse(true);\n  \n            var startPoint = textRangeToPoint(textRangeStart, true),\n            endPoint = textRangeToPoint(textRangeEnd, false);\n\n            // same visible point case: range was collapsed.\n            if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) &&\n                dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) &&\n                endPoint.node.nextSibling === startPoint.node) {\n              startPoint = endPoint;\n            }\n\n            sc = startPoint.cont;\n            so = startPoint.offset;\n            ec = endPoint.cont;\n            eo = endPoint.offset;\n          }\n        } else if (arguments.length === 2) { //collapsed\n          ec = sc;\n          eo = so;\n        }\n        return new WrappedRange(sc, so, ec, eo);\n      },\n\n      /**\n       * @method \n       * \n       * create WrappedRange from node\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNode: function (node) {\n        var sc = node;\n        var so = 0;\n        var ec = node;\n        var eo = dom.nodeLength(ec);\n\n        // browsers can't target a picture or void node\n        if (dom.isVoid(sc)) {\n          so = dom.listPrev(sc).length - 1;\n          sc = sc.parentNode;\n        }\n        if (dom.isBR(ec)) {\n          eo = dom.listPrev(ec).length - 1;\n          ec = ec.parentNode;\n        } else if (dom.isVoid(ec)) {\n          eo = dom.listPrev(ec).length;\n          ec = ec.parentNode;\n        }\n\n        return this.create(sc, so, ec, eo);\n      },\n\n      /**\n       * create WrappedRange from node after position\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNodeBefore: function (node) {\n        return this.createFromNode(node).collapse(true);\n      },\n\n      /**\n       * create WrappedRange from node after position\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNodeAfter: function (node) {\n        return this.createFromNode(node).collapse();\n      },\n\n      /**\n       * @method \n       * \n       * create WrappedRange from bookmark\n       *\n       * @param {Node} editable\n       * @param {Object} bookmark\n       * @return {WrappedRange}\n       */\n      createFromBookmark : function (editable, bookmark) {\n        var sc = dom.fromOffsetPath(editable, bookmark.s.path);\n        var so = bookmark.s.offset;\n        var ec = dom.fromOffsetPath(editable, bookmark.e.path);\n        var eo = bookmark.e.offset;\n        return new WrappedRange(sc, so, ec, eo);\n      },\n\n      /**\n       * @method \n       *\n       * create WrappedRange from paraBookmark\n       *\n       * @param {Object} bookmark\n       * @param {Node[]} paras\n       * @return {WrappedRange}\n       */\n      createFromParaBookmark: function (bookmark, paras) {\n        var so = bookmark.s.offset;\n        var eo = bookmark.e.offset;\n        var sc = dom.fromOffsetPath(list.head(paras), bookmark.s.path);\n        var ec = dom.fromOffsetPath(list.last(paras), bookmark.e.path);\n\n        return new WrappedRange(sc, so, ec, eo);\n      }\n    };\n  })();\n\n  /**\n   * @class defaults \n   * \n   * @singleton\n   */\n  var defaults = {\n    /** @property */\n    version: '0.6.16',\n\n    /**\n     * \n     * for event options, reference to EventHandler.attach\n     * \n     * @property {Object} options \n     * @property {String/Number} [options.width=null] set editor width \n     * @property {String/Number} [options.height=null] set editor height, ex) 300\n     * @property {String/Number} options.minHeight set minimum height of editor\n     * @property {String/Number} options.maxHeight\n     * @property {String/Number} options.focus \n     * @property {Number} options.tabsize \n     * @property {Boolean} options.styleWithSpan\n     * @property {Object} options.codemirror\n     * @property {Object} [options.codemirror.mode='text/html']\n     * @property {Object} [options.codemirror.htmlMode=true]\n     * @property {Object} [options.codemirror.lineNumbers=true]\n     * @property {String} [options.lang=en-US] language 'en-US', 'ko-KR', ...\n     * @property {String} [options.direction=null] text direction, ex) 'rtl'\n     * @property {Array} [options.toolbar]\n     * @property {Boolean} [options.airMode=false]\n     * @property {Array} [options.airPopover]\n     * @property {Fucntion} [options.onInit] initialize\n     * @property {Fucntion} [options.onsubmit]\n     */\n    options: {\n      width: null,                  // set editor width\n      height: null,                 // set editor height, ex) 300\n\n      minHeight: null,              // set minimum height of editor\n      maxHeight: null,              // set maximum height of editor\n\n      focus: false,                 // set focus to editable area after initializing summernote\n\n      tabsize: 4,                   // size of tab ex) 2 or 4\n      styleWithSpan: true,          // style with span (Chrome and FF only)\n\n      disableLinkTarget: false,     // hide link Target Checkbox\n      disableDragAndDrop: false,    // disable drag and drop event\n      disableResizeEditor: false,   // disable resizing editor\n      disableResizeImage: false,    // disable resizing image\n\n      shortcuts: true,              // enable keyboard shortcuts\n\n      textareaAutoSync: true,       // enable textarea auto sync\n\n      placeholder: false,           // enable placeholder text\n      prettifyHtml: true,           // enable prettifying html while toggling codeview\n\n      iconPrefix: 'fa fa-',         // prefix for css icon classes\n\n      icons: {\n        font: {\n          bold: 'bold',\n          italic: 'italic',\n          underline: 'underline',\n          clear: 'eraser',\n          height: 'text-height',\n          strikethrough: 'strikethrough',\n          superscript: 'superscript',\n          subscript: 'subscript'\n        },\n        image: {\n          image: 'picture-o',\n          floatLeft: 'align-left',\n          floatRight: 'align-right',\n          floatNone: 'align-justify',\n          shapeRounded: 'square',\n          shapeCircle: 'circle-o',\n          shapeThumbnail: 'picture-o',\n          shapeNone: 'times',\n          remove: 'trash-o'\n        },\n        link: {\n          link: 'link',\n          unlink: 'unlink',\n          edit: 'edit'\n        },\n        table: {\n          table: 'table'\n        },\n        hr: {\n          insert: 'minus'\n        },\n        style: {\n          style: 'magic'\n        },\n        lists: {\n          unordered: 'list-ul',\n          ordered: 'list-ol'\n        },\n        options: {\n          help: 'question',\n          fullscreen: 'arrows-alt',\n          codeview: 'code'\n        },\n        paragraph: {\n          paragraph: 'align-left',\n          outdent: 'outdent',\n          indent: 'indent',\n          left: 'align-left',\n          center: 'align-center',\n          right: 'align-right',\n          justify: 'align-justify'\n        },\n        color: {\n          recent: 'font'\n        },\n        history: {\n          undo: 'undo',\n          redo: 'repeat'\n        },\n        misc: {\n          check: 'check'\n        }\n      },\n\n      dialogsInBody: false,          // false will add dialogs into editor\n\n      codemirror: {                 // codemirror options\n        mode: 'text/html',\n        htmlMode: true,\n        lineNumbers: true\n      },\n\n      // language\n      lang: 'en-US',                // language 'en-US', 'ko-KR', ...\n      direction: null,              // text direction, ex) 'rtl'\n\n      // toolbar\n      toolbar: [\n        ['style', ['style']],\n        ['font', ['bold', 'italic', 'underline', 'clear']],\n        // ['font', ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']],\n        ['fontname', ['fontname']],\n        ['fontsize', ['fontsize']],\n        ['color', ['color']],\n        ['para', ['ul', 'ol', 'paragraph']],\n        ['height', ['height']],\n        ['table', ['table']],\n        ['insert', ['link', 'picture', 'hr']],\n        ['view', ['fullscreen', 'codeview']],\n        ['help', ['help']]\n      ],\n\n      plugin : { },\n\n      // air mode: inline editor\n      airMode: false,\n      // airPopover: [\n      //   ['style', ['style']],\n      //   ['font', ['bold', 'italic', 'underline', 'clear']],\n      //   ['fontname', ['fontname']],\n      //   ['color', ['color']],\n      //   ['para', ['ul', 'ol', 'paragraph']],\n      //   ['height', ['height']],\n      //   ['table', ['table']],\n      //   ['insert', ['link', 'picture']],\n      //   ['help', ['help']]\n      // ],\n      airPopover: [\n        ['color', ['color']],\n        ['font', ['bold', 'underline', 'clear']],\n        ['para', ['ul', 'paragraph']],\n        ['table', ['table']],\n        ['insert', ['link', 'picture']]\n      ],\n\n      // style tag\n      styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n\n      // default fontName\n      defaultFontName: 'Helvetica Neue',\n\n      // fontName\n      fontNames: [\n        'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',\n        'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande',\n        'Tahoma', 'Times New Roman', 'Verdana'\n      ],\n      fontNamesIgnoreCheck: [],\n\n      fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],\n\n      // pallete colors(n x n)\n      colors: [\n        ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'],\n        ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],\n        ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],\n        ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],\n        ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],\n        ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],\n        ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],\n        ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']\n      ],\n\n      // lineHeight\n      lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],\n\n      // insertTable max size\n      insertTableMaxSize: {\n        col: 10,\n        row: 10\n      },\n\n      // image\n      maximumImageFileSize: null, // size in bytes, null = no limit\n\n      // callbacks\n      oninit: null,             // initialize\n      onfocus: null,            // editable has focus\n      onblur: null,             // editable out of focus\n      onenter: null,            // enter key pressed\n      onkeyup: null,            // keyup\n      onkeydown: null,          // keydown\n      onImageUpload: null,      // imageUpload\n      onImageUploadError: null, // imageUploadError\n      onMediaDelete: null,      // media delete\n      onToolbarClick: null,\n      onsubmit: null,\n\n      /**\n       * manipulate link address when user create link\n       * @param {String} sLinkUrl\n       * @return {String}\n       */\n      onCreateLink: function (sLinkUrl) {\n        if (sLinkUrl.indexOf('@') !== -1 && sLinkUrl.indexOf(':') === -1) {\n          sLinkUrl =  'mailto:' + sLinkUrl;\n        }\n\n        return sLinkUrl;\n      },\n\n      keyMap: {\n        pc: {\n          'ENTER': 'insertParagraph',\n          'CTRL+Z': 'undo',\n          'CTRL+Y': 'redo',\n          'TAB': 'tab',\n          'SHIFT+TAB': 'untab',\n          'CTRL+B': 'bold',\n          'CTRL+I': 'italic',\n          'CTRL+U': 'underline',\n          'CTRL+SHIFT+S': 'strikethrough',\n          'CTRL+BACKSLASH': 'removeFormat',\n          'CTRL+SHIFT+L': 'justifyLeft',\n          'CTRL+SHIFT+E': 'justifyCenter',\n          'CTRL+SHIFT+R': 'justifyRight',\n          'CTRL+SHIFT+J': 'justifyFull',\n          'CTRL+SHIFT+NUM7': 'insertUnorderedList',\n          'CTRL+SHIFT+NUM8': 'insertOrderedList',\n          'CTRL+LEFTBRACKET': 'outdent',\n          'CTRL+RIGHTBRACKET': 'indent',\n          'CTRL+NUM0': 'formatPara',\n          'CTRL+NUM1': 'formatH1',\n          'CTRL+NUM2': 'formatH2',\n          'CTRL+NUM3': 'formatH3',\n          'CTRL+NUM4': 'formatH4',\n          'CTRL+NUM5': 'formatH5',\n          'CTRL+NUM6': 'formatH6',\n          'CTRL+ENTER': 'insertHorizontalRule',\n          'CTRL+K': 'showLinkDialog'\n        },\n\n        mac: {\n          'ENTER': 'insertParagraph',\n          'CMD+Z': 'undo',\n          'CMD+SHIFT+Z': 'redo',\n          'TAB': 'tab',\n          'SHIFT+TAB': 'untab',\n          'CMD+B': 'bold',\n          'CMD+I': 'italic',\n          'CMD+U': 'underline',\n          'CMD+SHIFT+S': 'strikethrough',\n          'CMD+BACKSLASH': 'removeFormat',\n          'CMD+SHIFT+L': 'justifyLeft',\n          'CMD+SHIFT+E': 'justifyCenter',\n          'CMD+SHIFT+R': 'justifyRight',\n          'CMD+SHIFT+J': 'justifyFull',\n          'CMD+SHIFT+NUM7': 'insertUnorderedList',\n          'CMD+SHIFT+NUM8': 'insertOrderedList',\n          'CMD+LEFTBRACKET': 'outdent',\n          'CMD+RIGHTBRACKET': 'indent',\n          'CMD+NUM0': 'formatPara',\n          'CMD+NUM1': 'formatH1',\n          'CMD+NUM2': 'formatH2',\n          'CMD+NUM3': 'formatH3',\n          'CMD+NUM4': 'formatH4',\n          'CMD+NUM5': 'formatH5',\n          'CMD+NUM6': 'formatH6',\n          'CMD+ENTER': 'insertHorizontalRule',\n          'CMD+K': 'showLinkDialog'\n        }\n      }\n    },\n\n    // default language: en-US\n    lang: {\n      'en-US': {\n        font: {\n          bold: 'Bold',\n          italic: 'Italic',\n          underline: 'Underline',\n          clear: 'Remove Font Style',\n          height: 'Line Height',\n          name: 'Font Family',\n          strikethrough: 'Strikethrough',\n          subscript: 'Subscript',\n          superscript: 'Superscript',\n          size: 'Font Size'\n        },\n        image: {\n          image: 'Picture',\n          insert: 'Insert Image',\n          resizeFull: 'Resize Full',\n          resizeHalf: 'Resize Half',\n          resizeQuarter: 'Resize Quarter',\n          floatLeft: 'Float Left',\n          floatRight: 'Float Right',\n          floatNone: 'Float None',\n          shapeRounded: 'Shape: Rounded',\n          shapeCircle: 'Shape: Circle',\n          shapeThumbnail: 'Shape: Thumbnail',\n          shapeNone: 'Shape: None',\n          dragImageHere: 'Drag image or text here',\n          dropImage: 'Drop image or Text',\n          selectFromFiles: 'Select from files',\n          maximumFileSize: 'Maximum file size',\n          maximumFileSizeError: 'Maximum file size exceeded.',\n          url: 'Image URL',\n          remove: 'Remove Image'\n        },\n        link: {\n          link: 'Link',\n          insert: 'Insert Link',\n          unlink: 'Unlink',\n          edit: 'Edit',\n          textToDisplay: 'Text to display',\n          url: 'To what URL should this link go?',\n          openInNewWindow: 'Open in new window'\n        },\n        table: {\n          table: 'Table'\n        },\n        hr: {\n          insert: 'Insert Horizontal Rule'\n        },\n        style: {\n          style: 'Style',\n          normal: 'Normal',\n          blockquote: 'Quote',\n          pre: 'Code',\n          h1: 'Header 1',\n          h2: 'Header 2',\n          h3: 'Header 3',\n          h4: 'Header 4',\n          h5: 'Header 5',\n          h6: 'Header 6'\n        },\n        lists: {\n          unordered: 'Unordered list',\n          ordered: 'Ordered list'\n        },\n        options: {\n          help: 'Help',\n          fullscreen: 'Full Screen',\n          codeview: 'Code View'\n        },\n        paragraph: {\n          paragraph: 'Paragraph',\n          outdent: 'Outdent',\n          indent: 'Indent',\n          left: 'Align left',\n          center: 'Align center',\n          right: 'Align right',\n          justify: 'Justify full'\n        },\n        color: {\n          recent: 'Recent Color',\n          more: 'More Color',\n          background: 'Background Color',\n          foreground: 'Foreground Color',\n          transparent: 'Transparent',\n          setTransparent: 'Set transparent',\n          reset: 'Reset',\n          resetToDefault: 'Reset to default'\n        },\n        shortcut: {\n          shortcuts: 'Keyboard shortcuts',\n          close: 'Close',\n          textFormatting: 'Text formatting',\n          action: 'Action',\n          paragraphFormatting: 'Paragraph formatting',\n          documentStyle: 'Document Style',\n          extraKeys: 'Extra keys'\n        },\n        history: {\n          undo: 'Undo',\n          redo: 'Redo'\n        }\n      }\n    }\n  };\n\n  /**\n   * @class core.async\n   *\n   * Async functions which returns `Promise`\n   *\n   * @singleton\n   * @alternateClassName async\n   */\n  var async = (function () {\n    /**\n     * @method readFileAsDataURL\n     *\n     * read contents of file as representing URL\n     *\n     * @param {File} file\n     * @return {Promise} - then: sDataUrl\n     */\n    var readFileAsDataURL = function (file) {\n      return $.Deferred(function (deferred) {\n        $.extend(new FileReader(), {\n          onload: function (e) {\n            var sDataURL = e.target.result;\n            deferred.resolve(sDataURL);\n          },\n          onerror: function () {\n            deferred.reject(this);\n          }\n        }).readAsDataURL(file);\n      }).promise();\n    };\n  \n    /**\n     * @method createImage\n     *\n     * create `<image>` from url string\n     *\n     * @param {String} sUrl\n     * @param {String} filename\n     * @return {Promise} - then: $image\n     */\n    var createImage = function (sUrl, filename) {\n      return $.Deferred(function (deferred) {\n        var $img = $('<img>');\n\n        $img.one('load', function () {\n          $img.off('error abort');\n          deferred.resolve($img);\n        }).one('error abort', function () {\n          $img.off('load').detach();\n          deferred.reject($img);\n        }).css({\n          display: 'none'\n        }).appendTo(document.body).attr({\n          'src': sUrl,\n          'data-filename': filename\n        });\n      }).promise();\n    };\n\n    return {\n      readFileAsDataURL: readFileAsDataURL,\n      createImage: createImage\n    };\n  })();\n\n  /**\n   * @class core.key\n   *\n   * Object for keycodes.\n   *\n   * @singleton\n   * @alternateClassName key\n   */\n  var key = (function () {\n    var keyMap = {\n      'BACKSPACE': 8,\n      'TAB': 9,\n      'ENTER': 13,\n      'SPACE': 32,\n\n      // Number: 0-9\n      'NUM0': 48,\n      'NUM1': 49,\n      'NUM2': 50,\n      'NUM3': 51,\n      'NUM4': 52,\n      'NUM5': 53,\n      'NUM6': 54,\n      'NUM7': 55,\n      'NUM8': 56,\n\n      // Alphabet: a-z\n      'B': 66,\n      'E': 69,\n      'I': 73,\n      'J': 74,\n      'K': 75,\n      'L': 76,\n      'R': 82,\n      'S': 83,\n      'U': 85,\n      'V': 86,\n      'Y': 89,\n      'Z': 90,\n\n      'SLASH': 191,\n      'LEFTBRACKET': 219,\n      'BACKSLASH': 220,\n      'RIGHTBRACKET': 221\n    };\n\n    return {\n      /**\n       * @method isEdit\n       *\n       * @param {Number} keyCode\n       * @return {Boolean}\n       */\n      isEdit: function (keyCode) {\n        return list.contains([8, 9, 13, 32], keyCode);\n      },\n      /**\n       * @method isMove\n       *\n       * @param {Number} keyCode\n       * @return {Boolean}\n       */\n      isMove: function (keyCode) {\n        return list.contains([37, 38, 39, 40], keyCode);\n      },\n      /**\n       * @property {Object} nameFromCode\n       * @property {String} nameFromCode.8 \"BACKSPACE\"\n       */\n      nameFromCode: func.invertObject(keyMap),\n      code: keyMap\n    };\n  })();\n\n  /**\n   * @class editing.History\n   *\n   * Editor History\n   *\n   */\n  var History = function ($editable) {\n    var stack = [], stackOffset = -1;\n    var editable = $editable[0];\n\n    var makeSnapshot = function () {\n      var rng = range.create();\n      var emptyBookmark = {s: {path: [], offset: 0}, e: {path: [], offset: 0}};\n\n      return {\n        contents: $editable.html(),\n        bookmark: (rng ? rng.bookmark(editable) : emptyBookmark)\n      };\n    };\n\n    var applySnapshot = function (snapshot) {\n      if (snapshot.contents !== null) {\n        $editable.html(snapshot.contents);\n      }\n      if (snapshot.bookmark !== null) {\n        range.createFromBookmark(editable, snapshot.bookmark).select();\n      }\n    };\n\n    /**\n     * undo\n     */\n    this.undo = function () {\n      // Create snap shot if not yet recorded\n      if ($editable.html() !== stack[stackOffset].contents) {\n        this.recordUndo();\n      }\n\n      if (0 < stackOffset) {\n        stackOffset--;\n        applySnapshot(stack[stackOffset]);\n      }\n    };\n\n    /**\n     * redo\n     */\n    this.redo = function () {\n      if (stack.length - 1 > stackOffset) {\n        stackOffset++;\n        applySnapshot(stack[stackOffset]);\n      }\n    };\n\n    /**\n     * recorded undo\n     */\n    this.recordUndo = function () {\n      stackOffset++;\n\n      // Wash out stack after stackOffset\n      if (stack.length > stackOffset) {\n        stack = stack.slice(0, stackOffset);\n      }\n\n      // Create new snapshot and push it to the end\n      stack.push(makeSnapshot());\n    };\n\n    // Create first undo stack\n    this.recordUndo();\n  };\n\n  /**\n   * @class editing.Style\n   *\n   * Style\n   *\n   */\n  var Style = function () {\n    /**\n     * @method jQueryCSS\n     *\n     * [workaround] for old jQuery\n     * passing an array of style properties to .css()\n     * will result in an object of property-value pairs.\n     * (compability with version < 1.9)\n     *\n     * @private\n     * @param  {jQuery} $obj\n     * @param  {Array} propertyNames - An array of one or more CSS properties.\n     * @return {Object}\n     */\n    var jQueryCSS = function ($obj, propertyNames) {\n      if (agent.jqueryVersion < 1.9) {\n        var result = {};\n        $.each(propertyNames, function (idx, propertyName) {\n          result[propertyName] = $obj.css(propertyName);\n        });\n        return result;\n      }\n      return $obj.css.call($obj, propertyNames);\n    };\n\n    /**\n     * returns style object from node\n     *\n     * @param {jQuery} $node\n     * @return {Object}\n     */\n    this.fromNode = function ($node) {\n      var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];\n      var styleInfo = jQueryCSS($node, properties) || {};\n      styleInfo['font-size'] = parseInt(styleInfo['font-size'], 10);\n      return styleInfo;\n    };\n\n    /**\n     * paragraph level style\n     *\n     * @param {WrappedRange} rng\n     * @param {Object} styleInfo\n     */\n    this.stylePara = function (rng, styleInfo) {\n      $.each(rng.nodes(dom.isPara, {\n        includeAncestor: true\n      }), function (idx, para) {\n        $(para).css(styleInfo);\n      });\n    };\n\n    /**\n     * insert and returns styleNodes on range.\n     *\n     * @param {WrappedRange} rng\n     * @param {Object} [options] - options for styleNodes\n     * @param {String} [options.nodeName] - default: `SPAN`\n     * @param {Boolean} [options.expandClosestSibling] - default: `false`\n     * @param {Boolean} [options.onlyPartialContains] - default: `false`\n     * @return {Node[]}\n     */\n    this.styleNodes = function (rng, options) {\n      rng = rng.splitText();\n\n      var nodeName = options && options.nodeName || 'SPAN';\n      var expandClosestSibling = !!(options && options.expandClosestSibling);\n      var onlyPartialContains = !!(options && options.onlyPartialContains);\n\n      if (rng.isCollapsed()) {\n        return [rng.insertNode(dom.create(nodeName))];\n      }\n\n      var pred = dom.makePredByNodeName(nodeName);\n      var nodes = rng.nodes(dom.isText, {\n        fullyContains: true\n      }).map(function (text) {\n        return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);\n      });\n\n      if (expandClosestSibling) {\n        if (onlyPartialContains) {\n          var nodesInRange = rng.nodes();\n          // compose with partial contains predication\n          pred = func.and(pred, function (node) {\n            return list.contains(nodesInRange, node);\n          });\n        }\n\n        return nodes.map(function (node) {\n          var siblings = dom.withClosestSiblings(node, pred);\n          var head = list.head(siblings);\n          var tails = list.tail(siblings);\n          $.each(tails, function (idx, elem) {\n            dom.appendChildNodes(head, elem.childNodes);\n            dom.remove(elem);\n          });\n          return list.head(siblings);\n        });\n      } else {\n        return nodes;\n      }\n    };\n\n    /**\n     * get current style on cursor\n     *\n     * @param {WrappedRange} rng\n     * @return {Object} - object contains style properties.\n     */\n    this.current = function (rng) {\n      var $cont = $(dom.isText(rng.sc) ? rng.sc.parentNode : rng.sc);\n      var styleInfo = this.fromNode($cont);\n\n      // document.queryCommandState for toggle state\n      styleInfo['font-bold'] = document.queryCommandState('bold') ? 'bold' : 'normal';\n      styleInfo['font-italic'] = document.queryCommandState('italic') ? 'italic' : 'normal';\n      styleInfo['font-underline'] = document.queryCommandState('underline') ? 'underline' : 'normal';\n      styleInfo['font-strikethrough'] = document.queryCommandState('strikeThrough') ? 'strikethrough' : 'normal';\n      styleInfo['font-superscript'] = document.queryCommandState('superscript') ? 'superscript' : 'normal';\n      styleInfo['font-subscript'] = document.queryCommandState('subscript') ? 'subscript' : 'normal';\n\n      // list-style-type to list-style(unordered, ordered)\n      if (!rng.isOnList()) {\n        styleInfo['list-style'] = 'none';\n      } else {\n        var aOrderedType = ['circle', 'disc', 'disc-leading-zero', 'square'];\n        var isUnordered = $.inArray(styleInfo['list-style-type'], aOrderedType) > -1;\n        styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';\n      }\n\n      var para = dom.ancestor(rng.sc, dom.isPara);\n      if (para && para.style['line-height']) {\n        styleInfo['line-height'] = para.style.lineHeight;\n      } else {\n        var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);\n        styleInfo['line-height'] = lineHeight.toFixed(1);\n      }\n\n      styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);\n      styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);\n      styleInfo.range = rng;\n\n      return styleInfo;\n    };\n  };\n\n\n  /**\n   * @class editing.Bullet\n   *\n   * @alternateClassName Bullet\n   */\n  var Bullet = function () {\n    /**\n     * @method insertOrderedList\n     *\n     * toggle ordered list\n     *\n     * @type command\n     */\n    this.insertOrderedList = function () {\n      this.toggleList('OL');\n    };\n\n    /**\n     * @method insertUnorderedList\n     *\n     * toggle unordered list\n     *\n     * @type command\n     */\n    this.insertUnorderedList = function () {\n      this.toggleList('UL');\n    };\n\n    /**\n     * @method indent\n     *\n     * indent\n     *\n     * @type command\n     */\n    this.indent = function () {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        if (dom.isLi(head)) {\n          self.wrapList(paras, head.parentNode.nodeName);\n        } else {\n          $.each(paras, function (idx, para) {\n            $(para).css('marginLeft', function (idx, val) {\n              return (parseInt(val, 10) || 0) + 25;\n            });\n          });\n        }\n      });\n\n      rng.select();\n    };\n\n    /**\n     * @method outdent\n     *\n     * outdent\n     *\n     * @type command\n     */\n    this.outdent = function () {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        if (dom.isLi(head)) {\n          self.releaseList([paras]);\n        } else {\n          $.each(paras, function (idx, para) {\n            $(para).css('marginLeft', function (idx, val) {\n              val = (parseInt(val, 10) || 0);\n              return val > 25 ? val - 25 : '';\n            });\n          });\n        }\n      });\n\n      rng.select();\n    };\n\n    /**\n     * @method toggleList\n     *\n     * toggle list\n     *\n     * @param {String} listName - OL or UL\n     */\n    this.toggleList = function (listName) {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var bookmark = rng.paraBookmark(paras);\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      // paragraph to list\n      if (list.find(paras, dom.isPurePara)) {\n        var wrappedParas = [];\n        $.each(clustereds, function (idx, paras) {\n          wrappedParas = wrappedParas.concat(self.wrapList(paras, listName));\n        });\n        paras = wrappedParas;\n      // list to paragraph or change list style\n      } else {\n        var diffLists = rng.nodes(dom.isList, {\n          includeAncestor: true\n        }).filter(function (listNode) {\n          return !$.nodeName(listNode, listName);\n        });\n\n        if (diffLists.length) {\n          $.each(diffLists, function (idx, listNode) {\n            dom.replace(listNode, listName);\n          });\n        } else {\n          paras = this.releaseList(clustereds, true);\n        }\n      }\n\n      range.createFromParaBookmark(bookmark, paras).select();\n    };\n\n    /**\n     * @method wrapList\n     *\n     * @param {Node[]} paras\n     * @param {String} listName\n     * @return {Node[]}\n     */\n    this.wrapList = function (paras, listName) {\n      var head = list.head(paras);\n      var last = list.last(paras);\n\n      var prevList = dom.isList(head.previousSibling) && head.previousSibling;\n      var nextList = dom.isList(last.nextSibling) && last.nextSibling;\n\n      var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last);\n\n      // P to LI\n      paras = paras.map(function (para) {\n        return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;\n      });\n\n      // append to list(<ul>, <ol>)\n      dom.appendChildNodes(listNode, paras);\n\n      if (nextList) {\n        dom.appendChildNodes(listNode, list.from(nextList.childNodes));\n        dom.remove(nextList);\n      }\n\n      return paras;\n    };\n\n    /**\n     * @method releaseList\n     *\n     * @param {Array[]} clustereds\n     * @param {Boolean} isEscapseToBody\n     * @return {Node[]}\n     */\n    this.releaseList = function (clustereds, isEscapseToBody) {\n      var releasedParas = [];\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        var last = list.last(paras);\n\n        var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) :\n                                         head.parentNode;\n        var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {\n          node: last.parentNode,\n          offset: dom.position(last) + 1\n        }, {\n          isSkipPaddingBlankHTML: true\n        }) : null;\n\n        var middleList = dom.splitTree(headList, {\n          node: head.parentNode,\n          offset: dom.position(head)\n        }, {\n          isSkipPaddingBlankHTML: true\n        });\n\n        paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) :\n                                  list.from(middleList.childNodes).filter(dom.isLi);\n\n        // LI to P\n        if (isEscapseToBody || !dom.isList(headList.parentNode)) {\n          paras = paras.map(function (para) {\n            return dom.replace(para, 'P');\n          });\n        }\n\n        $.each(list.from(paras).reverse(), function (idx, para) {\n          dom.insertAfter(para, headList);\n        });\n\n        // remove empty lists\n        var rootLists = list.compact([headList, middleList, lastList]);\n        $.each(rootLists, function (idx, rootList) {\n          var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));\n          $.each(listNodes.reverse(), function (idx, listNode) {\n            if (!dom.nodeLength(listNode)) {\n              dom.remove(listNode, true);\n            }\n          });\n        });\n\n        releasedParas = releasedParas.concat(paras);\n      });\n\n      return releasedParas;\n    };\n  };\n\n\n  /**\n   * @class editing.Typing\n   *\n   * Typing\n   *\n   */\n  var Typing = function () {\n\n    // a Bullet instance to toggle lists off\n    var bullet = new Bullet();\n\n    /**\n     * insert tab\n     *\n     * @param {jQuery} $editable\n     * @param {WrappedRange} rng\n     * @param {Number} tabsize\n     */\n    this.insertTab = function ($editable, rng, tabsize) {\n      var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));\n      rng = rng.deleteContents();\n      rng.insertNode(tab, true);\n\n      rng = range.create(tab, tabsize);\n      rng.select();\n    };\n\n    /**\n     * insert paragraph\n     */\n    this.insertParagraph = function () {\n      var rng = range.create();\n\n      // deleteContents on range.\n      rng = rng.deleteContents();\n\n      // Wrap range if it needs to be wrapped by paragraph\n      rng = rng.wrapBodyInlineWithPara();\n\n      // finding paragraph\n      var splitRoot = dom.ancestor(rng.sc, dom.isPara);\n\n      var nextPara;\n      // on paragraph: split paragraph\n      if (splitRoot) {\n        // if it is an empty line with li\n        if (dom.isEmpty(splitRoot) && dom.isLi(splitRoot)) {\n          // disable UL/OL and escape!\n          bullet.toggleList(splitRoot.parentNode.nodeName);\n          return;\n        // if new line has content (not a line break)\n        } else {\n          nextPara = dom.splitTree(splitRoot, rng.getStartPoint());\n\n          var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);\n          emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));\n\n          $.each(emptyAnchors, function (idx, anchor) {\n            dom.remove(anchor);\n          });\n        }\n      // no paragraph: insert empty paragraph\n      } else {\n        var next = rng.sc.childNodes[rng.so];\n        nextPara = $(dom.emptyPara)[0];\n        if (next) {\n          rng.sc.insertBefore(nextPara, next);\n        } else {\n          rng.sc.appendChild(nextPara);\n        }\n      }\n\n      range.create(nextPara, 0).normalize().select();\n\n    };\n\n  };\n\n  /**\n   * @class editing.Table\n   *\n   * Table\n   *\n   */\n  var Table = function () {\n    /**\n     * handle tab key\n     *\n     * @param {WrappedRange} rng\n     * @param {Boolean} isShift\n     */\n    this.tab = function (rng, isShift) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      var table = dom.ancestor(cell, dom.isTable);\n      var cells = dom.listDescendant(table, dom.isCell);\n\n      var nextCell = list[isShift ? 'prev' : 'next'](cells, cell);\n      if (nextCell) {\n        range.create(nextCell, 0).select();\n      }\n    };\n\n    /**\n     * create empty table element\n     *\n     * @param {Number} rowCount\n     * @param {Number} colCount\n     * @return {Node}\n     */\n    this.createTable = function (colCount, rowCount) {\n      var tds = [], tdHTML;\n      for (var idxCol = 0; idxCol < colCount; idxCol++) {\n        tds.push('<td>' + dom.blank + '</td>');\n      }\n      tdHTML = tds.join('');\n\n      var trs = [], trHTML;\n      for (var idxRow = 0; idxRow < rowCount; idxRow++) {\n        trs.push('<tr>' + tdHTML + '</tr>');\n      }\n      trHTML = trs.join('');\n      return $('<table class=\"table table-bordered\">' + trHTML + '</table>')[0];\n    };\n  };\n\n\n  var KEY_BOGUS = 'bogus';\n\n  /**\n   * @class editing.Editor\n   *\n   * Editor\n   *\n   */\n  var Editor = function (handler) {\n\n    var self = this;\n    var style = new Style();\n    var table = new Table();\n    var typing = new Typing();\n    var bullet = new Bullet();\n\n    /**\n     * @method createRange\n     *\n     * create range\n     *\n     * @param {jQuery} $editable\n     * @return {WrappedRange}\n     */\n    this.createRange = function ($editable) {\n      this.focus($editable);\n      return range.create();\n    };\n\n    /**\n     * @method saveRange\n     *\n     * save current range\n     *\n     * @param {jQuery} $editable\n     * @param {Boolean} [thenCollapse=false]\n     */\n    this.saveRange = function ($editable, thenCollapse) {\n      this.focus($editable);\n      $editable.data('range', range.create());\n      if (thenCollapse) {\n        range.create().collapse().select();\n      }\n    };\n\n    /**\n     * @method saveRange\n     *\n     * save current node list to $editable.data('childNodes')\n     *\n     * @param {jQuery} $editable\n     */\n    this.saveNode = function ($editable) {\n      // copy child node reference\n      var copy = [];\n      for (var key  = 0, len = $editable[0].childNodes.length; key < len; key++) {\n        copy.push($editable[0].childNodes[key]);\n      }\n      $editable.data('childNodes', copy);\n    };\n\n    /**\n     * @method restoreRange\n     *\n     * restore lately range\n     *\n     * @param {jQuery} $editable\n     */\n    this.restoreRange = function ($editable) {\n      var rng = $editable.data('range');\n      if (rng) {\n        rng.select();\n        this.focus($editable);\n      }\n    };\n\n    /**\n     * @method restoreNode\n     *\n     * restore lately node list\n     *\n     * @param {jQuery} $editable\n     */\n    this.restoreNode = function ($editable) {\n      $editable.html('');\n      var child = $editable.data('childNodes');\n      for (var index = 0, len = child.length; index < len; index++) {\n        $editable[0].appendChild(child[index]);\n      }\n    };\n\n    /**\n     * @method currentStyle\n     *\n     * current style\n     *\n     * @param {Node} target\n     * @return {Object|Boolean} unfocus\n     */\n    this.currentStyle = function (target) {\n      var rng = range.create();\n      var styleInfo =  rng && rng.isOnEditable() ? style.current(rng.normalize()) : {};\n      if (dom.isImg(target)) {\n        styleInfo.image = target;\n      }\n      return styleInfo;\n    };\n\n    /**\n     * style from node\n     *\n     * @param {jQuery} $node\n     * @return {Object}\n     */\n    this.styleFromNode = function ($node) {\n      return style.fromNode($node);\n    };\n\n    var triggerOnBeforeChange = function ($editable) {\n      var $holder = dom.makeLayoutInfo($editable).holder();\n      handler.bindCustomEvent(\n        $holder, $editable.data('callbacks'), 'before.command'\n      )($editable.html(), $editable);\n    };\n\n    var triggerOnChange = function ($editable) {\n      var $holder = dom.makeLayoutInfo($editable).holder();\n      handler.bindCustomEvent(\n        $holder, $editable.data('callbacks'), 'change'\n      )($editable.html(), $editable);\n    };\n\n    /**\n     * @method undo\n     * undo\n     * @param {jQuery} $editable\n     */\n    this.undo = function ($editable) {\n      triggerOnBeforeChange($editable);\n      $editable.data('NoteHistory').undo();\n      triggerOnChange($editable);\n    };\n\n    /**\n     * @method redo\n     * redo\n     * @param {jQuery} $editable\n     */\n    this.redo = function ($editable) {\n      triggerOnBeforeChange($editable);\n      $editable.data('NoteHistory').redo();\n      triggerOnChange($editable);\n    };\n\n    /**\n     * @method beforeCommand\n     * before command\n     * @param {jQuery} $editable\n     */\n    var beforeCommand = this.beforeCommand = function ($editable) {\n      triggerOnBeforeChange($editable);\n      // keep focus on editable before command execution\n      self.focus($editable);\n    };\n\n    /**\n     * @method afterCommand\n     * after command\n     * @param {jQuery} $editable\n     * @param {Boolean} isPreventTrigger\n     */\n    var afterCommand = this.afterCommand = function ($editable, isPreventTrigger) {\n      $editable.data('NoteHistory').recordUndo();\n      if (!isPreventTrigger) {\n        triggerOnChange($editable);\n      }\n    };\n\n    /**\n     * @method bold\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method italic\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method underline\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method strikethrough\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method formatBlock\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method superscript\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method subscript\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyLeft\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyCenter\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyRight\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyFull\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method formatBlock\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method removeFormat\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method backColor\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method foreColor\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method insertHorizontalRule\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method fontName\n     *\n     * change font name\n     *\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /* jshint ignore:start */\n    // native commands(with execCommand), generate function for execCommand\n    var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript',\n                    'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull',\n                    'formatBlock', 'removeFormat',\n                    'backColor', 'foreColor', 'fontName'];\n\n    for (var idx = 0, len = commands.length; idx < len; idx ++) {\n      this[commands[idx]] = (function (sCmd) {\n        return function ($editable, value) {\n          beforeCommand($editable);\n\n          document.execCommand(sCmd, false, value);\n\n          afterCommand($editable, true);\n        };\n      })(commands[idx]);\n    }\n    /* jshint ignore:end */\n\n    /**\n     * @method tab\n     *\n     * handle tab key\n     *\n     * @param {jQuery} $editable\n     * @param {Object} options\n     */\n    this.tab = function ($editable, options) {\n      var rng = this.createRange($editable);\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        table.tab(rng);\n      } else {\n        beforeCommand($editable);\n        typing.insertTab($editable, rng, options.tabsize);\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * @method untab\n     *\n     * handle shift+tab key\n     *\n     */\n    this.untab = function ($editable) {\n      var rng = this.createRange($editable);\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        table.tab(rng, true);\n      }\n    };\n\n    /**\n     * @method insertParagraph\n     *\n     * insert paragraph\n     *\n     * @param {Node} $editable\n     */\n    this.insertParagraph = function ($editable) {\n      beforeCommand($editable);\n      typing.insertParagraph($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @method insertOrderedList\n     *\n     * @param {jQuery} $editable\n     */\n    this.insertOrderedList = function ($editable) {\n      beforeCommand($editable);\n      bullet.insertOrderedList($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.insertUnorderedList = function ($editable) {\n      beforeCommand($editable);\n      bullet.insertUnorderedList($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.indent = function ($editable) {\n      beforeCommand($editable);\n      bullet.indent($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.outdent = function ($editable) {\n      beforeCommand($editable);\n      bullet.outdent($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * insert image\n     *\n     * @param {jQuery} $editable\n     * @param {String} sUrl\n     */\n    this.insertImage = function ($editable, sUrl, filename) {\n      async.createImage(sUrl, filename).then(function ($image) {\n        beforeCommand($editable);\n        $image.css({\n          display: '',\n          width: Math.min($editable.width(), $image.width())\n        });\n        range.create().insertNode($image[0]);\n        range.createFromNodeAfter($image[0]).select();\n        afterCommand($editable);\n      }).fail(function () {\n        var $holder = dom.makeLayoutInfo($editable).holder();\n        handler.bindCustomEvent(\n          $holder, $editable.data('callbacks'), 'image.upload.error'\n        )();\n      });\n    };\n\n    /**\n     * @method insertNode\n     * insert node\n     * @param {Node} $editable\n     * @param {Node} node\n     */\n    this.insertNode = function ($editable, node) {\n      beforeCommand($editable);\n      range.create().insertNode(node);\n      range.createFromNodeAfter(node).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * insert text\n     * @param {Node} $editable\n     * @param {String} text\n     */\n    this.insertText = function ($editable, text) {\n      beforeCommand($editable);\n      var textNode = range.create().insertNode(dom.createText(text));\n      range.create(textNode, dom.nodeLength(textNode)).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * paste HTML\n     * @param {Node} $editable\n     * @param {String} markup\n     */\n    this.pasteHTML = function ($editable, markup) {\n      beforeCommand($editable);\n      var contents = range.create().pasteHTML(markup);\n      range.createFromNodeAfter(list.last(contents)).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * formatBlock\n     *\n     * @param {jQuery} $editable\n     * @param {String} tagName\n     */\n    this.formatBlock = function ($editable, tagName) {\n      beforeCommand($editable);\n      // [workaround] for MSIE, IE need `<`\n      tagName = agent.isMSIE ? '<' + tagName + '>' : tagName;\n      document.execCommand('FormatBlock', false, tagName);\n      afterCommand($editable);\n    };\n\n    this.formatPara = function ($editable) {\n      beforeCommand($editable);\n      this.formatBlock($editable, 'P');\n      afterCommand($editable);\n    };\n\n    /* jshint ignore:start */\n    for (var idx = 1; idx <= 6; idx ++) {\n      this['formatH' + idx] = function (idx) {\n        return function ($editable) {\n          this.formatBlock($editable, 'H' + idx);\n        };\n      }(idx);\n    };\n    /* jshint ignore:end */\n\n    /**\n     * fontSize\n     *\n     * @param {jQuery} $editable\n     * @param {String} value - px\n     */\n    this.fontSize = function ($editable, value) {\n      var rng = range.create();\n\n      if (rng.isCollapsed()) {\n        var spans = style.styleNodes(rng);\n        var firstSpan = list.head(spans);\n\n        $(spans).css({\n          'font-size': value + 'px'\n        });\n\n        // [workaround] added styled bogus span for style\n        //  - also bogus character needed for cursor position\n        if (firstSpan && !dom.nodeLength(firstSpan)) {\n          firstSpan.innerHTML = dom.ZERO_WIDTH_NBSP_CHAR;\n          range.createFromNodeAfter(firstSpan.firstChild).select();\n          $editable.data(KEY_BOGUS, firstSpan);\n        }\n      } else {\n        beforeCommand($editable);\n        $(style.styleNodes(rng)).css({\n          'font-size': value + 'px'\n        });\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * insert horizontal rule\n     * @param {jQuery} $editable\n     */\n    this.insertHorizontalRule = function ($editable) {\n      beforeCommand($editable);\n\n      var rng = range.create();\n      var hrNode = rng.insertNode($('<HR/>')[0]);\n      if (hrNode.nextSibling) {\n        range.create(hrNode.nextSibling, 0).normalize().select();\n      }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * remove bogus node and character\n     */\n    this.removeBogus = function ($editable) {\n      var bogusNode = $editable.data(KEY_BOGUS);\n      if (!bogusNode) {\n        return;\n      }\n\n      var textNode = list.find(list.from(bogusNode.childNodes), dom.isText);\n\n      var bogusCharIdx = textNode.nodeValue.indexOf(dom.ZERO_WIDTH_NBSP_CHAR);\n      if (bogusCharIdx !== -1) {\n        textNode.deleteData(bogusCharIdx, 1);\n      }\n\n      if (dom.isEmpty(bogusNode)) {\n        dom.remove(bogusNode);\n      }\n\n      $editable.removeData(KEY_BOGUS);\n    };\n\n    /**\n     * lineHeight\n     * @param {jQuery} $editable\n     * @param {String} value\n     */\n    this.lineHeight = function ($editable, value) {\n      beforeCommand($editable);\n      style.stylePara(range.create(), {\n        lineHeight: value\n      });\n      afterCommand($editable);\n    };\n\n    /**\n     * unlink\n     *\n     * @type command\n     *\n     * @param {jQuery} $editable\n     */\n    this.unlink = function ($editable) {\n      var rng = this.createRange($editable);\n      if (rng.isOnAnchor()) {\n        var anchor = dom.ancestor(rng.sc, dom.isAnchor);\n        rng = range.createFromNode(anchor);\n        rng.select();\n\n        beforeCommand($editable);\n        document.execCommand('unlink');\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * create link (command)\n     *\n     * @param {jQuery} $editable\n     * @param {Object} linkInfo\n     * @param {Object} options\n     */\n    this.createLink = function ($editable, linkInfo, options) {\n      var linkUrl = linkInfo.url;\n      var linkText = linkInfo.text;\n      var isNewWindow = linkInfo.isNewWindow;\n      var rng = linkInfo.range || this.createRange($editable);\n      var isTextChanged = rng.toString() !== linkText;\n\n      options = options || dom.makeLayoutInfo($editable).editor().data('options');\n\n      beforeCommand($editable);\n\n      if (options.onCreateLink) {\n        linkUrl = options.onCreateLink(linkUrl);\n      }\n\n      var anchors = [];\n      if (isTextChanged) {\n        // Create a new link when text changed.\n        var anchor = rng.insertNode($('<A>' + linkText + '</A>')[0]);\n        anchors.push(anchor);\n      } else {\n        anchors = style.styleNodes(rng, {\n          nodeName: 'A',\n          expandClosestSibling: true,\n          onlyPartialContains: true\n        });\n      }\n\n      $.each(anchors, function (idx, anchor) {\n        $(anchor).attr('href', linkUrl);\n        if (isNewWindow) {\n          $(anchor).attr('target', '_blank');\n        } else {\n          $(anchor).removeAttr('target');\n        }\n      });\n\n      var startRange = range.createFromNodeBefore(list.head(anchors));\n      var startPoint = startRange.getStartPoint();\n      var endRange = range.createFromNodeAfter(list.last(anchors));\n      var endPoint = endRange.getEndPoint();\n\n      range.create(\n        startPoint.node,\n        startPoint.offset,\n        endPoint.node,\n        endPoint.offset\n      ).select();\n\n      afterCommand($editable);\n    };\n\n    /**\n     * returns link info\n     *\n     * @return {Object}\n     * @return {WrappedRange} return.range\n     * @return {String} return.text\n     * @return {Boolean} [return.isNewWindow=true]\n     * @return {String} [return.url=\"\"]\n     */\n    this.getLinkInfo = function ($editable) {\n      this.focus($editable);\n\n      var rng = range.create().expand(dom.isAnchor);\n\n      // Get the first anchor on range(for edit).\n      var $anchor = $(list.head(rng.nodes(dom.isAnchor)));\n\n      return {\n        range: rng,\n        text: rng.toString(),\n        isNewWindow: $anchor.length ? $anchor.attr('target') === '_blank' : false,\n        url: $anchor.length ? $anchor.attr('href') : ''\n      };\n    };\n\n    /**\n     * setting color\n     *\n     * @param {Node} $editable\n     * @param {Object} sObjColor  color code\n     * @param {String} sObjColor.foreColor foreground color\n     * @param {String} sObjColor.backColor background color\n     */\n    this.color = function ($editable, sObjColor) {\n      var oColor = JSON.parse(sObjColor);\n      var foreColor = oColor.foreColor, backColor = oColor.backColor;\n\n      beforeCommand($editable);\n\n      if (foreColor) { document.execCommand('foreColor', false, foreColor); }\n      if (backColor) { document.execCommand('backColor', false, backColor); }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * insert Table\n     *\n     * @param {Node} $editable\n     * @param {String} sDim dimension of table (ex : \"5x5\")\n     */\n    this.insertTable = function ($editable, sDim) {\n      var dimension = sDim.split('x');\n      beforeCommand($editable);\n\n      var rng = range.create().deleteContents();\n      rng.insertNode(table.createTable(dimension[0], dimension[1]));\n      afterCommand($editable);\n    };\n\n    /**\n     * float me\n     *\n     * @param {jQuery} $editable\n     * @param {String} value\n     * @param {jQuery} $target\n     */\n    this.floatMe = function ($editable, value, $target) {\n      beforeCommand($editable);\n      // bootstrap\n      $target.removeClass('pull-left pull-right');\n      if (value && value !== 'none') {\n        $target.addClass('pull-' + value);\n      }\n\n      // fallback for non-bootstrap\n      $target.css('float', value);\n      afterCommand($editable);\n    };\n\n    /**\n     * change image shape\n     *\n     * @param {jQuery} $editable\n     * @param {String} value css class\n     * @param {Node} $target\n     */\n    this.imageShape = function ($editable, value, $target) {\n      beforeCommand($editable);\n\n      $target.removeClass('img-rounded img-circle img-thumbnail');\n\n      if (value) {\n        $target.addClass(value);\n      }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * resize overlay element\n     * @param {jQuery} $editable\n     * @param {String} value\n     * @param {jQuery} $target - target element\n     */\n    this.resize = function ($editable, value, $target) {\n      beforeCommand($editable);\n\n      $target.css({\n        width: value * 100 + '%',\n        height: ''\n      });\n\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {Position} pos\n     * @param {jQuery} $target - target element\n     * @param {Boolean} [bKeepRatio] - keep ratio\n     */\n    this.resizeTo = function (pos, $target, bKeepRatio) {\n      var imageSize;\n      if (bKeepRatio) {\n        var newRatio = pos.y / pos.x;\n        var ratio = $target.data('ratio');\n        imageSize = {\n          width: ratio > newRatio ? pos.x : pos.y / ratio,\n          height: ratio > newRatio ? pos.x * ratio : pos.y\n        };\n      } else {\n        imageSize = {\n          width: pos.x,\n          height: pos.y\n        };\n      }\n\n      $target.css(imageSize);\n    };\n\n    /**\n     * remove media object\n     *\n     * @param {jQuery} $editable\n     * @param {String} value - dummy argument (for keep interface)\n     * @param {jQuery} $target - target element\n     */\n    this.removeMedia = function ($editable, value, $target) {\n      beforeCommand($editable);\n      $target.detach();\n\n      handler.bindCustomEvent(\n        $(), $editable.data('callbacks'), 'media.delete'\n      )($target, $editable);\n\n      afterCommand($editable);\n    };\n\n    /**\n     * set focus\n     *\n     * @param $editable\n     */\n    this.focus = function ($editable) {\n      $editable.focus();\n\n      // [workaround] for firefox bug http://goo.gl/lVfAaI\n      if (agent.isFF && !range.create().isOnEditable()) {\n        range.createFromNode($editable[0])\n             .normalize()\n             .collapse()\n             .select();\n      }\n    };\n\n    /**\n     * returns whether contents is empty or not.\n     *\n     * @param {jQuery} $editable\n     * @return {Boolean}\n     */\n    this.isEmpty = function ($editable) {\n      return dom.isEmpty($editable[0]) || dom.emptyPara === $editable.html();\n    };\n  };\n\n  /**\n   * @class module.Button\n   *\n   * Button\n   */\n  var Button = function () {\n    /**\n     * update button status\n     *\n     * @param {jQuery} $container\n     * @param {Object} styleInfo\n     */\n    this.update = function ($container, styleInfo) {\n      /**\n       * handle dropdown's check mark (for fontname, fontsize, lineHeight).\n       * @param {jQuery} $btn\n       * @param {Number} value\n       */\n      var checkDropdownMenu = function ($btn, value) {\n        $btn.find('.dropdown-menu li a').each(function () {\n          // always compare string to avoid creating another func.\n          var isChecked = ($(this).data('value') + '') === (value + '');\n          this.className = isChecked ? 'checked' : '';\n        });\n      };\n\n      /**\n       * update button state(active or not).\n       *\n       * @private\n       * @param {String} selector\n       * @param {Function} pred\n       */\n      var btnState = function (selector, pred) {\n        var $btn = $container.find(selector);\n        $btn.toggleClass('active', pred());\n      };\n\n      if (styleInfo.image) {\n        var $img = $(styleInfo.image);\n\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-rounded\"]', function () {\n          return $img.hasClass('img-rounded');\n        });\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-circle\"]', function () {\n          return $img.hasClass('img-circle');\n        });\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-thumbnail\"]', function () {\n          return $img.hasClass('img-thumbnail');\n        });\n        btnState('button[data-event=\"imageShape\"]:not([data-value])', function () {\n          return !$img.is('.img-rounded, .img-circle, .img-thumbnail');\n        });\n\n        var imgFloat = $img.css('float');\n        btnState('button[data-event=\"floatMe\"][data-value=\"left\"]', function () {\n          return imgFloat === 'left';\n        });\n        btnState('button[data-event=\"floatMe\"][data-value=\"right\"]', function () {\n          return imgFloat === 'right';\n        });\n        btnState('button[data-event=\"floatMe\"][data-value=\"none\"]', function () {\n          return imgFloat !== 'left' && imgFloat !== 'right';\n        });\n\n        var style = $img.attr('style');\n        btnState('button[data-event=\"resize\"][data-value=\"1\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*100%/.test(style);\n        });\n        btnState('button[data-event=\"resize\"][data-value=\"0.5\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*50%/.test(style);\n        });\n        btnState('button[data-event=\"resize\"][data-value=\"0.25\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*25%/.test(style);\n        });\n        return;\n      }\n\n      // fontname\n      var $fontname = $container.find('.note-fontname');\n      if ($fontname.length) {\n        var selectedFont = styleInfo['font-family'];\n        if (!!selectedFont) {\n\n          var list = selectedFont.split(',');\n          for (var i = 0, len = list.length; i < len; i++) {\n            selectedFont = list[i].replace(/[\\'\\\"]/g, '').replace(/\\s+$/, '').replace(/^\\s+/, '');\n            if (agent.isFontInstalled(selectedFont)) {\n              break;\n            }\n          }\n          \n          $fontname.find('.note-current-fontname').text(selectedFont);\n          checkDropdownMenu($fontname, selectedFont);\n\n        }\n      }\n\n      // fontsize\n      var $fontsize = $container.find('.note-fontsize');\n      $fontsize.find('.note-current-fontsize').text(styleInfo['font-size']);\n      checkDropdownMenu($fontsize, parseFloat(styleInfo['font-size']));\n\n      // lineheight\n      var $lineHeight = $container.find('.note-height');\n      checkDropdownMenu($lineHeight, parseFloat(styleInfo['line-height']));\n\n      btnState('button[data-event=\"bold\"]', function () {\n        return styleInfo['font-bold'] === 'bold';\n      });\n      btnState('button[data-event=\"italic\"]', function () {\n        return styleInfo['font-italic'] === 'italic';\n      });\n      btnState('button[data-event=\"underline\"]', function () {\n        return styleInfo['font-underline'] === 'underline';\n      });\n      btnState('button[data-event=\"strikethrough\"]', function () {\n        return styleInfo['font-strikethrough'] === 'strikethrough';\n      });\n      btnState('button[data-event=\"superscript\"]', function () {\n        return styleInfo['font-superscript'] === 'superscript';\n      });\n      btnState('button[data-event=\"subscript\"]', function () {\n        return styleInfo['font-subscript'] === 'subscript';\n      });\n      btnState('button[data-event=\"justifyLeft\"]', function () {\n        return styleInfo['text-align'] === 'left' || styleInfo['text-align'] === 'start';\n      });\n      btnState('button[data-event=\"justifyCenter\"]', function () {\n        return styleInfo['text-align'] === 'center';\n      });\n      btnState('button[data-event=\"justifyRight\"]', function () {\n        return styleInfo['text-align'] === 'right';\n      });\n      btnState('button[data-event=\"justifyFull\"]', function () {\n        return styleInfo['text-align'] === 'justify';\n      });\n      btnState('button[data-event=\"insertUnorderedList\"]', function () {\n        return styleInfo['list-style'] === 'unordered';\n      });\n      btnState('button[data-event=\"insertOrderedList\"]', function () {\n        return styleInfo['list-style'] === 'ordered';\n      });\n    };\n\n    /**\n     * update recent color\n     *\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {Mixed} value\n     */\n    this.updateRecentColor = function (button, eventName, value) {\n      var $color = $(button).closest('.note-color');\n      var $recentColor = $color.find('.note-recent-color');\n      var colorInfo = JSON.parse($recentColor.attr('data-value'));\n      colorInfo[eventName] = value;\n      $recentColor.attr('data-value', JSON.stringify(colorInfo));\n      var sKey = eventName === 'backColor' ? 'background-color' : 'color';\n      $recentColor.find('i').css(sKey, value);\n    };\n  };\n\n  /**\n   * @class module.Toolbar\n   *\n   * Toolbar\n   */\n  var Toolbar = function () {\n    var button = new Button();\n\n    this.update = function ($toolbar, styleInfo) {\n      button.update($toolbar, styleInfo);\n    };\n\n    /**\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {String} value\n     */\n    this.updateRecentColor = function (buttonNode, eventName, value) {\n      button.updateRecentColor(buttonNode, eventName, value);\n    };\n\n    /**\n     * activate buttons exclude codeview\n     * @param {jQuery} $toolbar\n     */\n    this.activate = function ($toolbar) {\n      $toolbar.find('button')\n              .not('button[data-event=\"codeview\"]')\n              .removeClass('disabled');\n    };\n\n    /**\n     * deactivate buttons exclude codeview\n     * @param {jQuery} $toolbar\n     */\n    this.deactivate = function ($toolbar) {\n      $toolbar.find('button')\n              .not('button[data-event=\"codeview\"]')\n              .addClass('disabled');\n    };\n\n    /**\n     * @param {jQuery} $container\n     * @param {Boolean} [bFullscreen=false]\n     */\n    this.updateFullscreen = function ($container, bFullscreen) {\n      var $btn = $container.find('button[data-event=\"fullscreen\"]');\n      $btn.toggleClass('active', bFullscreen);\n    };\n\n    /**\n     * @param {jQuery} $container\n     * @param {Boolean} [isCodeview=false]\n     */\n    this.updateCodeview = function ($container, isCodeview) {\n      var $btn = $container.find('button[data-event=\"codeview\"]');\n      $btn.toggleClass('active', isCodeview);\n\n      if (isCodeview) {\n        this.deactivate($container);\n      } else {\n        this.activate($container);\n      }\n    };\n\n    /**\n     * get button in toolbar \n     *\n     * @param {jQuery} $editable\n     * @param {String} name\n     * @return {jQuery}\n     */\n    this.get = function ($editable, name) {\n      var $toolbar = dom.makeLayoutInfo($editable).toolbar();\n\n      return $toolbar.find('[data-name=' + name + ']');\n    };\n\n    /**\n     * set button state\n     * @param {jQuery} $editable\n     * @param {String} name\n     * @param {Boolean} [isActive=true]\n     */\n    this.setButtonState = function ($editable, name, isActive) {\n      isActive = (isActive === false) ? false : true;\n\n      var $button = this.get($editable, name);\n      $button.toggleClass('active', isActive);\n    };\n  };\n\n  var EDITABLE_PADDING = 24;\n\n  var Statusbar = function () {\n    var $document = $(document);\n\n    this.attach = function (layoutInfo, options) {\n      if (!options.disableResizeEditor) {\n        layoutInfo.statusbar().on('mousedown', hStatusbarMousedown);\n      }\n    };\n\n    /**\n     * `mousedown` event handler on statusbar\n     *\n     * @param {MouseEvent} event\n     */\n    var hStatusbarMousedown = function (event) {\n      event.preventDefault();\n      event.stopPropagation();\n\n      var $editable = dom.makeLayoutInfo(event.target).editable();\n      var editableTop = $editable.offset().top - $document.scrollTop();\n\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      var options = layoutInfo.editor().data('options');\n\n      $document.on('mousemove', function (event) {\n        var nHeight = event.clientY - (editableTop + EDITABLE_PADDING);\n\n        nHeight = (options.minHeight > 0) ? Math.max(nHeight, options.minHeight) : nHeight;\n        nHeight = (options.maxHeight > 0) ? Math.min(nHeight, options.maxHeight) : nHeight;\n\n        $editable.height(nHeight);\n      }).one('mouseup', function () {\n        $document.off('mousemove');\n      });\n    };\n  };\n\n  /**\n   * @class module.Popover\n   *\n   * Popover (http://getbootstrap.com/javascript/#popovers)\n   *\n   */\n  var Popover = function () {\n    var button = new Button();\n\n    /**\n     * returns position from placeholder\n     *\n     * @private\n     * @param {Node} placeholder\n     * @param {Object} options\n     * @param {Boolean} options.isAirMode\n     * @return {Position}\n     */\n    var posFromPlaceholder = function (placeholder, options) {\n      var isAirMode = options && options.isAirMode;\n      var isLeftTop = options && options.isLeftTop;\n\n      var $placeholder = $(placeholder);\n      var pos = isAirMode ? $placeholder.offset() : $placeholder.position();\n      var height = isLeftTop ? 0 : $placeholder.outerHeight(true); // include margin\n\n      // popover below placeholder.\n      return {\n        left: pos.left,\n        top: pos.top + height\n      };\n    };\n\n    /**\n     * show popover\n     *\n     * @private\n     * @param {jQuery} popover\n     * @param {Position} pos\n     */\n    var showPopover = function ($popover, pos) {\n      $popover.css({\n        display: 'block',\n        left: pos.left,\n        top: pos.top\n      });\n    };\n\n    var PX_POPOVER_ARROW_OFFSET_X = 20;\n\n    /**\n     * update current state\n     * @param {jQuery} $popover - popover container\n     * @param {Object} styleInfo - style object\n     * @param {Boolean} isAirMode\n     */\n    this.update = function ($popover, styleInfo, isAirMode) {\n      button.update($popover, styleInfo);\n\n      var $linkPopover = $popover.find('.note-link-popover');\n      if (styleInfo.anchor) {\n        var $anchor = $linkPopover.find('a');\n        var href = $(styleInfo.anchor).attr('href');\n        var target = $(styleInfo.anchor).attr('target');\n        $anchor.attr('href', href).html(href);\n        if (!target) {\n          $anchor.removeAttr('target');\n        } else {\n          $anchor.attr('target', '_blank');\n        }\n        showPopover($linkPopover, posFromPlaceholder(styleInfo.anchor, {\n          isAirMode: isAirMode\n        }));\n      } else {\n        $linkPopover.hide();\n      }\n\n      var $imagePopover = $popover.find('.note-image-popover');\n      if (styleInfo.image) {\n        showPopover($imagePopover, posFromPlaceholder(styleInfo.image, {\n          isAirMode: isAirMode,\n          isLeftTop: true\n        }));\n      } else {\n        $imagePopover.hide();\n      }\n\n      var $airPopover = $popover.find('.note-air-popover');\n      if (isAirMode && styleInfo.range && !styleInfo.range.isCollapsed()) {\n        var rect = list.last(styleInfo.range.getClientRects());\n        if (rect) {\n          var bnd = func.rect2bnd(rect);\n          showPopover($airPopover, {\n            left: Math.max(bnd.left + bnd.width / 2 - PX_POPOVER_ARROW_OFFSET_X, 0),\n            top: bnd.top + bnd.height\n          });\n        }\n      } else {\n        $airPopover.hide();\n      }\n    };\n\n    /**\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {String} value\n     */\n    this.updateRecentColor = function (button, eventName, value) {\n      button.updateRecentColor(button, eventName, value);\n    };\n\n    /**\n     * hide all popovers\n     * @param {jQuery} $popover - popover container\n     */\n    this.hide = function ($popover) {\n      $popover.children().hide();\n    };\n  };\n\n  /**\n   * @class module.Handle\n   *\n   * Handle\n   */\n  var Handle = function (handler) {\n    var $document = $(document);\n\n    /**\n     * `mousedown` event handler on $handle\n     *  - controlSizing: resize image\n     *\n     * @param {MouseEvent} event\n     */\n    var hHandleMousedown = function (event) {\n      if (dom.isControlSizing(event.target)) {\n        event.preventDefault();\n        event.stopPropagation();\n\n        var layoutInfo = dom.makeLayoutInfo(event.target),\n            $handle = layoutInfo.handle(),\n            $popover = layoutInfo.popover(),\n            $editable = layoutInfo.editable(),\n            $editor = layoutInfo.editor();\n\n        var target = $handle.find('.note-control-selection').data('target'),\n            $target = $(target), posStart = $target.offset(),\n            scrollTop = $document.scrollTop();\n\n        var isAirMode = $editor.data('options').airMode;\n\n        $document.on('mousemove', function (event) {\n          handler.invoke('editor.resizeTo', {\n            x: event.clientX - posStart.left,\n            y: event.clientY - (posStart.top - scrollTop)\n          }, $target, !event.shiftKey);\n\n          handler.invoke('handle.update', $handle, {image: target}, isAirMode);\n          handler.invoke('popover.update', $popover, {image: target}, isAirMode);\n        }).one('mouseup', function () {\n          $document.off('mousemove');\n          handler.invoke('editor.afterCommand', $editable);\n        });\n\n        if (!$target.data('ratio')) { // original ratio.\n          $target.data('ratio', $target.height() / $target.width());\n        }\n      }\n    };\n\n    this.attach = function (layoutInfo) {\n      layoutInfo.handle().on('mousedown', hHandleMousedown);\n    };\n\n    /**\n     * update handle\n     * @param {jQuery} $handle\n     * @param {Object} styleInfo\n     * @param {Boolean} isAirMode\n     */\n    this.update = function ($handle, styleInfo, isAirMode) {\n      var $selection = $handle.find('.note-control-selection');\n      if (styleInfo.image) {\n        var $image = $(styleInfo.image);\n        var pos = isAirMode ? $image.offset() : $image.position();\n\n        // include margin\n        var imageSize = {\n          w: $image.outerWidth(true),\n          h: $image.outerHeight(true)\n        };\n\n        $selection.css({\n          display: 'block',\n          left: pos.left,\n          top: pos.top,\n          width: imageSize.w,\n          height: imageSize.h\n        }).data('target', styleInfo.image); // save current image element.\n        var sizingText = imageSize.w + 'x' + imageSize.h;\n        $selection.find('.note-control-selection-info').text(sizingText);\n      } else {\n        $selection.hide();\n      }\n    };\n\n    /**\n     * hide\n     *\n     * @param {jQuery} $handle\n     */\n    this.hide = function ($handle) {\n      $handle.children().hide();\n    };\n  };\n\n  var Fullscreen = function (handler) {\n    var $window = $(window);\n    var $scrollbar = $('html, body');\n\n    /**\n     * toggle fullscreen\n     *\n     * @param {Object} layoutInfo\n     */\n    this.toggle = function (layoutInfo) {\n\n      var $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable();\n\n      var resize = function (size) {\n        $editable.css('height', size.h);\n        $codable.css('height', size.h);\n        if ($codable.data('cmeditor')) {\n          $codable.data('cmeditor').setsize(null, size.h);\n        }\n      };\n\n      $editor.toggleClass('fullscreen');\n      var isFullscreen = $editor.hasClass('fullscreen');\n      if (isFullscreen) {\n        $editable.data('orgheight', $editable.css('height'));\n\n        $window.on('resize', function () {\n          resize({\n            h: $window.height() - $toolbar.outerHeight()\n          });\n        }).trigger('resize');\n\n        $scrollbar.css('overflow', 'hidden');\n      } else {\n        $window.off('resize');\n        resize({\n          h: $editable.data('orgheight')\n        });\n        $scrollbar.css('overflow', 'visible');\n      }\n\n      handler.invoke('toolbar.updateFullscreen', $toolbar, isFullscreen);\n    };\n  };\n\n\n  var CodeMirror;\n  if (agent.hasCodeMirror) {\n    if (agent.isSupportAmd) {\n      require(['CodeMirror'], function (cm) {\n        CodeMirror = cm;\n      });\n    } else {\n      CodeMirror = window.CodeMirror;\n    }\n  }\n\n  /**\n   * @class Codeview\n   */\n  var Codeview = function (handler) {\n\n    this.sync = function (layoutInfo) {\n      var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);\n      if (isCodeview && agent.hasCodeMirror) {\n        layoutInfo.codable().data('cmEditor').save();\n      }\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     * @return {Boolean}\n     */\n    this.isActivated = function (layoutInfo) {\n      var $editor = layoutInfo.editor();\n      return $editor.hasClass('codeview');\n    };\n\n    /**\n     * toggle codeview\n     *\n     * @param {Object} layoutInfo\n     */\n    this.toggle = function (layoutInfo) {\n      if (this.isActivated(layoutInfo)) {\n        this.deactivate(layoutInfo);\n      } else {\n        this.activate(layoutInfo);\n      }\n    };\n\n    /**\n     * activate code view\n     *\n     * @param {Object} layoutInfo\n     */\n    this.activate = function (layoutInfo) {\n      var $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable(),\n          $popover = layoutInfo.popover(),\n          $handle = layoutInfo.handle();\n\n      var options = $editor.data('options');\n\n      $codable.val(dom.html($editable, options.prettifyHtml));\n      $codable.height($editable.height());\n\n      handler.invoke('toolbar.updateCodeview', $toolbar, true);\n      handler.invoke('popover.hide', $popover);\n      handler.invoke('handle.hide', $handle);\n\n      $editor.addClass('codeview');\n\n      $codable.focus();\n\n      // activate CodeMirror as codable\n      if (agent.hasCodeMirror) {\n        var cmEditor = CodeMirror.fromTextArea($codable[0], options.codemirror);\n\n        // CodeMirror TernServer\n        if (options.codemirror.tern) {\n          var server = new CodeMirror.TernServer(options.codemirror.tern);\n          cmEditor.ternServer = server;\n          cmEditor.on('cursorActivity', function (cm) {\n            server.updateArgHints(cm);\n          });\n        }\n\n        // CodeMirror hasn't Padding.\n        cmEditor.setSize(null, $editable.outerHeight());\n        $codable.data('cmEditor', cmEditor);\n      }\n    };\n\n    /**\n     * deactivate code view\n     *\n     * @param {Object} layoutInfo\n     */\n    this.deactivate = function (layoutInfo) {\n      var $holder = layoutInfo.holder(),\n          $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable();\n\n      var options = $editor.data('options');\n\n      // deactivate CodeMirror as codable\n      if (agent.hasCodeMirror) {\n        var cmEditor = $codable.data('cmEditor');\n        $codable.val(cmEditor.getValue());\n        cmEditor.toTextArea();\n      }\n\n      var value = dom.value($codable, options.prettifyHtml) || dom.emptyPara;\n      var isChange = $editable.html() !== value;\n\n      $editable.html(value);\n      $editable.height(options.height ? $codable.height() : 'auto');\n      $editor.removeClass('codeview');\n\n      if (isChange) {\n        handler.bindCustomEvent(\n          $holder, $editable.data('callbacks'), 'change'\n        )($editable.html(), $editable);\n      }\n\n      $editable.focus();\n\n      handler.invoke('toolbar.updateCodeview', $toolbar, false);\n    };\n  };\n\n  var DragAndDrop = function (handler) {\n    var $document = $(document);\n\n    /**\n     * attach Drag and Drop Events\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options\n     */\n    this.attach = function (layoutInfo, options) {\n      if (options.airMode || options.disableDragAndDrop) {\n        // prevent default drop event\n        $document.on('drop', function (e) {\n          e.preventDefault();\n        });\n      } else {\n        this.attachDragAndDropEvent(layoutInfo, options);\n      }\n    };\n\n    /**\n     * attach Drag and Drop Events\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options\n     */\n    this.attachDragAndDropEvent = function (layoutInfo, options) {\n      var collection = $(),\n          $editor = layoutInfo.editor(),\n          $dropzone = layoutInfo.dropzone(),\n          $dropzoneMessage = $dropzone.find('.note-dropzone-message');\n\n      // show dropzone on dragenter when dragging a object to document\n      // -but only if the editor is visible, i.e. has a positive width and height\n      $document.on('dragenter', function (e) {\n        var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);\n        var hasEditorSize = $editor.width() > 0 && $editor.height() > 0;\n        if (!isCodeview && !collection.length && hasEditorSize) {\n          $editor.addClass('dragover');\n          $dropzone.width($editor.width());\n          $dropzone.height($editor.height());\n          $dropzoneMessage.text(options.langInfo.image.dragImageHere);\n        }\n        collection = collection.add(e.target);\n      }).on('dragleave', function (e) {\n        collection = collection.not(e.target);\n        if (!collection.length) {\n          $editor.removeClass('dragover');\n        }\n      }).on('drop', function () {\n        collection = $();\n        $editor.removeClass('dragover');\n      });\n\n      // change dropzone's message on hover.\n      $dropzone.on('dragenter', function () {\n        $dropzone.addClass('hover');\n        $dropzoneMessage.text(options.langInfo.image.dropImage);\n      }).on('dragleave', function () {\n        $dropzone.removeClass('hover');\n        $dropzoneMessage.text(options.langInfo.image.dragImageHere);\n      });\n\n      // attach dropImage\n      $dropzone.on('drop', function (event) {\n\n        var dataTransfer = event.originalEvent.dataTransfer;\n        var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n\n        if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {\n          event.preventDefault();\n          layoutInfo.editable().focus();\n          handler.insertImages(layoutInfo, dataTransfer.files);\n        } else {\n          var insertNodefunc = function () {\n            layoutInfo.holder().summernote('insertNode', this);\n          };\n\n          for (var i = 0, len = dataTransfer.types.length; i < len; i++) {\n            var type = dataTransfer.types[i];\n            var content = dataTransfer.getData(type);\n\n            if (type.toLowerCase().indexOf('text') > -1) {\n              layoutInfo.holder().summernote('pasteHTML', content);\n            } else {\n              $(content).each(insertNodefunc);\n            }\n          }\n        }\n      }).on('dragover', false); // prevent default dragover event\n    };\n  };\n\n  var Clipboard = function (handler) {\n    var $paste;\n\n    this.attach = function (layoutInfo) {\n      // [workaround] getting image from clipboard\n      //  - IE11 and Firefox: CTRL+v hook\n      //  - Webkit: event.clipboardData\n      if ((agent.isMSIE && agent.browserVersion > 10) || agent.isFF) {\n        $paste = $('<div />').attr('contenteditable', true).css({\n          position : 'absolute',\n          left : -100000,\n          opacity : 0\n        });\n\n        layoutInfo.editable().on('keydown', function (e) {\n          if (e.ctrlKey && e.keyCode === key.code.V) {\n            handler.invoke('saveRange', layoutInfo.editable());\n            $paste.focus();\n\n            setTimeout(function () {\n              pasteByHook(layoutInfo);\n            }, 0);\n          }\n        });\n\n        layoutInfo.editable().before($paste);\n      } else {\n        layoutInfo.editable().on('paste', pasteByEvent);\n      }\n    };\n\n    var pasteByHook = function (layoutInfo) {\n      var $editable = layoutInfo.editable();\n      var node = $paste[0].firstChild;\n\n      if (dom.isImg(node)) {\n        var dataURI = node.src;\n        var decodedData = atob(dataURI.split(',')[1]);\n        var array = new Uint8Array(decodedData.length);\n        for (var i = 0; i < decodedData.length; i++) {\n          array[i] = decodedData.charCodeAt(i);\n        }\n\n        var blob = new Blob([array], { type : 'image/png' });\n        blob.name = 'clipboard.png';\n\n        handler.invoke('restoreRange', $editable);\n        handler.invoke('focus', $editable);\n        handler.insertImages(layoutInfo, [blob]);\n      } else {\n        var pasteContent = $('<div />').html($paste.html()).html();\n        handler.invoke('restoreRange', $editable);\n        handler.invoke('focus', $editable);\n\n        if (pasteContent) {\n          handler.invoke('pasteHTML', $editable, pasteContent);\n        }\n      }\n\n      $paste.empty();\n    };\n\n    /**\n     * paste by clipboard event\n     *\n     * @param {Event} event\n     */\n    var pasteByEvent = function (event) {\n      var clipboardData = event.originalEvent.clipboardData;\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      var $editable = layoutInfo.editable();\n\n      if (clipboardData && clipboardData.items && clipboardData.items.length) {\n        var item = list.head(clipboardData.items);\n        if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {\n          handler.insertImages(layoutInfo, [item.getAsFile()]);\n        }\n        handler.invoke('editor.afterCommand', $editable);\n      }\n    };\n  };\n\n  var LinkDialog = function (handler) {\n\n    /**\n     * toggle button status\n     *\n     * @private\n     * @param {jQuery} $btn\n     * @param {Boolean} isEnable\n     */\n    var toggleBtn = function ($btn, isEnable) {\n      $btn.toggleClass('disabled', !isEnable);\n      $btn.attr('disabled', !isEnable);\n    };\n\n    /**\n     * bind enter key\n     *\n     * @private\n     * @param {jQuery} $input\n     * @param {jQuery} $btn\n     */\n    var bindEnterKey = function ($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          $btn.trigger('click');\n        }\n      });\n    };\n\n    /**\n     * Show link dialog and set event handlers on dialog controls.\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @param {Object} linkInfo\n     * @return {Promise}\n     */\n    this.showLinkDialog = function ($editable, $dialog, linkInfo) {\n      return $.Deferred(function (deferred) {\n        var $linkDialog = $dialog.find('.note-link-dialog');\n\n        var $linkText = $linkDialog.find('.note-link-text'),\n        $linkUrl = $linkDialog.find('.note-link-url'),\n        $linkBtn = $linkDialog.find('.note-link-btn'),\n        $openInNewWindow = $linkDialog.find('input[type=checkbox]');\n\n        $linkDialog.one('shown.bs.modal', function () {\n          $linkText.val(linkInfo.text);\n\n          $linkText.on('input', function () {\n            toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());\n            // if linktext was modified by keyup,\n            // stop cloning text from linkUrl\n            linkInfo.text = $linkText.val();\n          });\n\n          // if no url was given, copy text to url\n          if (!linkInfo.url) {\n            linkInfo.url = linkInfo.text || 'http://';\n            toggleBtn($linkBtn, linkInfo.text);\n          }\n\n          $linkUrl.on('input', function () {\n            toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());\n            // display same link on `Text to display` input\n            // when create a new link\n            if (!linkInfo.text) {\n              $linkText.val($linkUrl.val());\n            }\n          }).val(linkInfo.url).trigger('focus').trigger('select');\n\n          bindEnterKey($linkUrl, $linkBtn);\n          bindEnterKey($linkText, $linkBtn);\n\n          $openInNewWindow.prop('checked', linkInfo.isNewWindow);\n\n          $linkBtn.one('click', function (event) {\n            event.preventDefault();\n\n            deferred.resolve({\n              range: linkInfo.range,\n              url: $linkUrl.val(),\n              text: $linkText.val(),\n              isNewWindow: $openInNewWindow.is(':checked')\n            });\n            $linkDialog.modal('hide');\n          });\n        }).one('hidden.bs.modal', function () {\n          // detach events\n          $linkText.off('input keypress');\n          $linkUrl.off('input keypress');\n          $linkBtn.off('click');\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        }).modal('show');\n      }).promise();\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     */\n    this.show = function (layoutInfo) {\n      var $editor = layoutInfo.editor(),\n          $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable(),\n          $popover = layoutInfo.popover(),\n          linkInfo = handler.invoke('editor.getLinkInfo', $editable);\n\n      var options = $editor.data('options');\n\n      handler.invoke('editor.saveRange', $editable);\n      this.showLinkDialog($editable, $dialog, linkInfo).then(function (linkInfo) {\n        handler.invoke('editor.restoreRange', $editable);\n        handler.invoke('editor.createLink', $editable, linkInfo, options);\n        // hide popover after creating link\n        handler.invoke('popover.hide', $popover);\n      }).fail(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n  };\n\n  var ImageDialog = function (handler) {\n    /**\n     * toggle button status\n     *\n     * @private\n     * @param {jQuery} $btn\n     * @param {Boolean} isEnable\n     */\n    var toggleBtn = function ($btn, isEnable) {\n      $btn.toggleClass('disabled', !isEnable);\n      $btn.attr('disabled', !isEnable);\n    };\n\n    /**\n     * bind enter key\n     *\n     * @private\n     * @param {jQuery} $input\n     * @param {jQuery} $btn\n     */\n    var bindEnterKey = function ($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          $btn.trigger('click');\n        }\n      });\n    };\n\n    this.show = function (layoutInfo) {\n      var $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable();\n\n      handler.invoke('editor.saveRange', $editable);\n      this.showImageDialog($editable, $dialog).then(function (data) {\n        handler.invoke('editor.restoreRange', $editable);\n\n        if (typeof data === 'string') {\n          // image url\n          handler.invoke('editor.insertImage', $editable, data);\n        } else {\n          // array of files\n          handler.insertImages(layoutInfo, data);\n        }\n      }).fail(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n\n    /**\n     * show image dialog\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @return {Promise}\n     */\n    this.showImageDialog = function ($editable, $dialog) {\n      return $.Deferred(function (deferred) {\n        var $imageDialog = $dialog.find('.note-image-dialog');\n\n        var $imageInput = $dialog.find('.note-image-input'),\n            $imageUrl = $dialog.find('.note-image-url'),\n            $imageBtn = $dialog.find('.note-image-btn');\n\n        $imageDialog.one('shown.bs.modal', function () {\n          // Cloning imageInput to clear element.\n          $imageInput.replaceWith($imageInput.clone()\n            .on('change', function () {\n              deferred.resolve(this.files || this.value);\n              $imageDialog.modal('hide');\n            })\n            .val('')\n          );\n\n          $imageBtn.click(function (event) {\n            event.preventDefault();\n\n            deferred.resolve($imageUrl.val());\n            $imageDialog.modal('hide');\n          });\n\n          $imageUrl.on('keyup paste', function (event) {\n            var url;\n            \n            if (event.type === 'paste') {\n              url = event.originalEvent.clipboardData.getData('text');\n            } else {\n              url = $imageUrl.val();\n            }\n            \n            toggleBtn($imageBtn, url);\n          }).val('').trigger('focus');\n          bindEnterKey($imageUrl, $imageBtn);\n        }).one('hidden.bs.modal', function () {\n          $imageInput.off('change');\n          $imageUrl.off('keyup paste keypress');\n          $imageBtn.off('click');\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        }).modal('show');\n      });\n    };\n  };\n\n  var HelpDialog = function (handler) {\n    /**\n     * show help dialog\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @return {Promise}\n     */\n    this.showHelpDialog = function ($editable, $dialog) {\n      return $.Deferred(function (deferred) {\n        var $helpDialog = $dialog.find('.note-help-dialog');\n\n        $helpDialog.one('hidden.bs.modal', function () {\n          deferred.resolve();\n        }).modal('show');\n      }).promise();\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     */\n    this.show = function (layoutInfo) {\n      var $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable();\n\n      handler.invoke('editor.saveRange', $editable, true);\n      this.showHelpDialog($editable, $dialog).then(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n  };\n\n\n  /**\n   * @class EventHandler\n   *\n   * EventHandler\n   *  - TODO: new instance per a editor\n   */\n  var EventHandler = function () {\n    var self = this;\n\n    /**\n     * Modules\n     */\n    var modules = this.modules = {\n      editor: new Editor(this),\n      toolbar: new Toolbar(this),\n      statusbar: new Statusbar(this),\n      popover: new Popover(this),\n      handle: new Handle(this),\n      fullscreen: new Fullscreen(this),\n      codeview: new Codeview(this),\n      dragAndDrop: new DragAndDrop(this),\n      clipboard: new Clipboard(this),\n      linkDialog: new LinkDialog(this),\n      imageDialog: new ImageDialog(this),\n      helpDialog: new HelpDialog(this)\n    };\n\n    /**\n     * invoke module's method\n     *\n     * @param {String} moduleAndMethod - ex) 'editor.redo'\n     * @param {...*} arguments - arguments of method\n     * @return {*}\n     */\n    this.invoke = function () {\n      var moduleAndMethod = list.head(list.from(arguments));\n      var args = list.tail(list.from(arguments));\n\n      var splits = moduleAndMethod.split('.');\n      var hasSeparator = splits.length > 1;\n      var moduleName = hasSeparator && list.head(splits);\n      var methodName = hasSeparator ? list.last(splits) : list.head(splits);\n\n      var module = this.getModule(moduleName);\n      var method = module[methodName];\n\n      return method && method.apply(module, args);\n    };\n\n    /**\n     * returns module\n     *\n     * @param {String} moduleName - name of module\n     * @return {Module} - defaults is editor\n     */\n    this.getModule = function (moduleName) {\n      return this.modules[moduleName] || this.modules.editor;\n    };\n\n    /**\n     * @param {jQuery} $holder\n     * @param {Object} callbacks\n     * @param {String} eventNamespace\n     * @returns {Function}\n     */\n    var bindCustomEvent = this.bindCustomEvent = function ($holder, callbacks, eventNamespace) {\n      return function () {\n        var callback = callbacks[func.namespaceToCamel(eventNamespace, 'on')];\n        if (callback) {\n          callback.apply($holder[0], arguments);\n        }\n        return $holder.trigger('summernote.' + eventNamespace, arguments);\n      };\n    };\n\n    /**\n     * insert Images from file array.\n     *\n     * @private\n     * @param {Object} layoutInfo\n     * @param {File[]} files\n     */\n    this.insertImages = function (layoutInfo, files) {\n      var $editor = layoutInfo.editor(),\n          $editable = layoutInfo.editable(),\n          $holder = layoutInfo.holder();\n\n      var callbacks = $editable.data('callbacks');\n      var options = $editor.data('options');\n\n      // If onImageUpload options setted\n      if (callbacks.onImageUpload) {\n        bindCustomEvent($holder, callbacks, 'image.upload')(files);\n      // else insert Image as dataURL\n      } else {\n        $.each(files, function (idx, file) {\n          var filename = file.name;\n          if (options.maximumImageFileSize && options.maximumImageFileSize < file.size) {\n            bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);\n          } else {\n            async.readFileAsDataURL(file).then(function (sDataURL) {\n              modules.editor.insertImage($editable, sDataURL, filename);\n            }).fail(function () {\n              bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);\n            });\n          }\n        });\n      }\n    };\n\n    var commands = {\n      /**\n       * @param {Object} layoutInfo\n       */\n      showLinkDialog: function (layoutInfo) {\n        modules.linkDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      showImageDialog: function (layoutInfo) {\n        modules.imageDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      showHelpDialog: function (layoutInfo) {\n        modules.helpDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      fullscreen: function (layoutInfo) {\n        modules.fullscreen.toggle(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      codeview: function (layoutInfo) {\n        modules.codeview.toggle(layoutInfo);\n      }\n    };\n\n    var hMousedown = function (event) {\n      //preventDefault Selection for FF, IE8+\n      if (dom.isImg(event.target)) {\n        event.preventDefault();\n      }\n    };\n\n    var hKeyupAndMouseup = function (event) {\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      modules.editor.removeBogus(layoutInfo.editable());\n      hToolbarAndPopoverUpdate(event);\n    };\n\n    /**\n     * update sytle info\n     * @param {Object} styleInfo\n     * @param {Object} layoutInfo\n     */\n    this.updateStyleInfo = function (styleInfo, layoutInfo) {\n      if (!styleInfo) {\n        return;\n      }\n      var isAirMode = layoutInfo.editor().data('options').airMode;\n      if (!isAirMode) {\n        modules.toolbar.update(layoutInfo.toolbar(), styleInfo);\n      }\n\n      modules.popover.update(layoutInfo.popover(), styleInfo, isAirMode);\n      modules.handle.update(layoutInfo.handle(), styleInfo, isAirMode);\n    };\n\n    var hToolbarAndPopoverUpdate = function (event) {\n      var target = event.target;\n      // delay for range after mouseup\n      setTimeout(function () {\n        var layoutInfo = dom.makeLayoutInfo(target);\n        var styleInfo = modules.editor.currentStyle(target);\n        self.updateStyleInfo(styleInfo, layoutInfo);\n      }, 0);\n    };\n\n    var hScroll = function (event) {\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      //hide popover and handle when scrolled\n      modules.popover.hide(layoutInfo.popover());\n      modules.handle.hide(layoutInfo.handle());\n    };\n\n    var hToolbarAndPopoverMousedown = function (event) {\n      // prevent default event when insertTable (FF, Webkit)\n      var $btn = $(event.target).closest('[data-event]');\n      if ($btn.length) {\n        event.preventDefault();\n      }\n    };\n\n    var hToolbarAndPopoverClick = function (event) {\n      var $btn = $(event.target).closest('[data-event]');\n\n      if (!$btn.length) {\n        return;\n      }\n\n      var eventName = $btn.attr('data-event'),\n          value = $btn.attr('data-value'),\n          hide = $btn.attr('data-hide');\n\n      var layoutInfo = dom.makeLayoutInfo(event.target);\n\n      // before command: detect control selection element($target)\n      var $target;\n      if ($.inArray(eventName, ['resize', 'floatMe', 'removeMedia', 'imageShape']) !== -1) {\n        var $selection = layoutInfo.handle().find('.note-control-selection');\n        $target = $($selection.data('target'));\n      }\n\n      // If requested, hide the popover when the button is clicked.\n      // Useful for things like showHelpDialog.\n      if (hide) {\n        $btn.parents('.popover').hide();\n      }\n\n      if ($.isFunction($.summernote.pluginEvents[eventName])) {\n        $.summernote.pluginEvents[eventName](event, modules.editor, layoutInfo, value);\n      } else if (modules.editor[eventName]) { // on command\n        var $editable = layoutInfo.editable();\n        $editable.focus();\n        modules.editor[eventName]($editable, value, $target);\n        event.preventDefault();\n      } else if (commands[eventName]) {\n        commands[eventName].call(this, layoutInfo);\n        event.preventDefault();\n      }\n\n      // after command\n      if ($.inArray(eventName, ['backColor', 'foreColor']) !== -1) {\n        var options = layoutInfo.editor().data('options', options);\n        var module = options.airMode ? modules.popover : modules.toolbar;\n        module.updateRecentColor(list.head($btn), eventName, value);\n      }\n\n      hToolbarAndPopoverUpdate(event);\n    };\n\n    var PX_PER_EM = 18;\n    var hDimensionPickerMove = function (event, options) {\n      var $picker = $(event.target.parentNode); // target is mousecatcher\n      var $dimensionDisplay = $picker.next();\n      var $catcher = $picker.find('.note-dimension-picker-mousecatcher');\n      var $highlighted = $picker.find('.note-dimension-picker-highlighted');\n      var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');\n\n      var posOffset;\n      // HTML5 with jQuery - e.offsetX is undefined in Firefox\n      if (event.offsetX === undefined) {\n        var posCatcher = $(event.target).offset();\n        posOffset = {\n          x: event.pageX - posCatcher.left,\n          y: event.pageY - posCatcher.top\n        };\n      } else {\n        posOffset = {\n          x: event.offsetX,\n          y: event.offsetY\n        };\n      }\n\n      var dim = {\n        c: Math.ceil(posOffset.x / PX_PER_EM) || 1,\n        r: Math.ceil(posOffset.y / PX_PER_EM) || 1\n      };\n\n      $highlighted.css({ width: dim.c + 'em', height: dim.r + 'em' });\n      $catcher.attr('data-value', dim.c + 'x' + dim.r);\n\n      if (3 < dim.c && dim.c < options.insertTableMaxSize.col) {\n        $unhighlighted.css({ width: dim.c + 1 + 'em'});\n      }\n\n      if (3 < dim.r && dim.r < options.insertTableMaxSize.row) {\n        $unhighlighted.css({ height: dim.r + 1 + 'em'});\n      }\n\n      $dimensionDisplay.html(dim.c + ' x ' + dim.r);\n    };\n    \n    /**\n     * bind KeyMap on keydown\n     *\n     * @param {Object} layoutInfo\n     * @param {Object} keyMap\n     */\n    this.bindKeyMap = function (layoutInfo, keyMap) {\n      var $editor = layoutInfo.editor();\n      var $editable = layoutInfo.editable();\n\n      $editable.on('keydown', function (event) {\n        var keys = [];\n\n        // modifier\n        if (event.metaKey) { keys.push('CMD'); }\n        if (event.ctrlKey && !event.altKey) { keys.push('CTRL'); }\n        if (event.shiftKey) { keys.push('SHIFT'); }\n\n        // keycode\n        var keyName = key.nameFromCode[event.keyCode];\n        if (keyName) {\n          keys.push(keyName);\n        }\n\n        var pluginEvent;\n        var keyString = keys.join('+');\n        var eventName = keyMap[keyString];\n        if (eventName) {\n          // FIXME Summernote doesn't support event pipeline yet.\n          //  - Plugin -> Base Code\n          pluginEvent = $.summernote.pluginEvents[keyString];\n          if ($.isFunction(pluginEvent)) {\n            if (pluginEvent(event, modules.editor, layoutInfo)) {\n              return false;\n            }\n          }\n\n          pluginEvent = $.summernote.pluginEvents[eventName];\n\n          if ($.isFunction(pluginEvent)) {\n            pluginEvent(event, modules.editor, layoutInfo);\n          } else if (modules.editor[eventName]) {\n            modules.editor[eventName]($editable, $editor.data('options'));\n            event.preventDefault();\n          } else if (commands[eventName]) {\n            commands[eventName].call(this, layoutInfo);\n            event.preventDefault();\n          }\n        } else if (key.isEdit(event.keyCode)) {\n          modules.editor.afterCommand($editable);\n        }\n      });\n    };\n\n    /**\n     * attach eventhandler\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options - user options include custom event handlers\n     */\n    this.attach = function (layoutInfo, options) {\n      // handlers for editable\n      if (options.shortcuts) {\n        this.bindKeyMap(layoutInfo, options.keyMap[agent.isMac ? 'mac' : 'pc']);\n      }\n      layoutInfo.editable().on('mousedown', hMousedown);\n      layoutInfo.editable().on('keyup mouseup', hKeyupAndMouseup);\n      layoutInfo.editable().on('scroll', hScroll);\n\n      // handler for clipboard\n      modules.clipboard.attach(layoutInfo, options);\n\n      // handler for handle and popover\n      modules.handle.attach(layoutInfo, options);\n      layoutInfo.popover().on('click', hToolbarAndPopoverClick);\n      layoutInfo.popover().on('mousedown', hToolbarAndPopoverMousedown);\n\n      // handler for drag and drop\n      modules.dragAndDrop.attach(layoutInfo, options);\n\n      // handlers for frame mode (toolbar, statusbar)\n      if (!options.airMode) {\n        // handler for toolbar\n        layoutInfo.toolbar().on('click', hToolbarAndPopoverClick);\n        layoutInfo.toolbar().on('mousedown', hToolbarAndPopoverMousedown);\n\n        // handler for statusbar\n        modules.statusbar.attach(layoutInfo, options);\n      }\n\n      // handler for table dimension\n      var $catcherContainer = options.airMode ? layoutInfo.popover() :\n                                                layoutInfo.toolbar();\n      var $catcher = $catcherContainer.find('.note-dimension-picker-mousecatcher');\n      $catcher.css({\n        width: options.insertTableMaxSize.col + 'em',\n        height: options.insertTableMaxSize.row + 'em'\n      }).on('mousemove', function (event) {\n        hDimensionPickerMove(event, options);\n      });\n\n      // save options on editor\n      layoutInfo.editor().data('options', options);\n\n      // ret styleWithCSS for backColor / foreColor clearing with 'inherit'.\n      if (!agent.isMSIE) {\n        // [workaround] for Firefox\n        //  - protect FF Error: NS_ERROR_FAILURE: Failure\n        setTimeout(function () {\n          document.execCommand('styleWithCSS', 0, options.styleWithSpan);\n        }, 0);\n      }\n\n      // History\n      var history = new History(layoutInfo.editable());\n      layoutInfo.editable().data('NoteHistory', history);\n\n      // All editor status will be saved on editable with jquery's data\n      // for support multiple editor with singleton object.\n      layoutInfo.editable().data('callbacks', {\n        onInit: options.onInit,\n        onFocus: options.onFocus,\n        onBlur: options.onBlur,\n        onKeydown: options.onKeydown,\n        onKeyup: options.onKeyup,\n        onMousedown: options.onMousedown,\n        onEnter: options.onEnter,\n        onPaste: options.onPaste,\n        onBeforeCommand: options.onBeforeCommand,\n        onChange: options.onChange,\n        onImageUpload: options.onImageUpload,\n        onImageUploadError: options.onImageUploadError,\n        onMediaDelete: options.onMediaDelete,\n        onToolbarClick: options.onToolbarClick\n      });\n\n      var styleInfo = modules.editor.styleFromNode(layoutInfo.editable());\n      this.updateStyleInfo(styleInfo, layoutInfo);\n    };\n\n    /**\n     * attach jquery custom event\n     *\n     * @param {Object} layoutInfo - layout Informations\n     */\n    this.attachCustomEvent = function (layoutInfo, options) {\n      var $holder = layoutInfo.holder();\n      var $editable = layoutInfo.editable();\n      var callbacks = $editable.data('callbacks');\n\n      $editable.focus(bindCustomEvent($holder, callbacks, 'focus'));\n      $editable.blur(bindCustomEvent($holder, callbacks, 'blur'));\n\n      $editable.keydown(function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          bindCustomEvent($holder, callbacks, 'enter').call(this, event);\n        }\n        bindCustomEvent($holder, callbacks, 'keydown').call(this, event);\n      });\n      $editable.keyup(bindCustomEvent($holder, callbacks, 'keyup'));\n\n      $editable.on('mousedown', bindCustomEvent($holder, callbacks, 'mousedown'));\n      $editable.on('mouseup', bindCustomEvent($holder, callbacks, 'mouseup'));\n      $editable.on('scroll', bindCustomEvent($holder, callbacks, 'scroll'));\n\n      $editable.on('paste', bindCustomEvent($holder, callbacks, 'paste'));\n      \n      // [workaround] IE doesn't have input events for contentEditable\n      //  - see: https://goo.gl/4bfIvA\n      var changeEventName = agent.isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input';\n      $editable.on(changeEventName, function () {\n        bindCustomEvent($holder, callbacks, 'change')($editable.html(), $editable);\n      });\n\n      if (!options.airMode) {\n        layoutInfo.toolbar().click(bindCustomEvent($holder, callbacks, 'toolbar.click'));\n        layoutInfo.popover().click(bindCustomEvent($holder, callbacks, 'popover.click'));\n      }\n\n      // Textarea: auto filling the code before form submit.\n      if (dom.isTextarea(list.head($holder))) {\n        $holder.closest('form').submit(function (e) {\n          layoutInfo.holder().val(layoutInfo.holder().code());\n          bindCustomEvent($holder, callbacks, 'submit').call(this, e, $holder.code());\n        });\n      }\n\n      // textarea auto sync\n      if (dom.isTextarea(list.head($holder)) && options.textareaAutoSync) {\n        $holder.on('summernote.change', function () {\n          layoutInfo.holder().val(layoutInfo.holder().code());\n        });\n      }\n\n      // fire init event\n      bindCustomEvent($holder, callbacks, 'init')(layoutInfo);\n\n      // fire plugin init event\n      for (var i = 0, len = $.summernote.plugins.length; i < len; i++) {\n        if ($.isFunction($.summernote.plugins[i].init)) {\n          $.summernote.plugins[i].init(layoutInfo);\n        }\n      }\n    };\n      \n    this.detach = function (layoutInfo, options) {\n      layoutInfo.holder().off();\n      layoutInfo.editable().off();\n\n      layoutInfo.popover().off();\n      layoutInfo.handle().off();\n      layoutInfo.dialog().off();\n\n      if (!options.airMode) {\n        layoutInfo.dropzone().off();\n        layoutInfo.toolbar().off();\n        layoutInfo.statusbar().off();\n      }\n    };\n  };\n\n  /**\n   * @class Renderer\n   *\n   * renderer\n   *\n   * rendering toolbar and editable\n   */\n  var Renderer = function () {\n\n    /**\n     * bootstrap button template\n     * @private\n     * @param {String} label button name\n     * @param {Object} [options] button options\n     * @param {String} [options.event] data-event\n     * @param {String} [options.className] button's class name\n     * @param {String} [options.value] data-value\n     * @param {String} [options.title] button's title for popup\n     * @param {String} [options.dropdown] dropdown html\n     * @param {String} [options.hide] data-hide\n     */\n    var tplButton = function (label, options) {\n      var event = options.event;\n      var value = options.value;\n      var title = options.title;\n      var className = options.className;\n      var dropdown = options.dropdown;\n      var hide = options.hide;\n\n      return (dropdown ? '<div class=\"btn-group' +\n               (className ? ' ' + className : '') + '\">' : '') +\n               '<button type=\"button\"' +\n                 ' class=\"btn btn-default btn-sm' +\n                   ((!dropdown && className) ? ' ' + className : '') +\n                   (dropdown ? ' dropdown-toggle' : '') +\n                 '\"' +\n                 (dropdown ? ' data-toggle=\"dropdown\"' : '') +\n                 (title ? ' title=\"' + title + '\"' : '') +\n                 (event ? ' data-event=\"' + event + '\"' : '') +\n                 (value ? ' data-value=\\'' + value + '\\'' : '') +\n                 (hide ? ' data-hide=\\'' + hide + '\\'' : '') +\n                 ' tabindex=\"-1\">' +\n                 label +\n                 (dropdown ? ' <span class=\"caret\"></span>' : '') +\n               '</button>' +\n               (dropdown || '') +\n             (dropdown ? '</div>' : '');\n    };\n\n    /**\n     * bootstrap icon button template\n     * @private\n     * @param {String} iconClassName\n     * @param {Object} [options]\n     * @param {String} [options.event]\n     * @param {String} [options.value]\n     * @param {String} [options.title]\n     * @param {String} [options.dropdown]\n     */\n    var tplIconButton = function (iconClassName, options) {\n      var label = '<i class=\"' + iconClassName + '\"></i>';\n      return tplButton(label, options);\n    };\n\n    /**\n     * bootstrap popover template\n     * @private\n     * @param {String} className\n     * @param {String} content\n     */\n    var tplPopover = function (className, content) {\n      var $popover = $('<div class=\"' + className + ' popover bottom in\" style=\"display: none;\">' +\n               '<div class=\"arrow\"></div>' +\n               '<div class=\"popover-content\">' +\n               '</div>' +\n             '</div>');\n\n      $popover.find('.popover-content').append(content);\n      return $popover;\n    };\n\n    /**\n     * bootstrap dialog template\n     *\n     * @param {String} className\n     * @param {String} [title='']\n     * @param {String} body\n     * @param {String} [footer='']\n     */\n    var tplDialog = function (className, title, body, footer) {\n      return '<div class=\"' + className + ' modal\" aria-hidden=\"false\">' +\n               '<div class=\"modal-dialog\">' +\n                 '<div class=\"modal-content\">' +\n                   (title ?\n                   '<div class=\"modal-header\">' +\n                     '<button type=\"button\" class=\"close\" aria-hidden=\"true\" tabindex=\"-1\">&times;</button>' +\n                     '<h4 class=\"modal-title\">' + title + '</h4>' +\n                   '</div>' : ''\n                   ) +\n                   '<div class=\"modal-body\">' + body + '</div>' +\n                   (footer ?\n                   '<div class=\"modal-footer\">' + footer + '</div>' : ''\n                   ) +\n                 '</div>' +\n               '</div>' +\n             '</div>';\n    };\n\n    /**\n     * bootstrap dropdown template\n     *\n     * @param {String|String[]} contents\n     * @param {String} [className='']\n     * @param {String} [nodeName='']\n     */\n    var tplDropdown = function (contents, className, nodeName) {\n      var classes = 'dropdown-menu' + (className ? ' ' + className : '');\n      nodeName = nodeName || 'ul';\n      if (contents instanceof Array) {\n        contents = contents.join('');\n      }\n\n      return '<' + nodeName + ' class=\"' + classes + '\">' + contents + '</' + nodeName + '>';\n    };\n\n    var tplButtonInfo = {\n      picture: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.image.image, {\n          event: 'showImageDialog',\n          title: lang.image.image,\n          hide: true\n        });\n      },\n      link: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.link.link, {\n          event: 'showLinkDialog',\n          title: lang.link.link,\n          hide: true\n        });\n      },\n      table: function (lang, options) {\n        var dropdown = [\n          '<div class=\"note-dimension-picker\">',\n          '<div class=\"note-dimension-picker-mousecatcher\" data-event=\"insertTable\" data-value=\"1x1\"></div>',\n          '<div class=\"note-dimension-picker-highlighted\"></div>',\n          '<div class=\"note-dimension-picker-unhighlighted\"></div>',\n          '</div>',\n          '<div class=\"note-dimension-display\"> 1 x 1 </div>'\n        ];\n\n        return tplIconButton(options.iconPrefix + options.icons.table.table, {\n          title: lang.table.table,\n          dropdown: tplDropdown(dropdown, 'note-table')\n        });\n      },\n      style: function (lang, options) {\n        var items = options.styleTags.reduce(function (memo, v) {\n          var label = lang.style[v === 'p' ? 'normal' : v];\n          return memo + '<li><a data-event=\"formatBlock\" href=\"#\" data-value=\"' + v + '\">' +\n                   (\n                     (v === 'p' || v === 'pre') ? label :\n                     '<' + v + '>' + label + '</' + v + '>'\n                   ) +\n                 '</a></li>';\n        }, '');\n\n        return tplIconButton(options.iconPrefix + options.icons.style.style, {\n          title: lang.style.style,\n          dropdown: tplDropdown(items)\n        });\n      },\n      fontname: function (lang, options) {\n        var realFontList = [];\n        var items = options.fontNames.reduce(function (memo, v) {\n          if (!agent.isFontInstalled(v) && !list.contains(options.fontNamesIgnoreCheck, v)) {\n            return memo;\n          }\n          realFontList.push(v);\n          return memo + '<li><a data-event=\"fontName\" href=\"#\" data-value=\"' + v + '\" style=\"font-family:\\'' + v + '\\'\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        var hasDefaultFont = agent.isFontInstalled(options.defaultFontName);\n        var defaultFontName = (hasDefaultFont) ? options.defaultFontName : realFontList[0];\n\n        var label = '<span class=\"note-current-fontname\">' +\n                        defaultFontName +\n                     '</span>';\n        return tplButton(label, {\n          title: lang.font.name,\n          className: 'note-fontname',\n          dropdown: tplDropdown(items, 'note-check')\n        });\n      },\n      fontsize: function (lang, options) {\n        var items = options.fontSizes.reduce(function (memo, v) {\n          return memo + '<li><a data-event=\"fontSize\" href=\"#\" data-value=\"' + v + '\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        var label = '<span class=\"note-current-fontsize\">11</span>';\n        return tplButton(label, {\n          title: lang.font.size,\n          className: 'note-fontsize',\n          dropdown: tplDropdown(items, 'note-check')\n        });\n      },\n      color: function (lang, options) {\n        var colorButtonLabel = '<i class=\"' +\n                                  options.iconPrefix + options.icons.color.recent +\n                                '\" style=\"color:black;background-color:yellow;\"></i>';\n\n        var colorButton = tplButton(colorButtonLabel, {\n          className: 'note-recent-color',\n          title: lang.color.recent,\n          event: 'color',\n          value: '{\"backColor\":\"yellow\"}'\n        });\n\n        var items = [\n          '<li><div class=\"btn-group\">',\n          '<div class=\"note-palette-title\">' + lang.color.background + '</div>',\n          '<div class=\"note-color-reset\" data-event=\"backColor\"',\n          ' data-value=\"inherit\" title=\"' + lang.color.transparent + '\">' + lang.color.setTransparent + '</div>',\n          '<div class=\"note-color-palette\" data-target-event=\"backColor\"></div>',\n          '</div><div class=\"btn-group\">',\n          '<div class=\"note-palette-title\">' + lang.color.foreground + '</div>',\n          '<div class=\"note-color-reset\" data-event=\"foreColor\" data-value=\"inherit\" title=\"' + lang.color.reset + '\">',\n          lang.color.resetToDefault,\n          '</div>',\n          '<div class=\"note-color-palette\" data-target-event=\"foreColor\"></div>',\n          '</div></li>'\n        ];\n\n        var moreButton = tplButton('', {\n          title: lang.color.more,\n          dropdown: tplDropdown(items)\n        });\n\n        return colorButton + moreButton;\n      },\n      bold: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.bold, {\n          event: 'bold',\n          title: lang.font.bold\n        });\n      },\n      italic: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.italic, {\n          event: 'italic',\n          title: lang.font.italic\n        });\n      },\n      underline: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.underline, {\n          event: 'underline',\n          title: lang.font.underline\n        });\n      },\n      strikethrough: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.strikethrough, {\n          event: 'strikethrough',\n          title: lang.font.strikethrough\n        });\n      },\n      superscript: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.superscript, {\n          event: 'superscript',\n          title: lang.font.superscript\n        });\n      },\n      subscript: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.subscript, {\n          event: 'subscript',\n          title: lang.font.subscript\n        });\n      },\n      clear: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.clear, {\n          event: 'removeFormat',\n          title: lang.font.clear\n        });\n      },\n      ul: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.lists.unordered, {\n          event: 'insertUnorderedList',\n          title: lang.lists.unordered\n        });\n      },\n      ol: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.lists.ordered, {\n          event: 'insertOrderedList',\n          title: lang.lists.ordered\n        });\n      },\n      paragraph: function (lang, options) {\n        var leftButton = tplIconButton(options.iconPrefix + options.icons.paragraph.left, {\n          title: lang.paragraph.left,\n          event: 'justifyLeft'\n        });\n        var centerButton = tplIconButton(options.iconPrefix + options.icons.paragraph.center, {\n          title: lang.paragraph.center,\n          event: 'justifyCenter'\n        });\n        var rightButton = tplIconButton(options.iconPrefix + options.icons.paragraph.right, {\n          title: lang.paragraph.right,\n          event: 'justifyRight'\n        });\n        var justifyButton = tplIconButton(options.iconPrefix + options.icons.paragraph.justify, {\n          title: lang.paragraph.justify,\n          event: 'justifyFull'\n        });\n\n        var outdentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.outdent, {\n          title: lang.paragraph.outdent,\n          event: 'outdent'\n        });\n        var indentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.indent, {\n          title: lang.paragraph.indent,\n          event: 'indent'\n        });\n\n        var dropdown = [\n          '<div class=\"note-align btn-group\">',\n          leftButton + centerButton + rightButton + justifyButton,\n          '</div><div class=\"note-list btn-group\">',\n          indentButton + outdentButton,\n          '</div>'\n        ];\n\n        return tplIconButton(options.iconPrefix + options.icons.paragraph.paragraph, {\n          title: lang.paragraph.paragraph,\n          dropdown: tplDropdown(dropdown, '', 'div')\n        });\n      },\n      height: function (lang, options) {\n        var items = options.lineHeights.reduce(function (memo, v) {\n          return memo + '<li><a data-event=\"lineHeight\" href=\"#\" data-value=\"' + parseFloat(v) + '\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        return tplIconButton(options.iconPrefix + options.icons.font.height, {\n          title: lang.font.height,\n          dropdown: tplDropdown(items, 'note-check')\n        });\n\n      },\n      help: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.help, {\n          event: 'showHelpDialog',\n          title: lang.options.help,\n          hide: true\n        });\n      },\n      fullscreen: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.fullscreen, {\n          event: 'fullscreen',\n          title: lang.options.fullscreen\n        });\n      },\n      codeview: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.codeview, {\n          event: 'codeview',\n          title: lang.options.codeview\n        });\n      },\n      undo: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.history.undo, {\n          event: 'undo',\n          title: lang.history.undo\n        });\n      },\n      redo: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.history.redo, {\n          event: 'redo',\n          title: lang.history.redo\n        });\n      },\n      hr: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.hr.insert, {\n          event: 'insertHorizontalRule',\n          title: lang.hr.insert\n        });\n      }\n    };\n\n    var tplPopovers = function (lang, options) {\n      var tplLinkPopover = function () {\n        var linkButton = tplIconButton(options.iconPrefix + options.icons.link.edit, {\n          title: lang.link.edit,\n          event: 'showLinkDialog',\n          hide: true\n        });\n        var unlinkButton = tplIconButton(options.iconPrefix + options.icons.link.unlink, {\n          title: lang.link.unlink,\n          event: 'unlink'\n        });\n        var content = '<a href=\"http://www.google.com\" target=\"_blank\">www.google.com</a>&nbsp;&nbsp;' +\n                      '<div class=\"note-insert btn-group\">' +\n                        linkButton + unlinkButton +\n                      '</div>';\n        return tplPopover('note-link-popover', content);\n      };\n\n      var tplImagePopover = function () {\n        var fullButton = tplButton('<span class=\"note-fontsize-10\">100%</span>', {\n          title: lang.image.resizeFull,\n          event: 'resize',\n          value: '1'\n        });\n        var halfButton = tplButton('<span class=\"note-fontsize-10\">50%</span>', {\n          title: lang.image.resizeHalf,\n          event: 'resize',\n          value: '0.5'\n        });\n        var quarterButton = tplButton('<span class=\"note-fontsize-10\">25%</span>', {\n          title: lang.image.resizeQuarter,\n          event: 'resize',\n          value: '0.25'\n        });\n\n        var leftButton = tplIconButton(options.iconPrefix + options.icons.image.floatLeft, {\n          title: lang.image.floatLeft,\n          event: 'floatMe',\n          value: 'left'\n        });\n        var rightButton = tplIconButton(options.iconPrefix + options.icons.image.floatRight, {\n          title: lang.image.floatRight,\n          event: 'floatMe',\n          value: 'right'\n        });\n        var justifyButton = tplIconButton(options.iconPrefix + options.icons.image.floatNone, {\n          title: lang.image.floatNone,\n          event: 'floatMe',\n          value: 'none'\n        });\n\n        var roundedButton = tplIconButton(options.iconPrefix + options.icons.image.shapeRounded, {\n          title: lang.image.shapeRounded,\n          event: 'imageShape',\n          value: 'img-rounded'\n        });\n        var circleButton = tplIconButton(options.iconPrefix + options.icons.image.shapeCircle, {\n          title: lang.image.shapeCircle,\n          event: 'imageShape',\n          value: 'img-circle'\n        });\n        var thumbnailButton = tplIconButton(options.iconPrefix + options.icons.image.shapeThumbnail, {\n          title: lang.image.shapeThumbnail,\n          event: 'imageShape',\n          value: 'img-thumbnail'\n        });\n        var noneButton = tplIconButton(options.iconPrefix + options.icons.image.shapeNone, {\n          title: lang.image.shapeNone,\n          event: 'imageShape',\n          value: ''\n        });\n\n        var removeButton = tplIconButton(options.iconPrefix + options.icons.image.remove, {\n          title: lang.image.remove,\n          event: 'removeMedia',\n          value: 'none'\n        });\n\n        var content = (options.disableResizeImage ? '' : '<div class=\"btn-group\">' + fullButton + halfButton + quarterButton + '</div>') +\n                      '<div class=\"btn-group\">' + leftButton + rightButton + justifyButton + '</div><br>' +\n                      '<div class=\"btn-group\">' + roundedButton + circleButton + thumbnailButton + noneButton + '</div>' +\n                      '<div class=\"btn-group\">' + removeButton + '</div>';\n        return tplPopover('note-image-popover', content);\n      };\n\n      var tplAirPopover = function () {\n        var $content = $('<div />');\n        for (var idx = 0, len = options.airPopover.length; idx < len; idx ++) {\n          var group = options.airPopover[idx];\n\n          var $group = $('<div class=\"note-' + group[0] + ' btn-group\">');\n          for (var i = 0, lenGroup = group[1].length; i < lenGroup; i++) {\n            var $button = $(tplButtonInfo[group[1][i]](lang, options));\n\n            $button.attr('data-name', group[1][i]);\n\n            $group.append($button);\n          }\n          $content.append($group);\n        }\n\n        return tplPopover('note-air-popover', $content.children());\n      };\n\n      var $notePopover = $('<div class=\"note-popover\" />');\n\n      $notePopover.append(tplLinkPopover());\n      $notePopover.append(tplImagePopover());\n\n      if (options.airMode) {\n        $notePopover.append(tplAirPopover());\n      }\n\n      return $notePopover;\n    };\n\n    var tplHandles = function (options) {\n      return '<div class=\"note-handle\">' +\n               '<div class=\"note-control-selection\">' +\n                 '<div class=\"note-control-selection-bg\"></div>' +\n                 '<div class=\"note-control-holder note-control-nw\"></div>' +\n                 '<div class=\"note-control-holder note-control-ne\"></div>' +\n                 '<div class=\"note-control-holder note-control-sw\"></div>' +\n                 '<div class=\"' +\n                 (options.disableResizeImage ? 'note-control-holder' : 'note-control-sizing') +\n                 ' note-control-se\"></div>' +\n                 (options.disableResizeImage ? '' : '<div class=\"note-control-selection-info\"></div>') +\n               '</div>' +\n             '</div>';\n    };\n\n    /**\n     * shortcut table template\n     * @param {String} title\n     * @param {String} body\n     */\n    var tplShortcut = function (title, keys) {\n      var keyClass = 'note-shortcut-col col-xs-6 note-shortcut-';\n      var body = [];\n\n      for (var i in keys) {\n        if (keys.hasOwnProperty(i)) {\n          body.push(\n            '<div class=\"' + keyClass + 'key\">' + keys[i].kbd + '</div>' +\n            '<div class=\"' + keyClass + 'name\">' + keys[i].text + '</div>'\n            );\n        }\n      }\n\n      return '<div class=\"note-shortcut-row row\"><div class=\"' + keyClass + 'title col-xs-offset-6\">' + title + '</div></div>' +\n             '<div class=\"note-shortcut-row row\">' + body.join('</div><div class=\"note-shortcut-row row\">') + '</div>';\n    };\n\n    var tplShortcutText = function (lang) {\n      var keys = [\n        { kbd: '⌘ + B', text: lang.font.bold },\n        { kbd: '⌘ + I', text: lang.font.italic },\n        { kbd: '⌘ + U', text: lang.font.underline },\n        { kbd: '⌘ + \\\\', text: lang.font.clear }\n      ];\n\n      return tplShortcut(lang.shortcut.textFormatting, keys);\n    };\n\n    var tplShortcutAction = function (lang) {\n      var keys = [\n        { kbd: '⌘ + Z', text: lang.history.undo },\n        { kbd: '⌘ + ⇧ + Z', text: lang.history.redo },\n        { kbd: '⌘ + ]', text: lang.paragraph.indent },\n        { kbd: '⌘ + [', text: lang.paragraph.outdent },\n        { kbd: '⌘ + ENTER', text: lang.hr.insert }\n      ];\n\n      return tplShortcut(lang.shortcut.action, keys);\n    };\n\n    var tplShortcutPara = function (lang) {\n      var keys = [\n        { kbd: '⌘ + ⇧ + L', text: lang.paragraph.left },\n        { kbd: '⌘ + ⇧ + E', text: lang.paragraph.center },\n        { kbd: '⌘ + ⇧ + R', text: lang.paragraph.right },\n        { kbd: '⌘ + ⇧ + J', text: lang.paragraph.justify },\n        { kbd: '⌘ + ⇧ + NUM7', text: lang.lists.ordered },\n        { kbd: '⌘ + ⇧ + NUM8', text: lang.lists.unordered }\n      ];\n\n      return tplShortcut(lang.shortcut.paragraphFormatting, keys);\n    };\n\n    var tplShortcutStyle = function (lang) {\n      var keys = [\n        { kbd: '⌘ + NUM0', text: lang.style.normal },\n        { kbd: '⌘ + NUM1', text: lang.style.h1 },\n        { kbd: '⌘ + NUM2', text: lang.style.h2 },\n        { kbd: '⌘ + NUM3', text: lang.style.h3 },\n        { kbd: '⌘ + NUM4', text: lang.style.h4 },\n        { kbd: '⌘ + NUM5', text: lang.style.h5 },\n        { kbd: '⌘ + NUM6', text: lang.style.h6 }\n      ];\n\n      return tplShortcut(lang.shortcut.documentStyle, keys);\n    };\n\n    var tplExtraShortcuts = function (lang, options) {\n      var extraKeys = options.extraKeys;\n      var keys = [];\n\n      for (var key in extraKeys) {\n        if (extraKeys.hasOwnProperty(key)) {\n          keys.push({ kbd: key, text: extraKeys[key] });\n        }\n      }\n\n      return tplShortcut(lang.shortcut.extraKeys, keys);\n    };\n\n    var tplShortcutTable = function (lang, options) {\n      var colClass = 'class=\"note-shortcut note-shortcut-col col-sm-6 col-xs-12\"';\n      var template = [\n        '<div ' + colClass + '>' + tplShortcutAction(lang, options) + '</div>' +\n        '<div ' + colClass + '>' + tplShortcutText(lang, options) + '</div>',\n        '<div ' + colClass + '>' + tplShortcutStyle(lang, options) + '</div>' +\n        '<div ' + colClass + '>' + tplShortcutPara(lang, options) + '</div>'\n      ];\n\n      if (options.extraKeys) {\n        template.push('<div ' + colClass + '>' + tplExtraShortcuts(lang, options) + '</div>');\n      }\n\n      return '<div class=\"note-shortcut-row row\">' +\n               template.join('</div><div class=\"note-shortcut-row row\">') +\n             '</div>';\n    };\n\n    var replaceMacKeys = function (sHtml) {\n      return sHtml.replace(/⌘/g, 'Ctrl').replace(/⇧/g, 'Shift');\n    };\n\n    var tplDialogInfo = {\n      image: function (lang, options) {\n        var imageLimitation = '';\n        if (options.maximumImageFileSize) {\n          var unit = Math.floor(Math.log(options.maximumImageFileSize) / Math.log(1024));\n          var readableSize = (options.maximumImageFileSize / Math.pow(1024, unit)).toFixed(2) * 1 +\n                             ' ' + ' KMGTP'[unit] + 'B';\n          imageLimitation = '<small>' + lang.image.maximumFileSize + ' : ' + readableSize + '</small>';\n        }\n\n        var body = '<div class=\"form-group row note-group-select-from-files\">' +\n                     '<label>' + lang.image.selectFromFiles + '</label>' +\n                     '<input class=\"note-image-input form-control\" type=\"file\" name=\"files\" accept=\"image/*\" multiple=\"multiple\" />' +\n                     imageLimitation +\n                   '</div>' +\n                   '<div class=\"form-group row\">' +\n                     '<label>' + lang.image.url + '</label>' +\n                     '<input class=\"note-image-url form-control col-md-12\" type=\"text\" />' +\n                   '</div>';\n        var footer = '<button href=\"#\" class=\"btn btn-primary note-image-btn disabled\" disabled>' + lang.image.insert + '</button>';\n        return tplDialog('note-image-dialog', lang.image.insert, body, footer);\n      },\n\n      link: function (lang, options) {\n        var body = '<div class=\"form-group row\">' +\n                     '<label>' + lang.link.textToDisplay + '</label>' +\n                     '<div class=\"fg-line\">' +\n                        '<input class=\"note-link-text form-control\" type=\"text\" />' +\n                     '</div>' +\n\n                   '</div>' +\n                   '<div class=\"form-group row\">' +\n                     '<label>' + lang.link.url + '</label>' +\n                     '<div class=\"fg-line\">' +\n                        '<input class=\"note-link-url form-control col-md-12\" type=\"text\" value=\"http://\" />' +\n                     '</div>' +\n                   '</div>' +\n                   (!options.disableLinkTarget ?\n                     '<div class=\"checkbox\">' +\n                       '<label>' + '<input type=\"checkbox\" checked> ' +\n                         lang.link.openInNewWindow +\n                         '<i class=\"input-helper\"></i>' +\n                       '</label>' +\n                     '</div>' : ''\n                   );\n        var footer = '<button href=\"#\" class=\"btn btn-primary note-link-btn disabled\" disabled>' + lang.link.insert + '</button>';\n        return tplDialog('note-link-dialog', lang.link.insert, body, footer);\n      },\n\n      help: function (lang, options) {\n        var body = '<a class=\"modal-close pull-right\" aria-hidden=\"true\" tabindex=\"-1\">' + lang.shortcut.close + '</a>' +\n                   '<div class=\"title\">' + lang.shortcut.shortcuts + '</div>' +\n                   (agent.isMac ? tplShortcutTable(lang, options) : replaceMacKeys(tplShortcutTable(lang, options))) +\n                   '<p class=\"text-center\">' +\n                     '<a href=\"//summernote.org/\" target=\"_blank\">Summernote 0.6.16</a> · ' +\n                     '<a href=\"//github.com/summernote/summernote\" target=\"_blank\">Project</a> · ' +\n                     '<a href=\"//github.com/summernote/summernote/issues\" target=\"_blank\">Issues</a>' +\n                   '</p>';\n        return tplDialog('note-help-dialog', '', body, '');\n      }\n    };\n\n    var tplDialogs = function (lang, options) {\n      var dialogs = '';\n\n      $.each(tplDialogInfo, function (idx, tplDialog) {\n        dialogs += tplDialog(lang, options);\n      });\n\n      return '<div class=\"note-dialog\">' + dialogs + '</div>';\n    };\n\n    var tplStatusbar = function () {\n      return '<div class=\"note-resizebar\">' +\n               '<div class=\"note-icon-bar\"></div>' +\n               '<div class=\"note-icon-bar\"></div>' +\n               '<div class=\"note-icon-bar\"></div>' +\n             '</div>';\n    };\n\n    var representShortcut = function (str) {\n      if (agent.isMac) {\n        str = str.replace('CMD', '⌘').replace('SHIFT', '⇧');\n      }\n\n      return str.replace('BACKSLASH', '\\\\')\n                .replace('SLASH', '/')\n                .replace('LEFTBRACKET', '[')\n                .replace('RIGHTBRACKET', ']');\n    };\n\n    /**\n     * createTooltip\n     *\n     * @param {jQuery} $container\n     * @param {Object} keyMap\n     * @param {String} [sPlacement]\n     */\n    var createTooltip = function ($container, keyMap, sPlacement) {\n      var invertedKeyMap = func.invertObject(keyMap);\n      var $buttons = $container.find('button');\n\n      $buttons.each(function (i, elBtn) {\n        var $btn = $(elBtn);\n        var sShortcut = invertedKeyMap[$btn.data('event')];\n        if (sShortcut) {\n          $btn.attr('title', function (i, v) {\n            return v + ' (' + representShortcut(sShortcut) + ')';\n          });\n        }\n      // bootstrap tooltip on btn-group bug\n      // https://github.com/twbs/bootstrap/issues/5687\n      }).tooltip({\n        container: 'body',\n        trigger: 'hover',\n        placement: sPlacement || 'top'\n      }).on('click', function () {\n        $(this).tooltip('hide');\n      });\n    };\n\n    // createPalette\n    var createPalette = function ($container, options) {\n      var colorInfo = options.colors;\n      $container.find('.note-color-palette').each(function () {\n        var $palette = $(this), eventName = $palette.attr('data-target-event');\n        var paletteContents = [];\n        for (var row = 0, lenRow = colorInfo.length; row < lenRow; row++) {\n          var colors = colorInfo[row];\n          var buttons = [];\n          for (var col = 0, lenCol = colors.length; col < lenCol; col++) {\n            var color = colors[col];\n            buttons.push(['<button type=\"button\" class=\"note-color-btn\" style=\"background-color:', color,\n                           ';\" data-event=\"', eventName,\n                           '\" data-value=\"', color,\n                           '\" title=\"', color,\n                           '\" data-toggle=\"button\" tabindex=\"-1\"></button>'].join(''));\n          }\n          paletteContents.push('<div class=\"note-color-row\">' + buttons.join('') + '</div>');\n        }\n        $palette.html(paletteContents.join(''));\n      });\n    };\n\n    /**\n     * create summernote layout (air mode)\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayoutByAirMode = function ($holder, options) {\n      var langInfo = options.langInfo;\n      var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];\n      var id = func.uniqueId();\n\n      $holder.addClass('note-air-editor note-editable panel-body');\n      $holder.attr({\n        'id': 'note-editor-' + id,\n        'contentEditable': true\n      });\n\n      var body = document.body;\n\n      // create Popover\n      var $popover = $(tplPopovers(langInfo, options));\n      $popover.addClass('note-air-layout');\n      $popover.attr('id', 'note-popover-' + id);\n      $popover.appendTo(body);\n      createTooltip($popover, keyMap);\n      createPalette($popover, options);\n\n      // create Handle\n      var $handle = $(tplHandles(options));\n      $handle.addClass('note-air-layout');\n      $handle.attr('id', 'note-handle-' + id);\n      $handle.appendTo(body);\n\n      // create Dialog\n      var $dialog = $(tplDialogs(langInfo, options));\n      $dialog.addClass('note-air-layout');\n      $dialog.attr('id', 'note-dialog-' + id);\n      $dialog.find('button.close, a.modal-close').click(function () {\n        $(this).closest('.modal').modal('hide');\n      });\n      $dialog.appendTo(body);\n    };\n\n    /**\n     * create summernote layout (normal mode)\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayoutByFrame = function ($holder, options) {\n      var langInfo = options.langInfo;\n\n      //01. create Editor\n      var $editor = $('<div class=\"note-editor panel panel-default\" />');\n      if (options.width) {\n        $editor.width(options.width);\n      }\n\n      //02. statusbar (resizebar)\n      if (options.height > 0) {\n        $('<div class=\"note-statusbar\">' + (options.disableResizeEditor ? '' : tplStatusbar()) + '</div>').prependTo($editor);\n      }\n\n      //03 editing area\n      var $editingArea = $('<div class=\"note-editing-area\" />');\n      //03. create editable\n      var isContentEditable = !$holder.is(':disabled');\n      var $editable = $('<div class=\"note-editable panel-body\" contentEditable=\"' + isContentEditable + '\"></div>').prependTo($editingArea);\n      \n      if (options.height) {\n        $editable.height(options.height);\n      }\n      if (options.direction) {\n        $editable.attr('dir', options.direction);\n      }\n      var placeholder = $holder.attr('placeholder') || options.placeholder;\n      if (placeholder) {\n        $editable.attr('data-placeholder', placeholder);\n      }\n\n      $editable.html(dom.html($holder) || dom.emptyPara);\n\n      //031. create codable\n      $('<textarea class=\"note-codable\"></textarea>').prependTo($editingArea);\n\n      //04. create Popover\n      var $popover = $(tplPopovers(langInfo, options)).prependTo($editingArea);\n      createPalette($popover, options);\n      createTooltip($popover, keyMap);\n\n      //05. handle(control selection, ...)\n      $(tplHandles(options)).prependTo($editingArea);\n\n      $editingArea.prependTo($editor);\n\n      //06. create Toolbar\n      var $toolbar = $('<div class=\"note-toolbar panel-heading\" />');\n      for (var idx = 0, len = options.toolbar.length; idx < len; idx ++) {\n        var groupName = options.toolbar[idx][0];\n        var groupButtons = options.toolbar[idx][1];\n\n        var $group = $('<div class=\"note-' + groupName + ' btn-group\" />');\n        for (var i = 0, btnLength = groupButtons.length; i < btnLength; i++) {\n          var buttonInfo = tplButtonInfo[groupButtons[i]];\n          // continue creating toolbar even if a button doesn't exist\n          if (!$.isFunction(buttonInfo)) { continue; }\n\n          var $button = $(buttonInfo(langInfo, options));\n          $button.attr('data-name', groupButtons[i]);  // set button's alias, becuase to get button element from $toolbar\n          $group.append($button);\n        }\n        $toolbar.append($group);\n      }\n\n      var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];\n      createPalette($toolbar, options);\n      createTooltip($toolbar, keyMap, 'bottom');\n      $toolbar.prependTo($editor);\n\n      //07. create Dropzone\n      $('<div class=\"note-dropzone\"><div class=\"note-dropzone-message\"></div></div>').prependTo($editor);\n\n      //08. create Dialog\n      var $dialogContainer = options.dialogsInBody ? $(document.body) : $editor;\n      var $dialog = $(tplDialogs(langInfo, options)).prependTo($dialogContainer);\n      $dialog.find('button.close, a.modal-close').click(function () {\n        $(this).closest('.modal').modal('hide');\n      });\n\n      //09. Editor/Holder switch\n      $editor.insertAfter($holder);\n      $holder.hide();\n    };\n\n    this.hasNoteEditor = function ($holder) {\n      return this.noteEditorFromHolder($holder).length > 0;\n    };\n\n    this.noteEditorFromHolder = function ($holder) {\n      if ($holder.hasClass('note-air-editor')) {\n        return $holder;\n      } else if ($holder.next().hasClass('note-editor')) {\n        return $holder.next();\n      } else {\n        return $();\n      }\n    };\n\n    /**\n     * create summernote layout\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayout = function ($holder, options) {\n      if (options.airMode) {\n        this.createLayoutByAirMode($holder, options);\n      } else {\n        this.createLayoutByFrame($holder, options);\n      }\n    };\n\n    /**\n     * returns layoutInfo from holder\n     *\n     * @param {jQuery} $holder - placeholder\n     * @return {Object}\n     */\n    this.layoutInfoFromHolder = function ($holder) {\n      var $editor = this.noteEditorFromHolder($holder);\n      if (!$editor.length) {\n        return;\n      }\n\n      // connect $holder to $editor\n      $editor.data('holder', $holder);\n\n      return dom.buildLayoutInfo($editor);\n    };\n\n    /**\n     * removeLayout\n     *\n     * @param {jQuery} $holder - placeholder\n     * @param {Object} layoutInfo\n     * @param {Object} options\n     *\n     */\n    this.removeLayout = function ($holder, layoutInfo, options) {\n      if (options.airMode) {\n        $holder.removeClass('note-air-editor note-editable')\n               .removeAttr('id contentEditable');\n\n        layoutInfo.popover().remove();\n        layoutInfo.handle().remove();\n        layoutInfo.dialog().remove();\n      } else {\n        $holder.html(layoutInfo.editable().html());\n\n        if (options.dialogsInBody) {\n          layoutInfo.dialog().remove();\n        }\n        layoutInfo.editor().remove();\n        $holder.show();\n      }\n    };\n\n    /**\n     *\n     * @return {Object}\n     * @return {function(label, options=):string} return.button {@link #tplButton function to make text button}\n     * @return {function(iconClass, options=):string} return.iconButton {@link #tplIconButton function to make icon button}\n     * @return {function(className, title=, body=, footer=):string} return.dialog {@link #tplDialog function to make dialog}\n     */\n    this.getTemplate = function () {\n      return {\n        button: tplButton,\n        iconButton: tplIconButton,\n        dialog: tplDialog\n      };\n    };\n\n    /**\n     * add button information\n     *\n     * @param {String} name button name\n     * @param {Function} buttonInfo function to make button, reference to {@link #tplButton},{@link #tplIconButton}\n     */\n    this.addButtonInfo = function (name, buttonInfo) {\n      tplButtonInfo[name] = buttonInfo;\n    };\n\n    /**\n     *\n     * @param {String} name\n     * @param {Function} dialogInfo function to make dialog, reference to {@link #tplDialog}\n     */\n    this.addDialogInfo = function (name, dialogInfo) {\n      tplDialogInfo[name] = dialogInfo;\n    };\n  };\n\n\n  // jQuery namespace for summernote\n  /**\n   * @class $.summernote \n   * \n   * summernote attribute  \n   * \n   * @mixin defaults\n   * @singleton  \n   * \n   */\n  $.summernote = $.summernote || {};\n\n  // extends default settings\n  //  - $.summernote.version\n  //  - $.summernote.options\n  //  - $.summernote.lang\n  $.extend($.summernote, defaults);\n\n  var renderer = new Renderer();\n  var eventHandler = new EventHandler();\n\n  $.extend($.summernote, {\n    /** @property {Renderer} */\n    renderer: renderer,\n    /** @property {EventHandler} */\n    eventHandler: eventHandler,\n    /** \n     * @property {Object} core \n     * @property {core.agent} core.agent \n     * @property {core.dom} core.dom\n     * @property {core.range} core.range \n     */\n    core: {\n      agent: agent,\n      list : list,\n      dom: dom,\n      range: range\n    },\n    /** \n     * @property {Object} \n     * pluginEvents event list for plugins\n     * event has name and callback function.\n     * \n     * ``` \n     * $.summernote.addPlugin({\n     *     events : {\n     *          'hello' : function(layoutInfo, value, $target) {\n     *              console.log('event name is hello, value is ' + value );\n     *          }\n     *     }     \n     * })\n     * ```\n     * \n     * * event name is data-event property.\n     * * layoutInfo is a summernote layout information.\n     * * value is data-value property.\n     */\n    pluginEvents: {},\n\n    plugins : []\n  });\n\n  /**\n   * @method addPlugin\n   *\n   * add Plugin in Summernote \n   * \n   * Summernote can make a own plugin.\n   *\n   * ### Define plugin\n   * ```\n   * // get template function  \n   * var tmpl = $.summernote.renderer.getTemplate();\n   * \n   * // add a button   \n   * $.summernote.addPlugin({\n   *     buttons : {\n   *        // \"hello\"  is button's namespace.      \n   *        \"hello\" : function(lang, options) {\n   *            // make icon button by template function          \n   *            return tmpl.iconButton(options.iconPrefix + 'header', {\n   *                // callback function name when button clicked \n   *                event : 'hello',\n   *                // set data-value property                 \n   *                value : 'hello',                \n   *                hide : true\n   *            });           \n   *        }\n   *     \n   *     }, \n   *     \n   *     events : {\n   *        \"hello\" : function(layoutInfo, value) {\n   *            // here is event code \n   *        }\n   *     }     \n   * });\n   * ``` \n   * ### Use a plugin in toolbar\n   * \n   * ``` \n   *    $(\"#editor\").summernote({\n   *    ...\n   *    toolbar : [\n   *        // display hello plugin in toolbar     \n   *        ['group', [ 'hello' ]]\n   *    ]\n   *    ...    \n   *    });\n   * ```\n   *  \n   *  \n   * @param {Object} plugin\n   * @param {Object} [plugin.buttons] define plugin button. for detail, see to Renderer.addButtonInfo\n   * @param {Object} [plugin.dialogs] define plugin dialog. for detail, see to Renderer.addDialogInfo\n   * @param {Object} [plugin.events] add event in $.summernote.pluginEvents \n   * @param {Object} [plugin.langs] update $.summernote.lang\n   * @param {Object} [plugin.options] update $.summernote.options\n   */\n  $.summernote.addPlugin = function (plugin) {\n\n    // save plugin list\n    $.summernote.plugins.push(plugin);\n\n    if (plugin.buttons) {\n      $.each(plugin.buttons, function (name, button) {\n        renderer.addButtonInfo(name, button);\n      });\n    }\n\n    if (plugin.dialogs) {\n      $.each(plugin.dialogs, function (name, dialog) {\n        renderer.addDialogInfo(name, dialog);\n      });\n    }\n\n    if (plugin.events) {\n      $.each(plugin.events, function (name, event) {\n        $.summernote.pluginEvents[name] = event;\n      });\n    }\n\n    if (plugin.langs) {\n      $.each(plugin.langs, function (locale, lang) {\n        if ($.summernote.lang[locale]) {\n          $.extend($.summernote.lang[locale], lang);\n        }\n      });\n    }\n\n    if (plugin.options) {\n      $.extend($.summernote.options, plugin.options);\n    }\n  };\n\n  /*\n   * extend $.fn\n   */\n  $.fn.extend({\n    /**\n     * @method\n     * Initialize summernote\n     *  - create editor layout and attach Mouse and keyboard events.\n     * \n     * ```\n     * $(\"#summernote\").summernote( { options ..} );\n     * ```\n     *   \n     * @member $.fn\n     * @param {Object|String} options reference to $.summernote.options\n     * @return {this}\n     */\n    summernote: function () {\n      // check first argument's type\n      //  - {String}: External API call {{module}}.{{method}}\n      //  - {Object}: init options\n      var type = $.type(list.head(arguments));\n      var isExternalAPICalled = type === 'string';\n      var hasInitOptions = type === 'object';\n\n      // extend default options with custom user options\n      var options = hasInitOptions ? list.head(arguments) : {};\n\n      options = $.extend({}, $.summernote.options, options);\n      options.icons = $.extend({}, $.summernote.options.icons, options.icons);\n\n      // Include langInfo in options for later use, e.g. for image drag-n-drop\n      // Setup language info with en-US as default\n      options.langInfo = $.extend(true, {}, $.summernote.lang['en-US'], $.summernote.lang[options.lang]);\n\n      // override plugin options\n      if (!isExternalAPICalled && hasInitOptions) {\n        for (var i = 0, len = $.summernote.plugins.length; i < len; i++) {\n          var plugin = $.summernote.plugins[i];\n\n          if (options.plugin[plugin.name]) {\n            $.summernote.plugins[i] = $.extend(true, plugin, options.plugin[plugin.name]);\n          }\n        }\n      }\n\n      this.each(function (idx, holder) {\n        var $holder = $(holder);\n\n        // if layout isn't created yet, createLayout and attach events\n        if (!renderer.hasNoteEditor($holder)) {\n          renderer.createLayout($holder, options);\n\n          var layoutInfo = renderer.layoutInfoFromHolder($holder);\n          $holder.data('layoutInfo', layoutInfo);\n\n          eventHandler.attach(layoutInfo, options);\n          eventHandler.attachCustomEvent(layoutInfo, options);\n        }\n      });\n\n      var $first = this.first();\n      if ($first.length) {\n        var layoutInfo = renderer.layoutInfoFromHolder($first);\n\n        // external API\n        if (isExternalAPICalled) {\n          var moduleAndMethod = list.head(list.from(arguments));\n          var args = list.tail(list.from(arguments));\n\n          // TODO now external API only works for editor\n          var params = [moduleAndMethod, layoutInfo.editable()].concat(args);\n          return eventHandler.invoke.apply(eventHandler, params);\n        } else if (options.focus) {\n          // focus on first editable element for initialize editor\n          layoutInfo.editable().focus();\n        }\n      }\n\n      return this;\n    },\n\n    /**\n     * @method \n     * \n     * get the HTML contents of note or set the HTML contents of note.\n     *\n     * * get contents \n     * ```\n     * var content = $(\"#summernote\").code();\n     * ```\n     * * set contents \n     *\n     * ```\n     * $(\"#summernote\").code(html);\n     * ```\n     *\n     * @member $.fn \n     * @param {String} [html] - HTML contents(optional, set)\n     * @return {this|String} - context(set) or HTML contents of note(get).\n     */\n    code: function (html) {\n      // get the HTML contents of note\n      if (html === undefined) {\n        var $holder = this.first();\n        if (!$holder.length) {\n          return;\n        }\n\n        var layoutInfo = renderer.layoutInfoFromHolder($holder);\n        var $editable = layoutInfo && layoutInfo.editable();\n\n        if ($editable && $editable.length) {\n          var isCodeview = eventHandler.invoke('codeview.isActivated', layoutInfo);\n          eventHandler.invoke('codeview.sync', layoutInfo);\n          return isCodeview ? layoutInfo.codable().val() :\n                              layoutInfo.editable().html();\n        }\n        return dom.value($holder);\n      }\n\n      // set the HTML contents of note\n      this.each(function (i, holder) {\n        var layoutInfo = renderer.layoutInfoFromHolder($(holder));\n        var $editable = layoutInfo && layoutInfo.editable();\n        if ($editable) {\n          $editable.html(html);\n        }\n      });\n\n      return this;\n    },\n\n    /**\n     * @method\n     * \n     * destroy Editor Layout and detach Key and Mouse Event\n     *\n     * @member $.fn\n     * @return {this}\n     */\n    destroy: function () {\n      this.each(function (idx, holder) {\n        var $holder = $(holder);\n\n        if (!renderer.hasNoteEditor($holder)) {\n          return;\n        }\n\n        var info = renderer.layoutInfoFromHolder($holder);\n        var options = info.editor().data('options');\n\n        eventHandler.detach(info, options);\n        renderer.removeLayout($holder, info, options);\n      });\n\n      return this;\n    }\n  });\n}));\n"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/summernote/dist/summernote.css",
    "content": ".note-editor{position:relative;overflow:hidden;border:1px solid #a9a9a9}.note-editor .note-dropzone{position:absolute;z-index:100;display:none;color:#87cefa;background-color:white;opacity:.95;pointer-event:none}.note-editor .note-dropzone .note-dropzone-message{display:table-cell;font-size:28px;font-weight:bold;text-align:center;vertical-align:middle}.note-editor .note-dropzone.hover{color:#098ddf}.note-editor.dragover .note-dropzone{display:table}.note-editor.codeview .note-editing-area .note-editable{display:none}.note-editor.codeview .note-editing-area .note-codable{display:block}.note-editor.fullscreen{position:fixed;top:0;left:0;z-index:1050;width:100%}.note-editor.fullscreen .note-editable{background-color:white}.note-editor.fullscreen .note-resizebar{display:none}.note-editor .note-editing-area{position:relative;overflow:hidden}.note-editor .note-editing-area .note-editable{padding:10px;overflow:auto;color:#000;background-color:#fff;outline:0}.note-editor .note-editing-area .note-editable[contenteditable=true]:empty:not(:focus):before{content:attr(data-placeholder)}.note-editor .note-editing-area .note-editable[contenteditable=\"false\"]{background-color:#e5e5e5}.note-editor .note-editing-area .note-codable{display:none;width:100%;padding:10px;margin-bottom:0;font-family:Menlo,Monaco,monospace,sans-serif;font-size:14px;color:#ccc;background-color:#222;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;box-shadow:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;resize:none}.note-editor .note-statusbar{background-color:#f5f5f5}.note-editor .note-statusbar .note-resizebar{width:100%;height:8px;padding-top:1px;cursor:ns-resize}.note-editor .note-statusbar .note-resizebar .note-icon-bar{width:20px;margin:1px auto;border-top:1px solid #a9a9a9}.note-air-editor{outline:0}.note-popover .popover{max-width:none}.note-popover .popover .popover-content a{display:inline-block;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:middle}.note-popover .popover .arrow{left:20px}.note-popover .popover .popover-content,.panel-heading.note-toolbar{padding:0 0 5px 5px;margin:0}.note-popover .popover .popover-content>.btn-group,.panel-heading.note-toolbar>.btn-group{margin-top:5px;margin-right:5px;margin-left:0}.note-popover .popover .popover-content .btn-group .note-table,.panel-heading.note-toolbar .btn-group .note-table{min-width:0;padding:5px}.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker{font-size:18px}.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher{position:absolute!important;z-index:3;width:10em;height:10em;cursor:pointer}.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted{position:relative!important;z-index:1;width:5em;height:5em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-popover .popover .popover-content .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted,.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted{position:absolute!important;z-index:2;width:1em;height:1em;background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat}.note-popover .popover .popover-content .note-style h1,.panel-heading.note-toolbar .note-style h1,.note-popover .popover .popover-content .note-style h2,.panel-heading.note-toolbar .note-style h2,.note-popover .popover .popover-content .note-style h3,.panel-heading.note-toolbar .note-style h3,.note-popover .popover .popover-content .note-style h4,.panel-heading.note-toolbar .note-style h4,.note-popover .popover .popover-content .note-style h5,.panel-heading.note-toolbar .note-style h5,.note-popover .popover .popover-content .note-style h6,.panel-heading.note-toolbar .note-style h6,.note-popover .popover .popover-content .note-style blockquote,.panel-heading.note-toolbar .note-style blockquote{margin:0}.note-popover .popover .popover-content .note-color .dropdown-toggle,.panel-heading.note-toolbar .note-color .dropdown-toggle{width:20px;padding-left:5px}.note-popover .popover .popover-content .note-color .dropdown-menu,.panel-heading.note-toolbar .note-color .dropdown-menu{min-width:340px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group{margin:0}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group:first-child,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group:first-child{margin:0 5px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-palette-title,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title{margin:2px 7px;font-size:12px;text-align:center;border-bottom:1px solid #eee}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset{padding:0 3px;margin:3px;font-size:11px;cursor:pointer;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-row,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-row{height:20px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset:hover,.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover{background:#eee}.note-popover .popover .popover-content .note-para .dropdown-menu,.panel-heading.note-toolbar .note-para .dropdown-menu{min-width:216px;padding:5px}.note-popover .popover .popover-content .note-para .dropdown-menu>div:first-child,.panel-heading.note-toolbar .note-para .dropdown-menu>div:first-child{margin-right:5px}.note-popover .popover .popover-content .dropdown-menu,.panel-heading.note-toolbar .dropdown-menu{min-width:90px}.note-popover .popover .popover-content .dropdown-menu.right,.panel-heading.note-toolbar .dropdown-menu.right{right:0;left:auto}.note-popover .popover .popover-content .dropdown-menu.right::before,.panel-heading.note-toolbar .dropdown-menu.right::before{right:9px;left:auto!important}.note-popover .popover .popover-content .dropdown-menu.right::after,.panel-heading.note-toolbar .dropdown-menu.right::after{right:10px;left:auto!important}.note-popover .popover .popover-content .dropdown-menu.note-check li a i,.panel-heading.note-toolbar .dropdown-menu.note-check li a i{color:deepskyblue;visibility:hidden}.note-popover .popover .popover-content .dropdown-menu.note-check li a.checked i,.panel-heading.note-toolbar .dropdown-menu.note-check li a.checked i{visibility:visible}.note-popover .popover .popover-content .note-fontsize-10,.panel-heading.note-toolbar .note-fontsize-10{font-size:10px}.note-popover .popover .popover-content .note-color-palette,.panel-heading.note-toolbar .note-color-palette{line-height:1}.note-popover .popover .popover-content .note-color-palette div .note-color-btn,.panel-heading.note-toolbar .note-color-palette div .note-color-btn{width:20px;height:20px;padding:0;margin:0;border:1px solid #fff}.note-popover .popover .popover-content .note-color-palette div .note-color-btn:hover,.panel-heading.note-toolbar .note-color-palette div .note-color-btn:hover{border:1px solid #000}.note-dialog>div{display:none}.note-dialog .form-group{margin-right:0;margin-left:0}.note-dialog .note-modal-form{margin:0}.note-dialog .note-image-dialog .note-dropzone{min-height:100px;margin-bottom:10px;font-size:30px;line-height:4;color:lightgray;text-align:center;border:4px dashed lightgray}.note-dialog .note-help-dialog{font-size:12px;color:#ccc;background:transparent;background-color:#222!important;border:0;-webkit-opacity:.9;-khtml-opacity:.9;-moz-opacity:.9;opacity:.9;-ms-filter:alpha(opacity=90);filter:alpha(opacity=90)}.note-dialog .note-help-dialog .modal-content{background:transparent;border:1px solid white;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.note-dialog .note-help-dialog a{font-size:12px;color:white}.note-dialog .note-help-dialog .title{padding-bottom:5px;margin-bottom:10px;font-size:14px;font-weight:bold;color:white;border-bottom:white 1px solid}.note-dialog .note-help-dialog .modal-close{font-size:14px;color:#dd0;cursor:pointer}.note-dialog .note-help-dialog .text-center{margin:10px 0 0}.note-dialog .note-help-dialog .note-shortcut{padding-top:8px;padding-bottom:8px}.note-dialog .note-help-dialog .note-shortcut-row{margin-right:-5px;margin-left:-5px}.note-dialog .note-help-dialog .note-shortcut-col{padding-right:5px;padding-left:5px}.note-dialog .note-help-dialog .note-shortcut-title{font-size:13px;font-weight:bold;color:#dd0}.note-dialog .note-help-dialog .note-shortcut-key{font-family:\"Courier New\";color:#dd0;text-align:right}.note-handle .note-control-selection{position:absolute;display:none;border:1px solid black}.note-handle .note-control-selection>div{position:absolute}.note-handle .note-control-selection .note-control-selection-bg{width:100%;height:100%;background-color:black;-webkit-opacity:.3;-khtml-opacity:.3;-moz-opacity:.3;opacity:.3;-ms-filter:alpha(opacity=30);filter:alpha(opacity=30)}.note-handle .note-control-selection .note-control-handle{width:7px;height:7px;border:1px solid black}.note-handle .note-control-selection .note-control-holder{width:7px;height:7px;border:1px solid black}.note-handle .note-control-selection .note-control-sizing{width:7px;height:7px;background-color:white;border:1px solid black}.note-handle .note-control-selection .note-control-nw{top:-5px;left:-5px;border-right:0;border-bottom:0}.note-handle .note-control-selection .note-control-ne{top:-5px;right:-5px;border-bottom:0;border-left:none}.note-handle .note-control-selection .note-control-sw{bottom:-5px;left:-5px;border-top:0;border-right:0}.note-handle .note-control-selection .note-control-se{right:-5px;bottom:-5px;cursor:se-resize}.note-handle .note-control-selection .note-control-se.note-control-holder{cursor:default;border-top:0;border-left:none}.note-handle .note-control-selection .note-control-selection-info{right:0;bottom:0;padding:5px;margin:5px;font-size:12px;color:white;background-color:black;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-opacity:.7;-khtml-opacity:.7;-moz-opacity:.7;opacity:.7;-ms-filter:alpha(opacity=70);filter:alpha(opacity=70)}"
  },
  {
    "path": "material-manage/src/main/webapp/static/vendors/summernote/dist/summernote.js",
    "content": "/**\n * Super simple wysiwyg editor on Bootstrap v0.6.16\n * http://summernote.org/\n *\n * summernote.js\n * Copyright 2013-2015 Alan Hong. and other contributors\n * summernote may be freely distributed under the MIT license./\n *\n * Date: 2015-08-03T16:41Z\n */\n(function (factory) {\n  /* global define */\n  if (typeof define === 'function' && define.amd) {\n    // AMD. Register as an anonymous module.\n    define(['jquery'], factory);\n  } else {\n    // Browser globals: jQuery\n    factory(window.jQuery);\n  }\n}(function ($) {\n  \n\n\n  if (!Array.prototype.reduce) {\n    /**\n     * Array.prototype.reduce polyfill\n     *\n     * @param {Function} callback\n     * @param {Value} [initialValue]\n     * @return {Value}\n     *\n     * @see http://goo.gl/WNriQD\n     */\n    Array.prototype.reduce = function (callback) {\n      var t = Object(this), len = t.length >>> 0, k = 0, value;\n      if (arguments.length === 2) {\n        value = arguments[1];\n      } else {\n        while (k < len && !(k in t)) {\n          k++;\n        }\n        if (k >= len) {\n          throw new TypeError('Reduce of empty array with no initial value');\n        }\n        value = t[k++];\n      }\n      for (; k < len; k++) {\n        if (k in t) {\n          value = callback(value, t[k], k, t);\n        }\n      }\n      return value;\n    };\n  }\n\n  if ('function' !== typeof Array.prototype.filter) {\n    /**\n     * Array.prototype.filter polyfill\n     *\n     * @param {Function} func\n     * @return {Array}\n     *\n     * @see http://goo.gl/T1KFnq\n     */\n    Array.prototype.filter = function (func) {\n      var t = Object(this), len = t.length >>> 0;\n\n      var res = [];\n      var thisArg = arguments.length >= 2 ? arguments[1] : void 0;\n      for (var i = 0; i < len; i++) {\n        if (i in t) {\n          var val = t[i];\n          if (func.call(thisArg, val, i, t)) {\n            res.push(val);\n          }\n        }\n      }\n  \n      return res;\n    };\n  }\n\n  if (!Array.prototype.map) {\n    /**\n     * Array.prototype.map polyfill\n     *\n     * @param {Function} callback\n     * @return {Array}\n     *\n     * @see https://goo.gl/SMWaMK\n     */\n    Array.prototype.map = function (callback, thisArg) {\n      var T, A, k;\n      if (this === null) {\n        throw new TypeError(' this is null or not defined');\n      }\n\n      var O = Object(this);\n      var len = O.length >>> 0;\n      if (typeof callback !== 'function') {\n        throw new TypeError(callback + ' is not a function');\n      }\n  \n      if (arguments.length > 1) {\n        T = thisArg;\n      }\n  \n      A = new Array(len);\n      k = 0;\n  \n      while (k < len) {\n        var kValue, mappedValue;\n        if (k in O) {\n          kValue = O[k];\n          mappedValue = callback.call(T, kValue, k, O);\n          A[k] = mappedValue;\n        }\n        k++;\n      }\n      return A;\n    };\n  }\n\n  var isSupportAmd = typeof define === 'function' && define.amd;\n\n  /**\n   * returns whether font is installed or not.\n   *\n   * @param {String} fontName\n   * @return {Boolean}\n   */\n  var isFontInstalled = function (fontName) {\n    var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';\n    var $tester = $('<div>').css({\n      position: 'absolute',\n      left: '-9999px',\n      top: '-9999px',\n      fontSize: '200px'\n    }).text('mmmmmmmmmwwwwwww').appendTo(document.body);\n\n    var originalWidth = $tester.css('fontFamily', testFontName).width();\n    var width = $tester.css('fontFamily', fontName + ',' + testFontName).width();\n\n    $tester.remove();\n\n    return originalWidth !== width;\n  };\n\n  var userAgent = navigator.userAgent;\n  var isMSIE = /MSIE|Trident/i.test(userAgent);\n  var browserVersion;\n  if (isMSIE) {\n    var matches = /MSIE (\\d+[.]\\d+)/.exec(userAgent);\n    if (matches) {\n      browserVersion = parseFloat(matches[1]);\n    }\n    matches = /Trident\\/.*rv:([0-9]{1,}[\\.0-9]{0,})/.exec(userAgent);\n    if (matches) {\n      browserVersion = parseFloat(matches[1]);\n    }\n  }\n\n  /**\n   * @class core.agent\n   *\n   * Object which check platform and agent\n   *\n   * @singleton\n   * @alternateClassName agent\n   */\n  var agent = {\n    /** @property {Boolean} [isMac=false] true if this agent is Mac  */\n    isMac: navigator.appVersion.indexOf('Mac') > -1,\n    /** @property {Boolean} [isMSIE=false] true if this agent is a Internet Explorer  */\n    isMSIE: isMSIE,\n    /** @property {Boolean} [isFF=false] true if this agent is a Firefox  */\n    isFF: /firefox/i.test(userAgent),\n    isWebkit: /webkit/i.test(userAgent),\n    /** @property {Boolean} [isSafari=false] true if this agent is a Safari  */\n    isSafari: /safari/i.test(userAgent),\n    /** @property {Float} browserVersion current browser version  */\n    browserVersion: browserVersion,\n    /** @property {String} jqueryVersion current jQuery version string  */\n    jqueryVersion: parseFloat($.fn.jquery),\n    isSupportAmd: isSupportAmd,\n    hasCodeMirror: isSupportAmd ? require.specified('CodeMirror') : !!window.CodeMirror,\n    isFontInstalled: isFontInstalled,\n    isW3CRangeSupport: !!document.createRange\n  };\n\n  /**\n   * @class core.func\n   *\n   * func utils (for high-order func's arg)\n   *\n   * @singleton\n   * @alternateClassName func\n   */\n  var func = (function () {\n    var eq = function (itemA) {\n      return function (itemB) {\n        return itemA === itemB;\n      };\n    };\n\n    var eq2 = function (itemA, itemB) {\n      return itemA === itemB;\n    };\n\n    var peq2 = function (propName) {\n      return function (itemA, itemB) {\n        return itemA[propName] === itemB[propName];\n      };\n    };\n\n    var ok = function () {\n      return true;\n    };\n\n    var fail = function () {\n      return false;\n    };\n\n    var not = function (f) {\n      return function () {\n        return !f.apply(f, arguments);\n      };\n    };\n\n    var and = function (fA, fB) {\n      return function (item) {\n        return fA(item) && fB(item);\n      };\n    };\n\n    var self = function (a) {\n      return a;\n    };\n\n    var idCounter = 0;\n\n    /**\n     * generate a globally-unique id\n     *\n     * @param {String} [prefix]\n     */\n    var uniqueId = function (prefix) {\n      var id = ++idCounter + '';\n      return prefix ? prefix + id : id;\n    };\n\n    /**\n     * returns bnd (bounds) from rect\n     *\n     * - IE Compatability Issue: http://goo.gl/sRLOAo\n     * - Scroll Issue: http://goo.gl/sNjUc\n     *\n     * @param {Rect} rect\n     * @return {Object} bounds\n     * @return {Number} bounds.top\n     * @return {Number} bounds.left\n     * @return {Number} bounds.width\n     * @return {Number} bounds.height\n     */\n    var rect2bnd = function (rect) {\n      var $document = $(document);\n      return {\n        top: rect.top + $document.scrollTop(),\n        left: rect.left + $document.scrollLeft(),\n        width: rect.right - rect.left,\n        height: rect.bottom - rect.top\n      };\n    };\n\n    /**\n     * returns a copy of the object where the keys have become the values and the values the keys.\n     * @param {Object} obj\n     * @return {Object}\n     */\n    var invertObject = function (obj) {\n      var inverted = {};\n      for (var key in obj) {\n        if (obj.hasOwnProperty(key)) {\n          inverted[obj[key]] = key;\n        }\n      }\n      return inverted;\n    };\n\n    /**\n     * @param {String} namespace\n     * @param {String} [prefix]\n     * @return {String}\n     */\n    var namespaceToCamel = function (namespace, prefix) {\n      prefix = prefix || '';\n      return prefix + namespace.split('.').map(function (name) {\n        return name.substring(0, 1).toUpperCase() + name.substring(1);\n      }).join('');\n    };\n\n    return {\n      eq: eq,\n      eq2: eq2,\n      peq2: peq2,\n      ok: ok,\n      fail: fail,\n      self: self,\n      not: not,\n      and: and,\n      uniqueId: uniqueId,\n      rect2bnd: rect2bnd,\n      invertObject: invertObject,\n      namespaceToCamel: namespaceToCamel\n    };\n  })();\n\n  /**\n   * @class core.list\n   *\n   * list utils\n   *\n   * @singleton\n   * @alternateClassName list\n   */\n  var list = (function () {\n    /**\n     * returns the first item of an array.\n     *\n     * @param {Array} array\n     */\n    var head = function (array) {\n      return array[0];\n    };\n\n    /**\n     * returns the last item of an array.\n     *\n     * @param {Array} array\n     */\n    var last = function (array) {\n      return array[array.length - 1];\n    };\n\n    /**\n     * returns everything but the last entry of the array.\n     *\n     * @param {Array} array\n     */\n    var initial = function (array) {\n      return array.slice(0, array.length - 1);\n    };\n\n    /**\n     * returns the rest of the items in an array.\n     *\n     * @param {Array} array\n     */\n    var tail = function (array) {\n      return array.slice(1);\n    };\n\n    /**\n     * returns item of array\n     */\n    var find = function (array, pred) {\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        var item = array[idx];\n        if (pred(item)) {\n          return item;\n        }\n      }\n    };\n\n    /**\n     * returns true if all of the values in the array pass the predicate truth test.\n     */\n    var all = function (array, pred) {\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (!pred(array[idx])) {\n          return false;\n        }\n      }\n      return true;\n    };\n\n    /**\n     * returns index of item\n     */\n    var indexOf = function (array, item) {\n      return $.inArray(item, array);\n    };\n\n    /**\n     * returns true if the value is present in the list.\n     */\n    var contains = function (array, item) {\n      return indexOf(array, item) !== -1;\n    };\n\n    /**\n     * get sum from a list\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - iterator\n     */\n    var sum = function (array, fn) {\n      fn = fn || func.self;\n      return array.reduce(function (memo, v) {\n        return memo + fn(v);\n      }, 0);\n    };\n  \n    /**\n     * returns a copy of the collection with array type.\n     * @param {Collection} collection - collection eg) node.childNodes, ...\n     */\n    var from = function (collection) {\n      var result = [], idx = -1, length = collection.length;\n      while (++idx < length) {\n        result[idx] = collection[idx];\n      }\n      return result;\n    };\n  \n    /**\n     * cluster elements by predicate function.\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - predicate function for cluster rule\n     * @param {Array[]}\n     */\n    var clusterBy = function (array, fn) {\n      if (!array.length) { return []; }\n      var aTail = tail(array);\n      return aTail.reduce(function (memo, v) {\n        var aLast = last(memo);\n        if (fn(last(aLast), v)) {\n          aLast[aLast.length] = v;\n        } else {\n          memo[memo.length] = [v];\n        }\n        return memo;\n      }, [[head(array)]]);\n    };\n  \n    /**\n     * returns a copy of the array with all falsy values removed\n     *\n     * @param {Array} array - array\n     * @param {Function} fn - predicate function for cluster rule\n     */\n    var compact = function (array) {\n      var aResult = [];\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (array[idx]) { aResult.push(array[idx]); }\n      }\n      return aResult;\n    };\n\n    /**\n     * produces a duplicate-free version of the array\n     *\n     * @param {Array} array\n     */\n    var unique = function (array) {\n      var results = [];\n\n      for (var idx = 0, len = array.length; idx < len; idx ++) {\n        if (!contains(results, array[idx])) {\n          results.push(array[idx]);\n        }\n      }\n\n      return results;\n    };\n\n    /**\n     * returns next item.\n     * @param {Array} array\n     */\n    var next = function (array, item) {\n      var idx = indexOf(array, item);\n      if (idx === -1) { return null; }\n\n      return array[idx + 1];\n    };\n\n    /**\n     * returns prev item.\n     * @param {Array} array\n     */\n    var prev = function (array, item) {\n      var idx = indexOf(array, item);\n      if (idx === -1) { return null; }\n\n      return array[idx - 1];\n    };\n  \n    return { head: head, last: last, initial: initial, tail: tail,\n             prev: prev, next: next, find: find, contains: contains,\n             all: all, sum: sum, from: from,\n             clusterBy: clusterBy, compact: compact, unique: unique };\n  })();\n\n\n  var NBSP_CHAR = String.fromCharCode(160);\n  var ZERO_WIDTH_NBSP_CHAR = '\\ufeff';\n\n  /**\n   * @class core.dom\n   *\n   * Dom functions\n   *\n   * @singleton\n   * @alternateClassName dom\n   */\n  var dom = (function () {\n    /**\n     * @method isEditable\n     *\n     * returns whether node is `note-editable` or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isEditable = function (node) {\n      return node && $(node).hasClass('note-editable');\n    };\n\n    /**\n     * @method isControlSizing\n     *\n     * returns whether node is `note-control-sizing` or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isControlSizing = function (node) {\n      return node && $(node).hasClass('note-control-sizing');\n    };\n\n    /**\n     * @method  buildLayoutInfo\n     *\n     * build layoutInfo from $editor(.note-editor)\n     *\n     * @param {jQuery} $editor\n     * @return {Object}\n     * @return {Function} return.editor\n     * @return {Node} return.dropzone\n     * @return {Node} return.toolbar\n     * @return {Node} return.editable\n     * @return {Node} return.codable\n     * @return {Node} return.popover\n     * @return {Node} return.handle\n     * @return {Node} return.dialog\n     */\n    var buildLayoutInfo = function ($editor) {\n      var makeFinder;\n\n      // air mode\n      if ($editor.hasClass('note-air-editor')) {\n        var id = list.last($editor.attr('id').split('-'));\n        makeFinder = function (sIdPrefix) {\n          return function () { return $(sIdPrefix + id); };\n        };\n\n        return {\n          editor: function () { return $editor; },\n          holder : function () { return $editor.data('holder'); },\n          editable: function () { return $editor; },\n          popover: makeFinder('#note-popover-'),\n          handle: makeFinder('#note-handle-'),\n          dialog: makeFinder('#note-dialog-')\n        };\n\n        // frame mode\n      } else {\n        makeFinder = function (className, $base) {\n          $base = $base || $editor;\n          return function () { return $base.find(className); };\n        };\n\n        var options = $editor.data('options');\n        var $dialogHolder = (options && options.dialogsInBody) ? $(document.body) : null;\n\n        return {\n          editor: function () { return $editor; },\n          holder : function () { return $editor.data('holder'); },\n          dropzone: makeFinder('.note-dropzone'),\n          toolbar: makeFinder('.note-toolbar'),\n          editable: makeFinder('.note-editable'),\n          codable: makeFinder('.note-codable'),\n          statusbar: makeFinder('.note-statusbar'),\n          popover: makeFinder('.note-popover'),\n          handle: makeFinder('.note-handle'),\n          dialog: makeFinder('.note-dialog', $dialogHolder)\n        };\n      }\n    };\n\n    /**\n     * returns makeLayoutInfo from editor's descendant node.\n     *\n     * @private\n     * @param {Node} descendant\n     * @return {Object}\n     */\n    var makeLayoutInfo = function (descendant) {\n      var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout');\n\n      if (!$target.length) {\n        return null;\n      }\n\n      var $editor;\n      if ($target.is('.note-editor, .note-air-editor')) {\n        $editor = $target;\n      } else {\n        $editor = $('#note-editor-' + list.last($target.attr('id').split('-')));\n      }\n\n      return buildLayoutInfo($editor);\n    };\n\n    /**\n     * @method makePredByNodeName\n     *\n     * returns predicate which judge whether nodeName is same\n     *\n     * @param {String} nodeName\n     * @return {Function}\n     */\n    var makePredByNodeName = function (nodeName) {\n      nodeName = nodeName.toUpperCase();\n      return function (node) {\n        return node && node.nodeName.toUpperCase() === nodeName;\n      };\n    };\n\n    /**\n     * @method isText\n     *\n     *\n     *\n     * @param {Node} node\n     * @return {Boolean} true if node's type is text(3)\n     */\n    var isText = function (node) {\n      return node && node.nodeType === 3;\n    };\n\n    /**\n     * ex) br, col, embed, hr, img, input, ...\n     * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements\n     */\n    var isVoid = function (node) {\n      return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON/.test(node.nodeName.toUpperCase());\n    };\n\n    var isPara = function (node) {\n      if (isEditable(node)) {\n        return false;\n      }\n\n      // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph\n      return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());\n    };\n\n    var isLi = makePredByNodeName('LI');\n\n    var isPurePara = function (node) {\n      return isPara(node) && !isLi(node);\n    };\n\n    var isTable = makePredByNodeName('TABLE');\n\n    var isInline = function (node) {\n      return !isBodyContainer(node) &&\n             !isList(node) &&\n             !isHr(node) &&\n             !isPara(node) &&\n             !isTable(node) &&\n             !isBlockquote(node);\n    };\n\n    var isList = function (node) {\n      return node && /^UL|^OL/.test(node.nodeName.toUpperCase());\n    };\n\n    var isHr = makePredByNodeName('HR');\n\n    var isCell = function (node) {\n      return node && /^TD|^TH/.test(node.nodeName.toUpperCase());\n    };\n\n    var isBlockquote = makePredByNodeName('BLOCKQUOTE');\n\n    var isBodyContainer = function (node) {\n      return isCell(node) || isBlockquote(node) || isEditable(node);\n    };\n\n    var isAnchor = makePredByNodeName('A');\n\n    var isParaInline = function (node) {\n      return isInline(node) && !!ancestor(node, isPara);\n    };\n\n    var isBodyInline = function (node) {\n      return isInline(node) && !ancestor(node, isPara);\n    };\n\n    var isBody = makePredByNodeName('BODY');\n\n    /**\n     * returns whether nodeB is closest sibling of nodeA\n     *\n     * @param {Node} nodeA\n     * @param {Node} nodeB\n     * @return {Boolean}\n     */\n    var isClosestSibling = function (nodeA, nodeB) {\n      return nodeA.nextSibling === nodeB ||\n             nodeA.previousSibling === nodeB;\n    };\n\n    /**\n     * returns array of closest siblings with node\n     *\n     * @param {Node} node\n     * @param {function} [pred] - predicate function\n     * @return {Node[]}\n     */\n    var withClosestSiblings = function (node, pred) {\n      pred = pred || func.ok;\n\n      var siblings = [];\n      if (node.previousSibling && pred(node.previousSibling)) {\n        siblings.push(node.previousSibling);\n      }\n      siblings.push(node);\n      if (node.nextSibling && pred(node.nextSibling)) {\n        siblings.push(node.nextSibling);\n      }\n      return siblings;\n    };\n\n    /**\n     * blank HTML for cursor position\n     * - [workaround] old IE only works with &nbsp;\n     * - [workaround] IE11 and other browser works with bogus br\n     */\n    var blankHTML = agent.isMSIE && agent.browserVersion < 11 ? '&nbsp;' : '<br>';\n\n    /**\n     * @method nodeLength\n     *\n     * returns #text's text size or element's childNodes size\n     *\n     * @param {Node} node\n     */\n    var nodeLength = function (node) {\n      if (isText(node)) {\n        return node.nodeValue.length;\n      }\n\n      return node.childNodes.length;\n    };\n\n    /**\n     * returns whether node is empty or not.\n     *\n     * @param {Node} node\n     * @return {Boolean}\n     */\n    var isEmpty = function (node) {\n      var len = nodeLength(node);\n\n      if (len === 0) {\n        return true;\n      } else if (!isText(node) && len === 1 && node.innerHTML === blankHTML) {\n        // ex) <p><br></p>, <span><br></span>\n        return true;\n      } else if (list.all(node.childNodes, isText) && node.innerHTML === '') {\n        // ex) <p></p>, <span></span>\n        return true;\n      }\n\n      return false;\n    };\n\n    /**\n     * padding blankHTML if node is empty (for cursor position)\n     */\n    var paddingBlankHTML = function (node) {\n      if (!isVoid(node) && !nodeLength(node)) {\n        node.innerHTML = blankHTML;\n      }\n    };\n\n    /**\n     * find nearest ancestor predicate hit\n     *\n     * @param {Node} node\n     * @param {Function} pred - predicate function\n     */\n    var ancestor = function (node, pred) {\n      while (node) {\n        if (pred(node)) { return node; }\n        if (isEditable(node)) { break; }\n\n        node = node.parentNode;\n      }\n      return null;\n    };\n\n    /**\n     * find nearest ancestor only single child blood line and predicate hit\n     *\n     * @param {Node} node\n     * @param {Function} pred - predicate function\n     */\n    var singleChildAncestor = function (node, pred) {\n      node = node.parentNode;\n\n      while (node) {\n        if (nodeLength(node) !== 1) { break; }\n        if (pred(node)) { return node; }\n        if (isEditable(node)) { break; }\n\n        node = node.parentNode;\n      }\n      return null;\n    };\n\n    /**\n     * returns new array of ancestor nodes (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [optional] pred - predicate function\n     */\n    var listAncestor = function (node, pred) {\n      pred = pred || func.fail;\n\n      var ancestors = [];\n      ancestor(node, function (el) {\n        if (!isEditable(el)) {\n          ancestors.push(el);\n        }\n\n        return pred(el);\n      });\n      return ancestors;\n    };\n\n    /**\n     * find farthest ancestor predicate hit\n     */\n    var lastAncestor = function (node, pred) {\n      var ancestors = listAncestor(node);\n      return list.last(ancestors.filter(pred));\n    };\n\n    /**\n     * returns common ancestor node between two nodes.\n     *\n     * @param {Node} nodeA\n     * @param {Node} nodeB\n     */\n    var commonAncestor = function (nodeA, nodeB) {\n      var ancestors = listAncestor(nodeA);\n      for (var n = nodeB; n; n = n.parentNode) {\n        if ($.inArray(n, ancestors) > -1) { return n; }\n      }\n      return null; // difference document area\n    };\n\n    /**\n     * listing all previous siblings (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [optional] pred - predicate function\n     */\n    var listPrev = function (node, pred) {\n      pred = pred || func.fail;\n\n      var nodes = [];\n      while (node) {\n        if (pred(node)) { break; }\n        nodes.push(node);\n        node = node.previousSibling;\n      }\n      return nodes;\n    };\n\n    /**\n     * listing next siblings (until predicate hit).\n     *\n     * @param {Node} node\n     * @param {Function} [pred] - predicate function\n     */\n    var listNext = function (node, pred) {\n      pred = pred || func.fail;\n\n      var nodes = [];\n      while (node) {\n        if (pred(node)) { break; }\n        nodes.push(node);\n        node = node.nextSibling;\n      }\n      return nodes;\n    };\n\n    /**\n     * listing descendant nodes\n     *\n     * @param {Node} node\n     * @param {Function} [pred] - predicate function\n     */\n    var listDescendant = function (node, pred) {\n      var descendents = [];\n      pred = pred || func.ok;\n\n      // start DFS(depth first search) with node\n      (function fnWalk(current) {\n        if (node !== current && pred(current)) {\n          descendents.push(current);\n        }\n        for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {\n          fnWalk(current.childNodes[idx]);\n        }\n      })(node);\n\n      return descendents;\n    };\n\n    /**\n     * wrap node with new tag.\n     *\n     * @param {Node} node\n     * @param {Node} tagName of wrapper\n     * @return {Node} - wrapper\n     */\n    var wrap = function (node, wrapperName) {\n      var parent = node.parentNode;\n      var wrapper = $('<' + wrapperName + '>')[0];\n\n      parent.insertBefore(wrapper, node);\n      wrapper.appendChild(node);\n\n      return wrapper;\n    };\n\n    /**\n     * insert node after preceding\n     *\n     * @param {Node} node\n     * @param {Node} preceding - predicate function\n     */\n    var insertAfter = function (node, preceding) {\n      var next = preceding.nextSibling, parent = preceding.parentNode;\n      if (next) {\n        parent.insertBefore(node, next);\n      } else {\n        parent.appendChild(node);\n      }\n      return node;\n    };\n\n    /**\n     * append elements.\n     *\n     * @param {Node} node\n     * @param {Collection} aChild\n     */\n    var appendChildNodes = function (node, aChild) {\n      $.each(aChild, function (idx, child) {\n        node.appendChild(child);\n      });\n      return node;\n    };\n\n    /**\n     * returns whether boundaryPoint is left edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isLeftEdgePoint = function (point) {\n      return point.offset === 0;\n    };\n\n    /**\n     * returns whether boundaryPoint is right edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isRightEdgePoint = function (point) {\n      return point.offset === nodeLength(point.node);\n    };\n\n    /**\n     * returns whether boundaryPoint is edge or not.\n     *\n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isEdgePoint = function (point) {\n      return isLeftEdgePoint(point) || isRightEdgePoint(point);\n    };\n\n    /**\n     * returns wheter node is left edge of ancestor or not.\n     *\n     * @param {Node} node\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isLeftEdgeOf = function (node, ancestor) {\n      while (node && node !== ancestor) {\n        if (position(node) !== 0) {\n          return false;\n        }\n        node = node.parentNode;\n      }\n\n      return true;\n    };\n\n    /**\n     * returns whether node is right edge of ancestor or not.\n     *\n     * @param {Node} node\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isRightEdgeOf = function (node, ancestor) {\n      while (node && node !== ancestor) {\n        if (position(node) !== nodeLength(node.parentNode) - 1) {\n          return false;\n        }\n        node = node.parentNode;\n      }\n\n      return true;\n    };\n\n    /**\n     * returns whether point is left edge of ancestor or not.\n     * @param {BoundaryPoint} point\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isLeftEdgePointOf = function (point, ancestor) {\n      return isLeftEdgePoint(point) && isLeftEdgeOf(point.node, ancestor);\n    };\n\n    /**\n     * returns whether point is right edge of ancestor or not.\n     * @param {BoundaryPoint} point\n     * @param {Node} ancestor\n     * @return {Boolean}\n     */\n    var isRightEdgePointOf = function (point, ancestor) {\n      return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor);\n    };\n\n    /**\n     * returns offset from parent.\n     *\n     * @param {Node} node\n     */\n    var position = function (node) {\n      var offset = 0;\n      while ((node = node.previousSibling)) {\n        offset += 1;\n      }\n      return offset;\n    };\n\n    var hasChildren = function (node) {\n      return !!(node && node.childNodes && node.childNodes.length);\n    };\n\n    /**\n     * returns previous boundaryPoint\n     *\n     * @param {BoundaryPoint} point\n     * @param {Boolean} isSkipInnerOffset\n     * @return {BoundaryPoint}\n     */\n    var prevPoint = function (point, isSkipInnerOffset) {\n      var node, offset;\n\n      if (point.offset === 0) {\n        if (isEditable(point.node)) {\n          return null;\n        }\n\n        node = point.node.parentNode;\n        offset = position(point.node);\n      } else if (hasChildren(point.node)) {\n        node = point.node.childNodes[point.offset - 1];\n        offset = nodeLength(node);\n      } else {\n        node = point.node;\n        offset = isSkipInnerOffset ? 0 : point.offset - 1;\n      }\n\n      return {\n        node: node,\n        offset: offset\n      };\n    };\n\n    /**\n     * returns next boundaryPoint\n     *\n     * @param {BoundaryPoint} point\n     * @param {Boolean} isSkipInnerOffset\n     * @return {BoundaryPoint}\n     */\n    var nextPoint = function (point, isSkipInnerOffset) {\n      var node, offset;\n\n      if (nodeLength(point.node) === point.offset) {\n        if (isEditable(point.node)) {\n          return null;\n        }\n\n        node = point.node.parentNode;\n        offset = position(point.node) + 1;\n      } else if (hasChildren(point.node)) {\n        node = point.node.childNodes[point.offset];\n        offset = 0;\n      } else {\n        node = point.node;\n        offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;\n      }\n\n      return {\n        node: node,\n        offset: offset\n      };\n    };\n\n    /**\n     * returns whether pointA and pointB is same or not.\n     *\n     * @param {BoundaryPoint} pointA\n     * @param {BoundaryPoint} pointB\n     * @return {Boolean}\n     */\n    var isSamePoint = function (pointA, pointB) {\n      return pointA.node === pointB.node && pointA.offset === pointB.offset;\n    };\n\n    /**\n     * returns whether point is visible (can set cursor) or not.\n     * \n     * @param {BoundaryPoint} point\n     * @return {Boolean}\n     */\n    var isVisiblePoint = function (point) {\n      if (isText(point.node) || !hasChildren(point.node) || isEmpty(point.node)) {\n        return true;\n      }\n\n      var leftNode = point.node.childNodes[point.offset - 1];\n      var rightNode = point.node.childNodes[point.offset];\n      if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) {\n        return true;\n      }\n\n      return false;\n    };\n\n    /**\n     * @method prevPointUtil\n     *\n     * @param {BoundaryPoint} point\n     * @param {Function} pred\n     * @return {BoundaryPoint}\n     */\n    var prevPointUntil = function (point, pred) {\n      while (point) {\n        if (pred(point)) {\n          return point;\n        }\n\n        point = prevPoint(point);\n      }\n\n      return null;\n    };\n\n    /**\n     * @method nextPointUntil\n     *\n     * @param {BoundaryPoint} point\n     * @param {Function} pred\n     * @return {BoundaryPoint}\n     */\n    var nextPointUntil = function (point, pred) {\n      while (point) {\n        if (pred(point)) {\n          return point;\n        }\n\n        point = nextPoint(point);\n      }\n\n      return null;\n    };\n\n    /**\n     * returns whether point has character or not.\n     *\n     * @param {Point} point\n     * @return {Boolean}\n     */\n    var isCharPoint = function (point) {\n      if (!isText(point.node)) {\n        return false;\n      }\n\n      var ch = point.node.nodeValue.charAt(point.offset - 1);\n      return ch && (ch !== ' ' && ch !== NBSP_CHAR);\n    };\n\n    /**\n     * @method walkPoint\n     *\n     * @param {BoundaryPoint} startPoint\n     * @param {BoundaryPoint} endPoint\n     * @param {Function} handler\n     * @param {Boolean} isSkipInnerOffset\n     */\n    var walkPoint = function (startPoint, endPoint, handler, isSkipInnerOffset) {\n      var point = startPoint;\n\n      while (point) {\n        handler(point);\n\n        if (isSamePoint(point, endPoint)) {\n          break;\n        }\n\n        var isSkipOffset = isSkipInnerOffset &&\n                           startPoint.node !== point.node &&\n                           endPoint.node !== point.node;\n        point = nextPoint(point, isSkipOffset);\n      }\n    };\n\n    /**\n     * @method makeOffsetPath\n     *\n     * return offsetPath(array of offset) from ancestor\n     *\n     * @param {Node} ancestor - ancestor node\n     * @param {Node} node\n     */\n    var makeOffsetPath = function (ancestor, node) {\n      var ancestors = listAncestor(node, func.eq(ancestor));\n      return ancestors.map(position).reverse();\n    };\n\n    /**\n     * @method fromOffsetPath\n     *\n     * return element from offsetPath(array of offset)\n     *\n     * @param {Node} ancestor - ancestor node\n     * @param {array} offsets - offsetPath\n     */\n    var fromOffsetPath = function (ancestor, offsets) {\n      var current = ancestor;\n      for (var i = 0, len = offsets.length; i < len; i++) {\n        if (current.childNodes.length <= offsets[i]) {\n          current = current.childNodes[current.childNodes.length - 1];\n        } else {\n          current = current.childNodes[offsets[i]];\n        }\n      }\n      return current;\n    };\n\n    /**\n     * @method splitNode\n     *\n     * split element or #text\n     *\n     * @param {BoundaryPoint} point\n     * @param {Object} [options]\n     * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false\n     * @param {Boolean} [options.isNotSplitEdgePoint] - default: false\n     * @return {Node} right node of boundaryPoint\n     */\n    var splitNode = function (point, options) {\n      var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;\n      var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;\n\n      // edge case\n      if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {\n        if (isLeftEdgePoint(point)) {\n          return point.node;\n        } else if (isRightEdgePoint(point)) {\n          return point.node.nextSibling;\n        }\n      }\n\n      // split #text\n      if (isText(point.node)) {\n        return point.node.splitText(point.offset);\n      } else {\n        var childNode = point.node.childNodes[point.offset];\n        var clone = insertAfter(point.node.cloneNode(false), point.node);\n        appendChildNodes(clone, listNext(childNode));\n\n        if (!isSkipPaddingBlankHTML) {\n          paddingBlankHTML(point.node);\n          paddingBlankHTML(clone);\n        }\n\n        return clone;\n      }\n    };\n\n    /**\n     * @method splitTree\n     *\n     * split tree by point\n     *\n     * @param {Node} root - split root\n     * @param {BoundaryPoint} point\n     * @param {Object} [options]\n     * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false\n     * @param {Boolean} [options.isNotSplitEdgePoint] - default: false\n     * @return {Node} right node of boundaryPoint\n     */\n    var splitTree = function (root, point, options) {\n      // ex) [#text, <span>, <p>]\n      var ancestors = listAncestor(point.node, func.eq(root));\n\n      if (!ancestors.length) {\n        return null;\n      } else if (ancestors.length === 1) {\n        return splitNode(point, options);\n      }\n\n      return ancestors.reduce(function (node, parent) {\n        if (node === point.node) {\n          node = splitNode(point, options);\n        }\n\n        return splitNode({\n          node: parent,\n          offset: node ? dom.position(node) : nodeLength(parent)\n        }, options);\n      });\n    };\n\n    /**\n     * split point\n     *\n     * @param {Point} point\n     * @param {Boolean} isInline\n     * @return {Object}\n     */\n    var splitPoint = function (point, isInline) {\n      // find splitRoot, container\n      //  - inline: splitRoot is a child of paragraph\n      //  - block: splitRoot is a child of bodyContainer\n      var pred = isInline ? isPara : isBodyContainer;\n      var ancestors = listAncestor(point.node, pred);\n      var topAncestor = list.last(ancestors) || point.node;\n\n      var splitRoot, container;\n      if (pred(topAncestor)) {\n        splitRoot = ancestors[ancestors.length - 2];\n        container = topAncestor;\n      } else {\n        splitRoot = topAncestor;\n        container = splitRoot.parentNode;\n      }\n\n      // if splitRoot is exists, split with splitTree\n      var pivot = splitRoot && splitTree(splitRoot, point, {\n        isSkipPaddingBlankHTML: isInline,\n        isNotSplitEdgePoint: isInline\n      });\n\n      // if container is point.node, find pivot with point.offset\n      if (!pivot && container === point.node) {\n        pivot = point.node.childNodes[point.offset];\n      }\n\n      return {\n        rightNode: pivot,\n        container: container\n      };\n    };\n\n    var create = function (nodeName) {\n      return document.createElement(nodeName);\n    };\n\n    var createText = function (text) {\n      return document.createTextNode(text);\n    };\n\n    /**\n     * @method remove\n     *\n     * remove node, (isRemoveChild: remove child or not)\n     *\n     * @param {Node} node\n     * @param {Boolean} isRemoveChild\n     */\n    var remove = function (node, isRemoveChild) {\n      if (!node || !node.parentNode) { return; }\n      if (node.removeNode) { return node.removeNode(isRemoveChild); }\n\n      var parent = node.parentNode;\n      if (!isRemoveChild) {\n        var nodes = [];\n        var i, len;\n        for (i = 0, len = node.childNodes.length; i < len; i++) {\n          nodes.push(node.childNodes[i]);\n        }\n\n        for (i = 0, len = nodes.length; i < len; i++) {\n          parent.insertBefore(nodes[i], node);\n        }\n      }\n\n      parent.removeChild(node);\n    };\n\n    /**\n     * @method removeWhile\n     *\n     * @param {Node} node\n     * @param {Function} pred\n     */\n    var removeWhile = function (node, pred) {\n      while (node) {\n        if (isEditable(node) || !pred(node)) {\n          break;\n        }\n\n        var parent = node.parentNode;\n        remove(node);\n        node = parent;\n      }\n    };\n\n    /**\n     * @method replace\n     *\n     * replace node with provided nodeName\n     *\n     * @param {Node} node\n     * @param {String} nodeName\n     * @return {Node} - new node\n     */\n    var replace = function (node, nodeName) {\n      if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {\n        return node;\n      }\n\n      var newNode = create(nodeName);\n\n      if (node.style.cssText) {\n        newNode.style.cssText = node.style.cssText;\n      }\n\n      appendChildNodes(newNode, list.from(node.childNodes));\n      insertAfter(newNode, node);\n      remove(node);\n\n      return newNode;\n    };\n\n    var isTextarea = makePredByNodeName('TEXTAREA');\n\n    /**\n     * @param {jQuery} $node\n     * @param {Boolean} [stripLinebreaks] - default: false\n     */\n    var value = function ($node, stripLinebreaks) {\n      var val = isTextarea($node[0]) ? $node.val() : $node.html();\n      if (stripLinebreaks) {\n        return val.replace(/[\\n\\r]/g, '');\n      }\n      return val;\n    };\n\n    /**\n     * @method html\n     *\n     * get the HTML contents of node\n     *\n     * @param {jQuery} $node\n     * @param {Boolean} [isNewlineOnBlock]\n     */\n    var html = function ($node, isNewlineOnBlock) {\n      var markup = value($node);\n\n      if (isNewlineOnBlock) {\n        var regexTag = /<(\\/?)(\\b(?!!)[^>\\s]*)(.*?)(\\s*\\/?>)/g;\n        markup = markup.replace(regexTag, function (match, endSlash, name) {\n          name = name.toUpperCase();\n          var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) &&\n                                       !!endSlash;\n          var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);\n\n          return match + ((isEndOfInlineContainer || isBlockNode) ? '\\n' : '');\n        });\n        markup = $.trim(markup);\n      }\n\n      return markup;\n    };\n\n    return {\n      /** @property {String} NBSP_CHAR */\n      NBSP_CHAR: NBSP_CHAR,\n      /** @property {String} ZERO_WIDTH_NBSP_CHAR */\n      ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,\n      /** @property {String} blank */\n      blank: blankHTML,\n      /** @property {String} emptyPara */\n      emptyPara: '<p>' + blankHTML + '</p>',\n      makePredByNodeName: makePredByNodeName,\n      isEditable: isEditable,\n      isControlSizing: isControlSizing,\n      buildLayoutInfo: buildLayoutInfo,\n      makeLayoutInfo: makeLayoutInfo,\n      isText: isText,\n      isVoid: isVoid,\n      isPara: isPara,\n      isPurePara: isPurePara,\n      isInline: isInline,\n      isBlock: func.not(isInline),\n      isBodyInline: isBodyInline,\n      isBody: isBody,\n      isParaInline: isParaInline,\n      isList: isList,\n      isTable: isTable,\n      isCell: isCell,\n      isBlockquote: isBlockquote,\n      isBodyContainer: isBodyContainer,\n      isAnchor: isAnchor,\n      isDiv: makePredByNodeName('DIV'),\n      isLi: isLi,\n      isBR: makePredByNodeName('BR'),\n      isSpan: makePredByNodeName('SPAN'),\n      isB: makePredByNodeName('B'),\n      isU: makePredByNodeName('U'),\n      isS: makePredByNodeName('S'),\n      isI: makePredByNodeName('I'),\n      isImg: makePredByNodeName('IMG'),\n      isTextarea: isTextarea,\n      isEmpty: isEmpty,\n      isEmptyAnchor: func.and(isAnchor, isEmpty),\n      isClosestSibling: isClosestSibling,\n      withClosestSiblings: withClosestSiblings,\n      nodeLength: nodeLength,\n      isLeftEdgePoint: isLeftEdgePoint,\n      isRightEdgePoint: isRightEdgePoint,\n      isEdgePoint: isEdgePoint,\n      isLeftEdgeOf: isLeftEdgeOf,\n      isRightEdgeOf: isRightEdgeOf,\n      isLeftEdgePointOf: isLeftEdgePointOf,\n      isRightEdgePointOf: isRightEdgePointOf,\n      prevPoint: prevPoint,\n      nextPoint: nextPoint,\n      isSamePoint: isSamePoint,\n      isVisiblePoint: isVisiblePoint,\n      prevPointUntil: prevPointUntil,\n      nextPointUntil: nextPointUntil,\n      isCharPoint: isCharPoint,\n      walkPoint: walkPoint,\n      ancestor: ancestor,\n      singleChildAncestor: singleChildAncestor,\n      listAncestor: listAncestor,\n      lastAncestor: lastAncestor,\n      listNext: listNext,\n      listPrev: listPrev,\n      listDescendant: listDescendant,\n      commonAncestor: commonAncestor,\n      wrap: wrap,\n      insertAfter: insertAfter,\n      appendChildNodes: appendChildNodes,\n      position: position,\n      hasChildren: hasChildren,\n      makeOffsetPath: makeOffsetPath,\n      fromOffsetPath: fromOffsetPath,\n      splitTree: splitTree,\n      splitPoint: splitPoint,\n      create: create,\n      createText: createText,\n      remove: remove,\n      removeWhile: removeWhile,\n      replace: replace,\n      html: html,\n      value: value\n    };\n  })();\n\n\n  var range = (function () {\n\n    /**\n     * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js\n     *\n     * @param {TextRange} textRange\n     * @param {Boolean} isStart\n     * @return {BoundaryPoint}\n     *\n     * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx\n     */\n    var textRangeToPoint = function (textRange, isStart) {\n      var container = textRange.parentElement(), offset;\n  \n      var tester = document.body.createTextRange(), prevContainer;\n      var childNodes = list.from(container.childNodes);\n      for (offset = 0; offset < childNodes.length; offset++) {\n        if (dom.isText(childNodes[offset])) {\n          continue;\n        }\n        tester.moveToElementText(childNodes[offset]);\n        if (tester.compareEndPoints('StartToStart', textRange) >= 0) {\n          break;\n        }\n        prevContainer = childNodes[offset];\n      }\n  \n      if (offset !== 0 && dom.isText(childNodes[offset - 1])) {\n        var textRangeStart = document.body.createTextRange(), curTextNode = null;\n        textRangeStart.moveToElementText(prevContainer || container);\n        textRangeStart.collapse(!prevContainer);\n        curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;\n  \n        var pointTester = textRange.duplicate();\n        pointTester.setEndPoint('StartToStart', textRangeStart);\n        var textCount = pointTester.text.replace(/[\\r\\n]/g, '').length;\n  \n        while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {\n          textCount -= curTextNode.nodeValue.length;\n          curTextNode = curTextNode.nextSibling;\n        }\n  \n        /* jshint ignore:start */\n        var dummy = curTextNode.nodeValue; // enforce IE to re-reference curTextNode, hack\n        /* jshint ignore:end */\n  \n        if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) &&\n            textCount === curTextNode.nodeValue.length) {\n          textCount -= curTextNode.nodeValue.length;\n          curTextNode = curTextNode.nextSibling;\n        }\n  \n        container = curTextNode;\n        offset = textCount;\n      }\n  \n      return {\n        cont: container,\n        offset: offset\n      };\n    };\n    \n    /**\n     * return TextRange from boundary point (inspired by google closure-library)\n     * @param {BoundaryPoint} point\n     * @return {TextRange}\n     */\n    var pointToTextRange = function (point) {\n      var textRangeInfo = function (container, offset) {\n        var node, isCollapseToStart;\n  \n        if (dom.isText(container)) {\n          var prevTextNodes = dom.listPrev(container, func.not(dom.isText));\n          var prevContainer = list.last(prevTextNodes).previousSibling;\n          node =  prevContainer || container.parentNode;\n          offset += list.sum(list.tail(prevTextNodes), dom.nodeLength);\n          isCollapseToStart = !prevContainer;\n        } else {\n          node = container.childNodes[offset] || container;\n          if (dom.isText(node)) {\n            return textRangeInfo(node, 0);\n          }\n  \n          offset = 0;\n          isCollapseToStart = false;\n        }\n  \n        return {\n          node: node,\n          collapseToStart: isCollapseToStart,\n          offset: offset\n        };\n      };\n  \n      var textRange = document.body.createTextRange();\n      var info = textRangeInfo(point.node, point.offset);\n  \n      textRange.moveToElementText(info.node);\n      textRange.collapse(info.collapseToStart);\n      textRange.moveStart('character', info.offset);\n      return textRange;\n    };\n    \n    /**\n     * Wrapped Range\n     *\n     * @constructor\n     * @param {Node} sc - start container\n     * @param {Number} so - start offset\n     * @param {Node} ec - end container\n     * @param {Number} eo - end offset\n     */\n    var WrappedRange = function (sc, so, ec, eo) {\n      this.sc = sc;\n      this.so = so;\n      this.ec = ec;\n      this.eo = eo;\n  \n      // nativeRange: get nativeRange from sc, so, ec, eo\n      var nativeRange = function () {\n        if (agent.isW3CRangeSupport) {\n          var w3cRange = document.createRange();\n          w3cRange.setStart(sc, so);\n          w3cRange.setEnd(ec, eo);\n\n          return w3cRange;\n        } else {\n          var textRange = pointToTextRange({\n            node: sc,\n            offset: so\n          });\n\n          textRange.setEndPoint('EndToEnd', pointToTextRange({\n            node: ec,\n            offset: eo\n          }));\n\n          return textRange;\n        }\n      };\n\n      this.getPoints = function () {\n        return {\n          sc: sc,\n          so: so,\n          ec: ec,\n          eo: eo\n        };\n      };\n\n      this.getStartPoint = function () {\n        return {\n          node: sc,\n          offset: so\n        };\n      };\n\n      this.getEndPoint = function () {\n        return {\n          node: ec,\n          offset: eo\n        };\n      };\n\n      /**\n       * select update visible range\n       */\n      this.select = function () {\n        var nativeRng = nativeRange();\n        if (agent.isW3CRangeSupport) {\n          var selection = document.getSelection();\n          if (selection.rangeCount > 0) {\n            selection.removeAllRanges();\n          }\n          selection.addRange(nativeRng);\n        } else {\n          nativeRng.select();\n        }\n        \n        return this;\n      };\n\n      /**\n       * @return {WrappedRange}\n       */\n      this.normalize = function () {\n\n        /**\n         * @param {BoundaryPoint} point\n         * @param {Boolean} isLeftToRight\n         * @return {BoundaryPoint}\n         */\n        var getVisiblePoint = function (point, isLeftToRight) {\n          if ((dom.isVisiblePoint(point) && !dom.isEdgePoint(point)) ||\n              (dom.isVisiblePoint(point) && dom.isRightEdgePoint(point) && !isLeftToRight) ||\n              (dom.isVisiblePoint(point) && dom.isLeftEdgePoint(point) && isLeftToRight) ||\n              (dom.isVisiblePoint(point) && dom.isBlock(point.node) && dom.isEmpty(point.node))) {\n            return point;\n          }\n\n          // point on block's edge\n          var block = dom.ancestor(point.node, dom.isBlock);\n          if (((dom.isLeftEdgePointOf(point, block) || dom.isVoid(dom.prevPoint(point).node)) && !isLeftToRight) ||\n              ((dom.isRightEdgePointOf(point, block) || dom.isVoid(dom.nextPoint(point).node)) && isLeftToRight)) {\n\n            // returns point already on visible point\n            if (dom.isVisiblePoint(point)) {\n              return point;\n            }\n            // reverse direction \n            isLeftToRight = !isLeftToRight;\n          }\n\n          var nextPoint = isLeftToRight ? dom.nextPointUntil(dom.nextPoint(point), dom.isVisiblePoint) :\n                                          dom.prevPointUntil(dom.prevPoint(point), dom.isVisiblePoint);\n          return nextPoint || point;\n        };\n\n        var endPoint = getVisiblePoint(this.getEndPoint(), false);\n        var startPoint = this.isCollapsed() ? endPoint : getVisiblePoint(this.getStartPoint(), true);\n\n        return new WrappedRange(\n          startPoint.node,\n          startPoint.offset,\n          endPoint.node,\n          endPoint.offset\n        );\n      };\n\n      /**\n       * returns matched nodes on range\n       *\n       * @param {Function} [pred] - predicate function\n       * @param {Object} [options]\n       * @param {Boolean} [options.includeAncestor]\n       * @param {Boolean} [options.fullyContains]\n       * @return {Node[]}\n       */\n      this.nodes = function (pred, options) {\n        pred = pred || func.ok;\n\n        var includeAncestor = options && options.includeAncestor;\n        var fullyContains = options && options.fullyContains;\n\n        // TODO compare points and sort\n        var startPoint = this.getStartPoint();\n        var endPoint = this.getEndPoint();\n\n        var nodes = [];\n        var leftEdgeNodes = [];\n\n        dom.walkPoint(startPoint, endPoint, function (point) {\n          if (dom.isEditable(point.node)) {\n            return;\n          }\n\n          var node;\n          if (fullyContains) {\n            if (dom.isLeftEdgePoint(point)) {\n              leftEdgeNodes.push(point.node);\n            }\n            if (dom.isRightEdgePoint(point) && list.contains(leftEdgeNodes, point.node)) {\n              node = point.node;\n            }\n          } else if (includeAncestor) {\n            node = dom.ancestor(point.node, pred);\n          } else {\n            node = point.node;\n          }\n\n          if (node && pred(node)) {\n            nodes.push(node);\n          }\n        }, true);\n\n        return list.unique(nodes);\n      };\n\n      /**\n       * returns commonAncestor of range\n       * @return {Element} - commonAncestor\n       */\n      this.commonAncestor = function () {\n        return dom.commonAncestor(sc, ec);\n      };\n\n      /**\n       * returns expanded range by pred\n       *\n       * @param {Function} pred - predicate function\n       * @return {WrappedRange}\n       */\n      this.expand = function (pred) {\n        var startAncestor = dom.ancestor(sc, pred);\n        var endAncestor = dom.ancestor(ec, pred);\n\n        if (!startAncestor && !endAncestor) {\n          return new WrappedRange(sc, so, ec, eo);\n        }\n\n        var boundaryPoints = this.getPoints();\n\n        if (startAncestor) {\n          boundaryPoints.sc = startAncestor;\n          boundaryPoints.so = 0;\n        }\n\n        if (endAncestor) {\n          boundaryPoints.ec = endAncestor;\n          boundaryPoints.eo = dom.nodeLength(endAncestor);\n        }\n\n        return new WrappedRange(\n          boundaryPoints.sc,\n          boundaryPoints.so,\n          boundaryPoints.ec,\n          boundaryPoints.eo\n        );\n      };\n\n      /**\n       * @param {Boolean} isCollapseToStart\n       * @return {WrappedRange}\n       */\n      this.collapse = function (isCollapseToStart) {\n        if (isCollapseToStart) {\n          return new WrappedRange(sc, so, sc, so);\n        } else {\n          return new WrappedRange(ec, eo, ec, eo);\n        }\n      };\n\n      /**\n       * splitText on range\n       */\n      this.splitText = function () {\n        var isSameContainer = sc === ec;\n        var boundaryPoints = this.getPoints();\n\n        if (dom.isText(ec) && !dom.isEdgePoint(this.getEndPoint())) {\n          ec.splitText(eo);\n        }\n\n        if (dom.isText(sc) && !dom.isEdgePoint(this.getStartPoint())) {\n          boundaryPoints.sc = sc.splitText(so);\n          boundaryPoints.so = 0;\n\n          if (isSameContainer) {\n            boundaryPoints.ec = boundaryPoints.sc;\n            boundaryPoints.eo = eo - so;\n          }\n        }\n\n        return new WrappedRange(\n          boundaryPoints.sc,\n          boundaryPoints.so,\n          boundaryPoints.ec,\n          boundaryPoints.eo\n        );\n      };\n\n      /**\n       * delete contents on range\n       * @return {WrappedRange}\n       */\n      this.deleteContents = function () {\n        if (this.isCollapsed()) {\n          return this;\n        }\n\n        var rng = this.splitText();\n        var nodes = rng.nodes(null, {\n          fullyContains: true\n        });\n\n        // find new cursor point\n        var point = dom.prevPointUntil(rng.getStartPoint(), function (point) {\n          return !list.contains(nodes, point.node);\n        });\n\n        var emptyParents = [];\n        $.each(nodes, function (idx, node) {\n          // find empty parents\n          var parent = node.parentNode;\n          if (point.node !== parent && dom.nodeLength(parent) === 1) {\n            emptyParents.push(parent);\n          }\n          dom.remove(node, false);\n        });\n\n        // remove empty parents\n        $.each(emptyParents, function (idx, node) {\n          dom.remove(node, false);\n        });\n\n        return new WrappedRange(\n          point.node,\n          point.offset,\n          point.node,\n          point.offset\n        ).normalize();\n      };\n      \n      /**\n       * makeIsOn: return isOn(pred) function\n       */\n      var makeIsOn = function (pred) {\n        return function () {\n          var ancestor = dom.ancestor(sc, pred);\n          return !!ancestor && (ancestor === dom.ancestor(ec, pred));\n        };\n      };\n  \n      // isOnEditable: judge whether range is on editable or not\n      this.isOnEditable = makeIsOn(dom.isEditable);\n      // isOnList: judge whether range is on list node or not\n      this.isOnList = makeIsOn(dom.isList);\n      // isOnAnchor: judge whether range is on anchor node or not\n      this.isOnAnchor = makeIsOn(dom.isAnchor);\n      // isOnAnchor: judge whether range is on cell node or not\n      this.isOnCell = makeIsOn(dom.isCell);\n\n      /**\n       * @param {Function} pred\n       * @return {Boolean}\n       */\n      this.isLeftEdgeOf = function (pred) {\n        if (!dom.isLeftEdgePoint(this.getStartPoint())) {\n          return false;\n        }\n\n        var node = dom.ancestor(this.sc, pred);\n        return node && dom.isLeftEdgeOf(this.sc, node);\n      };\n\n      /**\n       * returns whether range was collapsed or not\n       */\n      this.isCollapsed = function () {\n        return sc === ec && so === eo;\n      };\n\n      /**\n       * wrap inline nodes which children of body with paragraph\n       *\n       * @return {WrappedRange}\n       */\n      this.wrapBodyInlineWithPara = function () {\n        if (dom.isBodyContainer(sc) && dom.isEmpty(sc)) {\n          sc.innerHTML = dom.emptyPara;\n          return new WrappedRange(sc.firstChild, 0, sc.firstChild, 0);\n        }\n\n        /**\n         * [workaround] firefox often create range on not visible point. so normalize here.\n         *  - firefox: |<p>text</p>|\n         *  - chrome: <p>|text|</p>\n         */\n        var rng = this.normalize();\n        if (dom.isParaInline(sc) || dom.isPara(sc)) {\n          return rng;\n        }\n\n        // find inline top ancestor\n        var topAncestor;\n        if (dom.isInline(rng.sc)) {\n          var ancestors = dom.listAncestor(rng.sc, func.not(dom.isInline));\n          topAncestor = list.last(ancestors);\n          if (!dom.isInline(topAncestor)) {\n            topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];\n          }\n        } else {\n          topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];\n        }\n\n        // siblings not in paragraph\n        var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();\n        inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline));\n\n        // wrap with paragraph\n        if (inlineSiblings.length) {\n          var para = dom.wrap(list.head(inlineSiblings), 'p');\n          dom.appendChildNodes(para, list.tail(inlineSiblings));\n        }\n\n        return this.normalize();\n      };\n\n      /**\n       * insert node at current cursor\n       *\n       * @param {Node} node\n       * @return {Node}\n       */\n      this.insertNode = function (node) {\n        var rng = this.wrapBodyInlineWithPara().deleteContents();\n        var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));\n\n        if (info.rightNode) {\n          info.rightNode.parentNode.insertBefore(node, info.rightNode);\n        } else {\n          info.container.appendChild(node);\n        }\n\n        return node;\n      };\n\n      /**\n       * insert html at current cursor\n       */\n      this.pasteHTML = function (markup) {\n        var contentsContainer = $('<div></div>').html(markup)[0];\n        var childNodes = list.from(contentsContainer.childNodes);\n\n        var rng = this.wrapBodyInlineWithPara().deleteContents();\n\n        return childNodes.reverse().map(function (childNode) {\n          return rng.insertNode(childNode);\n        }).reverse();\n      };\n  \n      /**\n       * returns text in range\n       *\n       * @return {String}\n       */\n      this.toString = function () {\n        var nativeRng = nativeRange();\n        return agent.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;\n      };\n\n      /**\n       * returns range for word before cursor\n       *\n       * @param {Boolean} [findAfter] - find after cursor, default: false\n       * @return {WrappedRange}\n       */\n      this.getWordRange = function (findAfter) {\n        var endPoint = this.getEndPoint();\n\n        if (!dom.isCharPoint(endPoint)) {\n          return this;\n        }\n\n        var startPoint = dom.prevPointUntil(endPoint, function (point) {\n          return !dom.isCharPoint(point);\n        });\n\n        if (findAfter) {\n          endPoint = dom.nextPointUntil(endPoint, function (point) {\n            return !dom.isCharPoint(point);\n          });\n        }\n\n        return new WrappedRange(\n          startPoint.node,\n          startPoint.offset,\n          endPoint.node,\n          endPoint.offset\n        );\n      };\n  \n      /**\n       * create offsetPath bookmark\n       *\n       * @param {Node} editable\n       */\n      this.bookmark = function (editable) {\n        return {\n          s: {\n            path: dom.makeOffsetPath(editable, sc),\n            offset: so\n          },\n          e: {\n            path: dom.makeOffsetPath(editable, ec),\n            offset: eo\n          }\n        };\n      };\n\n      /**\n       * create offsetPath bookmark base on paragraph\n       *\n       * @param {Node[]} paras\n       */\n      this.paraBookmark = function (paras) {\n        return {\n          s: {\n            path: list.tail(dom.makeOffsetPath(list.head(paras), sc)),\n            offset: so\n          },\n          e: {\n            path: list.tail(dom.makeOffsetPath(list.last(paras), ec)),\n            offset: eo\n          }\n        };\n      };\n\n      /**\n       * getClientRects\n       * @return {Rect[]}\n       */\n      this.getClientRects = function () {\n        var nativeRng = nativeRange();\n        return nativeRng.getClientRects();\n      };\n    };\n\n  /**\n   * @class core.range\n   *\n   * Data structure\n   *  * BoundaryPoint: a point of dom tree\n   *  * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range\n   *\n   * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position\n   *\n   * @singleton\n   * @alternateClassName range\n   */\n    return {\n      /**\n       * @method\n       * \n       * create Range Object From arguments or Browser Selection\n       *\n       * @param {Node} sc - start container\n       * @param {Number} so - start offset\n       * @param {Node} ec - end container\n       * @param {Number} eo - end offset\n       * @return {WrappedRange}\n       */\n      create : function (sc, so, ec, eo) {\n        if (!arguments.length) { // from Browser Selection\n          if (agent.isW3CRangeSupport) {\n            var selection = document.getSelection();\n            if (!selection || selection.rangeCount === 0) {\n              return null;\n            } else if (dom.isBody(selection.anchorNode)) {\n              // Firefox: returns entire body as range on initialization. We won't never need it.\n              return null;\n            }\n  \n            var nativeRng = selection.getRangeAt(0);\n            sc = nativeRng.startContainer;\n            so = nativeRng.startOffset;\n            ec = nativeRng.endContainer;\n            eo = nativeRng.endOffset;\n          } else { // IE8: TextRange\n            var textRange = document.selection.createRange();\n            var textRangeEnd = textRange.duplicate();\n            textRangeEnd.collapse(false);\n            var textRangeStart = textRange;\n            textRangeStart.collapse(true);\n  \n            var startPoint = textRangeToPoint(textRangeStart, true),\n            endPoint = textRangeToPoint(textRangeEnd, false);\n\n            // same visible point case: range was collapsed.\n            if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) &&\n                dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) &&\n                endPoint.node.nextSibling === startPoint.node) {\n              startPoint = endPoint;\n            }\n\n            sc = startPoint.cont;\n            so = startPoint.offset;\n            ec = endPoint.cont;\n            eo = endPoint.offset;\n          }\n        } else if (arguments.length === 2) { //collapsed\n          ec = sc;\n          eo = so;\n        }\n        return new WrappedRange(sc, so, ec, eo);\n      },\n\n      /**\n       * @method \n       * \n       * create WrappedRange from node\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNode: function (node) {\n        var sc = node;\n        var so = 0;\n        var ec = node;\n        var eo = dom.nodeLength(ec);\n\n        // browsers can't target a picture or void node\n        if (dom.isVoid(sc)) {\n          so = dom.listPrev(sc).length - 1;\n          sc = sc.parentNode;\n        }\n        if (dom.isBR(ec)) {\n          eo = dom.listPrev(ec).length - 1;\n          ec = ec.parentNode;\n        } else if (dom.isVoid(ec)) {\n          eo = dom.listPrev(ec).length;\n          ec = ec.parentNode;\n        }\n\n        return this.create(sc, so, ec, eo);\n      },\n\n      /**\n       * create WrappedRange from node after position\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNodeBefore: function (node) {\n        return this.createFromNode(node).collapse(true);\n      },\n\n      /**\n       * create WrappedRange from node after position\n       *\n       * @param {Node} node\n       * @return {WrappedRange}\n       */\n      createFromNodeAfter: function (node) {\n        return this.createFromNode(node).collapse();\n      },\n\n      /**\n       * @method \n       * \n       * create WrappedRange from bookmark\n       *\n       * @param {Node} editable\n       * @param {Object} bookmark\n       * @return {WrappedRange}\n       */\n      createFromBookmark : function (editable, bookmark) {\n        var sc = dom.fromOffsetPath(editable, bookmark.s.path);\n        var so = bookmark.s.offset;\n        var ec = dom.fromOffsetPath(editable, bookmark.e.path);\n        var eo = bookmark.e.offset;\n        return new WrappedRange(sc, so, ec, eo);\n      },\n\n      /**\n       * @method \n       *\n       * create WrappedRange from paraBookmark\n       *\n       * @param {Object} bookmark\n       * @param {Node[]} paras\n       * @return {WrappedRange}\n       */\n      createFromParaBookmark: function (bookmark, paras) {\n        var so = bookmark.s.offset;\n        var eo = bookmark.e.offset;\n        var sc = dom.fromOffsetPath(list.head(paras), bookmark.s.path);\n        var ec = dom.fromOffsetPath(list.last(paras), bookmark.e.path);\n\n        return new WrappedRange(sc, so, ec, eo);\n      }\n    };\n  })();\n\n  /**\n   * @class defaults \n   * \n   * @singleton\n   */\n  var defaults = {\n    /** @property */\n    version: '0.6.16',\n\n    /**\n     * \n     * for event options, reference to EventHandler.attach\n     * \n     * @property {Object} options \n     * @property {String/Number} [options.width=null] set editor width \n     * @property {String/Number} [options.height=null] set editor height, ex) 300\n     * @property {String/Number} options.minHeight set minimum height of editor\n     * @property {String/Number} options.maxHeight\n     * @property {String/Number} options.focus \n     * @property {Number} options.tabsize \n     * @property {Boolean} options.styleWithSpan\n     * @property {Object} options.codemirror\n     * @property {Object} [options.codemirror.mode='text/html']\n     * @property {Object} [options.codemirror.htmlMode=true]\n     * @property {Object} [options.codemirror.lineNumbers=true]\n     * @property {String} [options.lang=en-US] language 'en-US', 'ko-KR', ...\n     * @property {String} [options.direction=null] text direction, ex) 'rtl'\n     * @property {Array} [options.toolbar]\n     * @property {Boolean} [options.airMode=false]\n     * @property {Array} [options.airPopover]\n     * @property {Fucntion} [options.onInit] initialize\n     * @property {Fucntion} [options.onsubmit]\n     */\n    options: {\n      width: null,                  // set editor width\n      height: null,                 // set editor height, ex) 300\n\n      minHeight: null,              // set minimum height of editor\n      maxHeight: null,              // set maximum height of editor\n\n      focus: false,                 // set focus to editable area after initializing summernote\n\n      tabsize: 4,                   // size of tab ex) 2 or 4\n      styleWithSpan: true,          // style with span (Chrome and FF only)\n\n      disableLinkTarget: false,     // hide link Target Checkbox\n      disableDragAndDrop: false,    // disable drag and drop event\n      disableResizeEditor: false,   // disable resizing editor\n      disableResizeImage: false,    // disable resizing image\n\n      shortcuts: true,              // enable keyboard shortcuts\n\n      textareaAutoSync: true,       // enable textarea auto sync\n\n      placeholder: false,           // enable placeholder text\n      prettifyHtml: true,           // enable prettifying html while toggling codeview\n\n      iconPrefix: 'fa fa-',         // prefix for css icon classes\n\n      icons: {\n        font: {\n          bold: 'bold',\n          italic: 'italic',\n          underline: 'underline',\n          clear: 'eraser',\n          height: 'text-height',\n          strikethrough: 'strikethrough',\n          superscript: 'superscript',\n          subscript: 'subscript'\n        },\n        image: {\n          image: 'picture-o',\n          floatLeft: 'align-left',\n          floatRight: 'align-right',\n          floatNone: 'align-justify',\n          shapeRounded: 'square',\n          shapeCircle: 'circle-o',\n          shapeThumbnail: 'picture-o',\n          shapeNone: 'times',\n          remove: 'trash-o'\n        },\n        link: {\n          link: 'link',\n          unlink: 'unlink',\n          edit: 'edit'\n        },\n        table: {\n          table: 'table'\n        },\n        hr: {\n          insert: 'minus'\n        },\n        style: {\n          style: 'magic'\n        },\n        lists: {\n          unordered: 'list-ul',\n          ordered: 'list-ol'\n        },\n        options: {\n          help: 'question',\n          fullscreen: 'arrows-alt',\n          codeview: 'code'\n        },\n        paragraph: {\n          paragraph: 'align-left',\n          outdent: 'outdent',\n          indent: 'indent',\n          left: 'align-left',\n          center: 'align-center',\n          right: 'align-right',\n          justify: 'align-justify'\n        },\n        color: {\n          recent: 'font'\n        },\n        history: {\n          undo: 'undo',\n          redo: 'repeat'\n        },\n        misc: {\n          check: 'check'\n        }\n      },\n\n      dialogsInBody: false,          // false will add dialogs into editor\n\n      codemirror: {                 // codemirror options\n        mode: 'text/html',\n        htmlMode: true,\n        lineNumbers: true\n      },\n\n      // language\n      lang: 'en-US',                // language 'en-US', 'ko-KR', ...\n      direction: null,              // text direction, ex) 'rtl'\n\n      // toolbar\n      toolbar: [\n        ['style', ['style']],\n        ['font', ['bold', 'italic', 'underline', 'clear']],\n        // ['font', ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']],\n        ['fontname', ['fontname']],\n        ['fontsize', ['fontsize']],\n        ['color', ['color']],\n        ['para', ['ul', 'ol', 'paragraph']],\n        ['height', ['height']],\n        ['table', ['table']],\n        ['insert', ['link', 'picture', 'hr']],\n        ['view', ['fullscreen', 'codeview']],\n        ['help', ['help']]\n      ],\n\n      plugin : { },\n\n      // air mode: inline editor\n      airMode: false,\n      // airPopover: [\n      //   ['style', ['style']],\n      //   ['font', ['bold', 'italic', 'underline', 'clear']],\n      //   ['fontname', ['fontname']],\n      //   ['color', ['color']],\n      //   ['para', ['ul', 'ol', 'paragraph']],\n      //   ['height', ['height']],\n      //   ['table', ['table']],\n      //   ['insert', ['link', 'picture']],\n      //   ['help', ['help']]\n      // ],\n      airPopover: [\n        ['color', ['color']],\n        ['font', ['bold', 'underline', 'clear']],\n        ['para', ['ul', 'paragraph']],\n        ['table', ['table']],\n        ['insert', ['link', 'picture']]\n      ],\n\n      // style tag\n      styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],\n\n      // default fontName\n      defaultFontName: 'Helvetica Neue',\n\n      // fontName\n      fontNames: [\n        'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',\n        'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande',\n        'Tahoma', 'Times New Roman', 'Verdana'\n      ],\n      fontNamesIgnoreCheck: [],\n\n      fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],\n\n      // pallete colors(n x n)\n      colors: [\n        ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'],\n        ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],\n        ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],\n        ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],\n        ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],\n        ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],\n        ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],\n        ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']\n      ],\n\n      // lineHeight\n      lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],\n\n      // insertTable max size\n      insertTableMaxSize: {\n        col: 10,\n        row: 10\n      },\n\n      // image\n      maximumImageFileSize: null, // size in bytes, null = no limit\n\n      // callbacks\n      oninit: null,             // initialize\n      onfocus: null,            // editable has focus\n      onblur: null,             // editable out of focus\n      onenter: null,            // enter key pressed\n      onkeyup: null,            // keyup\n      onkeydown: null,          // keydown\n      onImageUpload: null,      // imageUpload\n      onImageUploadError: null, // imageUploadError\n      onMediaDelete: null,      // media delete\n      onToolbarClick: null,\n      onsubmit: null,\n\n      /**\n       * manipulate link address when user create link\n       * @param {String} sLinkUrl\n       * @return {String}\n       */\n      onCreateLink: function (sLinkUrl) {\n        if (sLinkUrl.indexOf('@') !== -1 && sLinkUrl.indexOf(':') === -1) {\n          sLinkUrl =  'mailto:' + sLinkUrl;\n        }\n\n        return sLinkUrl;\n      },\n\n      keyMap: {\n        pc: {\n          'ENTER': 'insertParagraph',\n          'CTRL+Z': 'undo',\n          'CTRL+Y': 'redo',\n          'TAB': 'tab',\n          'SHIFT+TAB': 'untab',\n          'CTRL+B': 'bold',\n          'CTRL+I': 'italic',\n          'CTRL+U': 'underline',\n          'CTRL+SHIFT+S': 'strikethrough',\n          'CTRL+BACKSLASH': 'removeFormat',\n          'CTRL+SHIFT+L': 'justifyLeft',\n          'CTRL+SHIFT+E': 'justifyCenter',\n          'CTRL+SHIFT+R': 'justifyRight',\n          'CTRL+SHIFT+J': 'justifyFull',\n          'CTRL+SHIFT+NUM7': 'insertUnorderedList',\n          'CTRL+SHIFT+NUM8': 'insertOrderedList',\n          'CTRL+LEFTBRACKET': 'outdent',\n          'CTRL+RIGHTBRACKET': 'indent',\n          'CTRL+NUM0': 'formatPara',\n          'CTRL+NUM1': 'formatH1',\n          'CTRL+NUM2': 'formatH2',\n          'CTRL+NUM3': 'formatH3',\n          'CTRL+NUM4': 'formatH4',\n          'CTRL+NUM5': 'formatH5',\n          'CTRL+NUM6': 'formatH6',\n          'CTRL+ENTER': 'insertHorizontalRule',\n          'CTRL+K': 'showLinkDialog'\n        },\n\n        mac: {\n          'ENTER': 'insertParagraph',\n          'CMD+Z': 'undo',\n          'CMD+SHIFT+Z': 'redo',\n          'TAB': 'tab',\n          'SHIFT+TAB': 'untab',\n          'CMD+B': 'bold',\n          'CMD+I': 'italic',\n          'CMD+U': 'underline',\n          'CMD+SHIFT+S': 'strikethrough',\n          'CMD+BACKSLASH': 'removeFormat',\n          'CMD+SHIFT+L': 'justifyLeft',\n          'CMD+SHIFT+E': 'justifyCenter',\n          'CMD+SHIFT+R': 'justifyRight',\n          'CMD+SHIFT+J': 'justifyFull',\n          'CMD+SHIFT+NUM7': 'insertUnorderedList',\n          'CMD+SHIFT+NUM8': 'insertOrderedList',\n          'CMD+LEFTBRACKET': 'outdent',\n          'CMD+RIGHTBRACKET': 'indent',\n          'CMD+NUM0': 'formatPara',\n          'CMD+NUM1': 'formatH1',\n          'CMD+NUM2': 'formatH2',\n          'CMD+NUM3': 'formatH3',\n          'CMD+NUM4': 'formatH4',\n          'CMD+NUM5': 'formatH5',\n          'CMD+NUM6': 'formatH6',\n          'CMD+ENTER': 'insertHorizontalRule',\n          'CMD+K': 'showLinkDialog'\n        }\n      }\n    },\n\n    // default language: en-US\n    lang: {\n      'en-US': {\n        font: {\n          bold: 'Bold',\n          italic: 'Italic',\n          underline: 'Underline',\n          clear: 'Remove Font Style',\n          height: 'Line Height',\n          name: 'Font Family',\n          strikethrough: 'Strikethrough',\n          subscript: 'Subscript',\n          superscript: 'Superscript',\n          size: 'Font Size'\n        },\n        image: {\n          image: 'Picture',\n          insert: 'Insert Image',\n          resizeFull: 'Resize Full',\n          resizeHalf: 'Resize Half',\n          resizeQuarter: 'Resize Quarter',\n          floatLeft: 'Float Left',\n          floatRight: 'Float Right',\n          floatNone: 'Float None',\n          shapeRounded: 'Shape: Rounded',\n          shapeCircle: 'Shape: Circle',\n          shapeThumbnail: 'Shape: Thumbnail',\n          shapeNone: 'Shape: None',\n          dragImageHere: 'Drag image or text here',\n          dropImage: 'Drop image or Text',\n          selectFromFiles: 'Select from files',\n          maximumFileSize: 'Maximum file size',\n          maximumFileSizeError: 'Maximum file size exceeded.',\n          url: 'Image URL',\n          remove: 'Remove Image'\n        },\n        link: {\n          link: 'Link',\n          insert: 'Insert Link',\n          unlink: 'Unlink',\n          edit: 'Edit',\n          textToDisplay: 'Text to display',\n          url: 'To what URL should this link go?',\n          openInNewWindow: 'Open in new window'\n        },\n        table: {\n          table: 'Table'\n        },\n        hr: {\n          insert: 'Insert Horizontal Rule'\n        },\n        style: {\n          style: 'Style',\n          normal: 'Normal',\n          blockquote: 'Quote',\n          pre: 'Code',\n          h1: 'Header 1',\n          h2: 'Header 2',\n          h3: 'Header 3',\n          h4: 'Header 4',\n          h5: 'Header 5',\n          h6: 'Header 6'\n        },\n        lists: {\n          unordered: 'Unordered list',\n          ordered: 'Ordered list'\n        },\n        options: {\n          help: 'Help',\n          fullscreen: 'Full Screen',\n          codeview: 'Code View'\n        },\n        paragraph: {\n          paragraph: 'Paragraph',\n          outdent: 'Outdent',\n          indent: 'Indent',\n          left: 'Align left',\n          center: 'Align center',\n          right: 'Align right',\n          justify: 'Justify full'\n        },\n        color: {\n          recent: 'Recent Color',\n          more: 'More Color',\n          background: 'Background Color',\n          foreground: 'Foreground Color',\n          transparent: 'Transparent',\n          setTransparent: 'Set transparent',\n          reset: 'Reset',\n          resetToDefault: 'Reset to default'\n        },\n        shortcut: {\n          shortcuts: 'Keyboard shortcuts',\n          close: 'Close',\n          textFormatting: 'Text formatting',\n          action: 'Action',\n          paragraphFormatting: 'Paragraph formatting',\n          documentStyle: 'Document Style',\n          extraKeys: 'Extra keys'\n        },\n        history: {\n          undo: 'Undo',\n          redo: 'Redo'\n        }\n      }\n    }\n  };\n\n  /**\n   * @class core.async\n   *\n   * Async functions which returns `Promise`\n   *\n   * @singleton\n   * @alternateClassName async\n   */\n  var async = (function () {\n    /**\n     * @method readFileAsDataURL\n     *\n     * read contents of file as representing URL\n     *\n     * @param {File} file\n     * @return {Promise} - then: sDataUrl\n     */\n    var readFileAsDataURL = function (file) {\n      return $.Deferred(function (deferred) {\n        $.extend(new FileReader(), {\n          onload: function (e) {\n            var sDataURL = e.target.result;\n            deferred.resolve(sDataURL);\n          },\n          onerror: function () {\n            deferred.reject(this);\n          }\n        }).readAsDataURL(file);\n      }).promise();\n    };\n  \n    /**\n     * @method createImage\n     *\n     * create `<image>` from url string\n     *\n     * @param {String} sUrl\n     * @param {String} filename\n     * @return {Promise} - then: $image\n     */\n    var createImage = function (sUrl, filename) {\n      return $.Deferred(function (deferred) {\n        var $img = $('<img>');\n\n        $img.one('load', function () {\n          $img.off('error abort');\n          deferred.resolve($img);\n        }).one('error abort', function () {\n          $img.off('load').detach();\n          deferred.reject($img);\n        }).css({\n          display: 'none'\n        }).appendTo(document.body).attr({\n          'src': sUrl,\n          'data-filename': filename\n        });\n      }).promise();\n    };\n\n    return {\n      readFileAsDataURL: readFileAsDataURL,\n      createImage: createImage\n    };\n  })();\n\n  /**\n   * @class core.key\n   *\n   * Object for keycodes.\n   *\n   * @singleton\n   * @alternateClassName key\n   */\n  var key = (function () {\n    var keyMap = {\n      'BACKSPACE': 8,\n      'TAB': 9,\n      'ENTER': 13,\n      'SPACE': 32,\n\n      // Number: 0-9\n      'NUM0': 48,\n      'NUM1': 49,\n      'NUM2': 50,\n      'NUM3': 51,\n      'NUM4': 52,\n      'NUM5': 53,\n      'NUM6': 54,\n      'NUM7': 55,\n      'NUM8': 56,\n\n      // Alphabet: a-z\n      'B': 66,\n      'E': 69,\n      'I': 73,\n      'J': 74,\n      'K': 75,\n      'L': 76,\n      'R': 82,\n      'S': 83,\n      'U': 85,\n      'V': 86,\n      'Y': 89,\n      'Z': 90,\n\n      'SLASH': 191,\n      'LEFTBRACKET': 219,\n      'BACKSLASH': 220,\n      'RIGHTBRACKET': 221\n    };\n\n    return {\n      /**\n       * @method isEdit\n       *\n       * @param {Number} keyCode\n       * @return {Boolean}\n       */\n      isEdit: function (keyCode) {\n        return list.contains([8, 9, 13, 32], keyCode);\n      },\n      /**\n       * @method isMove\n       *\n       * @param {Number} keyCode\n       * @return {Boolean}\n       */\n      isMove: function (keyCode) {\n        return list.contains([37, 38, 39, 40], keyCode);\n      },\n      /**\n       * @property {Object} nameFromCode\n       * @property {String} nameFromCode.8 \"BACKSPACE\"\n       */\n      nameFromCode: func.invertObject(keyMap),\n      code: keyMap\n    };\n  })();\n\n  /**\n   * @class editing.History\n   *\n   * Editor History\n   *\n   */\n  var History = function ($editable) {\n    var stack = [], stackOffset = -1;\n    var editable = $editable[0];\n\n    var makeSnapshot = function () {\n      var rng = range.create();\n      var emptyBookmark = {s: {path: [], offset: 0}, e: {path: [], offset: 0}};\n\n      return {\n        contents: $editable.html(),\n        bookmark: (rng ? rng.bookmark(editable) : emptyBookmark)\n      };\n    };\n\n    var applySnapshot = function (snapshot) {\n      if (snapshot.contents !== null) {\n        $editable.html(snapshot.contents);\n      }\n      if (snapshot.bookmark !== null) {\n        range.createFromBookmark(editable, snapshot.bookmark).select();\n      }\n    };\n\n    /**\n     * undo\n     */\n    this.undo = function () {\n      // Create snap shot if not yet recorded\n      if ($editable.html() !== stack[stackOffset].contents) {\n        this.recordUndo();\n      }\n\n      if (0 < stackOffset) {\n        stackOffset--;\n        applySnapshot(stack[stackOffset]);\n      }\n    };\n\n    /**\n     * redo\n     */\n    this.redo = function () {\n      if (stack.length - 1 > stackOffset) {\n        stackOffset++;\n        applySnapshot(stack[stackOffset]);\n      }\n    };\n\n    /**\n     * recorded undo\n     */\n    this.recordUndo = function () {\n      stackOffset++;\n\n      // Wash out stack after stackOffset\n      if (stack.length > stackOffset) {\n        stack = stack.slice(0, stackOffset);\n      }\n\n      // Create new snapshot and push it to the end\n      stack.push(makeSnapshot());\n    };\n\n    // Create first undo stack\n    this.recordUndo();\n  };\n\n  /**\n   * @class editing.Style\n   *\n   * Style\n   *\n   */\n  var Style = function () {\n    /**\n     * @method jQueryCSS\n     *\n     * [workaround] for old jQuery\n     * passing an array of style properties to .css()\n     * will result in an object of property-value pairs.\n     * (compability with version < 1.9)\n     *\n     * @private\n     * @param  {jQuery} $obj\n     * @param  {Array} propertyNames - An array of one or more CSS properties.\n     * @return {Object}\n     */\n    var jQueryCSS = function ($obj, propertyNames) {\n      if (agent.jqueryVersion < 1.9) {\n        var result = {};\n        $.each(propertyNames, function (idx, propertyName) {\n          result[propertyName] = $obj.css(propertyName);\n        });\n        return result;\n      }\n      return $obj.css.call($obj, propertyNames);\n    };\n\n    /**\n     * returns style object from node\n     *\n     * @param {jQuery} $node\n     * @return {Object}\n     */\n    this.fromNode = function ($node) {\n      var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];\n      var styleInfo = jQueryCSS($node, properties) || {};\n      styleInfo['font-size'] = parseInt(styleInfo['font-size'], 10);\n      return styleInfo;\n    };\n\n    /**\n     * paragraph level style\n     *\n     * @param {WrappedRange} rng\n     * @param {Object} styleInfo\n     */\n    this.stylePara = function (rng, styleInfo) {\n      $.each(rng.nodes(dom.isPara, {\n        includeAncestor: true\n      }), function (idx, para) {\n        $(para).css(styleInfo);\n      });\n    };\n\n    /**\n     * insert and returns styleNodes on range.\n     *\n     * @param {WrappedRange} rng\n     * @param {Object} [options] - options for styleNodes\n     * @param {String} [options.nodeName] - default: `SPAN`\n     * @param {Boolean} [options.expandClosestSibling] - default: `false`\n     * @param {Boolean} [options.onlyPartialContains] - default: `false`\n     * @return {Node[]}\n     */\n    this.styleNodes = function (rng, options) {\n      rng = rng.splitText();\n\n      var nodeName = options && options.nodeName || 'SPAN';\n      var expandClosestSibling = !!(options && options.expandClosestSibling);\n      var onlyPartialContains = !!(options && options.onlyPartialContains);\n\n      if (rng.isCollapsed()) {\n        return [rng.insertNode(dom.create(nodeName))];\n      }\n\n      var pred = dom.makePredByNodeName(nodeName);\n      var nodes = rng.nodes(dom.isText, {\n        fullyContains: true\n      }).map(function (text) {\n        return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);\n      });\n\n      if (expandClosestSibling) {\n        if (onlyPartialContains) {\n          var nodesInRange = rng.nodes();\n          // compose with partial contains predication\n          pred = func.and(pred, function (node) {\n            return list.contains(nodesInRange, node);\n          });\n        }\n\n        return nodes.map(function (node) {\n          var siblings = dom.withClosestSiblings(node, pred);\n          var head = list.head(siblings);\n          var tails = list.tail(siblings);\n          $.each(tails, function (idx, elem) {\n            dom.appendChildNodes(head, elem.childNodes);\n            dom.remove(elem);\n          });\n          return list.head(siblings);\n        });\n      } else {\n        return nodes;\n      }\n    };\n\n    /**\n     * get current style on cursor\n     *\n     * @param {WrappedRange} rng\n     * @return {Object} - object contains style properties.\n     */\n    this.current = function (rng) {\n      var $cont = $(dom.isText(rng.sc) ? rng.sc.parentNode : rng.sc);\n      var styleInfo = this.fromNode($cont);\n\n      // document.queryCommandState for toggle state\n      styleInfo['font-bold'] = document.queryCommandState('bold') ? 'bold' : 'normal';\n      styleInfo['font-italic'] = document.queryCommandState('italic') ? 'italic' : 'normal';\n      styleInfo['font-underline'] = document.queryCommandState('underline') ? 'underline' : 'normal';\n      styleInfo['font-strikethrough'] = document.queryCommandState('strikeThrough') ? 'strikethrough' : 'normal';\n      styleInfo['font-superscript'] = document.queryCommandState('superscript') ? 'superscript' : 'normal';\n      styleInfo['font-subscript'] = document.queryCommandState('subscript') ? 'subscript' : 'normal';\n\n      // list-style-type to list-style(unordered, ordered)\n      if (!rng.isOnList()) {\n        styleInfo['list-style'] = 'none';\n      } else {\n        var aOrderedType = ['circle', 'disc', 'disc-leading-zero', 'square'];\n        var isUnordered = $.inArray(styleInfo['list-style-type'], aOrderedType) > -1;\n        styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';\n      }\n\n      var para = dom.ancestor(rng.sc, dom.isPara);\n      if (para && para.style['line-height']) {\n        styleInfo['line-height'] = para.style.lineHeight;\n      } else {\n        var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);\n        styleInfo['line-height'] = lineHeight.toFixed(1);\n      }\n\n      styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);\n      styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);\n      styleInfo.range = rng;\n\n      return styleInfo;\n    };\n  };\n\n\n  /**\n   * @class editing.Bullet\n   *\n   * @alternateClassName Bullet\n   */\n  var Bullet = function () {\n    /**\n     * @method insertOrderedList\n     *\n     * toggle ordered list\n     *\n     * @type command\n     */\n    this.insertOrderedList = function () {\n      this.toggleList('OL');\n    };\n\n    /**\n     * @method insertUnorderedList\n     *\n     * toggle unordered list\n     *\n     * @type command\n     */\n    this.insertUnorderedList = function () {\n      this.toggleList('UL');\n    };\n\n    /**\n     * @method indent\n     *\n     * indent\n     *\n     * @type command\n     */\n    this.indent = function () {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        if (dom.isLi(head)) {\n          self.wrapList(paras, head.parentNode.nodeName);\n        } else {\n          $.each(paras, function (idx, para) {\n            $(para).css('marginLeft', function (idx, val) {\n              return (parseInt(val, 10) || 0) + 25;\n            });\n          });\n        }\n      });\n\n      rng.select();\n    };\n\n    /**\n     * @method outdent\n     *\n     * outdent\n     *\n     * @type command\n     */\n    this.outdent = function () {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        if (dom.isLi(head)) {\n          self.releaseList([paras]);\n        } else {\n          $.each(paras, function (idx, para) {\n            $(para).css('marginLeft', function (idx, val) {\n              val = (parseInt(val, 10) || 0);\n              return val > 25 ? val - 25 : '';\n            });\n          });\n        }\n      });\n\n      rng.select();\n    };\n\n    /**\n     * @method toggleList\n     *\n     * toggle list\n     *\n     * @param {String} listName - OL or UL\n     */\n    this.toggleList = function (listName) {\n      var self = this;\n      var rng = range.create().wrapBodyInlineWithPara();\n\n      var paras = rng.nodes(dom.isPara, { includeAncestor: true });\n      var bookmark = rng.paraBookmark(paras);\n      var clustereds = list.clusterBy(paras, func.peq2('parentNode'));\n\n      // paragraph to list\n      if (list.find(paras, dom.isPurePara)) {\n        var wrappedParas = [];\n        $.each(clustereds, function (idx, paras) {\n          wrappedParas = wrappedParas.concat(self.wrapList(paras, listName));\n        });\n        paras = wrappedParas;\n      // list to paragraph or change list style\n      } else {\n        var diffLists = rng.nodes(dom.isList, {\n          includeAncestor: true\n        }).filter(function (listNode) {\n          return !$.nodeName(listNode, listName);\n        });\n\n        if (diffLists.length) {\n          $.each(diffLists, function (idx, listNode) {\n            dom.replace(listNode, listName);\n          });\n        } else {\n          paras = this.releaseList(clustereds, true);\n        }\n      }\n\n      range.createFromParaBookmark(bookmark, paras).select();\n    };\n\n    /**\n     * @method wrapList\n     *\n     * @param {Node[]} paras\n     * @param {String} listName\n     * @return {Node[]}\n     */\n    this.wrapList = function (paras, listName) {\n      var head = list.head(paras);\n      var last = list.last(paras);\n\n      var prevList = dom.isList(head.previousSibling) && head.previousSibling;\n      var nextList = dom.isList(last.nextSibling) && last.nextSibling;\n\n      var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last);\n\n      // P to LI\n      paras = paras.map(function (para) {\n        return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;\n      });\n\n      // append to list(<ul>, <ol>)\n      dom.appendChildNodes(listNode, paras);\n\n      if (nextList) {\n        dom.appendChildNodes(listNode, list.from(nextList.childNodes));\n        dom.remove(nextList);\n      }\n\n      return paras;\n    };\n\n    /**\n     * @method releaseList\n     *\n     * @param {Array[]} clustereds\n     * @param {Boolean} isEscapseToBody\n     * @return {Node[]}\n     */\n    this.releaseList = function (clustereds, isEscapseToBody) {\n      var releasedParas = [];\n\n      $.each(clustereds, function (idx, paras) {\n        var head = list.head(paras);\n        var last = list.last(paras);\n\n        var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) :\n                                         head.parentNode;\n        var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {\n          node: last.parentNode,\n          offset: dom.position(last) + 1\n        }, {\n          isSkipPaddingBlankHTML: true\n        }) : null;\n\n        var middleList = dom.splitTree(headList, {\n          node: head.parentNode,\n          offset: dom.position(head)\n        }, {\n          isSkipPaddingBlankHTML: true\n        });\n\n        paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) :\n                                  list.from(middleList.childNodes).filter(dom.isLi);\n\n        // LI to P\n        if (isEscapseToBody || !dom.isList(headList.parentNode)) {\n          paras = paras.map(function (para) {\n            return dom.replace(para, 'P');\n          });\n        }\n\n        $.each(list.from(paras).reverse(), function (idx, para) {\n          dom.insertAfter(para, headList);\n        });\n\n        // remove empty lists\n        var rootLists = list.compact([headList, middleList, lastList]);\n        $.each(rootLists, function (idx, rootList) {\n          var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));\n          $.each(listNodes.reverse(), function (idx, listNode) {\n            if (!dom.nodeLength(listNode)) {\n              dom.remove(listNode, true);\n            }\n          });\n        });\n\n        releasedParas = releasedParas.concat(paras);\n      });\n\n      return releasedParas;\n    };\n  };\n\n\n  /**\n   * @class editing.Typing\n   *\n   * Typing\n   *\n   */\n  var Typing = function () {\n\n    // a Bullet instance to toggle lists off\n    var bullet = new Bullet();\n\n    /**\n     * insert tab\n     *\n     * @param {jQuery} $editable\n     * @param {WrappedRange} rng\n     * @param {Number} tabsize\n     */\n    this.insertTab = function ($editable, rng, tabsize) {\n      var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));\n      rng = rng.deleteContents();\n      rng.insertNode(tab, true);\n\n      rng = range.create(tab, tabsize);\n      rng.select();\n    };\n\n    /**\n     * insert paragraph\n     */\n    this.insertParagraph = function () {\n      var rng = range.create();\n\n      // deleteContents on range.\n      rng = rng.deleteContents();\n\n      // Wrap range if it needs to be wrapped by paragraph\n      rng = rng.wrapBodyInlineWithPara();\n\n      // finding paragraph\n      var splitRoot = dom.ancestor(rng.sc, dom.isPara);\n\n      var nextPara;\n      // on paragraph: split paragraph\n      if (splitRoot) {\n        // if it is an empty line with li\n        if (dom.isEmpty(splitRoot) && dom.isLi(splitRoot)) {\n          // disable UL/OL and escape!\n          bullet.toggleList(splitRoot.parentNode.nodeName);\n          return;\n        // if new line has content (not a line break)\n        } else {\n          nextPara = dom.splitTree(splitRoot, rng.getStartPoint());\n\n          var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);\n          emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));\n\n          $.each(emptyAnchors, function (idx, anchor) {\n            dom.remove(anchor);\n          });\n        }\n      // no paragraph: insert empty paragraph\n      } else {\n        var next = rng.sc.childNodes[rng.so];\n        nextPara = $(dom.emptyPara)[0];\n        if (next) {\n          rng.sc.insertBefore(nextPara, next);\n        } else {\n          rng.sc.appendChild(nextPara);\n        }\n      }\n\n      range.create(nextPara, 0).normalize().select();\n\n    };\n\n  };\n\n  /**\n   * @class editing.Table\n   *\n   * Table\n   *\n   */\n  var Table = function () {\n    /**\n     * handle tab key\n     *\n     * @param {WrappedRange} rng\n     * @param {Boolean} isShift\n     */\n    this.tab = function (rng, isShift) {\n      var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);\n      var table = dom.ancestor(cell, dom.isTable);\n      var cells = dom.listDescendant(table, dom.isCell);\n\n      var nextCell = list[isShift ? 'prev' : 'next'](cells, cell);\n      if (nextCell) {\n        range.create(nextCell, 0).select();\n      }\n    };\n\n    /**\n     * create empty table element\n     *\n     * @param {Number} rowCount\n     * @param {Number} colCount\n     * @return {Node}\n     */\n    this.createTable = function (colCount, rowCount) {\n      var tds = [], tdHTML;\n      for (var idxCol = 0; idxCol < colCount; idxCol++) {\n        tds.push('<td>' + dom.blank + '</td>');\n      }\n      tdHTML = tds.join('');\n\n      var trs = [], trHTML;\n      for (var idxRow = 0; idxRow < rowCount; idxRow++) {\n        trs.push('<tr>' + tdHTML + '</tr>');\n      }\n      trHTML = trs.join('');\n      return $('<table class=\"table table-bordered\">' + trHTML + '</table>')[0];\n    };\n  };\n\n\n  var KEY_BOGUS = 'bogus';\n\n  /**\n   * @class editing.Editor\n   *\n   * Editor\n   *\n   */\n  var Editor = function (handler) {\n\n    var self = this;\n    var style = new Style();\n    var table = new Table();\n    var typing = new Typing();\n    var bullet = new Bullet();\n\n    /**\n     * @method createRange\n     *\n     * create range\n     *\n     * @param {jQuery} $editable\n     * @return {WrappedRange}\n     */\n    this.createRange = function ($editable) {\n      this.focus($editable);\n      return range.create();\n    };\n\n    /**\n     * @method saveRange\n     *\n     * save current range\n     *\n     * @param {jQuery} $editable\n     * @param {Boolean} [thenCollapse=false]\n     */\n    this.saveRange = function ($editable, thenCollapse) {\n      this.focus($editable);\n      $editable.data('range', range.create());\n      if (thenCollapse) {\n        range.create().collapse().select();\n      }\n    };\n\n    /**\n     * @method saveRange\n     *\n     * save current node list to $editable.data('childNodes')\n     *\n     * @param {jQuery} $editable\n     */\n    this.saveNode = function ($editable) {\n      // copy child node reference\n      var copy = [];\n      for (var key  = 0, len = $editable[0].childNodes.length; key < len; key++) {\n        copy.push($editable[0].childNodes[key]);\n      }\n      $editable.data('childNodes', copy);\n    };\n\n    /**\n     * @method restoreRange\n     *\n     * restore lately range\n     *\n     * @param {jQuery} $editable\n     */\n    this.restoreRange = function ($editable) {\n      var rng = $editable.data('range');\n      if (rng) {\n        rng.select();\n        this.focus($editable);\n      }\n    };\n\n    /**\n     * @method restoreNode\n     *\n     * restore lately node list\n     *\n     * @param {jQuery} $editable\n     */\n    this.restoreNode = function ($editable) {\n      $editable.html('');\n      var child = $editable.data('childNodes');\n      for (var index = 0, len = child.length; index < len; index++) {\n        $editable[0].appendChild(child[index]);\n      }\n    };\n\n    /**\n     * @method currentStyle\n     *\n     * current style\n     *\n     * @param {Node} target\n     * @return {Object|Boolean} unfocus\n     */\n    this.currentStyle = function (target) {\n      var rng = range.create();\n      var styleInfo =  rng && rng.isOnEditable() ? style.current(rng.normalize()) : {};\n      if (dom.isImg(target)) {\n        styleInfo.image = target;\n      }\n      return styleInfo;\n    };\n\n    /**\n     * style from node\n     *\n     * @param {jQuery} $node\n     * @return {Object}\n     */\n    this.styleFromNode = function ($node) {\n      return style.fromNode($node);\n    };\n\n    var triggerOnBeforeChange = function ($editable) {\n      var $holder = dom.makeLayoutInfo($editable).holder();\n      handler.bindCustomEvent(\n        $holder, $editable.data('callbacks'), 'before.command'\n      )($editable.html(), $editable);\n    };\n\n    var triggerOnChange = function ($editable) {\n      var $holder = dom.makeLayoutInfo($editable).holder();\n      handler.bindCustomEvent(\n        $holder, $editable.data('callbacks'), 'change'\n      )($editable.html(), $editable);\n    };\n\n    /**\n     * @method undo\n     * undo\n     * @param {jQuery} $editable\n     */\n    this.undo = function ($editable) {\n      triggerOnBeforeChange($editable);\n      $editable.data('NoteHistory').undo();\n      triggerOnChange($editable);\n    };\n\n    /**\n     * @method redo\n     * redo\n     * @param {jQuery} $editable\n     */\n    this.redo = function ($editable) {\n      triggerOnBeforeChange($editable);\n      $editable.data('NoteHistory').redo();\n      triggerOnChange($editable);\n    };\n\n    /**\n     * @method beforeCommand\n     * before command\n     * @param {jQuery} $editable\n     */\n    var beforeCommand = this.beforeCommand = function ($editable) {\n      triggerOnBeforeChange($editable);\n      // keep focus on editable before command execution\n      self.focus($editable);\n    };\n\n    /**\n     * @method afterCommand\n     * after command\n     * @param {jQuery} $editable\n     * @param {Boolean} isPreventTrigger\n     */\n    var afterCommand = this.afterCommand = function ($editable, isPreventTrigger) {\n      $editable.data('NoteHistory').recordUndo();\n      if (!isPreventTrigger) {\n        triggerOnChange($editable);\n      }\n    };\n\n    /**\n     * @method bold\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method italic\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method underline\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method strikethrough\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method formatBlock\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method superscript\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method subscript\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyLeft\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyCenter\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyRight\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method justifyFull\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method formatBlock\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method removeFormat\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method backColor\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method foreColor\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method insertHorizontalRule\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /**\n     * @method fontName\n     *\n     * change font name\n     *\n     * @param {jQuery} $editable\n     * @param {Mixed} value\n     */\n\n    /* jshint ignore:start */\n    // native commands(with execCommand), generate function for execCommand\n    var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript',\n                    'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull',\n                    'formatBlock', 'removeFormat',\n                    'backColor', 'foreColor', 'fontName'];\n\n    for (var idx = 0, len = commands.length; idx < len; idx ++) {\n      this[commands[idx]] = (function (sCmd) {\n        return function ($editable, value) {\n          beforeCommand($editable);\n\n          document.execCommand(sCmd, false, value);\n\n          afterCommand($editable, true);\n        };\n      })(commands[idx]);\n    }\n    /* jshint ignore:end */\n\n    /**\n     * @method tab\n     *\n     * handle tab key\n     *\n     * @param {jQuery} $editable\n     * @param {Object} options\n     */\n    this.tab = function ($editable, options) {\n      var rng = this.createRange($editable);\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        table.tab(rng);\n      } else {\n        beforeCommand($editable);\n        typing.insertTab($editable, rng, options.tabsize);\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * @method untab\n     *\n     * handle shift+tab key\n     *\n     */\n    this.untab = function ($editable) {\n      var rng = this.createRange($editable);\n      if (rng.isCollapsed() && rng.isOnCell()) {\n        table.tab(rng, true);\n      }\n    };\n\n    /**\n     * @method insertParagraph\n     *\n     * insert paragraph\n     *\n     * @param {Node} $editable\n     */\n    this.insertParagraph = function ($editable) {\n      beforeCommand($editable);\n      typing.insertParagraph($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @method insertOrderedList\n     *\n     * @param {jQuery} $editable\n     */\n    this.insertOrderedList = function ($editable) {\n      beforeCommand($editable);\n      bullet.insertOrderedList($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.insertUnorderedList = function ($editable) {\n      beforeCommand($editable);\n      bullet.insertUnorderedList($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.indent = function ($editable) {\n      beforeCommand($editable);\n      bullet.indent($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {jQuery} $editable\n     */\n    this.outdent = function ($editable) {\n      beforeCommand($editable);\n      bullet.outdent($editable);\n      afterCommand($editable);\n    };\n\n    /**\n     * insert image\n     *\n     * @param {jQuery} $editable\n     * @param {String} sUrl\n     */\n    this.insertImage = function ($editable, sUrl, filename) {\n      async.createImage(sUrl, filename).then(function ($image) {\n        beforeCommand($editable);\n        $image.css({\n          display: '',\n          width: Math.min($editable.width(), $image.width())\n        });\n        range.create().insertNode($image[0]);\n        range.createFromNodeAfter($image[0]).select();\n        afterCommand($editable);\n      }).fail(function () {\n        var $holder = dom.makeLayoutInfo($editable).holder();\n        handler.bindCustomEvent(\n          $holder, $editable.data('callbacks'), 'image.upload.error'\n        )();\n      });\n    };\n\n    /**\n     * @method insertNode\n     * insert node\n     * @param {Node} $editable\n     * @param {Node} node\n     */\n    this.insertNode = function ($editable, node) {\n      beforeCommand($editable);\n      range.create().insertNode(node);\n      range.createFromNodeAfter(node).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * insert text\n     * @param {Node} $editable\n     * @param {String} text\n     */\n    this.insertText = function ($editable, text) {\n      beforeCommand($editable);\n      var textNode = range.create().insertNode(dom.createText(text));\n      range.create(textNode, dom.nodeLength(textNode)).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * paste HTML\n     * @param {Node} $editable\n     * @param {String} markup\n     */\n    this.pasteHTML = function ($editable, markup) {\n      beforeCommand($editable);\n      var contents = range.create().pasteHTML(markup);\n      range.createFromNodeAfter(list.last(contents)).select();\n      afterCommand($editable);\n    };\n\n    /**\n     * formatBlock\n     *\n     * @param {jQuery} $editable\n     * @param {String} tagName\n     */\n    this.formatBlock = function ($editable, tagName) {\n      beforeCommand($editable);\n      // [workaround] for MSIE, IE need `<`\n      tagName = agent.isMSIE ? '<' + tagName + '>' : tagName;\n      document.execCommand('FormatBlock', false, tagName);\n      afterCommand($editable);\n    };\n\n    this.formatPara = function ($editable) {\n      beforeCommand($editable);\n      this.formatBlock($editable, 'P');\n      afterCommand($editable);\n    };\n\n    /* jshint ignore:start */\n    for (var idx = 1; idx <= 6; idx ++) {\n      this['formatH' + idx] = function (idx) {\n        return function ($editable) {\n          this.formatBlock($editable, 'H' + idx);\n        };\n      }(idx);\n    };\n    /* jshint ignore:end */\n\n    /**\n     * fontSize\n     *\n     * @param {jQuery} $editable\n     * @param {String} value - px\n     */\n    this.fontSize = function ($editable, value) {\n      var rng = range.create();\n\n      if (rng.isCollapsed()) {\n        var spans = style.styleNodes(rng);\n        var firstSpan = list.head(spans);\n\n        $(spans).css({\n          'font-size': value + 'px'\n        });\n\n        // [workaround] added styled bogus span for style\n        //  - also bogus character needed for cursor position\n        if (firstSpan && !dom.nodeLength(firstSpan)) {\n          firstSpan.innerHTML = dom.ZERO_WIDTH_NBSP_CHAR;\n          range.createFromNodeAfter(firstSpan.firstChild).select();\n          $editable.data(KEY_BOGUS, firstSpan);\n        }\n      } else {\n        beforeCommand($editable);\n        $(style.styleNodes(rng)).css({\n          'font-size': value + 'px'\n        });\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * insert horizontal rule\n     * @param {jQuery} $editable\n     */\n    this.insertHorizontalRule = function ($editable) {\n      beforeCommand($editable);\n\n      var rng = range.create();\n      var hrNode = rng.insertNode($('<HR/>')[0]);\n      if (hrNode.nextSibling) {\n        range.create(hrNode.nextSibling, 0).normalize().select();\n      }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * remove bogus node and character\n     */\n    this.removeBogus = function ($editable) {\n      var bogusNode = $editable.data(KEY_BOGUS);\n      if (!bogusNode) {\n        return;\n      }\n\n      var textNode = list.find(list.from(bogusNode.childNodes), dom.isText);\n\n      var bogusCharIdx = textNode.nodeValue.indexOf(dom.ZERO_WIDTH_NBSP_CHAR);\n      if (bogusCharIdx !== -1) {\n        textNode.deleteData(bogusCharIdx, 1);\n      }\n\n      if (dom.isEmpty(bogusNode)) {\n        dom.remove(bogusNode);\n      }\n\n      $editable.removeData(KEY_BOGUS);\n    };\n\n    /**\n     * lineHeight\n     * @param {jQuery} $editable\n     * @param {String} value\n     */\n    this.lineHeight = function ($editable, value) {\n      beforeCommand($editable);\n      style.stylePara(range.create(), {\n        lineHeight: value\n      });\n      afterCommand($editable);\n    };\n\n    /**\n     * unlink\n     *\n     * @type command\n     *\n     * @param {jQuery} $editable\n     */\n    this.unlink = function ($editable) {\n      var rng = this.createRange($editable);\n      if (rng.isOnAnchor()) {\n        var anchor = dom.ancestor(rng.sc, dom.isAnchor);\n        rng = range.createFromNode(anchor);\n        rng.select();\n\n        beforeCommand($editable);\n        document.execCommand('unlink');\n        afterCommand($editable);\n      }\n    };\n\n    /**\n     * create link (command)\n     *\n     * @param {jQuery} $editable\n     * @param {Object} linkInfo\n     * @param {Object} options\n     */\n    this.createLink = function ($editable, linkInfo, options) {\n      var linkUrl = linkInfo.url;\n      var linkText = linkInfo.text;\n      var isNewWindow = linkInfo.isNewWindow;\n      var rng = linkInfo.range || this.createRange($editable);\n      var isTextChanged = rng.toString() !== linkText;\n\n      options = options || dom.makeLayoutInfo($editable).editor().data('options');\n\n      beforeCommand($editable);\n\n      if (options.onCreateLink) {\n        linkUrl = options.onCreateLink(linkUrl);\n      }\n\n      var anchors = [];\n      if (isTextChanged) {\n        // Create a new link when text changed.\n        var anchor = rng.insertNode($('<A>' + linkText + '</A>')[0]);\n        anchors.push(anchor);\n      } else {\n        anchors = style.styleNodes(rng, {\n          nodeName: 'A',\n          expandClosestSibling: true,\n          onlyPartialContains: true\n        });\n      }\n\n      $.each(anchors, function (idx, anchor) {\n        $(anchor).attr('href', linkUrl);\n        if (isNewWindow) {\n          $(anchor).attr('target', '_blank');\n        } else {\n          $(anchor).removeAttr('target');\n        }\n      });\n\n      var startRange = range.createFromNodeBefore(list.head(anchors));\n      var startPoint = startRange.getStartPoint();\n      var endRange = range.createFromNodeAfter(list.last(anchors));\n      var endPoint = endRange.getEndPoint();\n\n      range.create(\n        startPoint.node,\n        startPoint.offset,\n        endPoint.node,\n        endPoint.offset\n      ).select();\n\n      afterCommand($editable);\n    };\n\n    /**\n     * returns link info\n     *\n     * @return {Object}\n     * @return {WrappedRange} return.range\n     * @return {String} return.text\n     * @return {Boolean} [return.isNewWindow=true]\n     * @return {String} [return.url=\"\"]\n     */\n    this.getLinkInfo = function ($editable) {\n      this.focus($editable);\n\n      var rng = range.create().expand(dom.isAnchor);\n\n      // Get the first anchor on range(for edit).\n      var $anchor = $(list.head(rng.nodes(dom.isAnchor)));\n\n      return {\n        range: rng,\n        text: rng.toString(),\n        isNewWindow: $anchor.length ? $anchor.attr('target') === '_blank' : false,\n        url: $anchor.length ? $anchor.attr('href') : ''\n      };\n    };\n\n    /**\n     * setting color\n     *\n     * @param {Node} $editable\n     * @param {Object} sObjColor  color code\n     * @param {String} sObjColor.foreColor foreground color\n     * @param {String} sObjColor.backColor background color\n     */\n    this.color = function ($editable, sObjColor) {\n      var oColor = JSON.parse(sObjColor);\n      var foreColor = oColor.foreColor, backColor = oColor.backColor;\n\n      beforeCommand($editable);\n\n      if (foreColor) { document.execCommand('foreColor', false, foreColor); }\n      if (backColor) { document.execCommand('backColor', false, backColor); }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * insert Table\n     *\n     * @param {Node} $editable\n     * @param {String} sDim dimension of table (ex : \"5x5\")\n     */\n    this.insertTable = function ($editable, sDim) {\n      var dimension = sDim.split('x');\n      beforeCommand($editable);\n\n      var rng = range.create().deleteContents();\n      rng.insertNode(table.createTable(dimension[0], dimension[1]));\n      afterCommand($editable);\n    };\n\n    /**\n     * float me\n     *\n     * @param {jQuery} $editable\n     * @param {String} value\n     * @param {jQuery} $target\n     */\n    this.floatMe = function ($editable, value, $target) {\n      beforeCommand($editable);\n      // bootstrap\n      $target.removeClass('pull-left pull-right');\n      if (value && value !== 'none') {\n        $target.addClass('pull-' + value);\n      }\n\n      // fallback for non-bootstrap\n      $target.css('float', value);\n      afterCommand($editable);\n    };\n\n    /**\n     * change image shape\n     *\n     * @param {jQuery} $editable\n     * @param {String} value css class\n     * @param {Node} $target\n     */\n    this.imageShape = function ($editable, value, $target) {\n      beforeCommand($editable);\n\n      $target.removeClass('img-rounded img-circle img-thumbnail');\n\n      if (value) {\n        $target.addClass(value);\n      }\n\n      afterCommand($editable);\n    };\n\n    /**\n     * resize overlay element\n     * @param {jQuery} $editable\n     * @param {String} value\n     * @param {jQuery} $target - target element\n     */\n    this.resize = function ($editable, value, $target) {\n      beforeCommand($editable);\n\n      $target.css({\n        width: value * 100 + '%',\n        height: ''\n      });\n\n      afterCommand($editable);\n    };\n\n    /**\n     * @param {Position} pos\n     * @param {jQuery} $target - target element\n     * @param {Boolean} [bKeepRatio] - keep ratio\n     */\n    this.resizeTo = function (pos, $target, bKeepRatio) {\n      var imageSize;\n      if (bKeepRatio) {\n        var newRatio = pos.y / pos.x;\n        var ratio = $target.data('ratio');\n        imageSize = {\n          width: ratio > newRatio ? pos.x : pos.y / ratio,\n          height: ratio > newRatio ? pos.x * ratio : pos.y\n        };\n      } else {\n        imageSize = {\n          width: pos.x,\n          height: pos.y\n        };\n      }\n\n      $target.css(imageSize);\n    };\n\n    /**\n     * remove media object\n     *\n     * @param {jQuery} $editable\n     * @param {String} value - dummy argument (for keep interface)\n     * @param {jQuery} $target - target element\n     */\n    this.removeMedia = function ($editable, value, $target) {\n      beforeCommand($editable);\n      $target.detach();\n\n      handler.bindCustomEvent(\n        $(), $editable.data('callbacks'), 'media.delete'\n      )($target, $editable);\n\n      afterCommand($editable);\n    };\n\n    /**\n     * set focus\n     *\n     * @param $editable\n     */\n    this.focus = function ($editable) {\n      $editable.focus();\n\n      // [workaround] for firefox bug http://goo.gl/lVfAaI\n      if (agent.isFF && !range.create().isOnEditable()) {\n        range.createFromNode($editable[0])\n             .normalize()\n             .collapse()\n             .select();\n      }\n    };\n\n    /**\n     * returns whether contents is empty or not.\n     *\n     * @param {jQuery} $editable\n     * @return {Boolean}\n     */\n    this.isEmpty = function ($editable) {\n      return dom.isEmpty($editable[0]) || dom.emptyPara === $editable.html();\n    };\n  };\n\n  /**\n   * @class module.Button\n   *\n   * Button\n   */\n  var Button = function () {\n    /**\n     * update button status\n     *\n     * @param {jQuery} $container\n     * @param {Object} styleInfo\n     */\n    this.update = function ($container, styleInfo) {\n      /**\n       * handle dropdown's check mark (for fontname, fontsize, lineHeight).\n       * @param {jQuery} $btn\n       * @param {Number} value\n       */\n      var checkDropdownMenu = function ($btn, value) {\n        $btn.find('.dropdown-menu li a').each(function () {\n          // always compare string to avoid creating another func.\n          var isChecked = ($(this).data('value') + '') === (value + '');\n          this.className = isChecked ? 'checked' : '';\n        });\n      };\n\n      /**\n       * update button state(active or not).\n       *\n       * @private\n       * @param {String} selector\n       * @param {Function} pred\n       */\n      var btnState = function (selector, pred) {\n        var $btn = $container.find(selector);\n        $btn.toggleClass('active', pred());\n      };\n\n      if (styleInfo.image) {\n        var $img = $(styleInfo.image);\n\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-rounded\"]', function () {\n          return $img.hasClass('img-rounded');\n        });\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-circle\"]', function () {\n          return $img.hasClass('img-circle');\n        });\n        btnState('button[data-event=\"imageShape\"][data-value=\"img-thumbnail\"]', function () {\n          return $img.hasClass('img-thumbnail');\n        });\n        btnState('button[data-event=\"imageShape\"]:not([data-value])', function () {\n          return !$img.is('.img-rounded, .img-circle, .img-thumbnail');\n        });\n\n        var imgFloat = $img.css('float');\n        btnState('button[data-event=\"floatMe\"][data-value=\"left\"]', function () {\n          return imgFloat === 'left';\n        });\n        btnState('button[data-event=\"floatMe\"][data-value=\"right\"]', function () {\n          return imgFloat === 'right';\n        });\n        btnState('button[data-event=\"floatMe\"][data-value=\"none\"]', function () {\n          return imgFloat !== 'left' && imgFloat !== 'right';\n        });\n\n        var style = $img.attr('style');\n        btnState('button[data-event=\"resize\"][data-value=\"1\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*100%/.test(style);\n        });\n        btnState('button[data-event=\"resize\"][data-value=\"0.5\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*50%/.test(style);\n        });\n        btnState('button[data-event=\"resize\"][data-value=\"0.25\"]', function () {\n          return !!/(^|\\s)(max-)?width\\s*:\\s*25%/.test(style);\n        });\n        return;\n      }\n\n      // fontname\n      var $fontname = $container.find('.note-fontname');\n      if ($fontname.length) {\n        var selectedFont = styleInfo['font-family'];\n        if (!!selectedFont) {\n\n          var list = selectedFont.split(',');\n          for (var i = 0, len = list.length; i < len; i++) {\n            selectedFont = list[i].replace(/[\\'\\\"]/g, '').replace(/\\s+$/, '').replace(/^\\s+/, '');\n            if (agent.isFontInstalled(selectedFont)) {\n              break;\n            }\n          }\n          \n          $fontname.find('.note-current-fontname').text(selectedFont);\n          checkDropdownMenu($fontname, selectedFont);\n\n        }\n      }\n\n      // fontsize\n      var $fontsize = $container.find('.note-fontsize');\n      $fontsize.find('.note-current-fontsize').text(styleInfo['font-size']);\n      checkDropdownMenu($fontsize, parseFloat(styleInfo['font-size']));\n\n      // lineheight\n      var $lineHeight = $container.find('.note-height');\n      checkDropdownMenu($lineHeight, parseFloat(styleInfo['line-height']));\n\n      btnState('button[data-event=\"bold\"]', function () {\n        return styleInfo['font-bold'] === 'bold';\n      });\n      btnState('button[data-event=\"italic\"]', function () {\n        return styleInfo['font-italic'] === 'italic';\n      });\n      btnState('button[data-event=\"underline\"]', function () {\n        return styleInfo['font-underline'] === 'underline';\n      });\n      btnState('button[data-event=\"strikethrough\"]', function () {\n        return styleInfo['font-strikethrough'] === 'strikethrough';\n      });\n      btnState('button[data-event=\"superscript\"]', function () {\n        return styleInfo['font-superscript'] === 'superscript';\n      });\n      btnState('button[data-event=\"subscript\"]', function () {\n        return styleInfo['font-subscript'] === 'subscript';\n      });\n      btnState('button[data-event=\"justifyLeft\"]', function () {\n        return styleInfo['text-align'] === 'left' || styleInfo['text-align'] === 'start';\n      });\n      btnState('button[data-event=\"justifyCenter\"]', function () {\n        return styleInfo['text-align'] === 'center';\n      });\n      btnState('button[data-event=\"justifyRight\"]', function () {\n        return styleInfo['text-align'] === 'right';\n      });\n      btnState('button[data-event=\"justifyFull\"]', function () {\n        return styleInfo['text-align'] === 'justify';\n      });\n      btnState('button[data-event=\"insertUnorderedList\"]', function () {\n        return styleInfo['list-style'] === 'unordered';\n      });\n      btnState('button[data-event=\"insertOrderedList\"]', function () {\n        return styleInfo['list-style'] === 'ordered';\n      });\n    };\n\n    /**\n     * update recent color\n     *\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {Mixed} value\n     */\n    this.updateRecentColor = function (button, eventName, value) {\n      var $color = $(button).closest('.note-color');\n      var $recentColor = $color.find('.note-recent-color');\n      var colorInfo = JSON.parse($recentColor.attr('data-value'));\n      colorInfo[eventName] = value;\n      $recentColor.attr('data-value', JSON.stringify(colorInfo));\n      var sKey = eventName === 'backColor' ? 'background-color' : 'color';\n      $recentColor.find('i').css(sKey, value);\n    };\n  };\n\n  /**\n   * @class module.Toolbar\n   *\n   * Toolbar\n   */\n  var Toolbar = function () {\n    var button = new Button();\n\n    this.update = function ($toolbar, styleInfo) {\n      button.update($toolbar, styleInfo);\n    };\n\n    /**\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {String} value\n     */\n    this.updateRecentColor = function (buttonNode, eventName, value) {\n      button.updateRecentColor(buttonNode, eventName, value);\n    };\n\n    /**\n     * activate buttons exclude codeview\n     * @param {jQuery} $toolbar\n     */\n    this.activate = function ($toolbar) {\n      $toolbar.find('button')\n              .not('button[data-event=\"codeview\"]')\n              .removeClass('disabled');\n    };\n\n    /**\n     * deactivate buttons exclude codeview\n     * @param {jQuery} $toolbar\n     */\n    this.deactivate = function ($toolbar) {\n      $toolbar.find('button')\n              .not('button[data-event=\"codeview\"]')\n              .addClass('disabled');\n    };\n\n    /**\n     * @param {jQuery} $container\n     * @param {Boolean} [bFullscreen=false]\n     */\n    this.updateFullscreen = function ($container, bFullscreen) {\n      var $btn = $container.find('button[data-event=\"fullscreen\"]');\n      $btn.toggleClass('active', bFullscreen);\n    };\n\n    /**\n     * @param {jQuery} $container\n     * @param {Boolean} [isCodeview=false]\n     */\n    this.updateCodeview = function ($container, isCodeview) {\n      var $btn = $container.find('button[data-event=\"codeview\"]');\n      $btn.toggleClass('active', isCodeview);\n\n      if (isCodeview) {\n        this.deactivate($container);\n      } else {\n        this.activate($container);\n      }\n    };\n\n    /**\n     * get button in toolbar \n     *\n     * @param {jQuery} $editable\n     * @param {String} name\n     * @return {jQuery}\n     */\n    this.get = function ($editable, name) {\n      var $toolbar = dom.makeLayoutInfo($editable).toolbar();\n\n      return $toolbar.find('[data-name=' + name + ']');\n    };\n\n    /**\n     * set button state\n     * @param {jQuery} $editable\n     * @param {String} name\n     * @param {Boolean} [isActive=true]\n     */\n    this.setButtonState = function ($editable, name, isActive) {\n      isActive = (isActive === false) ? false : true;\n\n      var $button = this.get($editable, name);\n      $button.toggleClass('active', isActive);\n    };\n  };\n\n  var EDITABLE_PADDING = 24;\n\n  var Statusbar = function () {\n    var $document = $(document);\n\n    this.attach = function (layoutInfo, options) {\n      if (!options.disableResizeEditor) {\n        layoutInfo.statusbar().on('mousedown', hStatusbarMousedown);\n      }\n    };\n\n    /**\n     * `mousedown` event handler on statusbar\n     *\n     * @param {MouseEvent} event\n     */\n    var hStatusbarMousedown = function (event) {\n      event.preventDefault();\n      event.stopPropagation();\n\n      var $editable = dom.makeLayoutInfo(event.target).editable();\n      var editableTop = $editable.offset().top - $document.scrollTop();\n\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      var options = layoutInfo.editor().data('options');\n\n      $document.on('mousemove', function (event) {\n        var nHeight = event.clientY - (editableTop + EDITABLE_PADDING);\n\n        nHeight = (options.minHeight > 0) ? Math.max(nHeight, options.minHeight) : nHeight;\n        nHeight = (options.maxHeight > 0) ? Math.min(nHeight, options.maxHeight) : nHeight;\n\n        $editable.height(nHeight);\n      }).one('mouseup', function () {\n        $document.off('mousemove');\n      });\n    };\n  };\n\n  /**\n   * @class module.Popover\n   *\n   * Popover (http://getbootstrap.com/javascript/#popovers)\n   *\n   */\n  var Popover = function () {\n    var button = new Button();\n\n    /**\n     * returns position from placeholder\n     *\n     * @private\n     * @param {Node} placeholder\n     * @param {Object} options\n     * @param {Boolean} options.isAirMode\n     * @return {Position}\n     */\n    var posFromPlaceholder = function (placeholder, options) {\n      var isAirMode = options && options.isAirMode;\n      var isLeftTop = options && options.isLeftTop;\n\n      var $placeholder = $(placeholder);\n      var pos = isAirMode ? $placeholder.offset() : $placeholder.position();\n      var height = isLeftTop ? 0 : $placeholder.outerHeight(true); // include margin\n\n      // popover below placeholder.\n      return {\n        left: pos.left,\n        top: pos.top + height\n      };\n    };\n\n    /**\n     * show popover\n     *\n     * @private\n     * @param {jQuery} popover\n     * @param {Position} pos\n     */\n    var showPopover = function ($popover, pos) {\n      $popover.css({\n        display: 'block',\n        left: pos.left,\n        top: pos.top\n      });\n    };\n\n    var PX_POPOVER_ARROW_OFFSET_X = 20;\n\n    /**\n     * update current state\n     * @param {jQuery} $popover - popover container\n     * @param {Object} styleInfo - style object\n     * @param {Boolean} isAirMode\n     */\n    this.update = function ($popover, styleInfo, isAirMode) {\n      button.update($popover, styleInfo);\n\n      var $linkPopover = $popover.find('.note-link-popover');\n      if (styleInfo.anchor) {\n        var $anchor = $linkPopover.find('a');\n        var href = $(styleInfo.anchor).attr('href');\n        var target = $(styleInfo.anchor).attr('target');\n        $anchor.attr('href', href).html(href);\n        if (!target) {\n          $anchor.removeAttr('target');\n        } else {\n          $anchor.attr('target', '_blank');\n        }\n        showPopover($linkPopover, posFromPlaceholder(styleInfo.anchor, {\n          isAirMode: isAirMode\n        }));\n      } else {\n        $linkPopover.hide();\n      }\n\n      var $imagePopover = $popover.find('.note-image-popover');\n      if (styleInfo.image) {\n        showPopover($imagePopover, posFromPlaceholder(styleInfo.image, {\n          isAirMode: isAirMode,\n          isLeftTop: true\n        }));\n      } else {\n        $imagePopover.hide();\n      }\n\n      var $airPopover = $popover.find('.note-air-popover');\n      if (isAirMode && styleInfo.range && !styleInfo.range.isCollapsed()) {\n        var rect = list.last(styleInfo.range.getClientRects());\n        if (rect) {\n          var bnd = func.rect2bnd(rect);\n          showPopover($airPopover, {\n            left: Math.max(bnd.left + bnd.width / 2 - PX_POPOVER_ARROW_OFFSET_X, 0),\n            top: bnd.top + bnd.height\n          });\n        }\n      } else {\n        $airPopover.hide();\n      }\n    };\n\n    /**\n     * @param {Node} button\n     * @param {String} eventName\n     * @param {String} value\n     */\n    this.updateRecentColor = function (button, eventName, value) {\n      button.updateRecentColor(button, eventName, value);\n    };\n\n    /**\n     * hide all popovers\n     * @param {jQuery} $popover - popover container\n     */\n    this.hide = function ($popover) {\n      $popover.children().hide();\n    };\n  };\n\n  /**\n   * @class module.Handle\n   *\n   * Handle\n   */\n  var Handle = function (handler) {\n    var $document = $(document);\n\n    /**\n     * `mousedown` event handler on $handle\n     *  - controlSizing: resize image\n     *\n     * @param {MouseEvent} event\n     */\n    var hHandleMousedown = function (event) {\n      if (dom.isControlSizing(event.target)) {\n        event.preventDefault();\n        event.stopPropagation();\n\n        var layoutInfo = dom.makeLayoutInfo(event.target),\n            $handle = layoutInfo.handle(),\n            $popover = layoutInfo.popover(),\n            $editable = layoutInfo.editable(),\n            $editor = layoutInfo.editor();\n\n        var target = $handle.find('.note-control-selection').data('target'),\n            $target = $(target), posStart = $target.offset(),\n            scrollTop = $document.scrollTop();\n\n        var isAirMode = $editor.data('options').airMode;\n\n        $document.on('mousemove', function (event) {\n          handler.invoke('editor.resizeTo', {\n            x: event.clientX - posStart.left,\n            y: event.clientY - (posStart.top - scrollTop)\n          }, $target, !event.shiftKey);\n\n          handler.invoke('handle.update', $handle, {image: target}, isAirMode);\n          handler.invoke('popover.update', $popover, {image: target}, isAirMode);\n        }).one('mouseup', function () {\n          $document.off('mousemove');\n          handler.invoke('editor.afterCommand', $editable);\n        });\n\n        if (!$target.data('ratio')) { // original ratio.\n          $target.data('ratio', $target.height() / $target.width());\n        }\n      }\n    };\n\n    this.attach = function (layoutInfo) {\n      layoutInfo.handle().on('mousedown', hHandleMousedown);\n    };\n\n    /**\n     * update handle\n     * @param {jQuery} $handle\n     * @param {Object} styleInfo\n     * @param {Boolean} isAirMode\n     */\n    this.update = function ($handle, styleInfo, isAirMode) {\n      var $selection = $handle.find('.note-control-selection');\n      if (styleInfo.image) {\n        var $image = $(styleInfo.image);\n        var pos = isAirMode ? $image.offset() : $image.position();\n\n        // include margin\n        var imageSize = {\n          w: $image.outerWidth(true),\n          h: $image.outerHeight(true)\n        };\n\n        $selection.css({\n          display: 'block',\n          left: pos.left,\n          top: pos.top,\n          width: imageSize.w,\n          height: imageSize.h\n        }).data('target', styleInfo.image); // save current image element.\n        var sizingText = imageSize.w + 'x' + imageSize.h;\n        $selection.find('.note-control-selection-info').text(sizingText);\n      } else {\n        $selection.hide();\n      }\n    };\n\n    /**\n     * hide\n     *\n     * @param {jQuery} $handle\n     */\n    this.hide = function ($handle) {\n      $handle.children().hide();\n    };\n  };\n\n  var Fullscreen = function (handler) {\n    var $window = $(window);\n    var $scrollbar = $('html, body');\n\n    /**\n     * toggle fullscreen\n     *\n     * @param {Object} layoutInfo\n     */\n    this.toggle = function (layoutInfo) {\n\n      var $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable();\n\n      var resize = function (size) {\n        $editable.css('height', size.h);\n        $codable.css('height', size.h);\n        if ($codable.data('cmeditor')) {\n          $codable.data('cmeditor').setsize(null, size.h);\n        }\n      };\n\n      $editor.toggleClass('fullscreen');\n      var isFullscreen = $editor.hasClass('fullscreen');\n      if (isFullscreen) {\n        $editable.data('orgheight', $editable.css('height'));\n\n        $window.on('resize', function () {\n          resize({\n            h: $window.height() - $toolbar.outerHeight()\n          });\n        }).trigger('resize');\n\n        $scrollbar.css('overflow', 'hidden');\n      } else {\n        $window.off('resize');\n        resize({\n          h: $editable.data('orgheight')\n        });\n        $scrollbar.css('overflow', 'visible');\n      }\n\n      handler.invoke('toolbar.updateFullscreen', $toolbar, isFullscreen);\n    };\n  };\n\n\n  var CodeMirror;\n  if (agent.hasCodeMirror) {\n    if (agent.isSupportAmd) {\n      require(['CodeMirror'], function (cm) {\n        CodeMirror = cm;\n      });\n    } else {\n      CodeMirror = window.CodeMirror;\n    }\n  }\n\n  /**\n   * @class Codeview\n   */\n  var Codeview = function (handler) {\n\n    this.sync = function (layoutInfo) {\n      var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);\n      if (isCodeview && agent.hasCodeMirror) {\n        layoutInfo.codable().data('cmEditor').save();\n      }\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     * @return {Boolean}\n     */\n    this.isActivated = function (layoutInfo) {\n      var $editor = layoutInfo.editor();\n      return $editor.hasClass('codeview');\n    };\n\n    /**\n     * toggle codeview\n     *\n     * @param {Object} layoutInfo\n     */\n    this.toggle = function (layoutInfo) {\n      if (this.isActivated(layoutInfo)) {\n        this.deactivate(layoutInfo);\n      } else {\n        this.activate(layoutInfo);\n      }\n    };\n\n    /**\n     * activate code view\n     *\n     * @param {Object} layoutInfo\n     */\n    this.activate = function (layoutInfo) {\n      var $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable(),\n          $popover = layoutInfo.popover(),\n          $handle = layoutInfo.handle();\n\n      var options = $editor.data('options');\n\n      $codable.val(dom.html($editable, options.prettifyHtml));\n      $codable.height($editable.height());\n\n      handler.invoke('toolbar.updateCodeview', $toolbar, true);\n      handler.invoke('popover.hide', $popover);\n      handler.invoke('handle.hide', $handle);\n\n      $editor.addClass('codeview');\n\n      $codable.focus();\n\n      // activate CodeMirror as codable\n      if (agent.hasCodeMirror) {\n        var cmEditor = CodeMirror.fromTextArea($codable[0], options.codemirror);\n\n        // CodeMirror TernServer\n        if (options.codemirror.tern) {\n          var server = new CodeMirror.TernServer(options.codemirror.tern);\n          cmEditor.ternServer = server;\n          cmEditor.on('cursorActivity', function (cm) {\n            server.updateArgHints(cm);\n          });\n        }\n\n        // CodeMirror hasn't Padding.\n        cmEditor.setSize(null, $editable.outerHeight());\n        $codable.data('cmEditor', cmEditor);\n      }\n    };\n\n    /**\n     * deactivate code view\n     *\n     * @param {Object} layoutInfo\n     */\n    this.deactivate = function (layoutInfo) {\n      var $holder = layoutInfo.holder(),\n          $editor = layoutInfo.editor(),\n          $toolbar = layoutInfo.toolbar(),\n          $editable = layoutInfo.editable(),\n          $codable = layoutInfo.codable();\n\n      var options = $editor.data('options');\n\n      // deactivate CodeMirror as codable\n      if (agent.hasCodeMirror) {\n        var cmEditor = $codable.data('cmEditor');\n        $codable.val(cmEditor.getValue());\n        cmEditor.toTextArea();\n      }\n\n      var value = dom.value($codable, options.prettifyHtml) || dom.emptyPara;\n      var isChange = $editable.html() !== value;\n\n      $editable.html(value);\n      $editable.height(options.height ? $codable.height() : 'auto');\n      $editor.removeClass('codeview');\n\n      if (isChange) {\n        handler.bindCustomEvent(\n          $holder, $editable.data('callbacks'), 'change'\n        )($editable.html(), $editable);\n      }\n\n      $editable.focus();\n\n      handler.invoke('toolbar.updateCodeview', $toolbar, false);\n    };\n  };\n\n  var DragAndDrop = function (handler) {\n    var $document = $(document);\n\n    /**\n     * attach Drag and Drop Events\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options\n     */\n    this.attach = function (layoutInfo, options) {\n      if (options.airMode || options.disableDragAndDrop) {\n        // prevent default drop event\n        $document.on('drop', function (e) {\n          e.preventDefault();\n        });\n      } else {\n        this.attachDragAndDropEvent(layoutInfo, options);\n      }\n    };\n\n    /**\n     * attach Drag and Drop Events\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options\n     */\n    this.attachDragAndDropEvent = function (layoutInfo, options) {\n      var collection = $(),\n          $editor = layoutInfo.editor(),\n          $dropzone = layoutInfo.dropzone(),\n          $dropzoneMessage = $dropzone.find('.note-dropzone-message');\n\n      // show dropzone on dragenter when dragging a object to document\n      // -but only if the editor is visible, i.e. has a positive width and height\n      $document.on('dragenter', function (e) {\n        var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);\n        var hasEditorSize = $editor.width() > 0 && $editor.height() > 0;\n        if (!isCodeview && !collection.length && hasEditorSize) {\n          $editor.addClass('dragover');\n          $dropzone.width($editor.width());\n          $dropzone.height($editor.height());\n          $dropzoneMessage.text(options.langInfo.image.dragImageHere);\n        }\n        collection = collection.add(e.target);\n      }).on('dragleave', function (e) {\n        collection = collection.not(e.target);\n        if (!collection.length) {\n          $editor.removeClass('dragover');\n        }\n      }).on('drop', function () {\n        collection = $();\n        $editor.removeClass('dragover');\n      });\n\n      // change dropzone's message on hover.\n      $dropzone.on('dragenter', function () {\n        $dropzone.addClass('hover');\n        $dropzoneMessage.text(options.langInfo.image.dropImage);\n      }).on('dragleave', function () {\n        $dropzone.removeClass('hover');\n        $dropzoneMessage.text(options.langInfo.image.dragImageHere);\n      });\n\n      // attach dropImage\n      $dropzone.on('drop', function (event) {\n\n        var dataTransfer = event.originalEvent.dataTransfer;\n        var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n\n        if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {\n          event.preventDefault();\n          layoutInfo.editable().focus();\n          handler.insertImages(layoutInfo, dataTransfer.files);\n        } else {\n          var insertNodefunc = function () {\n            layoutInfo.holder().summernote('insertNode', this);\n          };\n\n          for (var i = 0, len = dataTransfer.types.length; i < len; i++) {\n            var type = dataTransfer.types[i];\n            var content = dataTransfer.getData(type);\n\n            if (type.toLowerCase().indexOf('text') > -1) {\n              layoutInfo.holder().summernote('pasteHTML', content);\n            } else {\n              $(content).each(insertNodefunc);\n            }\n          }\n        }\n      }).on('dragover', false); // prevent default dragover event\n    };\n  };\n\n  var Clipboard = function (handler) {\n    var $paste;\n\n    this.attach = function (layoutInfo) {\n      // [workaround] getting image from clipboard\n      //  - IE11 and Firefox: CTRL+v hook\n      //  - Webkit: event.clipboardData\n      if ((agent.isMSIE && agent.browserVersion > 10) || agent.isFF) {\n        $paste = $('<div />').attr('contenteditable', true).css({\n          position : 'absolute',\n          left : -100000,\n          opacity : 0\n        });\n\n        layoutInfo.editable().on('keydown', function (e) {\n          if (e.ctrlKey && e.keyCode === key.code.V) {\n            handler.invoke('saveRange', layoutInfo.editable());\n            $paste.focus();\n\n            setTimeout(function () {\n              pasteByHook(layoutInfo);\n            }, 0);\n          }\n        });\n\n        layoutInfo.editable().before($paste);\n      } else {\n        layoutInfo.editable().on('paste', pasteByEvent);\n      }\n    };\n\n    var pasteByHook = function (layoutInfo) {\n      var $editable = layoutInfo.editable();\n      var node = $paste[0].firstChild;\n\n      if (dom.isImg(node)) {\n        var dataURI = node.src;\n        var decodedData = atob(dataURI.split(',')[1]);\n        var array = new Uint8Array(decodedData.length);\n        for (var i = 0; i < decodedData.length; i++) {\n          array[i] = decodedData.charCodeAt(i);\n        }\n\n        var blob = new Blob([array], { type : 'image/png' });\n        blob.name = 'clipboard.png';\n\n        handler.invoke('restoreRange', $editable);\n        handler.invoke('focus', $editable);\n        handler.insertImages(layoutInfo, [blob]);\n      } else {\n        var pasteContent = $('<div />').html($paste.html()).html();\n        handler.invoke('restoreRange', $editable);\n        handler.invoke('focus', $editable);\n\n        if (pasteContent) {\n          handler.invoke('pasteHTML', $editable, pasteContent);\n        }\n      }\n\n      $paste.empty();\n    };\n\n    /**\n     * paste by clipboard event\n     *\n     * @param {Event} event\n     */\n    var pasteByEvent = function (event) {\n      var clipboardData = event.originalEvent.clipboardData;\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      var $editable = layoutInfo.editable();\n\n      if (clipboardData && clipboardData.items && clipboardData.items.length) {\n        var item = list.head(clipboardData.items);\n        if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {\n          handler.insertImages(layoutInfo, [item.getAsFile()]);\n        }\n        handler.invoke('editor.afterCommand', $editable);\n      }\n    };\n  };\n\n  var LinkDialog = function (handler) {\n\n    /**\n     * toggle button status\n     *\n     * @private\n     * @param {jQuery} $btn\n     * @param {Boolean} isEnable\n     */\n    var toggleBtn = function ($btn, isEnable) {\n      $btn.toggleClass('disabled', !isEnable);\n      $btn.attr('disabled', !isEnable);\n    };\n\n    /**\n     * bind enter key\n     *\n     * @private\n     * @param {jQuery} $input\n     * @param {jQuery} $btn\n     */\n    var bindEnterKey = function ($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          $btn.trigger('click');\n        }\n      });\n    };\n\n    /**\n     * Show link dialog and set event handlers on dialog controls.\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @param {Object} linkInfo\n     * @return {Promise}\n     */\n    this.showLinkDialog = function ($editable, $dialog, linkInfo) {\n      return $.Deferred(function (deferred) {\n        var $linkDialog = $dialog.find('.note-link-dialog');\n\n        var $linkText = $linkDialog.find('.note-link-text'),\n        $linkUrl = $linkDialog.find('.note-link-url'),\n        $linkBtn = $linkDialog.find('.note-link-btn'),\n        $openInNewWindow = $linkDialog.find('input[type=checkbox]');\n\n        $linkDialog.one('shown.bs.modal', function () {\n          $linkText.val(linkInfo.text);\n\n          $linkText.on('input', function () {\n            toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());\n            // if linktext was modified by keyup,\n            // stop cloning text from linkUrl\n            linkInfo.text = $linkText.val();\n          });\n\n          // if no url was given, copy text to url\n          if (!linkInfo.url) {\n            linkInfo.url = linkInfo.text || 'http://';\n            toggleBtn($linkBtn, linkInfo.text);\n          }\n\n          $linkUrl.on('input', function () {\n            toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());\n            // display same link on `Text to display` input\n            // when create a new link\n            if (!linkInfo.text) {\n              $linkText.val($linkUrl.val());\n            }\n          }).val(linkInfo.url).trigger('focus').trigger('select');\n\n          bindEnterKey($linkUrl, $linkBtn);\n          bindEnterKey($linkText, $linkBtn);\n\n          $openInNewWindow.prop('checked', linkInfo.isNewWindow);\n\n          $linkBtn.one('click', function (event) {\n            event.preventDefault();\n\n            deferred.resolve({\n              range: linkInfo.range,\n              url: $linkUrl.val(),\n              text: $linkText.val(),\n              isNewWindow: $openInNewWindow.is(':checked')\n            });\n            $linkDialog.modal('hide');\n          });\n        }).one('hidden.bs.modal', function () {\n          // detach events\n          $linkText.off('input keypress');\n          $linkUrl.off('input keypress');\n          $linkBtn.off('click');\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        }).modal('show');\n      }).promise();\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     */\n    this.show = function (layoutInfo) {\n      var $editor = layoutInfo.editor(),\n          $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable(),\n          $popover = layoutInfo.popover(),\n          linkInfo = handler.invoke('editor.getLinkInfo', $editable);\n\n      var options = $editor.data('options');\n\n      handler.invoke('editor.saveRange', $editable);\n      this.showLinkDialog($editable, $dialog, linkInfo).then(function (linkInfo) {\n        handler.invoke('editor.restoreRange', $editable);\n        handler.invoke('editor.createLink', $editable, linkInfo, options);\n        // hide popover after creating link\n        handler.invoke('popover.hide', $popover);\n      }).fail(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n  };\n\n  var ImageDialog = function (handler) {\n    /**\n     * toggle button status\n     *\n     * @private\n     * @param {jQuery} $btn\n     * @param {Boolean} isEnable\n     */\n    var toggleBtn = function ($btn, isEnable) {\n      $btn.toggleClass('disabled', !isEnable);\n      $btn.attr('disabled', !isEnable);\n    };\n\n    /**\n     * bind enter key\n     *\n     * @private\n     * @param {jQuery} $input\n     * @param {jQuery} $btn\n     */\n    var bindEnterKey = function ($input, $btn) {\n      $input.on('keypress', function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          $btn.trigger('click');\n        }\n      });\n    };\n\n    this.show = function (layoutInfo) {\n      var $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable();\n\n      handler.invoke('editor.saveRange', $editable);\n      this.showImageDialog($editable, $dialog).then(function (data) {\n        handler.invoke('editor.restoreRange', $editable);\n\n        if (typeof data === 'string') {\n          // image url\n          handler.invoke('editor.insertImage', $editable, data);\n        } else {\n          // array of files\n          handler.insertImages(layoutInfo, data);\n        }\n      }).fail(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n\n    /**\n     * show image dialog\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @return {Promise}\n     */\n    this.showImageDialog = function ($editable, $dialog) {\n      return $.Deferred(function (deferred) {\n        var $imageDialog = $dialog.find('.note-image-dialog');\n\n        var $imageInput = $dialog.find('.note-image-input'),\n            $imageUrl = $dialog.find('.note-image-url'),\n            $imageBtn = $dialog.find('.note-image-btn');\n\n        $imageDialog.one('shown.bs.modal', function () {\n          // Cloning imageInput to clear element.\n          $imageInput.replaceWith($imageInput.clone()\n            .on('change', function () {\n              deferred.resolve(this.files || this.value);\n              $imageDialog.modal('hide');\n            })\n            .val('')\n          );\n\n          $imageBtn.click(function (event) {\n            event.preventDefault();\n\n            deferred.resolve($imageUrl.val());\n            $imageDialog.modal('hide');\n          });\n\n          $imageUrl.on('keyup paste', function (event) {\n            var url;\n            \n            if (event.type === 'paste') {\n              url = event.originalEvent.clipboardData.getData('text');\n            } else {\n              url = $imageUrl.val();\n            }\n            \n            toggleBtn($imageBtn, url);\n          }).val('').trigger('focus');\n          bindEnterKey($imageUrl, $imageBtn);\n        }).one('hidden.bs.modal', function () {\n          $imageInput.off('change');\n          $imageUrl.off('keyup paste keypress');\n          $imageBtn.off('click');\n\n          if (deferred.state() === 'pending') {\n            deferred.reject();\n          }\n        }).modal('show');\n      });\n    };\n  };\n\n  var HelpDialog = function (handler) {\n    /**\n     * show help dialog\n     *\n     * @param {jQuery} $editable\n     * @param {jQuery} $dialog\n     * @return {Promise}\n     */\n    this.showHelpDialog = function ($editable, $dialog) {\n      return $.Deferred(function (deferred) {\n        var $helpDialog = $dialog.find('.note-help-dialog');\n\n        $helpDialog.one('hidden.bs.modal', function () {\n          deferred.resolve();\n        }).modal('show');\n      }).promise();\n    };\n\n    /**\n     * @param {Object} layoutInfo\n     */\n    this.show = function (layoutInfo) {\n      var $dialog = layoutInfo.dialog(),\n          $editable = layoutInfo.editable();\n\n      handler.invoke('editor.saveRange', $editable, true);\n      this.showHelpDialog($editable, $dialog).then(function () {\n        handler.invoke('editor.restoreRange', $editable);\n      });\n    };\n  };\n\n\n  /**\n   * @class EventHandler\n   *\n   * EventHandler\n   *  - TODO: new instance per a editor\n   */\n  var EventHandler = function () {\n    var self = this;\n\n    /**\n     * Modules\n     */\n    var modules = this.modules = {\n      editor: new Editor(this),\n      toolbar: new Toolbar(this),\n      statusbar: new Statusbar(this),\n      popover: new Popover(this),\n      handle: new Handle(this),\n      fullscreen: new Fullscreen(this),\n      codeview: new Codeview(this),\n      dragAndDrop: new DragAndDrop(this),\n      clipboard: new Clipboard(this),\n      linkDialog: new LinkDialog(this),\n      imageDialog: new ImageDialog(this),\n      helpDialog: new HelpDialog(this)\n    };\n\n    /**\n     * invoke module's method\n     *\n     * @param {String} moduleAndMethod - ex) 'editor.redo'\n     * @param {...*} arguments - arguments of method\n     * @return {*}\n     */\n    this.invoke = function () {\n      var moduleAndMethod = list.head(list.from(arguments));\n      var args = list.tail(list.from(arguments));\n\n      var splits = moduleAndMethod.split('.');\n      var hasSeparator = splits.length > 1;\n      var moduleName = hasSeparator && list.head(splits);\n      var methodName = hasSeparator ? list.last(splits) : list.head(splits);\n\n      var module = this.getModule(moduleName);\n      var method = module[methodName];\n\n      return method && method.apply(module, args);\n    };\n\n    /**\n     * returns module\n     *\n     * @param {String} moduleName - name of module\n     * @return {Module} - defaults is editor\n     */\n    this.getModule = function (moduleName) {\n      return this.modules[moduleName] || this.modules.editor;\n    };\n\n    /**\n     * @param {jQuery} $holder\n     * @param {Object} callbacks\n     * @param {String} eventNamespace\n     * @returns {Function}\n     */\n    var bindCustomEvent = this.bindCustomEvent = function ($holder, callbacks, eventNamespace) {\n      return function () {\n        var callback = callbacks[func.namespaceToCamel(eventNamespace, 'on')];\n        if (callback) {\n          callback.apply($holder[0], arguments);\n        }\n        return $holder.trigger('summernote.' + eventNamespace, arguments);\n      };\n    };\n\n    /**\n     * insert Images from file array.\n     *\n     * @private\n     * @param {Object} layoutInfo\n     * @param {File[]} files\n     */\n    this.insertImages = function (layoutInfo, files) {\n      var $editor = layoutInfo.editor(),\n          $editable = layoutInfo.editable(),\n          $holder = layoutInfo.holder();\n\n      var callbacks = $editable.data('callbacks');\n      var options = $editor.data('options');\n\n      // If onImageUpload options setted\n      if (callbacks.onImageUpload) {\n        bindCustomEvent($holder, callbacks, 'image.upload')(files);\n      // else insert Image as dataURL\n      } else {\n        $.each(files, function (idx, file) {\n          var filename = file.name;\n          if (options.maximumImageFileSize && options.maximumImageFileSize < file.size) {\n            bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);\n          } else {\n            async.readFileAsDataURL(file).then(function (sDataURL) {\n              modules.editor.insertImage($editable, sDataURL, filename);\n            }).fail(function () {\n              bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);\n            });\n          }\n        });\n      }\n    };\n\n    var commands = {\n      /**\n       * @param {Object} layoutInfo\n       */\n      showLinkDialog: function (layoutInfo) {\n        modules.linkDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      showImageDialog: function (layoutInfo) {\n        modules.imageDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      showHelpDialog: function (layoutInfo) {\n        modules.helpDialog.show(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      fullscreen: function (layoutInfo) {\n        modules.fullscreen.toggle(layoutInfo);\n      },\n\n      /**\n       * @param {Object} layoutInfo\n       */\n      codeview: function (layoutInfo) {\n        modules.codeview.toggle(layoutInfo);\n      }\n    };\n\n    var hMousedown = function (event) {\n      //preventDefault Selection for FF, IE8+\n      if (dom.isImg(event.target)) {\n        event.preventDefault();\n      }\n    };\n\n    var hKeyupAndMouseup = function (event) {\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      modules.editor.removeBogus(layoutInfo.editable());\n      hToolbarAndPopoverUpdate(event);\n    };\n\n    /**\n     * update sytle info\n     * @param {Object} styleInfo\n     * @param {Object} layoutInfo\n     */\n    this.updateStyleInfo = function (styleInfo, layoutInfo) {\n      if (!styleInfo) {\n        return;\n      }\n      var isAirMode = layoutInfo.editor().data('options').airMode;\n      if (!isAirMode) {\n        modules.toolbar.update(layoutInfo.toolbar(), styleInfo);\n      }\n\n      modules.popover.update(layoutInfo.popover(), styleInfo, isAirMode);\n      modules.handle.update(layoutInfo.handle(), styleInfo, isAirMode);\n    };\n\n    var hToolbarAndPopoverUpdate = function (event) {\n      var target = event.target;\n      // delay for range after mouseup\n      setTimeout(function () {\n        var layoutInfo = dom.makeLayoutInfo(target);\n        var styleInfo = modules.editor.currentStyle(target);\n        self.updateStyleInfo(styleInfo, layoutInfo);\n      }, 0);\n    };\n\n    var hScroll = function (event) {\n      var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);\n      //hide popover and handle when scrolled\n      modules.popover.hide(layoutInfo.popover());\n      modules.handle.hide(layoutInfo.handle());\n    };\n\n    var hToolbarAndPopoverMousedown = function (event) {\n      // prevent default event when insertTable (FF, Webkit)\n      var $btn = $(event.target).closest('[data-event]');\n      if ($btn.length) {\n        event.preventDefault();\n      }\n    };\n\n    var hToolbarAndPopoverClick = function (event) {\n      var $btn = $(event.target).closest('[data-event]');\n\n      if (!$btn.length) {\n        return;\n      }\n\n      var eventName = $btn.attr('data-event'),\n          value = $btn.attr('data-value'),\n          hide = $btn.attr('data-hide');\n\n      var layoutInfo = dom.makeLayoutInfo(event.target);\n\n      // before command: detect control selection element($target)\n      var $target;\n      if ($.inArray(eventName, ['resize', 'floatMe', 'removeMedia', 'imageShape']) !== -1) {\n        var $selection = layoutInfo.handle().find('.note-control-selection');\n        $target = $($selection.data('target'));\n      }\n\n      // If requested, hide the popover when the button is clicked.\n      // Useful for things like showHelpDialog.\n      if (hide) {\n        $btn.parents('.popover').hide();\n      }\n\n      if ($.isFunction($.summernote.pluginEvents[eventName])) {\n        $.summernote.pluginEvents[eventName](event, modules.editor, layoutInfo, value);\n      } else if (modules.editor[eventName]) { // on command\n        var $editable = layoutInfo.editable();\n        $editable.focus();\n        modules.editor[eventName]($editable, value, $target);\n        event.preventDefault();\n      } else if (commands[eventName]) {\n        commands[eventName].call(this, layoutInfo);\n        event.preventDefault();\n      }\n\n      // after command\n      if ($.inArray(eventName, ['backColor', 'foreColor']) !== -1) {\n        var options = layoutInfo.editor().data('options', options);\n        var module = options.airMode ? modules.popover : modules.toolbar;\n        module.updateRecentColor(list.head($btn), eventName, value);\n      }\n\n      hToolbarAndPopoverUpdate(event);\n    };\n\n    var PX_PER_EM = 18;\n    var hDimensionPickerMove = function (event, options) {\n      var $picker = $(event.target.parentNode); // target is mousecatcher\n      var $dimensionDisplay = $picker.next();\n      var $catcher = $picker.find('.note-dimension-picker-mousecatcher');\n      var $highlighted = $picker.find('.note-dimension-picker-highlighted');\n      var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');\n\n      var posOffset;\n      // HTML5 with jQuery - e.offsetX is undefined in Firefox\n      if (event.offsetX === undefined) {\n        var posCatcher = $(event.target).offset();\n        posOffset = {\n          x: event.pageX - posCatcher.left,\n          y: event.pageY - posCatcher.top\n        };\n      } else {\n        posOffset = {\n          x: event.offsetX,\n          y: event.offsetY\n        };\n      }\n\n      var dim = {\n        c: Math.ceil(posOffset.x / PX_PER_EM) || 1,\n        r: Math.ceil(posOffset.y / PX_PER_EM) || 1\n      };\n\n      $highlighted.css({ width: dim.c + 'em', height: dim.r + 'em' });\n      $catcher.attr('data-value', dim.c + 'x' + dim.r);\n\n      if (3 < dim.c && dim.c < options.insertTableMaxSize.col) {\n        $unhighlighted.css({ width: dim.c + 1 + 'em'});\n      }\n\n      if (3 < dim.r && dim.r < options.insertTableMaxSize.row) {\n        $unhighlighted.css({ height: dim.r + 1 + 'em'});\n      }\n\n      $dimensionDisplay.html(dim.c + ' x ' + dim.r);\n    };\n    \n    /**\n     * bind KeyMap on keydown\n     *\n     * @param {Object} layoutInfo\n     * @param {Object} keyMap\n     */\n    this.bindKeyMap = function (layoutInfo, keyMap) {\n      var $editor = layoutInfo.editor();\n      var $editable = layoutInfo.editable();\n\n      $editable.on('keydown', function (event) {\n        var keys = [];\n\n        // modifier\n        if (event.metaKey) { keys.push('CMD'); }\n        if (event.ctrlKey && !event.altKey) { keys.push('CTRL'); }\n        if (event.shiftKey) { keys.push('SHIFT'); }\n\n        // keycode\n        var keyName = key.nameFromCode[event.keyCode];\n        if (keyName) {\n          keys.push(keyName);\n        }\n\n        var pluginEvent;\n        var keyString = keys.join('+');\n        var eventName = keyMap[keyString];\n        if (eventName) {\n          // FIXME Summernote doesn't support event pipeline yet.\n          //  - Plugin -> Base Code\n          pluginEvent = $.summernote.pluginEvents[keyString];\n          if ($.isFunction(pluginEvent)) {\n            if (pluginEvent(event, modules.editor, layoutInfo)) {\n              return false;\n            }\n          }\n\n          pluginEvent = $.summernote.pluginEvents[eventName];\n\n          if ($.isFunction(pluginEvent)) {\n            pluginEvent(event, modules.editor, layoutInfo);\n          } else if (modules.editor[eventName]) {\n            modules.editor[eventName]($editable, $editor.data('options'));\n            event.preventDefault();\n          } else if (commands[eventName]) {\n            commands[eventName].call(this, layoutInfo);\n            event.preventDefault();\n          }\n        } else if (key.isEdit(event.keyCode)) {\n          modules.editor.afterCommand($editable);\n        }\n      });\n    };\n\n    /**\n     * attach eventhandler\n     *\n     * @param {Object} layoutInfo - layout Informations\n     * @param {Object} options - user options include custom event handlers\n     */\n    this.attach = function (layoutInfo, options) {\n      // handlers for editable\n      if (options.shortcuts) {\n        this.bindKeyMap(layoutInfo, options.keyMap[agent.isMac ? 'mac' : 'pc']);\n      }\n      layoutInfo.editable().on('mousedown', hMousedown);\n      layoutInfo.editable().on('keyup mouseup', hKeyupAndMouseup);\n      layoutInfo.editable().on('scroll', hScroll);\n\n      // handler for clipboard\n      modules.clipboard.attach(layoutInfo, options);\n\n      // handler for handle and popover\n      modules.handle.attach(layoutInfo, options);\n      layoutInfo.popover().on('click', hToolbarAndPopoverClick);\n      layoutInfo.popover().on('mousedown', hToolbarAndPopoverMousedown);\n\n      // handler for drag and drop\n      modules.dragAndDrop.attach(layoutInfo, options);\n\n      // handlers for frame mode (toolbar, statusbar)\n      if (!options.airMode) {\n        // handler for toolbar\n        layoutInfo.toolbar().on('click', hToolbarAndPopoverClick);\n        layoutInfo.toolbar().on('mousedown', hToolbarAndPopoverMousedown);\n\n        // handler for statusbar\n        modules.statusbar.attach(layoutInfo, options);\n      }\n\n      // handler for table dimension\n      var $catcherContainer = options.airMode ? layoutInfo.popover() :\n                                                layoutInfo.toolbar();\n      var $catcher = $catcherContainer.find('.note-dimension-picker-mousecatcher');\n      $catcher.css({\n        width: options.insertTableMaxSize.col + 'em',\n        height: options.insertTableMaxSize.row + 'em'\n      }).on('mousemove', function (event) {\n        hDimensionPickerMove(event, options);\n      });\n\n      // save options on editor\n      layoutInfo.editor().data('options', options);\n\n      // ret styleWithCSS for backColor / foreColor clearing with 'inherit'.\n      if (!agent.isMSIE) {\n        // [workaround] for Firefox\n        //  - protect FF Error: NS_ERROR_FAILURE: Failure\n        setTimeout(function () {\n          document.execCommand('styleWithCSS', 0, options.styleWithSpan);\n        }, 0);\n      }\n\n      // History\n      var history = new History(layoutInfo.editable());\n      layoutInfo.editable().data('NoteHistory', history);\n\n      // All editor status will be saved on editable with jquery's data\n      // for support multiple editor with singleton object.\n      layoutInfo.editable().data('callbacks', {\n        onInit: options.onInit,\n        onFocus: options.onFocus,\n        onBlur: options.onBlur,\n        onKeydown: options.onKeydown,\n        onKeyup: options.onKeyup,\n        onMousedown: options.onMousedown,\n        onEnter: options.onEnter,\n        onPaste: options.onPaste,\n        onBeforeCommand: options.onBeforeCommand,\n        onChange: options.onChange,\n        onImageUpload: options.onImageUpload,\n        onImageUploadError: options.onImageUploadError,\n        onMediaDelete: options.onMediaDelete,\n        onToolbarClick: options.onToolbarClick\n      });\n\n      var styleInfo = modules.editor.styleFromNode(layoutInfo.editable());\n      this.updateStyleInfo(styleInfo, layoutInfo);\n    };\n\n    /**\n     * attach jquery custom event\n     *\n     * @param {Object} layoutInfo - layout Informations\n     */\n    this.attachCustomEvent = function (layoutInfo, options) {\n      var $holder = layoutInfo.holder();\n      var $editable = layoutInfo.editable();\n      var callbacks = $editable.data('callbacks');\n\n      $editable.focus(bindCustomEvent($holder, callbacks, 'focus'));\n      $editable.blur(bindCustomEvent($holder, callbacks, 'blur'));\n\n      $editable.keydown(function (event) {\n        if (event.keyCode === key.code.ENTER) {\n          bindCustomEvent($holder, callbacks, 'enter').call(this, event);\n        }\n        bindCustomEvent($holder, callbacks, 'keydown').call(this, event);\n      });\n      $editable.keyup(bindCustomEvent($holder, callbacks, 'keyup'));\n\n      $editable.on('mousedown', bindCustomEvent($holder, callbacks, 'mousedown'));\n      $editable.on('mouseup', bindCustomEvent($holder, callbacks, 'mouseup'));\n      $editable.on('scroll', bindCustomEvent($holder, callbacks, 'scroll'));\n\n      $editable.on('paste', bindCustomEvent($holder, callbacks, 'paste'));\n      \n      // [workaround] IE doesn't have input events for contentEditable\n      //  - see: https://goo.gl/4bfIvA\n      var changeEventName = agent.isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input';\n      $editable.on(changeEventName, function () {\n        bindCustomEvent($holder, callbacks, 'change')($editable.html(), $editable);\n      });\n\n      if (!options.airMode) {\n        layoutInfo.toolbar().click(bindCustomEvent($holder, callbacks, 'toolbar.click'));\n        layoutInfo.popover().click(bindCustomEvent($holder, callbacks, 'popover.click'));\n      }\n\n      // Textarea: auto filling the code before form submit.\n      if (dom.isTextarea(list.head($holder))) {\n        $holder.closest('form').submit(function (e) {\n          layoutInfo.holder().val(layoutInfo.holder().code());\n          bindCustomEvent($holder, callbacks, 'submit').call(this, e, $holder.code());\n        });\n      }\n\n      // textarea auto sync\n      if (dom.isTextarea(list.head($holder)) && options.textareaAutoSync) {\n        $holder.on('summernote.change', function () {\n          layoutInfo.holder().val(layoutInfo.holder().code());\n        });\n      }\n\n      // fire init event\n      bindCustomEvent($holder, callbacks, 'init')(layoutInfo);\n\n      // fire plugin init event\n      for (var i = 0, len = $.summernote.plugins.length; i < len; i++) {\n        if ($.isFunction($.summernote.plugins[i].init)) {\n          $.summernote.plugins[i].init(layoutInfo);\n        }\n      }\n    };\n      \n    this.detach = function (layoutInfo, options) {\n      layoutInfo.holder().off();\n      layoutInfo.editable().off();\n\n      layoutInfo.popover().off();\n      layoutInfo.handle().off();\n      layoutInfo.dialog().off();\n\n      if (!options.airMode) {\n        layoutInfo.dropzone().off();\n        layoutInfo.toolbar().off();\n        layoutInfo.statusbar().off();\n      }\n    };\n  };\n\n  /**\n   * @class Renderer\n   *\n   * renderer\n   *\n   * rendering toolbar and editable\n   */\n  var Renderer = function () {\n\n    /**\n     * bootstrap button template\n     * @private\n     * @param {String} label button name\n     * @param {Object} [options] button options\n     * @param {String} [options.event] data-event\n     * @param {String} [options.className] button's class name\n     * @param {String} [options.value] data-value\n     * @param {String} [options.title] button's title for popup\n     * @param {String} [options.dropdown] dropdown html\n     * @param {String} [options.hide] data-hide\n     */\n    var tplButton = function (label, options) {\n      var event = options.event;\n      var value = options.value;\n      var title = options.title;\n      var className = options.className;\n      var dropdown = options.dropdown;\n      var hide = options.hide;\n\n      return (dropdown ? '<div class=\"btn-group' +\n               (className ? ' ' + className : '') + '\">' : '') +\n               '<button type=\"button\"' +\n                 ' class=\"btn btn-default btn-sm' +\n                   ((!dropdown && className) ? ' ' + className : '') +\n                   (dropdown ? ' dropdown-toggle' : '') +\n                 '\"' +\n                 (dropdown ? ' data-toggle=\"dropdown\"' : '') +\n                 (title ? ' title=\"' + title + '\"' : '') +\n                 (event ? ' data-event=\"' + event + '\"' : '') +\n                 (value ? ' data-value=\\'' + value + '\\'' : '') +\n                 (hide ? ' data-hide=\\'' + hide + '\\'' : '') +\n                 ' tabindex=\"-1\">' +\n                 label +\n                 (dropdown ? ' <span class=\"caret\"></span>' : '') +\n               '</button>' +\n               (dropdown || '') +\n             (dropdown ? '</div>' : '');\n    };\n\n    /**\n     * bootstrap icon button template\n     * @private\n     * @param {String} iconClassName\n     * @param {Object} [options]\n     * @param {String} [options.event]\n     * @param {String} [options.value]\n     * @param {String} [options.title]\n     * @param {String} [options.dropdown]\n     */\n    var tplIconButton = function (iconClassName, options) {\n      var label = '<i class=\"' + iconClassName + '\"></i>';\n      return tplButton(label, options);\n    };\n\n    /**\n     * bootstrap popover template\n     * @private\n     * @param {String} className\n     * @param {String} content\n     */\n    var tplPopover = function (className, content) {\n      var $popover = $('<div class=\"' + className + ' popover bottom in\" style=\"display: none;\">' +\n               '<div class=\"arrow\"></div>' +\n               '<div class=\"popover-content\">' +\n               '</div>' +\n             '</div>');\n\n      $popover.find('.popover-content').append(content);\n      return $popover;\n    };\n\n    /**\n     * bootstrap dialog template\n     *\n     * @param {String} className\n     * @param {String} [title='']\n     * @param {String} body\n     * @param {String} [footer='']\n     */\n    var tplDialog = function (className, title, body, footer) {\n      return '<div class=\"' + className + ' modal\" aria-hidden=\"false\">' +\n               '<div class=\"modal-dialog\">' +\n                 '<div class=\"modal-content\">' +\n                   (title ?\n                   '<div class=\"modal-header\">' +\n                     '<button type=\"button\" class=\"close\" aria-hidden=\"true\" tabindex=\"-1\">&times;</button>' +\n                     '<h4 class=\"modal-title\">' + title + '</h4>' +\n                   '</div>' : ''\n                   ) +\n                   '<div class=\"modal-body\">' + body + '</div>' +\n                   (footer ?\n                   '<div class=\"modal-footer\">' + footer + '</div>' : ''\n                   ) +\n                 '</div>' +\n               '</div>' +\n             '</div>';\n    };\n\n    /**\n     * bootstrap dropdown template\n     *\n     * @param {String|String[]} contents\n     * @param {String} [className='']\n     * @param {String} [nodeName='']\n     */\n    var tplDropdown = function (contents, className, nodeName) {\n      var classes = 'dropdown-menu' + (className ? ' ' + className : '');\n      nodeName = nodeName || 'ul';\n      if (contents instanceof Array) {\n        contents = contents.join('');\n      }\n\n      return '<' + nodeName + ' class=\"' + classes + '\">' + contents + '</' + nodeName + '>';\n    };\n\n    var tplButtonInfo = {\n      picture: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.image.image, {\n          event: 'showImageDialog',\n          title: lang.image.image,\n          hide: true\n        });\n      },\n      link: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.link.link, {\n          event: 'showLinkDialog',\n          title: lang.link.link,\n          hide: true\n        });\n      },\n      table: function (lang, options) {\n        var dropdown = [\n          '<div class=\"note-dimension-picker\">',\n          '<div class=\"note-dimension-picker-mousecatcher\" data-event=\"insertTable\" data-value=\"1x1\"></div>',\n          '<div class=\"note-dimension-picker-highlighted\"></div>',\n          '<div class=\"note-dimension-picker-unhighlighted\"></div>',\n          '</div>',\n          '<div class=\"note-dimension-display\"> 1 x 1 </div>'\n        ];\n\n        return tplIconButton(options.iconPrefix + options.icons.table.table, {\n          title: lang.table.table,\n          dropdown: tplDropdown(dropdown, 'note-table')\n        });\n      },\n      style: function (lang, options) {\n        var items = options.styleTags.reduce(function (memo, v) {\n          var label = lang.style[v === 'p' ? 'normal' : v];\n          return memo + '<li><a data-event=\"formatBlock\" href=\"#\" data-value=\"' + v + '\">' +\n                   (\n                     (v === 'p' || v === 'pre') ? label :\n                     '<' + v + '>' + label + '</' + v + '>'\n                   ) +\n                 '</a></li>';\n        }, '');\n\n        return tplIconButton(options.iconPrefix + options.icons.style.style, {\n          title: lang.style.style,\n          dropdown: tplDropdown(items)\n        });\n      },\n      fontname: function (lang, options) {\n        var realFontList = [];\n        var items = options.fontNames.reduce(function (memo, v) {\n          if (!agent.isFontInstalled(v) && !list.contains(options.fontNamesIgnoreCheck, v)) {\n            return memo;\n          }\n          realFontList.push(v);\n          return memo + '<li><a data-event=\"fontName\" href=\"#\" data-value=\"' + v + '\" style=\"font-family:\\'' + v + '\\'\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        var hasDefaultFont = agent.isFontInstalled(options.defaultFontName);\n        var defaultFontName = (hasDefaultFont) ? options.defaultFontName : realFontList[0];\n\n        var label = '<span class=\"note-current-fontname\">' +\n                        defaultFontName +\n                     '</span>';\n        return tplButton(label, {\n          title: lang.font.name,\n          className: 'note-fontname',\n          dropdown: tplDropdown(items, 'note-check')\n        });\n      },\n      fontsize: function (lang, options) {\n        var items = options.fontSizes.reduce(function (memo, v) {\n          return memo + '<li><a data-event=\"fontSize\" href=\"#\" data-value=\"' + v + '\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        var label = '<span class=\"note-current-fontsize\">11</span>';\n        return tplButton(label, {\n          title: lang.font.size,\n          className: 'note-fontsize',\n          dropdown: tplDropdown(items, 'note-check')\n        });\n      },\n      color: function (lang, options) {\n        var colorButtonLabel = '<i class=\"' +\n                                  options.iconPrefix + options.icons.color.recent +\n                                '\" style=\"color:black;background-color:yellow;\"></i>';\n\n        var colorButton = tplButton(colorButtonLabel, {\n          className: 'note-recent-color',\n          title: lang.color.recent,\n          event: 'color',\n          value: '{\"backColor\":\"yellow\"}'\n        });\n\n        var items = [\n          '<li><div class=\"btn-group\">',\n          '<div class=\"note-palette-title\">' + lang.color.background + '</div>',\n          '<div class=\"note-color-reset\" data-event=\"backColor\"',\n          ' data-value=\"inherit\" title=\"' + lang.color.transparent + '\">' + lang.color.setTransparent + '</div>',\n          '<div class=\"note-color-palette\" data-target-event=\"backColor\"></div>',\n          '</div><div class=\"btn-group\">',\n          '<div class=\"note-palette-title\">' + lang.color.foreground + '</div>',\n          '<div class=\"note-color-reset\" data-event=\"foreColor\" data-value=\"inherit\" title=\"' + lang.color.reset + '\">',\n          lang.color.resetToDefault,\n          '</div>',\n          '<div class=\"note-color-palette\" data-target-event=\"foreColor\"></div>',\n          '</div></li>'\n        ];\n\n        var moreButton = tplButton('', {\n          title: lang.color.more,\n          dropdown: tplDropdown(items)\n        });\n\n        return colorButton + moreButton;\n      },\n      bold: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.bold, {\n          event: 'bold',\n          title: lang.font.bold\n        });\n      },\n      italic: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.italic, {\n          event: 'italic',\n          title: lang.font.italic\n        });\n      },\n      underline: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.underline, {\n          event: 'underline',\n          title: lang.font.underline\n        });\n      },\n      strikethrough: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.strikethrough, {\n          event: 'strikethrough',\n          title: lang.font.strikethrough\n        });\n      },\n      superscript: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.superscript, {\n          event: 'superscript',\n          title: lang.font.superscript\n        });\n      },\n      subscript: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.subscript, {\n          event: 'subscript',\n          title: lang.font.subscript\n        });\n      },\n      clear: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.font.clear, {\n          event: 'removeFormat',\n          title: lang.font.clear\n        });\n      },\n      ul: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.lists.unordered, {\n          event: 'insertUnorderedList',\n          title: lang.lists.unordered\n        });\n      },\n      ol: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.lists.ordered, {\n          event: 'insertOrderedList',\n          title: lang.lists.ordered\n        });\n      },\n      paragraph: function (lang, options) {\n        var leftButton = tplIconButton(options.iconPrefix + options.icons.paragraph.left, {\n          title: lang.paragraph.left,\n          event: 'justifyLeft'\n        });\n        var centerButton = tplIconButton(options.iconPrefix + options.icons.paragraph.center, {\n          title: lang.paragraph.center,\n          event: 'justifyCenter'\n        });\n        var rightButton = tplIconButton(options.iconPrefix + options.icons.paragraph.right, {\n          title: lang.paragraph.right,\n          event: 'justifyRight'\n        });\n        var justifyButton = tplIconButton(options.iconPrefix + options.icons.paragraph.justify, {\n          title: lang.paragraph.justify,\n          event: 'justifyFull'\n        });\n\n        var outdentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.outdent, {\n          title: lang.paragraph.outdent,\n          event: 'outdent'\n        });\n        var indentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.indent, {\n          title: lang.paragraph.indent,\n          event: 'indent'\n        });\n\n        var dropdown = [\n          '<div class=\"note-align btn-group\">',\n          leftButton + centerButton + rightButton + justifyButton,\n          '</div><div class=\"note-list btn-group\">',\n          indentButton + outdentButton,\n          '</div>'\n        ];\n\n        return tplIconButton(options.iconPrefix + options.icons.paragraph.paragraph, {\n          title: lang.paragraph.paragraph,\n          dropdown: tplDropdown(dropdown, '', 'div')\n        });\n      },\n      height: function (lang, options) {\n        var items = options.lineHeights.reduce(function (memo, v) {\n          return memo + '<li><a data-event=\"lineHeight\" href=\"#\" data-value=\"' + parseFloat(v) + '\">' +\n                          '<i class=\"' + options.iconPrefix + options.icons.misc.check + '\"></i> ' + v +\n                        '</a></li>';\n        }, '');\n\n        return tplIconButton(options.iconPrefix + options.icons.font.height, {\n          title: lang.font.height,\n          dropdown: tplDropdown(items, 'note-check')\n        });\n\n      },\n      help: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.help, {\n          event: 'showHelpDialog',\n          title: lang.options.help,\n          hide: true\n        });\n      },\n      fullscreen: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.fullscreen, {\n          event: 'fullscreen',\n          title: lang.options.fullscreen\n        });\n      },\n      codeview: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.options.codeview, {\n          event: 'codeview',\n          title: lang.options.codeview\n        });\n      },\n      undo: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.history.undo, {\n          event: 'undo',\n          title: lang.history.undo\n        });\n      },\n      redo: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.history.redo, {\n          event: 'redo',\n          title: lang.history.redo\n        });\n      },\n      hr: function (lang, options) {\n        return tplIconButton(options.iconPrefix + options.icons.hr.insert, {\n          event: 'insertHorizontalRule',\n          title: lang.hr.insert\n        });\n      }\n    };\n\n    var tplPopovers = function (lang, options) {\n      var tplLinkPopover = function () {\n        var linkButton = tplIconButton(options.iconPrefix + options.icons.link.edit, {\n          title: lang.link.edit,\n          event: 'showLinkDialog',\n          hide: true\n        });\n        var unlinkButton = tplIconButton(options.iconPrefix + options.icons.link.unlink, {\n          title: lang.link.unlink,\n          event: 'unlink'\n        });\n        var content = '<a href=\"http://www.google.com\" target=\"_blank\">www.google.com</a>&nbsp;&nbsp;' +\n                      '<div class=\"note-insert btn-group\">' +\n                        linkButton + unlinkButton +\n                      '</div>';\n        return tplPopover('note-link-popover', content);\n      };\n\n      var tplImagePopover = function () {\n        var fullButton = tplButton('<span class=\"note-fontsize-10\">100%</span>', {\n          title: lang.image.resizeFull,\n          event: 'resize',\n          value: '1'\n        });\n        var halfButton = tplButton('<span class=\"note-fontsize-10\">50%</span>', {\n          title: lang.image.resizeHalf,\n          event: 'resize',\n          value: '0.5'\n        });\n        var quarterButton = tplButton('<span class=\"note-fontsize-10\">25%</span>', {\n          title: lang.image.resizeQuarter,\n          event: 'resize',\n          value: '0.25'\n        });\n\n        var leftButton = tplIconButton(options.iconPrefix + options.icons.image.floatLeft, {\n          title: lang.image.floatLeft,\n          event: 'floatMe',\n          value: 'left'\n        });\n        var rightButton = tplIconButton(options.iconPrefix + options.icons.image.floatRight, {\n          title: lang.image.floatRight,\n          event: 'floatMe',\n          value: 'right'\n        });\n        var justifyButton = tplIconButton(options.iconPrefix + options.icons.image.floatNone, {\n          title: lang.image.floatNone,\n          event: 'floatMe',\n          value: 'none'\n        });\n\n        var roundedButton = tplIconButton(options.iconPrefix + options.icons.image.shapeRounded, {\n          title: lang.image.shapeRounded,\n          event: 'imageShape',\n          value: 'img-rounded'\n        });\n        var circleButton = tplIconButton(options.iconPrefix + options.icons.image.shapeCircle, {\n          title: lang.image.shapeCircle,\n          event: 'imageShape',\n          value: 'img-circle'\n        });\n        var thumbnailButton = tplIconButton(options.iconPrefix + options.icons.image.shapeThumbnail, {\n          title: lang.image.shapeThumbnail,\n          event: 'imageShape',\n          value: 'img-thumbnail'\n        });\n        var noneButton = tplIconButton(options.iconPrefix + options.icons.image.shapeNone, {\n          title: lang.image.shapeNone,\n          event: 'imageShape',\n          value: ''\n        });\n\n        var removeButton = tplIconButton(options.iconPrefix + options.icons.image.remove, {\n          title: lang.image.remove,\n          event: 'removeMedia',\n          value: 'none'\n        });\n\n        var content = (options.disableResizeImage ? '' : '<div class=\"btn-group\">' + fullButton + halfButton + quarterButton + '</div>') +\n                      '<div class=\"btn-group\">' + leftButton + rightButton + justifyButton + '</div><br>' +\n                      '<div class=\"btn-group\">' + roundedButton + circleButton + thumbnailButton + noneButton + '</div>' +\n                      '<div class=\"btn-group\">' + removeButton + '</div>';\n        return tplPopover('note-image-popover', content);\n      };\n\n      var tplAirPopover = function () {\n        var $content = $('<div />');\n        for (var idx = 0, len = options.airPopover.length; idx < len; idx ++) {\n          var group = options.airPopover[idx];\n\n          var $group = $('<div class=\"note-' + group[0] + ' btn-group\">');\n          for (var i = 0, lenGroup = group[1].length; i < lenGroup; i++) {\n            var $button = $(tplButtonInfo[group[1][i]](lang, options));\n\n            $button.attr('data-name', group[1][i]);\n\n            $group.append($button);\n          }\n          $content.append($group);\n        }\n\n        return tplPopover('note-air-popover', $content.children());\n      };\n\n      var $notePopover = $('<div class=\"note-popover\" />');\n\n      $notePopover.append(tplLinkPopover());\n      $notePopover.append(tplImagePopover());\n\n      if (options.airMode) {\n        $notePopover.append(tplAirPopover());\n      }\n\n      return $notePopover;\n    };\n\n    var tplHandles = function (options) {\n      return '<div class=\"note-handle\">' +\n               '<div class=\"note-control-selection\">' +\n                 '<div class=\"note-control-selection-bg\"></div>' +\n                 '<div class=\"note-control-holder note-control-nw\"></div>' +\n                 '<div class=\"note-control-holder note-control-ne\"></div>' +\n                 '<div class=\"note-control-holder note-control-sw\"></div>' +\n                 '<div class=\"' +\n                 (options.disableResizeImage ? 'note-control-holder' : 'note-control-sizing') +\n                 ' note-control-se\"></div>' +\n                 (options.disableResizeImage ? '' : '<div class=\"note-control-selection-info\"></div>') +\n               '</div>' +\n             '</div>';\n    };\n\n    /**\n     * shortcut table template\n     * @param {String} title\n     * @param {String} body\n     */\n    var tplShortcut = function (title, keys) {\n      var keyClass = 'note-shortcut-col col-xs-6 note-shortcut-';\n      var body = [];\n\n      for (var i in keys) {\n        if (keys.hasOwnProperty(i)) {\n          body.push(\n            '<div class=\"' + keyClass + 'key\">' + keys[i].kbd + '</div>' +\n            '<div class=\"' + keyClass + 'name\">' + keys[i].text + '</div>'\n            );\n        }\n      }\n\n      return '<div class=\"note-shortcut-row row\"><div class=\"' + keyClass + 'title col-xs-offset-6\">' + title + '</div></div>' +\n             '<div class=\"note-shortcut-row row\">' + body.join('</div><div class=\"note-shortcut-row row\">') + '</div>';\n    };\n\n    var tplShortcutText = function (lang) {\n      var keys = [\n        { kbd: '⌘ + B', text: lang.font.bold },\n        { kbd: '⌘ + I', text: lang.font.italic },\n        { kbd: '⌘ + U', text: lang.font.underline },\n        { kbd: '⌘ + \\\\', text: lang.font.clear }\n      ];\n\n      return tplShortcut(lang.shortcut.textFormatting, keys);\n    };\n\n    var tplShortcutAction = function (lang) {\n      var keys = [\n        { kbd: '⌘ + Z', text: lang.history.undo },\n        { kbd: '⌘ + ⇧ + Z', text: lang.history.redo },\n        { kbd: '⌘ + ]', text: lang.paragraph.indent },\n        { kbd: '⌘ + [', text: lang.paragraph.outdent },\n        { kbd: '⌘ + ENTER', text: lang.hr.insert }\n      ];\n\n      return tplShortcut(lang.shortcut.action, keys);\n    };\n\n    var tplShortcutPara = function (lang) {\n      var keys = [\n        { kbd: '⌘ + ⇧ + L', text: lang.paragraph.left },\n        { kbd: '⌘ + ⇧ + E', text: lang.paragraph.center },\n        { kbd: '⌘ + ⇧ + R', text: lang.paragraph.right },\n        { kbd: '⌘ + ⇧ + J', text: lang.paragraph.justify },\n        { kbd: '⌘ + ⇧ + NUM7', text: lang.lists.ordered },\n        { kbd: '⌘ + ⇧ + NUM8', text: lang.lists.unordered }\n      ];\n\n      return tplShortcut(lang.shortcut.paragraphFormatting, keys);\n    };\n\n    var tplShortcutStyle = function (lang) {\n      var keys = [\n        { kbd: '⌘ + NUM0', text: lang.style.normal },\n        { kbd: '⌘ + NUM1', text: lang.style.h1 },\n        { kbd: '⌘ + NUM2', text: lang.style.h2 },\n        { kbd: '⌘ + NUM3', text: lang.style.h3 },\n        { kbd: '⌘ + NUM4', text: lang.style.h4 },\n        { kbd: '⌘ + NUM5', text: lang.style.h5 },\n        { kbd: '⌘ + NUM6', text: lang.style.h6 }\n      ];\n\n      return tplShortcut(lang.shortcut.documentStyle, keys);\n    };\n\n    var tplExtraShortcuts = function (lang, options) {\n      var extraKeys = options.extraKeys;\n      var keys = [];\n\n      for (var key in extraKeys) {\n        if (extraKeys.hasOwnProperty(key)) {\n          keys.push({ kbd: key, text: extraKeys[key] });\n        }\n      }\n\n      return tplShortcut(lang.shortcut.extraKeys, keys);\n    };\n\n    var tplShortcutTable = function (lang, options) {\n      var colClass = 'class=\"note-shortcut note-shortcut-col col-sm-6 col-xs-12\"';\n      var template = [\n        '<div ' + colClass + '>' + tplShortcutAction(lang, options) + '</div>' +\n        '<div ' + colClass + '>' + tplShortcutText(lang, options) + '</div>',\n        '<div ' + colClass + '>' + tplShortcutStyle(lang, options) + '</div>' +\n        '<div ' + colClass + '>' + tplShortcutPara(lang, options) + '</div>'\n      ];\n\n      if (options.extraKeys) {\n        template.push('<div ' + colClass + '>' + tplExtraShortcuts(lang, options) + '</div>');\n      }\n\n      return '<div class=\"note-shortcut-row row\">' +\n               template.join('</div><div class=\"note-shortcut-row row\">') +\n             '</div>';\n    };\n\n    var replaceMacKeys = function (sHtml) {\n      return sHtml.replace(/⌘/g, 'Ctrl').replace(/⇧/g, 'Shift');\n    };\n\n    var tplDialogInfo = {\n      image: function (lang, options) {\n        var imageLimitation = '';\n        if (options.maximumImageFileSize) {\n          var unit = Math.floor(Math.log(options.maximumImageFileSize) / Math.log(1024));\n          var readableSize = (options.maximumImageFileSize / Math.pow(1024, unit)).toFixed(2) * 1 +\n                             ' ' + ' KMGTP'[unit] + 'B';\n          imageLimitation = '<small>' + lang.image.maximumFileSize + ' : ' + readableSize + '</small>';\n        }\n\n        var body = '<div class=\"form-group row note-group-select-from-files\">' +\n                     '<label>' + lang.image.selectFromFiles + '</label>' +\n                     '<input class=\"note-image-input form-control\" type=\"file\" name=\"files\" accept=\"image/*\" multiple=\"multiple\" />' +\n                     imageLimitation +\n                   '</div>' +\n                   '<div class=\"form-group row\">' +\n                     '<label>' + lang.image.url + '</label>' +\n                     '<input class=\"note-image-url form-control col-md-12\" type=\"text\" />' +\n                   '</div>';\n        var footer = '<button href=\"#\" class=\"btn btn-primary note-image-btn disabled\" disabled>' + lang.image.insert + '</button>';\n        return tplDialog('note-image-dialog', lang.image.insert, body, footer);\n      },\n\n      link: function (lang, options) {\n        var body = '<div class=\"form-group row\">' +\n                     '<label>' + lang.link.textToDisplay + '</label>' +\n                     '<input class=\"note-link-text form-control col-md-12\" type=\"text\" />' +\n                   '</div>' +\n                   '<div class=\"form-group row\">' +\n                     '<label>' + lang.link.url + '</label>' +\n                     '<input class=\"note-link-url form-control col-md-12\" type=\"text\" value=\"http://\" />' +\n                   '</div>' +\n                   (!options.disableLinkTarget ?\n                     '<div class=\"checkbox\">' +\n                       '<label>' + '<input type=\"checkbox\" checked> ' +\n                         lang.link.openInNewWindow +\n                       '</label>' +\n                     '</div>' : ''\n                   );\n        var footer = '<button href=\"#\" class=\"btn btn-primary note-link-btn disabled\" disabled>' + lang.link.insert + '</button>';\n        return tplDialog('note-link-dialog', lang.link.insert, body, footer);\n      },\n\n      help: function (lang, options) {\n        var body = '<a class=\"modal-close pull-right\" aria-hidden=\"true\" tabindex=\"-1\">' + lang.shortcut.close + '</a>' +\n                   '<div class=\"title\">' + lang.shortcut.shortcuts + '</div>' +\n                   (agent.isMac ? tplShortcutTable(lang, options) : replaceMacKeys(tplShortcutTable(lang, options))) +\n                   '<p class=\"text-center\">' +\n                     '<a href=\"//summernote.org/\" target=\"_blank\">Summernote 0.6.16</a> · ' +\n                     '<a href=\"//github.com/summernote/summernote\" target=\"_blank\">Project</a> · ' +\n                     '<a href=\"//github.com/summernote/summernote/issues\" target=\"_blank\">Issues</a>' +\n                   '</p>';\n        return tplDialog('note-help-dialog', '', body, '');\n      }\n    };\n\n    var tplDialogs = function (lang, options) {\n      var dialogs = '';\n\n      $.each(tplDialogInfo, function (idx, tplDialog) {\n        dialogs += tplDialog(lang, options);\n      });\n\n      return '<div class=\"note-dialog\">' + dialogs + '</div>';\n    };\n\n    var tplStatusbar = function () {\n      return '<div class=\"note-resizebar\">' +\n               '<div class=\"note-icon-bar\"></div>' +\n               '<div class=\"note-icon-bar\"></div>' +\n               '<div class=\"note-icon-bar\"></div>' +\n             '</div>';\n    };\n\n    var representShortcut = function (str) {\n      if (agent.isMac) {\n        str = str.replace('CMD', '⌘').replace('SHIFT', '⇧');\n      }\n\n      return str.replace('BACKSLASH', '\\\\')\n                .replace('SLASH', '/')\n                .replace('LEFTBRACKET', '[')\n                .replace('RIGHTBRACKET', ']');\n    };\n\n    /**\n     * createTooltip\n     *\n     * @param {jQuery} $container\n     * @param {Object} keyMap\n     * @param {String} [sPlacement]\n     */\n    var createTooltip = function ($container, keyMap, sPlacement) {\n      var invertedKeyMap = func.invertObject(keyMap);\n      var $buttons = $container.find('button');\n\n      $buttons.each(function (i, elBtn) {\n        var $btn = $(elBtn);\n        var sShortcut = invertedKeyMap[$btn.data('event')];\n        if (sShortcut) {\n          $btn.attr('title', function (i, v) {\n            return v + ' (' + representShortcut(sShortcut) + ')';\n          });\n        }\n      // bootstrap tooltip on btn-group bug\n      // https://github.com/twbs/bootstrap/issues/5687\n      }).tooltip({\n        container: 'body',\n        trigger: 'hover',\n        placement: sPlacement || 'top'\n      }).on('click', function () {\n        $(this).tooltip('hide');\n      });\n    };\n\n    // createPalette\n    var createPalette = function ($container, options) {\n      var colorInfo = options.colors;\n      $container.find('.note-color-palette').each(function () {\n        var $palette = $(this), eventName = $palette.attr('data-target-event');\n        var paletteContents = [];\n        for (var row = 0, lenRow = colorInfo.length; row < lenRow; row++) {\n          var colors = colorInfo[row];\n          var buttons = [];\n          for (var col = 0, lenCol = colors.length; col < lenCol; col++) {\n            var color = colors[col];\n            buttons.push(['<button type=\"button\" class=\"note-color-btn\" style=\"background-color:', color,\n                           ';\" data-event=\"', eventName,\n                           '\" data-value=\"', color,\n                           '\" title=\"', color,\n                           '\" data-toggle=\"button\" tabindex=\"-1\"></button>'].join(''));\n          }\n          paletteContents.push('<div class=\"note-color-row\">' + buttons.join('') + '</div>');\n        }\n        $palette.html(paletteContents.join(''));\n      });\n    };\n\n    /**\n     * create summernote layout (air mode)\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayoutByAirMode = function ($holder, options) {\n      var langInfo = options.langInfo;\n      var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];\n      var id = func.uniqueId();\n\n      $holder.addClass('note-air-editor note-editable panel-body');\n      $holder.attr({\n        'id': 'note-editor-' + id,\n        'contentEditable': true\n      });\n\n      var body = document.body;\n\n      // create Popover\n      var $popover = $(tplPopovers(langInfo, options));\n      $popover.addClass('note-air-layout');\n      $popover.attr('id', 'note-popover-' + id);\n      $popover.appendTo(body);\n      createTooltip($popover, keyMap);\n      createPalette($popover, options);\n\n      // create Handle\n      var $handle = $(tplHandles(options));\n      $handle.addClass('note-air-layout');\n      $handle.attr('id', 'note-handle-' + id);\n      $handle.appendTo(body);\n\n      // create Dialog\n      var $dialog = $(tplDialogs(langInfo, options));\n      $dialog.addClass('note-air-layout');\n      $dialog.attr('id', 'note-dialog-' + id);\n      $dialog.find('button.close, a.modal-close').click(function () {\n        $(this).closest('.modal').modal('hide');\n      });\n      $dialog.appendTo(body);\n    };\n\n    /**\n     * create summernote layout (normal mode)\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayoutByFrame = function ($holder, options) {\n      var langInfo = options.langInfo;\n\n      //01. create Editor\n      var $editor = $('<div class=\"note-editor panel panel-default\" />');\n      if (options.width) {\n        $editor.width(options.width);\n      }\n\n      //02. statusbar (resizebar)\n      if (options.height > 0) {\n        $('<div class=\"note-statusbar\">' + (options.disableResizeEditor ? '' : tplStatusbar()) + '</div>').prependTo($editor);\n      }\n\n      //03 editing area\n      var $editingArea = $('<div class=\"note-editing-area\" />');\n      //03. create editable\n      var isContentEditable = !$holder.is(':disabled');\n      var $editable = $('<div class=\"note-editable panel-body\" contentEditable=\"' + isContentEditable + '\"></div>').prependTo($editingArea);\n      \n      if (options.height) {\n        $editable.height(options.height);\n      }\n      if (options.direction) {\n        $editable.attr('dir', options.direction);\n      }\n      var placeholder = $holder.attr('placeholder') || options.placeholder;\n      if (placeholder) {\n        $editable.attr('data-placeholder', placeholder);\n      }\n\n      $editable.html(dom.html($holder) || dom.emptyPara);\n\n      //031. create codable\n      $('<textarea class=\"note-codable\"></textarea>').prependTo($editingArea);\n\n      //04. create Popover\n      var $popover = $(tplPopovers(langInfo, options)).prependTo($editingArea);\n      createPalette($popover, options);\n      createTooltip($popover, keyMap);\n\n      //05. handle(control selection, ...)\n      $(tplHandles(options)).prependTo($editingArea);\n\n      $editingArea.prependTo($editor);\n\n      //06. create Toolbar\n      var $toolbar = $('<div class=\"note-toolbar panel-heading\" />');\n      for (var idx = 0, len = options.toolbar.length; idx < len; idx ++) {\n        var groupName = options.toolbar[idx][0];\n        var groupButtons = options.toolbar[idx][1];\n\n        var $group = $('<div class=\"note-' + groupName + ' btn-group\" />');\n        for (var i = 0, btnLength = groupButtons.length; i < btnLength; i++) {\n          var buttonInfo = tplButtonInfo[groupButtons[i]];\n          // continue creating toolbar even if a button doesn't exist\n          if (!$.isFunction(buttonInfo)) { continue; }\n\n          var $button = $(buttonInfo(langInfo, options));\n          $button.attr('data-name', groupButtons[i]);  // set button's alias, becuase to get button element from $toolbar\n          $group.append($button);\n        }\n        $toolbar.append($group);\n      }\n\n      var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];\n      createPalette($toolbar, options);\n      createTooltip($toolbar, keyMap, 'bottom');\n      $toolbar.prependTo($editor);\n\n      //07. create Dropzone\n      $('<div class=\"note-dropzone\"><div class=\"note-dropzone-message\"></div></div>').prependTo($editor);\n\n      //08. create Dialog\n      var $dialogContainer = options.dialogsInBody ? $(document.body) : $editor;\n      var $dialog = $(tplDialogs(langInfo, options)).prependTo($dialogContainer);\n      $dialog.find('button.close, a.modal-close').click(function () {\n        $(this).closest('.modal').modal('hide');\n      });\n\n      //09. Editor/Holder switch\n      $editor.insertAfter($holder);\n      $holder.hide();\n    };\n\n    this.hasNoteEditor = function ($holder) {\n      return this.noteEditorFromHolder($holder).length > 0;\n    };\n\n    this.noteEditorFromHolder = function ($holder) {\n      if ($holder.hasClass('note-air-editor')) {\n        return $holder;\n      } else if ($holder.next().hasClass('note-editor')) {\n        return $holder.next();\n      } else {\n        return $();\n      }\n    };\n\n    /**\n     * create summernote layout\n     *\n     * @param {jQuery} $holder\n     * @param {Object} options\n     */\n    this.createLayout = function ($holder, options) {\n      if (options.airMode) {\n        this.createLayoutByAirMode($holder, options);\n      } else {\n        this.createLayoutByFrame($holder, options);\n      }\n    };\n\n    /**\n     * returns layoutInfo from holder\n     *\n     * @param {jQuery} $holder - placeholder\n     * @return {Object}\n     */\n    this.layoutInfoFromHolder = function ($holder) {\n      var $editor = this.noteEditorFromHolder($holder);\n      if (!$editor.length) {\n        return;\n      }\n\n      // connect $holder to $editor\n      $editor.data('holder', $holder);\n\n      return dom.buildLayoutInfo($editor);\n    };\n\n    /**\n     * removeLayout\n     *\n     * @param {jQuery} $holder - placeholder\n     * @param {Object} layoutInfo\n     * @param {Object} options\n     *\n     */\n    this.removeLayout = function ($holder, layoutInfo, options) {\n      if (options.airMode) {\n        $holder.removeClass('note-air-editor note-editable')\n               .removeAttr('id contentEditable');\n\n        layoutInfo.popover().remove();\n        layoutInfo.handle().remove();\n        layoutInfo.dialog().remove();\n      } else {\n        $holder.html(layoutInfo.editable().html());\n\n        if (options.dialogsInBody) {\n          layoutInfo.dialog().remove();\n        }\n        layoutInfo.editor().remove();\n        $holder.show();\n      }\n    };\n\n    /**\n     *\n     * @return {Object}\n     * @return {function(label, options=):string} return.button {@link #tplButton function to make text button}\n     * @return {function(iconClass, options=):string} return.iconButton {@link #tplIconButton function to make icon button}\n     * @return {function(className, title=, body=, footer=):string} return.dialog {@link #tplDialog function to make dialog}\n     */\n    this.getTemplate = function () {\n      return {\n        button: tplButton,\n        iconButton: tplIconButton,\n        dialog: tplDialog\n      };\n    };\n\n    /**\n     * add button information\n     *\n     * @param {String} name button name\n     * @param {Function} buttonInfo function to make button, reference to {@link #tplButton},{@link #tplIconButton}\n     */\n    this.addButtonInfo = function (name, buttonInfo) {\n      tplButtonInfo[name] = buttonInfo;\n    };\n\n    /**\n     *\n     * @param {String} name\n     * @param {Function} dialogInfo function to make dialog, reference to {@link #tplDialog}\n     */\n    this.addDialogInfo = function (name, dialogInfo) {\n      tplDialogInfo[name] = dialogInfo;\n    };\n  };\n\n\n  // jQuery namespace for summernote\n  /**\n   * @class $.summernote \n   * \n   * summernote attribute  \n   * \n   * @mixin defaults\n   * @singleton  \n   * \n   */\n  $.summernote = $.summernote || {};\n\n  // extends default settings\n  //  - $.summernote.version\n  //  - $.summernote.options\n  //  - $.summernote.lang\n  $.extend($.summernote, defaults);\n\n  var renderer = new Renderer();\n  var eventHandler = new EventHandler();\n\n  $.extend($.summernote, {\n    /** @property {Renderer} */\n    renderer: renderer,\n    /** @property {EventHandler} */\n    eventHandler: eventHandler,\n    /** \n     * @property {Object} core \n     * @property {core.agent} core.agent \n     * @property {core.dom} core.dom\n     * @property {core.range} core.range \n     */\n    core: {\n      agent: agent,\n      list : list,\n      dom: dom,\n      range: range\n    },\n    /** \n     * @property {Object} \n     * pluginEvents event list for plugins\n     * event has name and callback function.\n     * \n     * ``` \n     * $.summernote.addPlugin({\n     *     events : {\n     *          'hello' : function(layoutInfo, value, $target) {\n     *              console.log('event name is hello, value is ' + value );\n     *          }\n     *     }     \n     * })\n     * ```\n     * \n     * * event name is data-event property.\n     * * layoutInfo is a summernote layout information.\n     * * value is data-value property.\n     */\n    pluginEvents: {},\n\n    plugins : []\n  });\n\n  /**\n   * @method addPlugin\n   *\n   * add Plugin in Summernote \n   * \n   * Summernote can make a own plugin.\n   *\n   * ### Define plugin\n   * ```\n   * // get template function  \n   * var tmpl = $.summernote.renderer.getTemplate();\n   * \n   * // add a button   \n   * $.summernote.addPlugin({\n   *     buttons : {\n   *        // \"hello\"  is button's namespace.      \n   *        \"hello\" : function(lang, options) {\n   *            // make icon button by template function          \n   *            return tmpl.iconButton(options.iconPrefix + 'header', {\n   *                // callback function name when button clicked \n   *                event : 'hello',\n   *                // set data-value property                 \n   *                value : 'hello',                \n   *                hide : true\n   *            });           \n   *        }\n   *     \n   *     }, \n   *     \n   *     events : {\n   *        \"hello\" : function(layoutInfo, value) {\n   *            // here is event code \n   *        }\n   *     }     \n   * });\n   * ``` \n   * ### Use a plugin in toolbar\n   * \n   * ``` \n   *    $(\"#editor\").summernote({\n   *    ...\n   *    toolbar : [\n   *        // display hello plugin in toolbar     \n   *        ['group', [ 'hello' ]]\n   *    ]\n   *    ...    \n   *    });\n   * ```\n   *  \n   *  \n   * @param {Object} plugin\n   * @param {Object} [plugin.buttons] define plugin button. for detail, see to Renderer.addButtonInfo\n   * @param {Object} [plugin.dialogs] define plugin dialog. for detail, see to Renderer.addDialogInfo\n   * @param {Object} [plugin.events] add event in $.summernote.pluginEvents \n   * @param {Object} [plugin.langs] update $.summernote.lang\n   * @param {Object} [plugin.options] update $.summernote.options\n   */\n  $.summernote.addPlugin = function (plugin) {\n\n    // save plugin list\n    $.summernote.plugins.push(plugin);\n\n    if (plugin.buttons) {\n      $.each(plugin.buttons, function (name, button) {\n        renderer.addButtonInfo(name, button);\n      });\n    }\n\n    if (plugin.dialogs) {\n      $.each(plugin.dialogs, function (name, dialog) {\n        renderer.addDialogInfo(name, dialog);\n      });\n    }\n\n    if (plugin.events) {\n      $.each(plugin.events, function (name, event) {\n        $.summernote.pluginEvents[name] = event;\n      });\n    }\n\n    if (plugin.langs) {\n      $.each(plugin.langs, function (locale, lang) {\n        if ($.summernote.lang[locale]) {\n          $.extend($.summernote.lang[locale], lang);\n        }\n      });\n    }\n\n    if (plugin.options) {\n      $.extend($.summernote.options, plugin.options);\n    }\n  };\n\n  /*\n   * extend $.fn\n   */\n  $.fn.extend({\n    /**\n     * @method\n     * Initialize summernote\n     *  - create editor layout and attach Mouse and keyboard events.\n     * \n     * ```\n     * $(\"#summernote\").summernote( { options ..} );\n     * ```\n     *   \n     * @member $.fn\n     * @param {Object|String} options reference to $.summernote.options\n     * @return {this}\n     */\n    summernote: function () {\n      // check first argument's type\n      //  - {String}: External API call {{module}}.{{method}}\n      //  - {Object}: init options\n      var type = $.type(list.head(arguments));\n      var isExternalAPICalled = type === 'string';\n      var hasInitOptions = type === 'object';\n\n      // extend default options with custom user options\n      var options = hasInitOptions ? list.head(arguments) : {};\n\n      options = $.extend({}, $.summernote.options, options);\n      options.icons = $.extend({}, $.summernote.options.icons, options.icons);\n\n      // Include langInfo in options for later use, e.g. for image drag-n-drop\n      // Setup language info with en-US as default\n      options.langInfo = $.extend(true, {}, $.summernote.lang['en-US'], $.summernote.lang[options.lang]);\n\n      // override plugin options\n      if (!isExternalAPICalled && hasInitOptions) {\n        for (var i = 0, len = $.summernote.plugins.length; i < len; i++) {\n          var plugin = $.summernote.plugins[i];\n\n          if (options.plugin[plugin.name]) {\n            $.summernote.plugins[i] = $.extend(true, plugin, options.plugin[plugin.name]);\n          }\n        }\n      }\n\n      this.each(function (idx, holder) {\n        var $holder = $(holder);\n\n        // if layout isn't created yet, createLayout and attach events\n        if (!renderer.hasNoteEditor($holder)) {\n          renderer.createLayout($holder, options);\n\n          var layoutInfo = renderer.layoutInfoFromHolder($holder);\n          $holder.data('layoutInfo', layoutInfo);\n\n          eventHandler.attach(layoutInfo, options);\n          eventHandler.attachCustomEvent(layoutInfo, options);\n        }\n      });\n\n      var $first = this.first();\n      if ($first.length) {\n        var layoutInfo = renderer.layoutInfoFromHolder($first);\n\n        // external API\n        if (isExternalAPICalled) {\n          var moduleAndMethod = list.head(list.from(arguments));\n          var args = list.tail(list.from(arguments));\n\n          // TODO now external API only works for editor\n          var params = [moduleAndMethod, layoutInfo.editable()].concat(args);\n          return eventHandler.invoke.apply(eventHandler, params);\n        } else if (options.focus) {\n          // focus on first editable element for initialize editor\n          layoutInfo.editable().focus();\n        }\n      }\n\n      return this;\n    },\n\n    /**\n     * @method \n     * \n     * get the HTML contents of note or set the HTML contents of note.\n     *\n     * * get contents \n     * ```\n     * var content = $(\"#summernote\").code();\n     * ```\n     * * set contents \n     *\n     * ```\n     * $(\"#summernote\").code(html);\n     * ```\n     *\n     * @member $.fn \n     * @param {String} [html] - HTML contents(optional, set)\n     * @return {this|String} - context(set) or HTML contents of note(get).\n     */\n    code: function (html) {\n      // get the HTML contents of note\n      if (html === undefined) {\n        var $holder = this.first();\n        if (!$holder.length) {\n          return;\n        }\n\n        var layoutInfo = renderer.layoutInfoFromHolder($holder);\n        var $editable = layoutInfo && layoutInfo.editable();\n\n        if ($editable && $editable.length) {\n          var isCodeview = eventHandler.invoke('codeview.isActivated', layoutInfo);\n          eventHandler.invoke('codeview.sync', layoutInfo);\n          return isCodeview ? layoutInfo.codable().val() :\n                              layoutInfo.editable().html();\n        }\n        return dom.value($holder);\n      }\n\n      // set the HTML contents of note\n      this.each(function (i, holder) {\n        var layoutInfo = renderer.layoutInfoFromHolder($(holder));\n        var $editable = layoutInfo && layoutInfo.editable();\n        if ($editable) {\n          $editable.html(html);\n        }\n      });\n\n      return this;\n    },\n\n    /**\n     * @method\n     * \n     * destroy Editor Layout and detach Key and Mouse Event\n     *\n     * @member $.fn\n     * @return {this}\n     */\n    destroy: function () {\n      this.each(function (idx, holder) {\n        var $holder = $(holder);\n\n        if (!renderer.hasNoteEditor($holder)) {\n          return;\n        }\n\n        var info = renderer.layoutInfoFromHolder($holder);\n        var options = info.editor().data('options');\n\n        eventHandler.detach(info, options);\n        renderer.removeLayout($holder, info, options);\n      });\n\n      return this;\n    }\n  });\n}));\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>cn.enilu</groupId>\n    <artifactId>material-admin</artifactId>\n    <packaging>pom</packaging>\n    <version>0.1</version>\n    <modules>\n        <module>material-core</module>\n        <module>material-manage</module>\n        <module>material-generator</module>\n        <module>material-lab</module>\n    </modules>\n\n    <properties>\n        <spring.boot.version>2.1.1.RELEASE</spring.boot.version>\n        <springframework.version>5.1.3.RELEASE</springframework.version>\n\n        <!-- Log libs -->\n        <slf4j.version>1.7.21</slf4j.version>\n        <logback.version>1.1.7</logback.version>\n        <!-- Test libs -->\n        <junit.version>4.12</junit.version>\n        <!--build libs-->\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n        <java_source_version>1.8</java_source_version>\n        <java_target_version>1.8</java_target_version>\n        <file_encoding>UTF-8</file_encoding>\n        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n        <!--driver libs-->\n        <mysql.connector.java.version>5.1.45</mysql.connector.java.version>\n        <!--auth libs-->\n        <shiro.version>1.4.0</shiro.version>\n        <spring.security.jwt.version>1.0.9.RELEASE</spring.security.jwt.version>\n        <spring.security.oauth2.version>2.2.0.RELEASE</spring.security.oauth2.version>\n        <!--util libs-->\n        <guava.version>20.0</guava.version>\n        <mail.version>1.4.7</mail.version>\n        <httpcomponents.version>4.4.1</httpcomponents.version>\n        <jackson.version>2.9.0</jackson.version>\n        <fastjson.version>1.2.44</fastjson.version>\n        <velocity.version>1.7</velocity.version>\n        <quartz.version>2.2.1</quartz.version>\n        <ehcache.version>3.3.1</ehcache.version>\n        <ehcache.core.version>2.10.5</ehcache.core.version>\n        <zxing.version>3.2.1</zxing.version>\n        <beetl.version>2.7.15</beetl.version>\n        <swagger.version>2.2.2</swagger.version>\n        <commons.io.version>2.5</commons.io.version>\n        <commons-lang3.version>3.6</commons-lang3.version>\n        <flowable.version>6.2.0</flowable.version>\n        <hutool.version>4.0.0</hutool.version>\n        <kaptcha.version>2.3.2</kaptcha.version>\n        <github.kaptcha.version>1.0.0</github.kaptcha.version>\n        <lombok.version>1.18.2</lombok.version>\n    </properties>\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-dependencies</artifactId>\n                <version>${spring.boot.version}</version>\n                <type>pom</type>\n                <scope>import</scope>\n            </dependency>\n            <dependency>\n                <groupId>org.projectlombok</groupId>\n                <artifactId>lombok</artifactId>\n                <scope>compile</scope>\n                <version>${lombok.version}</version>\n            </dependency>\n\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-data-jpa</artifactId>\n                <version>${spring.boot.version}</version>\n            </dependency>\n\n\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>druid-spring-boot-starter</artifactId>\n                <version>1.1.13</version>\n            </dependency>\n\n            <dependency>\n                <groupId>mysql</groupId>\n                <artifactId>mysql-connector-java</artifactId>\n                <version>${mysql.connector.java.version}</version>\n            </dependency>\n            <!--admin-->\n            <dependency>\n                <groupId>com.ibeetl</groupId>\n                <artifactId>beetl</artifactId>\n                <version>${beetl.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.springfox</groupId>\n                <artifactId>springfox-swagger2</artifactId>\n                <version>${swagger.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>io.springfox</groupId>\n                <artifactId>springfox-swagger-ui</artifactId>\n                <version>${swagger.version}</version>\n            </dependency>\n\n            <dependency>\n                <groupId>com.github.penggle</groupId>\n                <artifactId>kaptcha</artifactId>\n                <version>${kaptcha.version}</version>\n            </dependency>\n            <!--shiro依赖-->\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-core</artifactId>\n                <version>${shiro.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-spring</artifactId>\n                <version>${shiro.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.shiro</groupId>\n                <artifactId>shiro-ehcache</artifactId>\n                <version>${shiro.version}</version>\n            </dependency>\n\n            <dependency>\n                <groupId>commons-io</groupId>\n                <artifactId>commons-io</artifactId>\n                <version>${commons.io.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.commons</groupId>\n                <artifactId>commons-lang3</artifactId>\n                <version>${commons-lang3.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.zxing</groupId>\n                <artifactId>core</artifactId>\n                <version>${zxing.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.velocity</groupId>\n                <artifactId>velocity</artifactId>\n                <version>${velocity.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>fastjson</artifactId>\n                <version>${fastjson.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.flowable</groupId>\n                <artifactId>flowable-spring-boot-starter-basic</artifactId>\n                <version>${flowable.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.ehcache</groupId>\n                <artifactId>ehcache</artifactId>\n                <version>${ehcache.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>net.sf.ehcache.internal</groupId>\n                <artifactId>ehcache-core</artifactId>\n                <version>${ehcache.core.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-test</artifactId>\n                <scope>test</scope>\n                <version>${spring.boot.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.github.napp-com</groupId>\n                <artifactId>kaptcha</artifactId>\n                <version>${github.kaptcha.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-security</artifactId>\n                <version>${spring.boot.jpa.version}</version>\n            </dependency>\n\n            <dependency>\n                <groupId>org.springframework.security.oauth</groupId>\n                <artifactId>spring-security-oauth2</artifactId>\n                <version>${spring.security.oauth2.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-data-redis</artifactId>\n                <version>${spring.boot.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework.security</groupId>\n                <artifactId>spring-security-jwt</artifactId>\n                <version>${spring.security.jwt.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-context-support</artifactId>\n                <version>${springframework.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-messaging</artifactId>\n                <version>${springframework.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>guava</artifactId>\n                <version>${guava.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>javax.mail</groupId>\n                <artifactId>mail</artifactId>\n                <version>${mail.version}</version>\n            </dependency>\n            <!-- Http Lib -->\n            <dependency>\n                <groupId>org.apache.httpcomponents</groupId>\n                <artifactId>httpclient</artifactId>\n                <version>${httpcomponents.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.httpcomponents</groupId>\n                <artifactId>httpcore</artifactId>\n                <version>${httpcomponents.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.httpcomponents</groupId>\n                <artifactId>httpmime</artifactId>\n                <version>${httpcomponents.version}</version>\n            </dependency>\n\n            <!-- Http Lib End -->\n            <dependency>\n                <groupId>net.sourceforge.htmlunit</groupId>\n                <artifactId>htmlunit</artifactId>\n                <version>2.12</version>\n                <exclusions>\n                    <exclusion>\n                        <groupId>xml-apis</groupId>\n                        <artifactId>xml-apis</artifactId>\n                    </exclusion>\n                </exclusions>\n            </dependency>\n            <dependency>\n                <groupId>commons-httpclient</groupId>\n                <artifactId>commons-httpclient</artifactId>\n                <version>3.1</version>\n            </dependency>\n\n            <!-- json lib-->\n\n            <dependency>\n                <groupId>com.fasterxml.jackson.core</groupId>\n                <artifactId>jackson-annotations</artifactId>\n                <version>${jackson.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.fasterxml.jackson.core</groupId>\n                <artifactId>jackson-core</artifactId>\n                <version>${jackson.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>com.fasterxml.jackson.core</groupId>\n                <artifactId>jackson-databind</artifactId>\n                <version>${jackson.version}</version>\n            </dependency>\n\n            <dependency>\n                <groupId>eu.bitwalker</groupId>\n                <artifactId>UserAgentUtils</artifactId>\n                <version>1.21</version>\n            </dependency>\n\n            <dependency>\n                <groupId>nl.bitwalker</groupId>\n                <artifactId>UserAgentUtils</artifactId>\n                <version>1.2.4</version>\n            </dependency>\n\n            <dependency>\n                <groupId>org.springframework.boot</groupId>\n                <artifactId>spring-boot-starter-jdbc</artifactId>\n                <version>${spring.boot.version}</version>\n            </dependency>\n\n            <dependency>\n                <groupId>org.quartz-scheduler</groupId>\n                <artifactId>quartz</artifactId>\n                <version>${quartz.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.quartz-scheduler</groupId>\n                <artifactId>quartz-jobs</artifactId>\n                <version>${quartz.version}</version>\n            </dependency>\n            <dependency>\n                <groupId>org.nutz</groupId>\n                <artifactId>nutz</artifactId>\n                <version>1.r.60</version>\n            </dependency>\n            <!-- message  start-->\n            <dependency>\n                <groupId>com.github.qcloudsms</groupId>\n                <artifactId>qcloudsms</artifactId>\n                <version>1.0.6</version>\n            </dependency>\n            <!-- message end-->\n        </dependencies>\n\n    </dependencyManagement>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <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            </plugin>\n        </plugins>\n    </build>\n\n</project>"
  }
]